VLCHTTPConnection.m 26.5 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12
/*****************************************************************************
 * VLCHTTPConnection.m
 * VLC for iOS
 *****************************************************************************
 * Copyright (c) 2013 VideoLAN. All rights reserved.
 * $Id$
 *
 * Authors: Felix Paul Kühne <fkuehne # videolan.org>
 *          Jean-Baptiste Kempf <jb # videolan.org>
 *
 * Refer to the COPYING file of the official project for license.
 *****************************************************************************/
13 14 15 16 17 18 19 20 21

#import "VLCAppDelegate.h"
#import "VLCHTTPConnection.h"
#import "HTTPConnection.h"
#import "MultipartFormDataParser.h"
#import "HTTPMessage.h"
#import "HTTPDataResponse.h"
#import "HTTPFileResponse.h"
#import "MultipartMessageHeaderField.h"
22
#import "VLCHTTPUploaderController.h"
23
#import "HTTPDynamicFileResponse.h"
24
#import "VLCThumbnailsCache.h"
25
#import "NSString+SupportedMedia.h"
26 27 28

@interface VLCHTTPConnection()
{
29 30 31
    MultipartFormDataParser *_parser;
    NSFileHandle *_storeFile;
    NSString *_filepath;
32 33
    UInt64 _contentLength;
    UInt64 _receivedContent;
34
}
35 36 37

@property (nonatomic) VLCHTTPUploaderController *uploadController;

38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
@end

@implementation VLCHTTPConnection

- (BOOL)supportsMethod:(NSString *)method atPath:(NSString *)path
{
    // Add support for POST
    if ([method isEqualToString:@"POST"]) {
        if ([path isEqualToString:@"/upload.json"])
            return YES;
    }

    return [super supportsMethod:method atPath:path];
}

- (BOOL)expectsRequestBodyFromMethod:(NSString *)method atPath:(NSString *)path
{
    // Inform HTTP server that we expect a body to accompany a POST request
    if ([method isEqualToString:@"POST"] && [path isEqualToString:@"/upload.json"]) {
        // here we need to make sure, boundary is set in header
        NSString* contentType = [request headerField:@"Content-Type"];
        NSUInteger paramsSeparator = [contentType rangeOfString:@";"].location;
        if (NSNotFound == paramsSeparator)
            return NO;

        if (paramsSeparator >= contentType.length - 1)
            return NO;

        NSString* type = [contentType substringToIndex:paramsSeparator];
        if (![type isEqualToString:@"multipart/form-data"]) {
            // we expect multipart/form-data content type
            return NO;
        }

        // enumerate all params in content-type, and find boundary there
        NSArray* params = [[contentType substringFromIndex:paramsSeparator + 1] componentsSeparatedByString:@";"];
        for (NSString* param in params) {
            paramsSeparator = [param rangeOfString:@"="].location;
            if ((NSNotFound == paramsSeparator) || paramsSeparator >= param.length - 1)
                continue;

            NSString* paramName = [param substringWithRange:NSMakeRange(1, paramsSeparator-1)];
            NSString* paramValue = [param substringFromIndex:paramsSeparator+1];

            if ([paramName isEqualToString: @"boundary"])
                // let's separate the boundary from content-type, to make it more handy to handle
                [request setHeaderField:@"boundary" value:paramValue];
        }
        // check if boundary specified
        if (nil == [request headerField:@"boundary"])
            return NO;

        return YES;
    }
    return [super expectsRequestBodyFromMethod:method atPath:path];
}

- (NSObject<HTTPResponse> *)httpResponseForMethod:(NSString *)method URI:(NSString *)path
{
    if ([method isEqualToString:@"POST"] && [path isEqualToString:@"/upload.json"]) {
        return [[HTTPDataResponse alloc] initWithData:[@"\"OK\"" dataUsingEncoding:NSUTF8StringEncoding]];
    }
100 101
    if ([path hasPrefix:@"/download/"]) {
        NSString *filePath = [[path stringByReplacingOccurrencesOfString:@"/download/" withString:@""]stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
102 103 104
        HTTPFileResponse *fileResponse = [[HTTPFileResponse alloc] initWithFilePath:filePath forConnection:self];
        fileResponse.contentType = @"application/octet-stream";
        return fileResponse;
105
    }
106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122
    if ([path hasPrefix:@"/thumbnail"]) {
        NSString *filePath = [[path stringByReplacingOccurrencesOfString:@"/thumbnail/" withString:@""]stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
        filePath = [filePath stringByReplacingOccurrencesOfString:@".png" withString:@""];

        NSManagedObjectContext *moc = [[MLMediaLibrary sharedMediaLibrary] managedObjectContext];
        NSPersistentStoreCoordinator *psc = [moc persistentStoreCoordinator];
        NSManagedObject *mo = [moc existingObjectWithID:[psc managedObjectIDForURIRepresentation:[NSURL URLWithString:filePath]] error:nil];

        NSData *theData;
        if ([mo isKindOfClass:[MLFile class]])
            theData = UIImagePNGRepresentation([VLCThumbnailsCache thumbnailForMediaFile:(MLFile *)mo]);
        else if ([mo isKindOfClass:[MLShow class]])
            theData = UIImagePNGRepresentation([VLCThumbnailsCache thumbnailForShow:(MLShow *)mo]);
        else if ([mo isKindOfClass:[MLLabel class]])
            theData = UIImagePNGRepresentation([VLCThumbnailsCache thumbnailForLabel:(MLLabel *)mo]);
        else if ([mo isKindOfClass:[MLAlbum class]])
            theData = UIImagePNGRepresentation([VLCThumbnailsCache thumbnailForMediaFile:[[(MLAlbum *)mo tracks].anyObject files].anyObject]);
123 124 125 126
        else if ([mo isKindOfClass:[MLAlbumTrack class]])
            theData = UIImagePNGRepresentation([VLCThumbnailsCache thumbnailForMediaFile:[(MLAlbumTrack *)mo files].anyObject]);
        else if ([mo isKindOfClass:[MLShowEpisode class]])
            theData = UIImagePNGRepresentation([VLCThumbnailsCache thumbnailForMediaFile:[(MLShowEpisode *)mo files].anyObject]);
127

128 129 130 131 132
        if (theData) {
            HTTPDataResponse *dataResponse = [[HTTPDataResponse alloc] initWithData:theData];
            dataResponse.contentType = @"image/png";
            return dataResponse;
        }
133
    }
134 135 136 137
    NSString *filePath = [self filePathForURI:path];
    NSString *documentRoot = [config documentRoot];
    NSString *relativePath = [filePath substringFromIndex:[documentRoot length]];

138
    if (([relativePath isEqualToString:@"/index.html"]) || ([relativePath isEqualToString:@"/libMediaVLC.xml"])) {
139 140 141
        NSMutableArray *allMedia = [[NSMutableArray alloc] init];

        /* add all albums */
142 143
        NSArray *allAlbums = [MLAlbum allAlbums];
        for (MLAlbum *album in allAlbums) {
144 145
            if (album.name.length > 0 && album.tracks.count > 1)
                [allMedia addObject:album];
146
        }
147 148

        /* add all shows */
149 150
        NSArray *allShows = [MLShow allShows];
        for (MLShow *show in allShows) {
151 152
            if (show.name.length > 0 && show.episodes.count > 1)
                [allMedia addObject:show];
153
        }
154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176

        /* add all folders*/
        NSArray *allFolders = [MLLabel allLabels];
        for (MLLabel *folder in allFolders)
            [allMedia addObject:folder];

        /* add all remaining files */
        NSArray *allFiles = [MLFile allFiles];
        for (MLFile *file in allFiles) {
            if (file.labels.count > 0) continue;

            if (!file.isShowEpisode && !file.isAlbumTrack)
                [allMedia addObject:file];
            else if (file.isShowEpisode) {
                if (file.showEpisode.show.episodes.count < 2)
                    [allMedia addObject:file];
            } else if (file.isAlbumTrack) {
                if (file.albumTrack.album.tracks.count < 2)
                    [allMedia addObject:file];
            }
        }

        NSMutableArray *mediaInHtml = [[NSMutableArray alloc] initWithCapacity:allMedia.count];
177 178 179
        NSMutableArray *mediaInXml = [[NSMutableArray alloc] initWithCapacity:allMedia.count];
        self.uploadController = [[VLCHTTPUploaderController alloc] init];
        NSString *hostName = [self.uploadController hostname];
180
        NSString *pathLibrary = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) objectAtIndex:0];
181
        NSString *duration;
182 183

        for (NSManagedObject *mo in allMedia) {
184
            if ([mo isKindOfClass:[MLFile class]]) {
185
                duration = [[VLCTime timeWithNumber:[(MLFile *)mo duration]] stringValue];
186 187
                [mediaInHtml addObject:[NSString stringWithFormat:
                                        @"<div style=\"background-image:url('thumbnail/%@.png')\"> \
188
                                        <a href=\"download/%@\" class=\"inner\"> \
189 190 191
                                        <div class=\"down icon\"></div> \
                                        <div class=\"infos\"> \
                                        <span class=\"first-line\">%@</span> \
192
                                        <span class=\"second-line\">%@ - %0.2f MB</span> \
193 194 195 196 197
                                        </div> \
                                        </a> \
                                        </div>",
                                        mo.objectID.URIRepresentation,
                                        [[(MLFile *)mo url] stringByReplacingOccurrencesOfString:@"file://"withString:@""],
198 199
                                        [(MLFile *)mo title],
                                        duration, (float)([(MLFile *)mo fileSizeInBytes] / 1e6)]];
200 201 202 203 204 205
                if ([relativePath isEqualToString:@"/libMediaVLC.xml"]) {
                    NSString *pathSub = [self _checkSubtitleFound:[(MLFile *)mo url]];
                    if (![pathSub isEqualToString:@""])
                        pathSub = [NSString stringWithFormat:@"http://%@/download/%@", hostName, pathSub];
                    [mediaInXml addObject:[NSString stringWithFormat:@"<Media title=\"%@\" thumb=\"http://%@/download/%@/Thumbnails/File/%@.png\" duration=\"%@\" size=\"%li\" pathfile=\"http://%@/download/%@\" pathSubtitle=\"%@\"/>", [(MLFile *)mo title], hostName, pathLibrary, [[NSString stringWithFormat:@"%@", mo.objectID.URIRepresentation] lastPathComponent], duration, [(MLFile *)mo fileSizeInBytes], hostName, [[(MLFile *)mo url] stringByReplacingOccurrencesOfString:@"file://"withString:@""], pathSub]];
                }
206
            }
207 208
            else if ([mo isKindOfClass:[MLShow class]]) {
                NSArray *episodes = [(MLShow *)mo sortedEpisodes];
209 210
                [mediaInHtml addObject:[NSString stringWithFormat:
                                        @"<div style=\"background-image:url('thumbnail/%@.png')\"> \
211
                                        <a href=\"#\" class=\"inner folder\"> \
212 213 214
                                        <div class=\"open icon\"></div> \
                                        <div class=\"infos\"> \
                                        <span class=\"first-line\">%@</span> \
Felix Paul Kühne's avatar
Felix Paul Kühne committed
215
                                        <span class=\"second-line\">%lu items</span> \
216 217 218 219
                                        </div> \
                                        </a> \
                                        <div class=\"content\">",
                                        mo.objectID.URIRepresentation,
220
                                        [(MLShow *)mo name],
Felix Paul Kühne's avatar
Felix Paul Kühne committed
221
                                        (unsigned long)[episodes count]]];
222
                for (MLShowEpisode *showEp in episodes) {
223
                    duration = [[VLCTime timeWithNumber:[(MLFile *)[[showEp files] anyObject] duration]] stringValue];
224 225
                    [mediaInHtml addObject:[NSString stringWithFormat:
                                            @"<div style=\"background-image:url('thumbnail/%@.png')\"> \
226
                                            <a href=\"download/%@\" class=\"inner\"> \
227 228 229
                                            <div class=\"down icon\"></div> \
                                            <div class=\"infos\"> \
                                            <span class=\"first-line\">S%@E%@ - %@</span> \
230
                                            <span class=\"second-line\">%@ - %0.2f MB</span> \
231 232 233 234 235 236 237
                                            </div> \
                                            </a> \
                                            </div>",
                                            showEp.objectID.URIRepresentation,
                                            [[(MLFile *)[[showEp files] anyObject] url] stringByReplacingOccurrencesOfString:@"file://"withString:@""],
                                            showEp.seasonNumber,
                                            showEp.episodeNumber,
238 239
                                            showEp.name,
                                            duration, (float)([(MLFile *)[[showEp files] anyObject] fileSizeInBytes] / 1e6)]];
240 241 242 243 244 245
                    if ([relativePath isEqualToString:@"/libMediaVLC.xml"]) {
                        NSString *pathSub = [self _checkSubtitleFound:[(MLFile *)[[showEp files] anyObject] url]];
                        if (![pathSub isEqualToString:@""])
                            pathSub = [NSString stringWithFormat:@"http://%@/download/%@", hostName, pathSub];
                        [mediaInXml addObject:[NSString stringWithFormat:@"<Media title=\"%@ - S%@E%@\" thumb=\"http://%@/download/%@/Thumbnails/File/%@.png\" duration=\"%@\" size=\"%li\" pathfile=\"http://%@/download/%@\" pathSubtitle=\"%@\"/>", [(MLShow *)mo name], showEp.seasonNumber, showEp.episodeNumber, hostName, pathLibrary, [[NSString stringWithFormat:@"%@", showEp.objectID.URIRepresentation] lastPathComponent], duration, [(MLFile *)[[showEp files] anyObject] fileSizeInBytes], hostName, [[(MLFile *)[[showEp files] anyObject] url] stringByReplacingOccurrencesOfString:@"file://"withString:@""], pathSub]];
                    }
246
                }
247
                [mediaInHtml addObject:@"</div></div>"];
248 249
            } else if ([mo isKindOfClass:[MLLabel class]]) {
                NSArray *folderItems = [(MLLabel *)mo sortedFolderItems];
250 251
                [mediaInHtml addObject:[NSString stringWithFormat:
                                        @"<div style=\"background-image:url('thumbnail/%@.png')\"> \
252
                                        <a href=\"#\" class=\"inner folder\"> \
253 254 255
                                        <div class=\"open icon\"></div> \
                                        <div class=\"infos\"> \
                                        <span class=\"first-line\">%@</span> \
Felix Paul Kühne's avatar
Felix Paul Kühne committed
256
                                        <span class=\"second-line\">%lu items</span> \
257 258 259 260
                                        </div> \
                                        </a> \
                                        <div class=\"content\">",
                                        mo.objectID.URIRepresentation,
261
                                        [(MLLabel *)mo name],
Felix Paul Kühne's avatar
Felix Paul Kühne committed
262
                                        (unsigned long)[folderItems count]]];
263
                for (MLFile *file in folderItems) {
264
                    duration = [[VLCTime timeWithNumber:[file duration]] stringValue];
265 266
                    [mediaInHtml addObject:[NSString stringWithFormat:
                                            @"<div style=\"background-image:url('thumbnail/%@.png')\"> \
267
                                            <a href=\"download/%@\" class=\"inner\"> \
268 269 270
                                            <div class=\"down icon\"></div> \
                                            <div class=\"infos\"> \
                                            <span class=\"first-line\">%@</span> \
271
                                            <span class=\"second-line\">%@ - %0.2f MB</span> \
272 273 274 275 276
                                            </div> \
                                            </a> \
                                            </div>",
                                            file.objectID.URIRepresentation,
                                            [[file url] stringByReplacingOccurrencesOfString:@"file://"withString:@""],
277 278
                                            file.title,
                                            duration, (float)([file fileSizeInBytes] / 1e6)]];
279 280 281 282 283 284
                    if ([relativePath isEqualToString:@"/libMediaVLC.xml"]) {
                        NSString *pathSub = [self _checkSubtitleFound:[file url]];
                        if (![pathSub isEqualToString:@""])
                            pathSub = [NSString stringWithFormat:@"http://%@/download/%@", hostName, pathSub];
                        [mediaInXml addObject:[NSString stringWithFormat:@"<Media title=\"%@\" thumb=\"http://%@/download/%@/Thumbnails/File/%@.png\" duration=\"%@\" size=\"%li\" pathfile=\"http://%@/download/%@\" pathSubtitle=\"%@\"/>", file.title, hostName, pathLibrary, [[NSString stringWithFormat:@"%@", file.objectID.URIRepresentation] lastPathComponent], duration, [file fileSizeInBytes], hostName, [[file url] stringByReplacingOccurrencesOfString:@"file://"withString:@""], pathSub]];
                    }
285
                }
286
                [mediaInHtml addObject:@"</div></div>"];
287 288
            } else if ([mo isKindOfClass:[MLAlbum class]]) {
                NSArray *albumTracks = [(MLAlbum *)mo sortedTracks];
289 290
                [mediaInHtml addObject:[NSString stringWithFormat:
                                        @"<div style=\"background-image:url('thumbnail/%@.png')\"> \
291
                                        <a href=\"#\" class=\"inner folder\"> \
292 293 294
                                        <div class=\"open icon\"></div> \
                                        <div class=\"infos\"> \
                                        <span class=\"first-line\">%@</span> \
Felix Paul Kühne's avatar
Felix Paul Kühne committed
295
                                        <span class=\"second-line\">%lu items</span> \
296 297 298 299
                                        </div> \
                                        </a> \
                                        <div class=\"content\">",
                                        mo.objectID.URIRepresentation,
300
                                        [(MLAlbum *)mo name],
Felix Paul Kühne's avatar
Felix Paul Kühne committed
301
                                        (unsigned long)[albumTracks count]]];
302
                for (MLAlbumTrack *track in albumTracks) {
303
                    duration = [[VLCTime timeWithNumber:[(MLFile *)[[track files] anyObject] duration]] stringValue];
304 305
                    [mediaInHtml addObject:[NSString stringWithFormat:
                                            @"<div style=\"background-image:url('thumbnail/%@.png')\"> \
306
                                            <a href=\"download/%@\" class=\"inner\"> \
307 308 309
                                            <div class=\"down icon\"></div> \
                                            <div class=\"infos\"> \
                                            <span class=\"first-line\">%@</span> \
310
                                            <span class=\"second-line\">%@ - %0.2f MB</span> \
311 312 313 314 315
                                            </div> \
                                            </a> \
                                            </div>",
                                            track.objectID.URIRepresentation,
                                            [[(MLFile *)[[track files] anyObject] url] stringByReplacingOccurrencesOfString:@"file://"withString:@""],
316 317
                                            track.title,
                                            duration, (float)([(MLFile *)[[track files] anyObject] fileSizeInBytes] / 1e6)]];
318 319
                    if ([relativePath isEqualToString:@"/libMediaVLC.xml"])
                        [mediaInXml addObject:[NSString stringWithFormat:@"<Media title=\"%@\" thumb=\"http://%@/download/%@/Thumbnails/File/%@.png\" duration=\"%@\" size=\"%li\" pathfile=\"http://%@/download/%@\" pathSubtitle=\"\"/>", track.title, hostName, pathLibrary, [[NSString stringWithFormat:@"%@", track.objectID.URIRepresentation] lastPathComponent], duration, [(MLFile *)[[track files] anyObject] fileSizeInBytes], hostName, [[(MLFile *)[[track files] anyObject] url] stringByReplacingOccurrencesOfString:@"file://"withString:@""]]];
320
                }
321
                [mediaInHtml addObject:@"</div></div>"];
322
            }
323
        }
324

325
        NSString *deviceModel = [[UIDevice currentDevice] model];
326 327 328 329 330 331 332 333 334 335 336 337 338
        NSDictionary *replacementDict;

        if ([relativePath isEqualToString:@"/libMediaVLC.xml"]) {
            replacementDict = @{@"FILES" : [mediaInXml componentsJoinedByString:@" "],
                                @"NB_FILE" : [NSString stringWithFormat:@"%li", (unsigned long)mediaInXml.count],
                                @"LIB_TITLE" : [[UIDevice currentDevice] name]};
        } else
            replacementDict = @{@"FILES" : [mediaInHtml componentsJoinedByString:@" "],
                                @"WEBINTF_TITLE" : NSLocalizedString(@"WEBINTF_TITLE", nil),
                                @"WEBINTF_DROPFILES" : NSLocalizedString(@"WEBINTF_DROPFILES", nil),
                                @"WEBINTF_DROPFILES_LONG" : [NSString stringWithFormat:NSLocalizedString(@"WEBINTF_DROPFILES_LONG", nil), deviceModel],
                                @"WEBINTF_DOWNLOADFILES" : NSLocalizedString(@"WEBINTF_DOWNLOADFILES", nil),
                                @"WEBINTF_DOWNLOADFILES_LONG" : [NSString stringWithFormat: NSLocalizedString(@"WEBINTF_DOWNLOADFILES_LONG", nil), deviceModel]};
339 340 341 342 343 344

        return [[HTTPDynamicFileResponse alloc] initWithFilePath:[self filePathForURI:path]
                                                   forConnection:self
                                                       separator:@"%%"
                                           replacementDictionary:replacementDict];
    } else if ([relativePath isEqualToString:@"/style.css"]) {
345
        NSDictionary *replacementDict = @{@"WEBINTF_TITLE" : NSLocalizedString(@"WEBINTF_TITLE", nil)};
346 347 348 349 350
        return [[HTTPDynamicFileResponse alloc] initWithFilePath:[self filePathForURI:path]
                                                   forConnection:self
                                                       separator:@"%%"
                                           replacementDictionary:replacementDict];
    }
351

352 353 354 355 356 357 358 359 360 361
    return [super httpResponseForMethod:method URI:path];
}

