Commit 70606d95 authored by Pierre's avatar Pierre

MLFile: Make sure each file gets parsed, and expose the parsed meta data.

parent 20f288d9
......@@ -25,25 +25,27 @@ extern NSString *kMLFileTypeTVShowEpisode;
- (BOOL)isClip;
- (BOOL)isShowEpisode;
@property (nonatomic, retain) NSNumber * seasonNumber;
@property (nonatomic, retain) NSNumber * remainingTime;
@property (nonatomic, retain) NSString * releaseYear;
@property (nonatomic, retain) NSNumber * lastPosition;
@property (nonatomic, retain) NSNumber * playCount;
@property (nonatomic, retain) NSString * artworkURL;
@property (nonatomic, retain) NSString * url;
@property (nonatomic, retain) NSString * type;
@property (nonatomic, retain) NSString * title;
@property (nonatomic, retain) NSString * shortSummary;
@property (nonatomic, retain) NSNumber * currentlyWatching;
@property (nonatomic, retain) NSNumber * episodeNumber;
@property (nonatomic, retain) NSNumber * unread;
@property (nonatomic, retain) NSNumber * hasFetchedInfo;
@property (nonatomic, retain) NSNumber * noOnlineMetaData;
@property (nonatomic, retain) NSNumber *seasonNumber;
@property (nonatomic, retain) NSNumber *remainingTime;
@property (nonatomic, retain) NSString *releaseYear;
@property (nonatomic, retain) NSNumber *lastPosition;
@property (nonatomic, retain) NSNumber *playCount;
@property (nonatomic, retain) NSString *artworkURL;
@property (nonatomic, retain) NSString *url;
@property (nonatomic, retain) NSString *type;
@property (nonatomic, retain) NSString *title;
@property (nonatomic, retain) NSString *shortSummary;
@property (nonatomic, retain) NSNumber *currentlyWatching;
@property (nonatomic, retain) NSNumber *episodeNumber;
@property (nonatomic, retain) NSNumber *unread;
@property (nonatomic, retain) NSNumber *hasFetchedInfo;
@property (nonatomic, retain) NSNumber *noOnlineMetaData;
@property (nonatomic, retain) NSData * computedThumbnail;
@property (nonatomic, retain) MLShowEpisode * showEpisode;
@property (nonatomic, retain) NSSet* labels;
@property (nonatomic, retain) NSNumber* isOnDisk;
@property (nonatomic, retain) MLShowEpisode *showEpisode;
@property (nonatomic, retain) NSSet *labels;
@property (nonatomic, retain) NSSet *tracks;
@property (nonatomic, retain) NSNumber *isOnDisk;
@property (nonatomic, retain) NSNumber *duration;
/**
* the data in this object are about to be put on screen
......@@ -61,6 +63,14 @@ extern NSString *kMLFileTypeTVShowEpisode;
* \see willDisplay
*/
- (void)didHide;
/**
* Shortcuts to the videoTracks.
*/
- (NSManagedObject *)videoTrack;
- (size_t)fileSizeInBytes;
@end
......@@ -70,5 +80,9 @@ extern NSString *kMLFileTypeTVShowEpisode;
- (void)addLabels:(NSSet *)value;
- (void)removeLabels:(NSSet *)value;
- (void)addTracksObject:(NSManagedObject *)value;
- (void)removeTracksObject:(NSManagedObject *)value;
- (void)addTracks:(NSSet *)value;
- (void)removeTracks:(NSSet *)value;
@end
......@@ -31,6 +31,7 @@
6320368011F76EA9002861C2 /* NSXMLNode_Additions.m in Sources */ = {isa = PBXBuildFile; fileRef = 6320365E11F76EA9002861C2 /* NSXMLNode_Additions.m */; };
63C092E911F77CF200A824BC /* MediaLibrary.xcdatamodel in Sources */ = {isa = PBXBuildFile; fileRef = 63C092E811F77CF200A824BC /* MediaLibrary.xcdatamodel */; };
63C093DB11F78D8100A824BC /* MLThumbnailerQueue.m in Sources */ = {isa = PBXBuildFile; fileRef = 63C093D911F78D8100A824BC /* MLThumbnailerQueue.m */; };
63CD005D12109CD100414314 /* MLFileParserQueue.m in Sources */ = {isa = PBXBuildFile; fileRef = 63CD005C12109CD100414314 /* MLFileParserQueue.m */; };
7A37EDB71208A1F000D41964 /* MLShowEpisode.h in Copy Public headers */ = {isa = PBXBuildFile; fileRef = 63C0920A11F776D300A824BC /* MLShowEpisode.h */; };
7A37EDB81208A1F000D41964 /* MLFile.h in Copy Public headers */ = {isa = PBXBuildFile; fileRef = 6320368E11F76EC3002861C2 /* MLFile.h */; };
7A37EDB91208A1F000D41964 /* MLLabel.h in Copy Public headers */ = {isa = PBXBuildFile; fileRef = 6320368F11F76EC3002861C2 /* MLLabel.h */; };
......@@ -117,6 +118,8 @@
63C092E811F77CF200A824BC /* MediaLibrary.xcdatamodel */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = wrapper.xcdatamodel; path = MediaLibrary.xcdatamodel; sourceTree = SOURCE_ROOT; };
63C093D811F78D8100A824BC /* MLThumbnailerQueue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MLThumbnailerQueue.h; sourceTree = "<group>"; };
63C093D911F78D8100A824BC /* MLThumbnailerQueue.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MLThumbnailerQueue.m; sourceTree = "<group>"; };
63CD005B12109CD100414314 /* MLFileParserQueue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MLFileParserQueue.h; sourceTree = "<group>"; };
63CD005C12109CD100414314 /* MLFileParserQueue.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MLFileParserQueue.m; sourceTree = "<group>"; };
7A37ED0112089E4A00D41964 /* MobileVLCKit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobileVLCKit.h; sourceTree = "<group>"; };
7A37ED0212089E4A00D41964 /* VLCAudio.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VLCAudio.h; sourceTree = "<group>"; };
7A37ED0312089E4A00D41964 /* VLCLibrary.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VLCLibrary.h; sourceTree = "<group>"; };
......@@ -260,6 +263,8 @@
6320365E11F76EA9002861C2 /* NSXMLNode_Additions.m */,
63C093D811F78D8100A824BC /* MLThumbnailerQueue.h */,
63C093D911F78D8100A824BC /* MLThumbnailerQueue.m */,
63CD005B12109CD100414314 /* MLFileParserQueue.h */,
63CD005C12109CD100414314 /* MLFileParserQueue.m */,
63C092E811F77CF200A824BC /* MediaLibrary.xcdatamodel */,
);
path = Sources;
......@@ -401,6 +406,7 @@
6320368011F76EA9002861C2 /* NSXMLNode_Additions.m in Sources */,
63C092E911F77CF200A824BC /* MediaLibrary.xcdatamodel in Sources */,
63C093DB11F78D8100A824BC /* MLThumbnailerQueue.m in Sources */,
63CD005D12109CD100414314 /* MLFileParserQueue.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
......
......@@ -13,6 +13,8 @@
#import "MLMediaLibrary.h"
#import "MLThumbnailerQueue.h"
#import <Foundation/Foundation.h>
NSString *kMLFileTypeMovie = @"movie";
NSString *kMLFileTypeClip = @"clip";
NSString *kMLFileTypeTVShowEpisode = @"tvShowEpisode";
......@@ -25,6 +27,7 @@ NSString *kMLFileTypeTVShowEpisode = @"tvShowEpisode";
NSManagedObjectContext *moc = [[MLMediaLibrary sharedMediaLibrary] managedObjectContext];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"File" inManagedObjectContext:moc];
[request setEntity:entity];
[request setPredicate:[NSPredicate predicateWithFormat:@"isOnDisk == YES"]];
NSSortDescriptor *descriptor = [[NSSortDescriptor alloc] initWithKey:@"title" ascending:YES];
[request setSortDescriptors:[NSArray arrayWithObject:descriptor]];
......@@ -93,7 +96,9 @@ NSString *kMLFileTypeTVShowEpisode = @"tvShowEpisode";
@dynamic computedThumbnail;
@dynamic showEpisode;
@dynamic labels;
@dynamic tracks;
@dynamic isOnDisk;
@dynamic duration;
- (void)willDisplay
{
......@@ -105,4 +110,24 @@ NSString *kMLFileTypeTVShowEpisode = @"tvShowEpisode";
[[MLThumbnailerQueue sharedThumbnailerQueue] setDefaultPriorityForFile:self];
}
- (NSManagedObject *)videoTrack
{
NSSet *tracks = [self tracks];
if (!tracks)
return nil;
for (NSManagedObject *track in tracks) {
if ([[[track entity] name] isEqualToString:@"VideoTrackInformation"])
return track;
}
return nil;
}
- (size_t)fileSizeInBytes
{
NSFileManager *manager = [NSFileManager defaultManager];
NSDictionary *fileAttributes = [manager fileAttributesAtPath:[[NSURL URLWithString:self.url] path] traverseLink:YES];
NSNumber *fileSize = [fileAttributes objectForKey:NSFileSize];
return [fileSize unsignedLongLongValue];
}
@end
//
// MLFileParserQueue.h
// MobileMediaLibraryKit
//
// Created by Pierre d'Herbemont on 8/9/10.
// Copyright 2010 __MyCompanyName__. All rights reserved.
//
#import <Foundation/Foundation.h>
@class MLFile;
@interface MLFileParserQueue : NSOperationQueue {
NSDictionary *_fileDescriptionToOperation;
}
+ (MLFileParserQueue *)sharedFileParserQueue;
- (void)addFile:(MLFile *)file;
- (void)setHighPriorityForFile:(MLFile *)file;
- (void)setDefaultPriorityForFile:(MLFile *)file;
- (void)stop;
- (void)resume;
@end
//
// MLFileParserQueue.m
// MobileMediaLibraryKit
//
// Created by Pierre d'Herbemont on 8/9/10.
// Copyright 2010 __MyCompanyName__. All rights reserved.
//
#import <MobileVLCKit/MobileVLCKit.h>
#import "MLFileParserQueue.h"
#import "MLFile.h"
#import "MLMediaLibrary.h"
@interface MLParsingOperation : NSOperation
{
MLFile *_file;
VLCMedia *_media;
}
@property (retain,readwrite) MLFile *file;
@end
@interface MLFileParserQueue ()
- (void)didFinishOperation:(MLParsingOperation *)op;
@end
@implementation MLParsingOperation
@synthesize file=_file;
- (id)initWithFile:(MLFile *)file;
{
if (!(self = [super init]))
return nil;
self.file = file;
return self;
}
- (void)dealloc
{
[_media release];
[_file release];
[super dealloc];
}
- (void)parse
{
NSAssert(!_media, @"We are already parsing");
_media = [[VLCMedia mediaWithURL:[NSURL URLWithString:self.file.url]] retain];
_media.delegate = self;
[_media parse];
MLFileParserQueue *parserQueue = [MLFileParserQueue sharedFileParserQueue];
[parserQueue setSuspended:YES]; // Balanced in -mediaDidFinishParsing
[parserQueue didFinishOperation:self];
[self retain]; // Balanced in -mediaDidFinishParsing:
}
- (void)main
{
[self performSelectorOnMainThread:@selector(parse) withObject:nil waitUntilDone:YES];
}
- (void)mediaDidFinishParsing:(VLCMedia *)media
{
NSLog(@"Parsed %@ - %d tracks", media, [[_media tracksInformation] count]);
_media.delegate = nil;
NSArray *tracks = [_media tracksInformation];
NSMutableSet *tracksSet = [NSMutableSet setWithCapacity:[tracks count]];
for (NSDictionary *track in tracks) {
NSString *type = [track objectForKey:VLCMediaTracksInformationType];
NSManagedObject *trackInfo = nil;
if ([type isEqualToString:VLCMediaTracksInformationTypeVideo]) {
trackInfo = [[MLMediaLibrary sharedMediaLibrary] createObjectForEntity:@"VideoTrackInformation"];
[trackInfo setValue:[track objectForKey:VLCMediaTracksInformationVideoWidth] forKey:@"width"];
[trackInfo setValue:[track objectForKey:VLCMediaTracksInformationVideoHeight] forKey:@"height"];
} else if ([type isEqualToString:VLCMediaTracksInformationTypeAudio]) {
trackInfo = [[MLMediaLibrary sharedMediaLibrary] createObjectForEntity:@"AudioTrackInformation"];
[trackInfo setValue:[track objectForKey:VLCMediaTracksInformationAudioRate] forKey:@"bitrate"];
[trackInfo setValue:[track objectForKey:VLCMediaTracksInformationAudioChannelsNumber] forKey:@"channelsNumber"];
}
[tracksSet addObject:trackInfo];
}
NSAssert([[self.file tracks] count] == 0, @"Reparsing a file with existing tracks");
[self.file setTracks:tracksSet];
[self.file setDuration:[[_media length] numberValue]];
[[MLFileParserQueue sharedFileParserQueue] setSuspended:NO];
[_media release];
_media = nil;
[self release];
}
@end
@implementation MLFileParserQueue
+ (MLFileParserQueue *)sharedFileParserQueue
{
static MLFileParserQueue *shared = nil;
if (!shared) {
shared = [[MLFileParserQueue alloc] init];
[shared setMaxConcurrentOperationCount:1];
}
return shared;
}
- (id)init
{
self = [super init];
if (self != nil) {
_fileDescriptionToOperation = [[NSMutableDictionary alloc] init];
}
return self;
}
- (void)dealloc
{
[_fileDescriptionToOperation release];
[super dealloc];
}
static inline NSString *hashFromFile(MLFile *file)
{
return [NSString stringWithFormat:@"%p", [[file objectID] URIRepresentation]];
}
- (void)didFinishOperation:(MLParsingOperation *)op
{
[_fileDescriptionToOperation setValue:nil forKey:hashFromFile(op.file)];
}
- (void)addFile:(MLFile *)file
{
MLParsingOperation *op = [[MLParsingOperation alloc] initWithFile:file];
[_fileDescriptionToOperation setValue:op forKey:hashFromFile(file)];
[self addOperation:op];
}
- (void)stop
{
[self setMaxConcurrentOperationCount:0];
}
- (void)resume
{
[self setMaxConcurrentOperationCount:1];
}
- (void)setHighPriorityForFile:(MLFile *)file
{
MLParsingOperation *op = [_fileDescriptionToOperation objectForKey:hashFromFile(file)];
[op setQueuePriority:NSOperationQueuePriorityHigh];
}
- (void)setDefaultPriorityForFile:(MLFile *)file
{
MLParsingOperation *op = [_fileDescriptionToOperation objectForKey:hashFromFile(file)];
[op setQueuePriority:NSOperationQueuePriorityNormal];
}
@end
......@@ -16,6 +16,7 @@
#import "MLShowEpisode.h"
#import "MLThumbnailerQueue.h"
#import "MLShow.h"
#import "MLFileParserQueue.h"
#define DEBUG 1
......@@ -440,6 +441,9 @@ static NSString *kLastTVDBUpdateServerTime = @"MLLastTVDBUpdateServerTime";
{
MLLog(@"Fetching meta data for %@", file.title);
if (!file.tracks)
[[MLFileParserQueue sharedFileParserQueue] addFile:file];
NSDictionary *tvShowEpisodeInfo = [MLTitleDecrapifier tvShowEpisodeInfoFromString:file.title];
if (tvShowEpisodeInfo) {
[self addTVShowEpisodeWithInfo:tvShowEpisodeInfo andFile:file];
......@@ -589,10 +593,19 @@ static NSString *kLastTVDBUpdateServerTime = @"MLLastTVDBUpdateServerTime";
for (MLFile *file in results) {
NSString *urlString = [file url];
NSURL *fileURL = [NSURL URLWithString:urlString];
BOOL exists = [fileManager fileExistsAtPath:[fileURL absoluteString]];
BOOL exists = [fileManager fileExistsAtPath:[fileURL path]];
if (!exists)
NSLog(@"Marking - %@", [fileURL absoluteString]);
file.isOnDisk = [NSNumber numberWithBool:exists];
}
// Get the file to parse
request = [self fetchRequestForEntity:@"File"];
[request setPredicate:[NSPredicate predicateWithFormat:@"isOnDisk == YES && tracks.@count == 0"]];
results = [[self managedObjectContext] executeFetchRequest:request error:nil];
for (MLFile *file in results)
[[MLFileParserQueue sharedFileParserQueue] addFile:file];
// Get the thumbnails to compute
request = [self fetchRequestForEntity:@"File"];
[request setPredicate:[NSPredicate predicateWithFormat:@"isOnDisk == YES && hasFetchedInfo == 1 && artworkURL == nil && computedThumbnail == nil"]];
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment