Skip to content
Browse files

Merge pull request #7 from Bilalh/master

Added a menu item to play the next episode.
  • Loading branch information...
2 parents 257454d + d53695a commit 4941e66dd1bb64efe9242df2306ce2cacd219965 @sttz committed Mar 18, 2012
View
6 mposxext.xcodeproj/project.pbxproj
@@ -196,6 +196,7 @@
92E8E40F141D1E4800FFA813 /* wmv.icns in Resources */ = {isa = PBXBuildFile; fileRef = 92E8E402141D1E4800FFA813 /* wmv.icns */; };
92E8E411141D1E9000FFA813 /* mp4.icns in Resources */ = {isa = PBXBuildFile; fileRef = 92E8E410141D1E9000FFA813 /* mp4.icns */; };
92E8E413141D1F2E00FFA813 /* m4v.icns in Resources */ = {isa = PBXBuildFile; fileRef = 92E8E412141D1F2E00FFA813 /* m4v.icns */; };
+ 92E9A6C81449139800223BE0 /* MovieMethods.m in Sources */ = {isa = PBXBuildFile; fileRef = 92E9A6C71449139800223BE0 /* MovieMethods.m */; };
/* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */
@@ -460,6 +461,8 @@
92E8E402141D1E4800FFA813 /* wmv.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = wmv.icns; sourceTree = "<group>"; };
92E8E410141D1E9000FFA813 /* mp4.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = mp4.icns; sourceTree = "<group>"; };
92E8E412141D1F2E00FFA813 /* m4v.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = m4v.icns; sourceTree = "<group>"; };
+ 92E9A6C61449139800223BE0 /* MovieMethods.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MovieMethods.h; sourceTree = "<group>"; };
+ 92E9A6C71449139800223BE0 /* MovieMethods.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MovieMethods.m; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -614,6 +617,8 @@
3A7A6932139AB44D006A8B4A /* PlayListController.m */,
3A7A6933139AB44D006A8B4A /* PreferencesController2.h */,
3A7A6934139AB44D006A8B4A /* PreferencesController2.m */,
+ 92E9A6C61449139800223BE0 /* MovieMethods.h */,
+ 92E9A6C71449139800223BE0 /* MovieMethods.m */,
);
path = controllers;
sourceTree = "<group>";
@@ -1195,6 +1200,7 @@
3A7A6A41139AB44D006A8B4A /* Debug.m in Sources */,
3A7A6A42139AB44D006A8B4A /* LocalUserDefaults.m in Sources */,
3A4C775F13A51041000EDD78 /* ToggleEditLabel.m in Sources */,
+ 92E9A6C81449139800223BE0 /* MovieMethods.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
View
3,135 resources/en.lproj/MainMenu.xib
2,263 additions, 872 deletions not shown because the diff is too large. Please use a local Git client to view these changes.
View
1 source/controllers/AppController.h
@@ -104,6 +104,7 @@ PlayListController, MenuController, InspectorController, MovieInfo;
- (void) restart;
+- (void) openFilePath:(NSString*)filepath;
// actions
- (IBAction) openFile:(id)sender;
- (IBAction) addToPlaylist:(id)sender;
View
57 source/controllers/AppController.m
@@ -29,6 +29,8 @@
#import "PFMoveApplication.h"
#import "RegexKitLite.h"
+#import "MovieMethods.h"
+
NSString* const MPENewPlayerOpenedNotification = @"MPENewPlayerOpenedNotification";
NSString* const MPEPlayerClosedNotification = @"MPEPlayerClosedNotification";
NSString* const MPEPlayerNotificationPlayerControllerKey = @"MPEPlayerNotificationPlayerControllerKey";
@@ -39,9 +41,9 @@ @implementation AppController
static AppController *instance = nil;
-/************************************************************************************
- INITIALIZATION
- ************************************************************************************/
+/************************************************************************************/
+#pragma mark - INITIALIZATION
+/************************************************************************************/
- (id)init
{
if ((self = [super init])) {
@@ -120,9 +122,9 @@ - (InspectorController *)inspectorController
return inspectorController;
}
-/************************************************************************************
- INTERFACE
- ************************************************************************************/
+/************************************************************************************/
+#pragma mark - INTERFACE
+/************************************************************************************/
- (NSUserDefaults *) preferences
{
return [NSUserDefaults standardUserDefaults];
@@ -257,26 +259,33 @@ - (void) applyChangesWithRestart:(BOOL)restart
}
}
-/************************************************************************************
- ACTIONS
- ************************************************************************************/
+/************************************************************************************/
+#pragma mark - ACTIONS
+/************************************************************************************/
- (IBAction) openFile:(id)sender
{
NSString *theFile;
// present open dialog
theFile = [self openDialogForType:MP_DIALOG_MEDIA];
- if (theFile) {
+ [self openFilePath:theFile];
+}
+
+- (void) openFilePath:(NSString*)filepath
+{
+ if (filepath) {
// if any file, create new item and play it
- MovieInfo *item = [MovieInfo movieInfoWithPathToFile:theFile];
+ MovieInfo *item = [MovieInfo movieInfoWithPathToFile:filepath];
// apply selection from binary selection popup
NSString *binary = [preferencesController identifierFromSelectionInView];
if (binary)
[[item prefs] setObject:binary forKey:MPESelectedBinary];
[[self getPlayer] playItem:item];
}
}
+
+
//BETA//////////////////////////////////////////////////////////////////////////////////
- (IBAction) openVIDEO_TS:(id)sender
{
@@ -452,9 +461,9 @@ - (IBAction) closeWindow:(id)sender
[[NSApp keyWindow] performClose:self];
}
-/************************************************************************************
- BUNDLE ACCESS
- ************************************************************************************/
+/************************************************************************************/
+#pragma mark - BUNDLE ACCESS
+/************************************************************************************/
// return array of document extensions of specified document type name
- (NSArray *) typeExtensionsForName:(NSString *)typeName
{
@@ -514,9 +523,9 @@ - (BOOL) isDVD:(NSString *)path
return NO;
}
-/************************************************************************************
- MISC METHODS
- ************************************************************************************/
+/************************************************************************************/
+#pragma mark - MISC METHODS
+/************************************************************************************/
// presents open dialog for certain types
- (NSString *) openDialogForType:(int)type
{
@@ -659,10 +668,18 @@ - (BOOL) animateInterface
return YES;
}
+// Play the next episode based on the current file's filepath
+- (IBAction) playNextEpisode:(id)sender
+{
+ NSString *filename = [[self.movieInfoProvider currentMovieInfo] filename];
+ NSString *result = [MovieMethods findNextEpisodePathFrom:filename];
+ [Debug log:ASL_LEVEL_INFO withMessage:@"currentFile=%@ nextFile=%@",filename, result ];
+ if (result) [self openFilePath:result];
+}
-/************************************************************************************
- DELEGATE METHODS
- ************************************************************************************/
+/************************************************************************************/
+#pragma mark - DELEGATE METHODS
+/*************************************************************************************/
// app delegate method
// executes when file is double clicked or dropped on apps icon
// immediatlely starts to play dropped file without adding it to the playlist
View
40 source/controllers/MovieMethods.h
@@ -0,0 +1,40 @@
+/*
+ * MovieMethods.h
+ * MPlayerOSX Extended
+ *
+ * Created by Bilal Syed Hussain on 2011-10-15
+ *
+ */
+
+#import <Foundation/Foundation.h>
+
+
+@interface MovieMethods : NSObject {
+@private
+
+}
+
+// Return the filepath of the Next episode based on filepath
+// returns nil if not found.
+// exts is the set of vaild extension, pass null to consider all extensions
++ (NSString*) findNextEpisodePathFrom:(NSString*)filepath inFormats:(NSSet*)exts;
+
+// As Above with all movie formats
++ (NSString*) findNextEpisodePathFrom:(NSString*)filepath;
+
+
+// Return the filepath of the Previous episode based on filepath
+// returns nil if not found.
+// exts is the set of vaild extension, pass null to consider all extensions
++ (NSString*) findPreviousEpisodePathFrom:(NSString*)filepath inFormats:(NSSet*)exts;
+// As Above with all movie formats
++ (NSString*) findPreviousEpisodePathFrom:(NSString*)filepath;
+
+// Return the filepath of the episode that is accepted by the selector based on the filepath
+// returns nil if not found.
+// exts is the set of vaild extension, pass null to consider all extensions
++ (NSString*) episodePathFrom:(NSString*)filepath
+ inFormats:(NSSet*)exts
+ accept:(SEL)accept;
+
+@end
View
250 source/controllers/MovieMethods.m
@@ -0,0 +1,250 @@
+/*
+ * MovieMethods.h
+ * MPlayerOSX Extended
+ *
+ * Created by Bilal Syed Hussain on 2011-10-15
+ *
+ */
+
+#import "MovieMethods.h"
+#import "Debug.h"
+
+#include <ctype.h>
+#include <stdlib.h>
+
+@interface MovieMethods(){}
++ (NSArray*) enumerateAllFilesAtDirectory:(NSString*)dirPath
+ withExtensions:(NSSet*)exts
+ beginningWith:(NSString*)seriesName;
+
++ (NSNumber*) acceptNextEpisode:(NSNumber*)current
+ number:(NSNumber*)newNumber;
+
++ (NSNumber*) acceptPreviousEpisode:(NSNumber*)current
+ number:(NSNumber*)newNumber;
+
+@end
+
+static char ** ep_num (char *s);
+
+@implementation MovieMethods
+
+#pragma mark - Finding the Next Episode
+
++(NSArray*) enumerateAllFilesAtDirectory:(NSString*)dirPath
+ withExtensions:(NSSet*)exts
+ beginningWith:(NSString*)seriesName
+{
+ NSMutableArray *ret = nil;
+
+ NSDirectoryEnumerator *directoryEnumerator = [[NSFileManager defaultManager] enumeratorAtPath:dirPath];
+
+ for (NSString *file in directoryEnumerator) {
+ // enumerate the directory
+ NSDictionary *fileAttr = [directoryEnumerator fileAttributes];
+
+ if ([[fileAttr objectForKey:NSFileType] isEqualToString:NSFileTypeDirectory]) {
+ // skip all subdirectories
+ [directoryEnumerator skipDescendants];
+
+ // the normal file and the file extension is OK or if exts is nil, don't care the extensions
+ } else if ([[fileAttr objectForKey:NSFileType] isEqualToString: NSFileTypeRegular] &&
+ ((exts && [exts containsObject:[[file pathExtension] lowercaseString]]) || (!exts))) {
+ if ([file rangeOfString:seriesName options:NSAnchoredSearch].location != NSNotFound){
+ if (!ret) { // lazy load
+ ret = [[NSMutableArray alloc] initWithCapacity:20];
+ }
+ [ret addObject:file];
+ }
+ }
+ }
+ return [ret autorelease];
+}
+
+
+
++ (NSString*) findNextEpisodePathFrom:(NSString*)filepath
+{
+ // All Movies
+ NSSet *exts = [NSSet setWithObjects:@"3gp", @"3iv", @"asf", @"avi", @"asf", @"bin", @"cpk", @"dat", @"divx", @"dv", @"dvr-ms", @"fli", @"flv", @"h264", @"i263", @"m1v", @"m2t", @"m2ts", @"m2v", @"m4v", @"mkv", @"mov", @"mp2", @"mp4", @"mpeg", @"mpg", @"mpg2", @"mpg4", @"mpv", @"mqv", @"nut", @"nuv", @"nsv", @"ogg", @"ogm", @"ogv", @"qt", @"ram", @"rec", @"rm", @"rmvb", @"ts", @"vcd", @"vfw", @"vob", @"wmv", @"webm", nil];
+
+ return [self findNextEpisodePathFrom:filepath
+ inFormats:exts];
+}
+
+
++(NSString*) findNextEpisodePathFrom:(NSString*)filepath inFormats:(NSSet*)exts
+{
+ return [self episodePathFrom:filepath
+ inFormats:exts
+ accept:@selector(acceptNextEpisode:number:)];
+}
+
++ (NSString*) findPreviousEpisodePathFrom:(NSString*)filepath
+{
+ // All Movies
+ NSSet *exts = [NSSet setWithObjects:@"3gp", @"3iv", @"asf", @"avi", @"asf", @"bin", @"cpk", @"dat", @"divx", @"dv", @"dvr-ms", @"fli", @"flv", @"h264", @"i263", @"m1v", @"m2t", @"m2ts", @"m2v", @"m4v", @"mkv", @"mov", @"mp2", @"mp4", @"mpeg", @"mpg", @"mpg2", @"mpg4", @"mpv", @"mqv", @"nut", @"nuv", @"nsv", @"ogg", @"ogm", @"ogv", @"qt", @"ram", @"rec", @"rm", @"rmvb", @"ts", @"vcd", @"vfw", @"vob", @"wmv", @"webm", nil];
+
+ return [self findPreviousEpisodePathFrom:filepath
+ inFormats:exts];
+}
+
+
++ (NSString*) findPreviousEpisodePathFrom:(NSString*)filepath inFormats:(NSSet*)exts
+{
+ return [self episodePathFrom:filepath
+ inFormats:exts
+ accept:@selector(acceptPreviousEpisode:number:)];
+}
+
+
+
+// Finds the next episode that that is accept by the selector
++ (NSString*) episodePathFrom:(NSString*)filepath
+ inFormats:(NSSet*)exts
+ accept:(SEL)accept
+{
+ NSString *nextPath = nil;
+ if (filepath) {
+ NSString *dirPath = [filepath stringByDeletingLastPathComponent];
+ NSString *movieName = [[filepath lastPathComponent] stringByDeletingPathExtension];
+ char* cMovieName = strdup([movieName UTF8String]);
+ char **ans = ep_num(cMovieName);
+ if (ans[0] != NULL) { // The filename was parsed successfully
+ // Gets the episodeNumber
+ long episodeNumber = strtol(ans[0] + 1, NULL, 10);
+ if (episodeNumber == 0 ) episodeNumber++;
+
+ // Get the series name
+ int index = ans[1] != NULL ? 1 : 0;
+ char name[ ans[index] - cMovieName + 1];
+ strncpy(name, cMovieName, ans[index] - cMovieName);
+ name[ans[index] - cMovieName] = '\0';
+
+ free(ans);
+ free(cMovieName);
+
+
+ NSArray *arr = [self enumerateAllFilesAtDirectory:dirPath
+ withExtensions:exts
+ beginningWith:[[NSString alloc] initWithUTF8String:name]];
+
+ if (arr){
+ [Debug log:ASL_LEVEL_DEBUG withMessage:@"Resulting filenames=%@ ",arr ];
+ for (NSString *s in arr) {
+ char* cName = strdup([s UTF8String]);
+ char **result = ep_num(cName);
+ if (result[0] != NULL){
+ long newEpisodeNumber = strtol(result[0] + 1, NULL, 10);
+ BOOL use =
+ [[self performSelector:accept
+ withObject:[NSNumber numberWithInt:episodeNumber]
+ withObject:[NSNumber numberWithInt:newEpisodeNumber]] boolValue];
+ if (use){
+ nextPath = [dirPath stringByAppendingPathComponent:s];
+ free(result);
+ free(cName);
+ break;
+ }
+ }
+ free(result);
+ free(cName);
+ }
+ }
+ }
+ }
+ [Debug log:ASL_LEVEL_DEBUG withMessage:@"nextPath =%@ ",nextPath ];
+ return [nextPath retain];
+}
+
++ (NSNumber*) acceptNextEpisode:(NSNumber*)current
+ number:(NSNumber*)newNumber
+{
+ return [NSNumber numberWithInt:[current intValue]+1 == [newNumber intValue]];
+}
+
++ (NSNumber*) acceptPreviousEpisode:(NSNumber*)current
+ number:(NSNumber*)newNumber
+{
+ return [NSNumber numberWithInt:[current intValue]-1 == [newNumber intValue]];
+}
+
+
+/**
+ * Get the postion of the name and number from the filename.
+ *
+ * @param s - A c string.
+ * @return An array containg:
+ * [0] - The index before the number starts.
+ * [1] - arr[index - s + 1] is the name part of the string,
+ * where index = (arr[1] != NULL) ? 1 : 0
+ *
+ * @error [0] == NULL - Number not found
+ */
+static char **ep_num (char *s)
+{
+ assert (s);
+ char *start = s;
+ char **ans = calloc(2, sizeof(size_t));
+ int index = 0;
+ int num = 0;
+ int dashes = 0;
+
+ bool hack = false;
+
+ // To handle space at start of filename
+ if (*s == ' ') hack = true;
+ while (*s == ' ') s++;
+
+ if (hack){
+ start = s;
+ }
+
+ // finds the end of the string
+ while (*s != '\0' ) {
+ if (num ==0 && isdigit(*s) ) num++;
+ else if (*s == '-' ) dashes++;
+ s++;
+ }
+
+ // if there is no number (e.g movie) the whole string is the name.
+ if (num == 0 ){
+ ans[0] = ans[1] = s;
+ char *temp = s - 1;
+ while ( temp != start ){
+ if ( *temp == '.'){
+ ans[1] = temp;
+ break;
+ }
+ temp--;
+ }
+ return ans;
+ }
+
+ while (*s != *start) {
+ if (index == 0 && (*s == '-' || *s == ' ' || *s == '_' || *s == '~' ) ) {
+ //if for 'word - 22 .mkv' types
+ if(! isdigit(*(s-1))){
+ ans[index] = s;
+ index++;
+ // To handle - types
+ if( (s - start) >=2 ) ans[index] = s-2;
+ }
+ }
+
+ if(index == 1 && !(*s == ' ' || *s == '-' || *s == '_' || *s == '~' ) ) {
+ char *t = (s + 1);
+ if( *t == ' ' || *t == '-' || *t == '_' || *t == '~' ) {
+ if (*t == '~' && dashes > 0 ) t++;
+ ans[index] = t;
+ break;
+ }
+ }
+
+ s--;
+ }
+
+ return ans;
+}
+
+@end
View
1 source/controllers/PlayerController.h
@@ -153,6 +153,7 @@
- (void)skipToPreviousChapter;
- (void)skipForwardIncludingChapters:(BOOL)includeChapters;
- (void)skipBackwardIncludingChapters:(BOOL)includeChapters;
+- (BOOL) automaticallyPlayEpisode:(BOOL)next;
- (void)clearStreamMenus;
- (void)fillStreamMenus;
View
36 source/controllers/PlayerController.m
@@ -19,6 +19,8 @@
#import "Preferences.h"
#import "CocoaAdditions.h"
+#import "MovieMethods.h"
+
// custom classes
#import "VideoOpenGLView.h"
#import "VolumeSlider.h"
@@ -728,7 +730,7 @@ - (void)skipForwardIncludingChapters:(BOOL)includeChapters
else {
if (playingFromPlaylist)
[playListController finishedPlayingItem:movieInfo];
- else
+ else if (! [self automaticallyPlayEpisode:true])
[self stop:nil];
//[self seek:100 mode:MISeekingModePercent];
}
@@ -746,9 +748,27 @@ - (void)skipBackwardIncludingChapters:(BOOL)includeChapters
{
if (includeChapters && movieInfo && [movieInfo chapterCount] > 0)
[self skipToPreviousChapter];
- else
+ else if ([self automaticallyPlayEpisode:false])
+
[self seek:0 mode:MISeekingModePercent];
+
+ }
+}
+
+- (BOOL) automaticallyPlayEpisode:(BOOL)next
+{
+ if ([PREFS boolForKey:MPEAutomaticallyPlayNextEpisode]){
+ NSString *filename = [[self currentMovieInfo] filename];
+ NSString *result = next
+ ? [MovieMethods findNextEpisodePathFrom:filename]
+ : [MovieMethods findPreviousEpisodePathFrom:filename];
+ if (result){
+ MovieInfo *item = [MovieInfo movieInfoWithPathToFile:result];
+ [self playItem:item];
+ return YES;
+ }
}
+ return NO;
}
#pragma mark - Chapters
@@ -1708,8 +1728,12 @@ - (void) interface:(MPlayerInterface *)mi hasChangedStateTo:(NSNumber *)statenum
else
[self stopFromPlaylist];
// Regular play mode
- } else
- [videoOpenGLView close];
+ } else{
+ if (state != MIStateFinished || ![self automaticallyPlayEpisode:true]){
+ [videoOpenGLView close];
+ }
+
+ }
// Next item already waiting, don't clean up
} else
continuousPlayback = NO;
@@ -1721,6 +1745,10 @@ - (void) interface:(MPlayerInterface *)mi hasChangedStateTo:(NSNumber *)statenum
// Update on-top
[self updateWindowOnTop];
}
+
+
+
+
/************************************************************************************/
- (void) interface:(MPlayerInterface *)mi streamUpate:(MovieInfo *)item
{
View
3 source/core/Preferences.h
@@ -178,3 +178,6 @@ extern NSString* const MPEVideoEqualizerContrast;
extern NSString* const MPEVideoEqualizerGamma;
extern NSString* const MPEVideoEqualizerHue;
extern NSString* const MPEVideoEqualizerSaturation;
+
+// *** For play next episode
+extern NSString* const MPEAutomaticallyPlayNextEpisode;
View
1 source/core/Preferences.m
@@ -166,3 +166,4 @@
NSString* const MPEVideoEqualizerHue = @"MPEVideoEqualizerHue";
NSString* const MPEVideoEqualizerSaturation = @"MPEVideoEqualizerSaturation";
+NSString* const MPEAutomaticallyPlayNextEpisode = @"MPEAutomaticallyPlayNextEpisode";

0 comments on commit 4941e66

Please sign in to comment.
Something went wrong with that request. Please try again.