- (void)prepareForBodyWithSize:(UInt64)contentLength
{
    // set up mime parser
    NSString* boundary = [request headerField:@"boundary"];
    _parser = [[MultipartFormDataParser alloc] initWithBoundary:boundary formEncoding:NSUTF8StringEncoding];
    _parser.delegate = self;

362 363
    APLog(@"expecting file of size %lli kB", contentLength / 1024);
    _contentLength = contentLength;
364 365 366 367 368 369 370
}

- (void)processBodyData:(NSData *)postDataChunk
{
    /* append data to the parser. It will invoke callbacks to let us handle
     * parsed data. */
    [_parser appendData:postDataChunk];
371

372
    _receivedContent += postDataChunk.length;
373

374
    APLog(@"received %lli kB (%lli %%)", _receivedContent / 1024, ((_receivedContent * 100) / _contentLength));
375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394
}

//-----------------------------------------------------------------
#pragma mark multipart form data parser delegate


- (void)processStartOfPartWithHeader:(MultipartMessageHeader*) header
{
    /* in this sample, we are not interested in parts, other then file parts.
     * check content disposition to find out filename */

    MultipartMessageHeaderField* disposition = (header.fields)[@"Content-Disposition"];
    NSString* filename = [(disposition.params)[@"filename"] lastPathComponent];

    if ((nil == filename) || [filename isEqualToString: @""]) {
        // it's either not a file part, or
        // an empty form sent. we won't handle it.
        return;
    }

395
    // create the path where to store the media temporarily
396
    NSArray *searchPaths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
397
    NSString* uploadDirPath = [searchPaths[0] stringByAppendingPathComponent:@"Upload"];
398
    NSFileManager *fileManager = [NSFileManager defaultManager];
399 400

    BOOL isDir = YES;
401 402
    if (![fileManager fileExistsAtPath:uploadDirPath isDirectory:&isDir ]) {
        [fileManager createDirectoryAtPath:uploadDirPath withIntermediateDirectories:YES attributes:nil error:nil];
403 404
    }

405
    _filepath = [uploadDirPath stringByAppendingPathComponent: filename];
406

407
    APLog(@"Saving file to %@", _filepath);
408
    if (![fileManager createDirectoryAtPath:uploadDirPath withIntermediateDirectories:true attributes:nil error:nil])
409
        APLog(@"Could not create directory at path: %@", _filepath);
410

411
    if (![fileManager createFileAtPath:_filepath contents:nil attributes:nil])
412
        APLog(@"Could not create file at path: %@", _filepath);
413

414
    _storeFile = [NSFileHandle fileHandleForWritingAtPath:_filepath];
415
    [(VLCAppDelegate*)[UIApplication sharedApplication].delegate networkActivityStarted];
416
    [(VLCAppDelegate*)[UIApplication sharedApplication].delegate disableIdleTimer];
417 418 419 420 421
}

