From 5ad0fe636d59809146c6f13b5ff50cc8833e3df5 Mon Sep 17 00:00:00 2001 From: Simone Manganelli Date: Tue, 30 Jun 2009 17:30:38 +0800 Subject: [PATCH] HD H.264 support added; also, ClickToFlash now reliably detects H.264 and HD H.264 versions by actually testing the URLs instead of relying on YouTube's flash vars Signed-off-by: Jonathan 'Wolf' Rentzsch --- Plugin/English.lproj/WhitelistPanel.xib | 135 ++++++++++++++++++------ Plugin/Plugin.h | 2 + Plugin/Plugin.m | 123 +++++++++++++++++++-- 3 files changed, 216 insertions(+), 44 deletions(-) diff --git a/Plugin/English.lproj/WhitelistPanel.xib b/Plugin/English.lproj/WhitelistPanel.xib index 74653e3b..5129ea2f 100755 --- a/Plugin/English.lproj/WhitelistPanel.xib +++ b/Plugin/English.lproj/WhitelistPanel.xib @@ -8,6 +8,7 @@ 353.00 YES + YES @@ -37,7 +38,7 @@ 15 2 - {{80, 209}, {527, 494}} + {{80, 187}, {527, 516}} -534248448 Q2xpY2sgdG8gRmxhc2gg4oCUIFNldHRpbmdzA NSPanel @@ -45,7 +46,7 @@ {3.40282e+38, 3.40282e+38} {420, 400} - + 274 YES @@ -287,7 +288,7 @@ 268 - {{93, 194}, {286, 18}} + {{93, 216}, {286, 18}} YES @@ -315,6 +316,28 @@ 25 + + + 268 + {{120, 196}, {259, 18}} + + YES + + -2080244224 + 0 + Load HD videos + + + 1211912703 + 130 + + + + + 200 + 25 + + 268 @@ -340,7 +363,7 @@ 268 - {{17, 215}, {67, 17}} + {{17, 237}, {67, 17}} YES @@ -717,7 +740,7 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA 268 - {{93, 214}, {286, 18}} + {{93, 236}, {286, 18}} YES @@ -757,7 +780,7 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA - {{65, 246}, {397, 252}} + {{65, 246}, {397, 274}} NSView @@ -778,7 +801,8 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA - {527, 494} + {527, 516} + {{0, 0}, {1280, 778}} {420, 422} @@ -812,6 +836,7 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA sifrMode checkForUpdatesOnFirstLoad siteInfo + useYouTubeHDH264 YES @@ -1304,22 +1329,6 @@ dG8gdW5pbnN0YWxsIENsaWNrVG9GbGFzaC4 178 - - - value: values.useYouTubeH264 - - - - - - value: values.useYouTubeH264 - value - values.useYouTubeH264 - 2 - - - 179 - value: values.autoLoadInvisibleViews @@ -1452,6 +1461,38 @@ dG8gdW5pbnN0YWxsIENsaWNrVG9GbGFzaC4 239 + + + value: values.useYouTubeHDH264 + + + + + + value: values.useYouTubeHDH264 + value + values.useYouTubeHDH264 + 2 + + + 245 + + + + value: values.useYouTubeH264 + + + + + + value: values.useYouTubeH264 + value + values.useYouTubeH264 + 2 + + + 251 + @@ -1608,17 +1649,18 @@ dG8gdW5pbnN0YWxsIENsaWNrVG9GbGFzaC4 YES - - - + + + + + - + - + - @@ -2068,6 +2110,20 @@ dG8gdW5pbnN0YWxsIENsaWNrVG9GbGFzaC4 + + 240 + + + YES + + + + + + 241 + + + @@ -2190,6 +2246,9 @@ dG8gdW5pbnN0YWxsIENsaWNrVG9GbGFzaC4 232.IBPluginDependency 233.IBPluginDependency 234.IBPluginDependency + 240.IBAttributePlaceholdersKey + 240.IBPluginDependency + 241.IBPluginDependency 31.IBPluginDependency 32.IBPluginDependency 36.IBAttributePlaceholdersKey @@ -2208,9 +2267,9 @@ dG8gdW5pbnN0YWxsIENsaWNrVG9GbGFzaC4 com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilderKit com.apple.InterfaceBuilderKit - {{12, 251}, {527, 494}} - - {{12, 251}, {527, 494}} + {{186, 118}, {527, 516}} + + {{186, 118}, {527, 516}} {196, 240} {{202, 428}, {480, 270}} @@ -2363,6 +2422,16 @@ dG8gdW5pbnN0YWxsIENsaWNrVG9GbGFzaC4 com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin + + ToolTip + + ToolTip + + Loads HD versions of the movie, if possible. + + + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin @@ -2404,7 +2473,7 @@ dG8gdW5pbnN0YWxsIENsaWNrVG9GbGFzaC4 - 239 + 251 diff --git a/Plugin/Plugin.h b/Plugin/Plugin.h index c7ba6029..90fe9712 100755 --- a/Plugin/Plugin.h +++ b/Plugin/Plugin.h @@ -39,6 +39,8 @@ THE SOFTWARE. BOOL mouseInside; BOOL _isLoadingFromWhitelist; BOOL _fromYouTube; + BOOL _hasH264Version; + BOOL _hasHDH264Version; WebView *_webView; NSUInteger _sifrVersion; NSString *_baseURL; diff --git a/Plugin/Plugin.m b/Plugin/Plugin.m index 6fa732f2..8d2d296c 100755 --- a/Plugin/Plugin.m +++ b/Plugin/Plugin.m @@ -45,6 +45,7 @@ of this software and associated documentation files (the "Software"), to deal // CTFUserDefaultsController keys static NSString *sUseYouTubeH264DefaultsKey = @"useYouTubeH264"; +static NSString *sUseYouTubeHDH264DefaultsKey = @"useYouTubeHDH264"; static NSString *sAutoLoadInvisibleFlashViewsKey = @"autoLoadInvisibleViews"; static NSString *sPluginEnabled = @"pluginEnabled"; static NSString *sApplicationWhitelist = @"applicationWhitelist"; @@ -71,8 +72,11 @@ - (void) _loadContentForWindow: (NSNotification*) notification; - (NSDictionary*) _flashVarDictionary: (NSString*) flashvarString; - (NSDictionary*) _flashVarDictionaryFromYouTubePageHTML: (NSString*) youTubePageHTML; - (NSString*) flashvarWithName: (NSString*) argName; +- (void) _checkForH264VideoVariants; - (BOOL) _hasH264Version; - (BOOL) _useH264Version; +- (BOOL) _hasHDH264Version; +- (BOOL) _useHDH264Version; - (NSString *)launchedAppBundleIdentifier; @end @@ -153,11 +157,6 @@ - (id) initWithArguments:(NSDictionary *)arguments NSString* flashvars = [[self attributes] objectForKey: @"flashvars" ]; if( flashvars != nil ) _flashVars = [ [ self _flashVarDictionary: flashvars ] retain ]; - -#if LOGGING_ENABLED - NSLog( @"arguments = %@", arguments ); - NSLog( @"flashvars = %@", _flashVars ); -#endif // check whether it's from YouTube and get the video_id @@ -195,9 +194,17 @@ - (id) initWithArguments:(NSDictionary *)arguments if (! pageSourceError) _flashVars = [[self _flashVarDictionaryFromYouTubePageHTML:pageSourceString] retain]; } } + + [self _checkForH264VideoVariants]; } +#if LOGGING_ENABLED + NSLog( @"arguments = %@", arguments ); + NSLog( @"flashvars = %@", _flashVars ); +#endif + + // check whether plugin is disabled, load all content as normal if so CTFUserDefaultsController *standardUserDefaults = [CTFUserDefaultsController standardUserDefaults]; @@ -649,6 +656,8 @@ - (void) _loadInvisibleContentForWindow: (NSNotification*) notification - (NSString*) badgeLabelText { + if( [ self _useHDH264Version ] ) + return NSLocalizedString( @"HD H.264", @"HD H.264 badge text" ); if( [ self _useH264Version ] ) return NSLocalizedString( @"H.264", @"H.264 badge text" ); else if( [ self _hasH264Version ] ) @@ -996,12 +1005,98 @@ - (NSString*) _videoHash return [ self flashvarWithName: @"t" ]; } +- (void) _checkForH264VideoVariants +{ + NSString* video_id = [self videoId]; + NSString* video_hash = [ self _videoHash ]; + + NSString* src = [ NSString stringWithFormat: @"http://www.youtube.com/get_video?fmt=18&video_id=%@&t=%@", + video_id, video_hash ]; + NSString* HDSrc = [ NSString stringWithFormat: @"http://www.youtube.com/get_video?fmt=22&video_id=%@&t=%@", + video_id, video_hash ]; + + NSMutableURLRequest *URLRequest = [[NSMutableURLRequest alloc] init]; + [URLRequest setURL:[NSURL URLWithString:src]]; + + + // this header is required, because otherwise the URLRequest will download + // the whole video before returning, which completely defeats the purpose + // of checking for the video variants in the first place + + // this limits the download to the first 2 bytes of the video, which is + // sufficient to see if there is a video there or not. + [URLRequest setValue:@"bytes=0-1" forHTTPHeaderField:@"Range"]; + NSError *requestError = nil; + NSHTTPURLResponse *requestResponse = nil; + NSData *returnedData = [NSURLConnection sendSynchronousRequest:URLRequest + returningResponse:&requestResponse + error:&requestError]; + int statusCode = [requestResponse statusCode]; + + // 206 status code means partial content has been delivered, because of the + // range header + if (statusCode == 206) _hasH264Version = YES; + + [URLRequest setURL:[NSURL URLWithString:HDSrc]]; + returnedData = [NSURLConnection sendSynchronousRequest:URLRequest + returningResponse:&requestResponse + error:&requestError]; + + statusCode = [requestResponse statusCode]; + if (statusCode == 206) _hasHDH264Version = YES; + + [URLRequest release]; +} + +- (BOOL) _hasHDH264Version +{ + /*BOOL _hasHDH264Version = NO; + if (_fromYouTube) { + NSString *fmtMapString = [ self flashvarWithName: @"fmt_map" ]; + NSArray *fmtMapArray = [fmtMapString componentsSeparatedByString:@","]; + + CTFForEachObject( NSString, currentMapString, fmtMapArray ) { + NSString *fmtQuality = [[currentMapString componentsSeparatedByString:@"/"] objectAtIndex:0]; + if ([fmtQuality isEqualToString:@"22"]) { + _hasHDH264Version = YES; + break; + } + } + }*/ + + return (_fromYouTube && _hasHDH264Version); +} + - (BOOL) _hasH264Version { - if( _fromYouTube ) - return [self videoId] != nil && [ self _videoHash ] != nil; - else - return NO; + /*BOOL _hasH264Version = NO; + if ( _fromYouTube ) { + NSString *fmtMapString = [ self flashvarWithName: @"fmt_map" ]; + NSArray *fmtMapArray = [fmtMapString componentsSeparatedByString:@","]; + + CTFForEachObject( NSString, currentMapString, fmtMapArray ) { + NSString *fmtQuality = [[currentMapString componentsSeparatedByString:@"/"] objectAtIndex:0]; + if ([fmtQuality isEqualToString:@"18"] || [fmtQuality isEqualToString:@"22"]) { + _hasH264Version = YES; + break; + } + } + }*/ + + return (_fromYouTube && _hasH264Version); + + // sometimes, even though we have a videoId and a videoHash, the movie + // still doesn't have an H.264 version, so this logic is flawed + + // return [self videoId] != nil && [ self _videoHash ] != nil; +} + +- (BOOL) _useHDH264Version +{ + return [ self _hasHDH264Version ] + && [ [ CTFUserDefaultsController standardUserDefaults ] boolForKey: sUseYouTubeH264DefaultsKey ] + && [ [ CTFUserDefaultsController standardUserDefaults ] boolForKey: sUseYouTubeHDH264DefaultsKey ] + && [ [ CTFUserDefaultsController standardUserDefaults ] boolForKey: sPluginEnabled ]; } - (BOOL) _useH264Version @@ -1016,8 +1111,14 @@ - (void) _convertElementForMP4: (DOMElement*) element NSString* video_id = [self videoId]; NSString* video_hash = [ self _videoHash ]; - NSString* src = [ NSString stringWithFormat: @"http://www.youtube.com/get_video?fmt=18&video_id=%@&t=%@", - video_id, video_hash ]; + NSString* src; + if ([self _hasHDH264Version]) { + src = [ NSString stringWithFormat: @"http://www.youtube.com/get_video?fmt=22&video_id=%@&t=%@", + video_id, video_hash ]; + } else { + src = [ NSString stringWithFormat: @"http://www.youtube.com/get_video?fmt=18&video_id=%@&t=%@", + video_id, video_hash ]; + } [ element setAttribute: @"src" value: src ]; [ element setAttribute: @"type" value: @"video/mp4" ];