Commit 476b4e66 authored by Pierre SAGASPE's avatar Pierre SAGASPE Committed by Felix Paul Kühne

plex: add VLCPlexWebAPI

Signed-off-by: Felix Paul Kühne's avatarFelix Paul Kühne <fkuehne@videolan.org>
(cherry picked from commit a71fd6b8)
Signed-off-by: Felix Paul Kühne's avatarFelix Paul Kühne <fkuehne@videolan.org>
parent 36491c3e
/*****************************************************************************
* VLCPlexWebAPI.h
* VLC for iOS
*****************************************************************************
* Copyright (c) 2015 VideoLAN. All rights reserved.
*
* Authors: Pierre Sagaspe <pierre.sagaspe # me.com>
*
* Refer to the COPYING file of the official project for license.
*****************************************************************************/
#import <UIKit/UIKit.h>
@interface VLCPlexWebAPI : NSObject
- (BOOL)PlexCreateIdentification:(NSString *)username password:(NSString *)password;
- (NSArray *)PlexBasicAuthentification:(NSString *)username password:(NSString *)password;
- (NSString *)PlexAuthentification:(NSString *)username password:(NSString *)password;
- (NSString *)urlAuth:(NSString *)url autentification:(NSString *)auth;
- (NSData *)HttpRequestWithCookie:(NSURL *)url cookies:(NSArray *)authToken HTTPMethod:(NSString *)method;
- (NSURL *)CreatePlexStreamingURL:(NSString *)adress port:(NSString *)port videoKey:(NSString *)key username:(NSString *)username deviceInfo:(NSMutableArray *)deviceInfo session:(NSString *)session;
- (void)stopSession:(NSString *)adress port:(NSString *)port session:(NSString *)session;
- (NSInteger)MarkWatchedUnwatchedMedia:(NSString *)adress port:(NSString *)port videoRatingKey:(NSString *)ratingKey state:(NSString *)state authentification:(NSString *)auth;
- (NSString *)getFileSubtitleFromPlexServer:(NSMutableArray *)mutableMediaObject modeStream:(BOOL)modeStream;
- (NSString *)getSession;
- (NSData *)PlexDeviceInfo:(NSArray *)cookies;
@end
/*****************************************************************************
* VLCPlexWebAPI.m
* VLC for iOS
*****************************************************************************
* Copyright (c) 2014-2015 VideoLAN. All rights reserved.
*
* Authors: Pierre Sagaspe <pierre.sagaspe # me.com>
*
* Refer to the COPYING file of the official project for license.
*****************************************************************************/
#import "VLCPlexWebAPI.h"
#import "VLCPlexParser.h"
#import "UIDevice+VLC.h"
#define kPlexMediaServerSignIn @"https://plex.tv/users/sign_in.xml"
#define kPlexURLdeviceInfo @"https://plex.tv/devices.xml"
@interface VLCPlexWebAPI ()
{
}
@end
@implementation VLCPlexWebAPI
#pragma mark - Authentification
- (NSArray *)PlexBasicAuthentification:(NSString *)username password:(NSString *)password
{
NSArray *authToken = nil;
NSURL *url = [NSURL URLWithString:kPlexMediaServerSignIn];
NSString *authString = [NSString stringWithFormat:@"%@:%@", username, password];
NSData *authData = [authString dataUsingEncoding:NSASCIIStringEncoding];
NSString *authBase64 = [NSString stringWithFormat:@"Basic %@", [authData base64EncodedStringWithOptions:0]];
NSString *timeString = [NSString stringWithFormat:@"%ld", (long)[[NSDate date] timeIntervalSince1970]];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:5.0];
[request setHTTPMethod:@"POST"];
[request setValue:authBase64 forHTTPHeaderField:@"Authorization"];
[request setValue:timeString forHTTPHeaderField:@"X-Plex-Access-Time"];
NSHTTPURLResponse *response = nil;
NSError *error = nil;
[NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
authToken = [NSHTTPCookie cookiesWithResponseHeaderFields:[response allHeaderFields] forURL:[NSURL URLWithString:@""]];
return authToken;
}
- (BOOL)PlexCreateIdentification:(NSString *)username password:(NSString *)password
{
NSURL *url = [NSURL URLWithString:kPlexMediaServerSignIn];
NSString *authString = [NSString stringWithFormat:@"%@:%@", username, password];
NSData *authData = [authString dataUsingEncoding:NSASCIIStringEncoding];
NSString *authBase64 = [NSString stringWithFormat:@"Basic %@", [authData base64EncodedStringWithOptions:0]];
NSString *appVersion = [NSString stringWithFormat:@"%@", [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleShortVersionString"]];
NSString *timeString = [NSString stringWithFormat:@"%ld", (long)[[NSDate date] timeIntervalSince1970]];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:5.0];
[request setHTTPMethod:@"POST"];
[request setValue:authBase64 forHTTPHeaderField:@"Authorization"];
[request setValue:@"iOS" forHTTPHeaderField:@"X-Plex-Platform"];
[request setValue:[[UIDevice currentDevice] systemVersion] forHTTPHeaderField:@"X-Plex-Platform-Version"];
[request setValue:@"client" forHTTPHeaderField:@"X-Plex-Provides"];
[request setValue:[[[UIDevice currentDevice] identifierForVendor] UUIDString] forHTTPHeaderField:@"X-Plex-Client-Identifier"];
[request setValue:@"PlexVLC" forHTTPHeaderField:@"X-Plex-Product"];
[request setValue:appVersion forHTTPHeaderField:@"X-Plex-Version"];
[request setValue:@"VLC for iOS" forHTTPHeaderField:@"X-Plex-Device-Name"];
[request setValue:[[UIDevice currentDevice] model] forHTTPHeaderField:@"X-Plex-Device"];
[request setValue:timeString forHTTPHeaderField:@"X-Plex-Access-Time"];
NSHTTPURLResponse *response = nil;
NSError *error = nil;
[NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
if ([response statusCode] == 201)
return YES;
else {
APLog(@"Plex Create Identification Error : %@", [response allHeaderFields]);
return NO;
}
}
- (NSData *)HttpRequestWithCookie:(NSURL *)url cookies:(NSArray *)authToken HTTPMethod:(NSString *)method
{
NSString *timeString = [NSString stringWithFormat:@"%ld", (long)[[NSDate date] timeIntervalSince1970]];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:5.0];
NSDictionary *headers = [NSHTTPCookie requestHeaderFieldsWithCookies:authToken];
[request setHTTPMethod:method];
[request setAllHTTPHeaderFields:headers];
[request setValue:timeString forHTTPHeaderField:@"X-Plex-Access-Time"];
NSHTTPURLResponse *response = nil;
NSError *error = nil;
NSData *urlData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
// for debug
//NSString *debugStr = [[NSString alloc] initWithData:urlData encoding:NSUTF8StringEncoding];
//NSLog(@"data : %@", debugStr);
return urlData;
}
- (NSString *)PlexAuthentification:(NSString *)username password:(NSString *)password
{
NSString *authentification = @"";
if ((![username isEqualToString:@""]) && (![password isEqualToString:@""])) {
NSMutableArray *deviceInfo = [[NSMutableArray alloc] init];
NSString *appVersion = [NSString stringWithFormat:@"%@", [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleShortVersionString"]];
NSArray *authToken = [self PlexBasicAuthentification:username password:password];
NSData *data = [self PlexDeviceInfo:authToken];
VLCPlexParser *plexParser = [[VLCPlexParser alloc] init];
deviceInfo = [plexParser PlexExtractDeviceInfo:data];
if ((deviceInfo.count == 0) || ((![[[deviceInfo objectAtIndex:0] objectForKey:@"productVersion"] isEqualToString:appVersion]) || (![[[deviceInfo objectAtIndex:0] objectForKey:@"platformVersion"] isEqualToString:[[UIDevice currentDevice] systemVersion]]))) {
[deviceInfo removeAllObjects];
[self PlexCreateIdentification:username password:password];
data = [self PlexDeviceInfo:authToken];
deviceInfo = [plexParser PlexExtractDeviceInfo:data];
}
if (deviceInfo.count != 0)
authentification = [[NSString stringWithFormat:@"X-Plex-Product=%@&X-Plex-Version=%@&X-Plex-Client-Identifier=%@&X-Plex-Platform=iOS&X-Plex-Platform-Version=%@&X-Plex-Device=%@&X-Plex-Device-Name=%@&X-Plex-Token=%@&X-Plex-Username=%@", [[deviceInfo objectAtIndex:0] objectForKey:@"product"], [[deviceInfo objectAtIndex:0] objectForKey:@"productVersion"], [[deviceInfo objectAtIndex:0] objectForKey:@"clientIdentifier"], [[UIDevice currentDevice] systemVersion], [[UIDevice currentDevice] model], [[deviceInfo objectAtIndex:0] objectForKey:@"name"], [[deviceInfo objectAtIndex:0] objectForKey:@"token"], username] stringByReplacingOccurrencesOfString:@" " withString:@"+"];
}
return authentification;
}
- (NSString *)urlAuth:(NSString *)url autentification:(NSString *)auth
{
NSString *key = @"";
if (![auth isEqualToString:@""]) {
NSRange isRange = [url rangeOfString:@"?" options:NSCaseInsensitiveSearch];
if(isRange.location != NSNotFound)
key = @"&";
else
key = @"?";
}
return [NSString stringWithFormat:@"%@%@%@", url, key, auth];
}
#pragma mark - Unofficial API
- (NSInteger)MarkWatchedUnwatchedMedia:(NSString *)adress port:(NSString *)port videoRatingKey:(NSString *)ratingKey state:(NSString *)state authentification:(NSString *)auth
{
NSString *url = nil;
if ([state isEqualToString:@"watched"])
url = [NSString stringWithFormat:@"http://%@%@/:/unscrobble?identifier=com.plexapp.plugins.library&key=%@", adress, port, ratingKey];
else
url = [NSString stringWithFormat:@"http://%@%@/:/scrobble?identifier=com.plexapp.plugins.library&key=%@", adress, port, ratingKey];
NSURLRequest *request = [[NSURLRequest alloc] initWithURL:[NSURL URLWithString:[[[VLCPlexWebAPI alloc] init] urlAuth:url autentification:auth]] cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData timeoutInterval:20];
NSURLResponse *response = nil;
NSError *error = nil;
[NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
NSInteger httpStatus = [(NSHTTPURLResponse *)response statusCode];
if (httpStatus != 200)
APLog(@"Mark Watched Unwatched Media Error status: %ld at URL : %@", (long)httpStatus, url);
return httpStatus;
}
- (NSString *)getFileSubtitleFromPlexServer:(NSMutableArray *)mutableMediaObject modeStream:(BOOL)modeStream
{
NSString *FileSubtitlePath = nil;
NSString *fileName = [[[[mutableMediaObject objectAtIndex:0] objectForKey:@"namefile"] stringByDeletingPathExtension] stringByAppendingPathExtension:[[mutableMediaObject objectAtIndex:0] objectForKey:@"codecSubtitle"]];
VLCPlexWebAPI *PlexWebAPI = [[VLCPlexWebAPI alloc] init];
NSURL *url = [[NSURL alloc] initWithString:[PlexWebAPI urlAuth:[[mutableMediaObject objectAtIndex:0] objectForKey:@"keySubtitle"] autentification:[[mutableMediaObject objectAtIndex:0] objectForKey:@"authentification"]]];
NSData *receivedSub = [NSData dataWithContentsOfURL:url];
if (receivedSub.length < [[UIDevice currentDevice] freeDiskspace].longLongValue) {
NSArray *searchPaths = nil;
if (modeStream)
searchPaths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
else
searchPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *directoryPath = [searchPaths objectAtIndex:0];
FileSubtitlePath = [directoryPath stringByAppendingPathComponent:fileName];
NSFileManager *fileManager = [NSFileManager defaultManager];
if (![fileManager fileExistsAtPath:FileSubtitlePath]) {
[fileManager createFileAtPath:FileSubtitlePath contents:nil attributes:nil];
if (![fileManager fileExistsAtPath:FileSubtitlePath])
APLog(@"file creation failed, no data was saved");
}
[receivedSub writeToFile:FileSubtitlePath atomically:YES];
} else {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"DISK_FULL", nil) message:[NSString stringWithFormat:NSLocalizedString(@"DISK_FULL_FORMAT", nil), fileName, [[UIDevice currentDevice] model]] delegate:self cancelButtonTitle:NSLocalizedString(@"BUTTON_OK", nil) otherButtonTitles:nil];
[alert show];
}
return FileSubtitlePath;
}
- (NSURL *)CreatePlexStreamingURL:(NSString *)adress port:(NSString *)port videoKey:(NSString *)key username:(NSString *)username deviceInfo:(NSMutableArray *)deviceInfo session:(NSString *)session
{
/* it starts video transcoding but without sound !!! why ? */
NSString *authentification = [[NSString stringWithFormat:@"&X-Plex-Product=%@&X-Plex-Version=%@&X-Plex-Client-Identifier=%@&X-Plex-Platform=iOS&X-Plex-Platform-Version=%@&X-Plex-Device=%@&X-Plex-Device-Name=%@&X-Plex-Token=%@&X-Plex-Username=%@", [[deviceInfo objectAtIndex:0] objectForKey:@"product"], [[deviceInfo objectAtIndex:0] objectForKey:@"productVersion"], [[deviceInfo objectAtIndex:0] objectForKey:@"clientIdentifier"], [[UIDevice currentDevice] systemVersion], [[UIDevice currentDevice] model], [[deviceInfo objectAtIndex:0] objectForKey:@"name"], [[deviceInfo objectAtIndex:0] objectForKey:@"token"], username] stringByReplacingOccurrencesOfString:@" " withString:@"+"];
NSString *unescaped = [NSString stringWithFormat:@"http://127.0.0.1:32400%@", key];
NSString *escapedString = [unescaped stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLHostAllowedCharacterSet]];
NSURL *url = [NSURL URLWithString:[[NSString stringWithFormat:@"http://%@%@/video/:/transcode/universal/start.m3u8?path=%@&mediaIndex=0&partIndex=0&protocol=hls&offset=0&fastSeek=1&directPlay=0&directStream=1&subtitleSize=100&audioBoost=100&session=%@&subtitles=burn", adress, port, escapedString, session] stringByAppendingString:authentification]];
return url;
}
- (void)stopSession:(NSString *)adress port:(NSString *)port session:(NSString *)session
{
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"http://%@:%@/video/:/transcode/universal/stop?session=%@", adress, port, session]];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:5.0];
NSHTTPURLResponse *response = nil;
NSError *error = nil;
[NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
if ([response statusCode] != 200)
NSLog(@"Plex stop Session %@ : %@", session, [response allHeaderFields]);
}
#pragma mark -
- (NSString *)getSession
{
NSString *session = [NSString stringWithFormat:@"%ld", (long)[[NSDate date] timeIntervalSince1970]];
return session;
}
- (NSData *)PlexDeviceInfo:(NSArray *)cookies
{
NSURL *url = [NSURL URLWithString:kPlexURLdeviceInfo];
NSData *data = [self HttpRequestWithCookie:url cookies:cookies HTTPMethod:@"GET"];
return data;
}
@end
\ No newline at end of file
......@@ -15,6 +15,7 @@
260B41E11A75006300DA89C9 /* OneDriveWhite@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 260B41DB1A75006300DA89C9 /* OneDriveWhite@3x.png */; };
262C71591A98FA9200F7ED34 /* VLCPlexMediaInformationViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 262C71581A98FA9200F7ED34 /* VLCPlexMediaInformationViewController.m */; };
262C715B1A98FDE300F7ED34 /* VLCPlexMediaInformationViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 262C715A1A98FDE300F7ED34 /* VLCPlexMediaInformationViewController.xib */; };
2640FAE61B01477A00E359D6 /* VLCPlexWebAPI.m in Sources */ = {isa = PBXBuildFile; fileRef = 2640FAE51B01477A00E359D6 /* VLCPlexWebAPI.m */; };
265D511C1922746C00E38383 /* VLCLocalPlexFolderListViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 265D51191922746C00E38383 /* VLCLocalPlexFolderListViewController.m */; };
265D511D1922746C00E38383 /* VLCPlexParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 265D511B1922746C00E38383 /* VLCPlexParser.m */; };
26D4AF8D1A78379000D5EC65 /* VLCSharedLibraryListViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 26D4AF8A1A78379000D5EC65 /* VLCSharedLibraryListViewController.m */; };
......@@ -617,6 +618,8 @@
262C71571A98FA9200F7ED34 /* VLCPlexMediaInformationViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = VLCPlexMediaInformationViewController.h; path = Sources/VLCPlexMediaInformationViewController.h; sourceTree = SOURCE_ROOT; };
262C71581A98FA9200F7ED34 /* VLCPlexMediaInformationViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = VLCPlexMediaInformationViewController.m; path = Sources/VLCPlexMediaInformationViewController.m; sourceTree = SOURCE_ROOT; };
262C715A1A98FDE300F7ED34 /* VLCPlexMediaInformationViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = VLCPlexMediaInformationViewController.xib; path = Resources/VLCPlexMediaInformationViewController.xib; sourceTree = SOURCE_ROOT; };
2640FAE41B01477A00E359D6 /* VLCPlexWebAPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = VLCPlexWebAPI.h; path = Sources/VLCPlexWebAPI.h; sourceTree = SOURCE_ROOT; };
2640FAE51B01477A00E359D6 /* VLCPlexWebAPI.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = VLCPlexWebAPI.m; path = Sources/VLCPlexWebAPI.m; sourceTree = SOURCE_ROOT; };
265D51181922746C00E38383 /* VLCLocalPlexFolderListViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = VLCLocalPlexFolderListViewController.h; path = Sources/VLCLocalPlexFolderListViewController.h; sourceTree = SOURCE_ROOT; };
265D51191922746C00E38383 /* VLCLocalPlexFolderListViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = VLCLocalPlexFolderListViewController.m; path = Sources/VLCLocalPlexFolderListViewController.m; sourceTree = SOURCE_ROOT; };
265D511A1922746C00E38383 /* VLCPlexParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = VLCPlexParser.h; path = Sources/VLCPlexParser.h; sourceTree = SOURCE_ROOT; };
......@@ -2113,6 +2116,8 @@
children = (
265D511A1922746C00E38383 /* VLCPlexParser.h */,
265D511B1922746C00E38383 /* VLCPlexParser.m */,
2640FAE41B01477A00E359D6 /* VLCPlexWebAPI.h */,
2640FAE51B01477A00E359D6 /* VLCPlexWebAPI.m */,
26D4AF8B1A78379000D5EC65 /* VLCSharedLibraryParser.h */,
26D4AF8C1A78379000D5EC65 /* VLCSharedLibraryParser.m */,
7D30F3D1183AB2F100FFC021 /* VLCLocalNetworkListCell.h */,
......@@ -3796,6 +3801,7 @@
7D30F3D0183AB2AC00FFC021 /* VLCMediaFileDiscoverer.m in Sources */,
493B1A1D195D06B1000A491A /* BasicUPnPDevice+VLC.m in Sources */,
265D511D1922746C00E38383 /* VLCPlexParser.m in Sources */,
2640FAE61B01477A00E359D6 /* VLCPlexWebAPI.m in Sources */,
7DB847D71A5871570002DC30 /* VLCOneDriveObject.m in Sources */,
7D1052E91A4DCC1100295F08 /* VLCOneDriveTableViewController.m in Sources */,
7D30F3D7183AB2F100FFC021 /* VLCLocalNetworkListCell.m in Sources */,
......
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