- (void)processContent:(NSData*)data WithHeader:(MultipartMessageHeader*) header
{
    // here we just write the output from parser to the file.
422 423 424 425 426 427 428 429 430 431 432 433 434
    if (_storeFile) {
        @try {
            [_storeFile writeData:data];
        }
        @catch (NSException *exception) {
            APLog(@"File to write further data because storage is full.");
            [_storeFile closeFile];
            _storeFile = nil;
            /* don't block */
            [self performSelector:@selector(stop) withObject:nil afterDelay:0.1];
        }
    }

435 436 437 438 439
}

- (void)processEndOfPartWithHeader:(MultipartMessageHeader*)header
{
    // as the file part is over, we close the file.
440
    APLog(@"closing file");
441 442 443 444
    [_storeFile closeFile];
    _storeFile = nil;
}

445
- (BOOL)shouldDie
446
{
447 448 449
    if (_filepath) {
        if (_filepath.length > 0)
            [[(VLCAppDelegate*)[UIApplication sharedApplication].delegate uploadController] moveFileFrom:_filepath];
450
    }
451
    return [super shouldDie];
452 453
}

454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484
#pragma mark subtitle

- (NSMutableArray *)_listOfSubtitle
{
    NSMutableArray *listOfSubtitle = [[NSMutableArray alloc] init];
    NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
    NSArray *allfiles = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:documentsDirectory error:nil];
    NSString *filePath;
    for (int count = 0; count < allfiles.count; count++) {
        filePath = [[NSString stringWithFormat:@"%@/%@", documentsDirectory, allfiles[count]] stringByReplacingOccurrencesOfString:@"file://"withString:@""];
        if ([filePath isSupportedSubtitleFormat])
            [listOfSubtitle addObject:filePath];
    }
    return listOfSubtitle;
}

- (NSString *)_checkSubtitleFound:(NSString *)fileURL
{
    NSString *subtitlePath = @"";
    NSString *fileName = [[fileURL lastPathComponent] stringByDeletingPathExtension];
    NSMutableArray *listOfSubtitle = [[NSMutableArray alloc] init];
    listOfSubtitle = [self _listOfSubtitle];
    NSString *fileSub;
    for (int count = 0; count < listOfSubtitle.count; count++) {
        fileSub = [NSString stringWithFormat:@"%@", listOfSubtitle[count]];
        if ([fileSub rangeOfString:fileName].location != NSNotFound)
            subtitlePath = [listOfSubtitle objectAtIndex:count];
    }
    return subtitlePath;
}

485
@end