VLCOpenNetworkStreamViewController.m 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  1. /*****************************************************************************
  2. * VLCOpenNetworkStreamViewController.m
  3. * VLC for iOS
  4. *****************************************************************************
  5. * Copyright (c) 2013 VideoLAN. All rights reserved.
  6. * $Id$
  7. *
  8. * Authors: Felix Paul Kühne <fkuehne # videolan.org>
  9. * Gleb Pinigin <gpinigin # gmail.com>
  10. * Pierre Sagaspe <pierre.sagaspe # me.com>
  11. *
  12. * Refer to the COPYING file of the official project for license.
  13. *****************************************************************************/
  14. #import "VLCOpenNetworkStreamViewController.h"
  15. #import "VLCAppDelegate.h"
  16. #import "VLCPlaylistViewController.h"
  17. #import "UIBarButtonItem+Theme.h"
  18. #import "UINavigationController+Theme.h"
  19. #import "VLCMenuTableViewController.h"
  20. #import "UIDevice+VLC.h"
  21. @interface VLCOpenNetworkStreamViewController () <UITableViewDataSource, UITableViewDelegate, UITextFieldDelegate>
  22. {
  23. NSMutableArray *_recentURLs;
  24. }
  25. @end
  26. @implementation VLCOpenNetworkStreamViewController
  27. + (void)initialize
  28. {
  29. NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
  30. NSDictionary *appDefaults = @{kVLCRecentURLs : @[], kVLCPrivateWebStreaming : @(NO)};
  31. [defaults registerDefaults:appDefaults];
  32. }
  33. - (void)applicationDidBecomeActive:(NSNotification *)notification
  34. {
  35. [self updatePasteboardTextInURLField];
  36. }
  37. - (void)dealloc
  38. {
  39. [[NSNotificationCenter defaultCenter] removeObserver:self
  40. name:UIApplicationDidBecomeActiveNotification
  41. object:[UIApplication sharedApplication]];
  42. }
  43. - (void)viewDidLoad
  44. {
  45. [super viewDidLoad];
  46. /*
  47. * Observe changes to the pasteboard so we can automatically paste it into the URL field.
  48. * Do not use UIPasteboardChangedNotification because we have copy actions that will trigger it on this screen.
  49. * Instead when the user comes back to the application from the background (or the inactive state by pulling down notification center), update the URL field.
  50. * Using the 'active' rather than 'foreground' notification for future proofing if iOS ever allows running multiple apps on the same screen (which would allow the pasteboard to be changed without truly backgrounding the app).
  51. */
  52. [[NSNotificationCenter defaultCenter] addObserver:self
  53. selector:@selector(applicationDidBecomeActive:)
  54. name:UIApplicationDidBecomeActiveNotification
  55. object:[UIApplication sharedApplication]];
  56. if (SYSTEM_RUNS_IOS7_OR_LATER)
  57. [self.openButton setTitle:NSLocalizedString(@"OPEN_NETWORK", nil) forState:UIControlStateNormal];
  58. else
  59. [self.openButton setTitle:NSLocalizedString(@"BUTTON_OPEN", nil) forState:UIControlStateNormal];
  60. [self.privateModeLabel setText:NSLocalizedString(@"PRIVATE_PLAYBACK_TOGGLE", nil)];
  61. [self.ScanSubModeLabel setText:NSLocalizedString(@"SCAN_SUBTITLE_TOGGLE", nil)];
  62. [self.ScanSubModeLabel setAdjustsFontSizeToFitWidth:YES];
  63. [self.ScanSubModeLabel setNumberOfLines:0];
  64. self.title = NSLocalizedString(@"OPEN_NETWORK", nil);
  65. self.navigationItem.leftBarButtonItem = [UIBarButtonItem themedRevealMenuButtonWithTarget:self andSelector:@selector(goBack:)];
  66. [self.whatToOpenHelpLabel setText:NSLocalizedString(@"OPEN_NETWORK_HELP", nil)];
  67. self.urlField.delegate = self;
  68. self.urlField.keyboardType = UIKeyboardTypeURL;
  69. if (SYSTEM_RUNS_IOS7_OR_LATER) {
  70. NSAttributedString *coloredAttributedPlaceholder = [[NSAttributedString alloc] initWithString:@"http://myserver.com/file.mkv" attributes:@{NSForegroundColorAttributeName: [UIColor VLCLightTextColor]}];
  71. self.urlField.attributedPlaceholder = coloredAttributedPlaceholder;
  72. self.edgesForExtendedLayout = UIRectEdgeNone;
  73. }
  74. // This will be called every time this VC is opened by the side menu controller
  75. [self updatePasteboardTextInURLField];
  76. }
  77. - (void)updatePasteboardTextInURLField
  78. {
  79. UIPasteboard *pasteboard = [UIPasteboard generalPasteboard];
  80. if ([pasteboard containsPasteboardTypes:@[@"public.url"]])
  81. self.urlField.text = [[pasteboard valueForPasteboardType:@"public.url"] absoluteString];
  82. }
  83. - (void)viewWillAppear:(BOOL)animated
  84. {
  85. NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
  86. _recentURLs = [NSMutableArray arrayWithArray:[defaults objectForKey:kVLCRecentURLs]];
  87. self.privateToggleSwitch.on = [defaults boolForKey:kVLCPrivateWebStreaming];
  88. self.ScanSubToggleSwitch.on = [defaults boolForKey:kVLChttpScanSubtitle];
  89. [super viewWillAppear:animated];
  90. }
  91. - (void)viewWillDisappear:(BOOL)animated
  92. {
  93. [[NSNotificationCenter defaultCenter] removeObserver:self
  94. name:UIApplicationDidBecomeActiveNotification
  95. object:[UIApplication sharedApplication]];
  96. NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
  97. [defaults setObject:[NSArray arrayWithArray:_recentURLs] forKey:kVLCRecentURLs];
  98. [defaults setBool:self.privateToggleSwitch.on forKey:kVLCPrivateWebStreaming];
  99. [defaults setBool:self.ScanSubToggleSwitch.on forKey:kVLChttpScanSubtitle];
  100. [defaults synchronize];
  101. [super viewWillDisappear:animated];
  102. }
  103. - (CGSize)contentSizeForViewInPopover {
  104. return [self.view sizeThatFits:CGSizeMake(320, 800)];
  105. }
  106. #pragma mark - UI interaction
  107. - (BOOL)shouldAutorotate
  108. {
  109. UIInterfaceOrientation toInterfaceOrientation = [[UIApplication sharedApplication] statusBarOrientation];
  110. if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone && toInterfaceOrientation == UIInterfaceOrientationPortraitUpsideDown)
  111. return NO;
  112. return YES;
  113. }
  114. - (IBAction)goBack:(id)sender
  115. {
  116. [self.view endEditing:YES];
  117. [[(VLCAppDelegate*)[UIApplication sharedApplication].delegate revealController] toggleSidebar:![(VLCAppDelegate*)[UIApplication sharedApplication].delegate revealController].sidebarShowing duration:kGHRevealSidebarDefaultAnimationDuration];
  118. }
  119. - (IBAction)openButtonAction:(id)sender
  120. {
  121. if ([self.urlField.text length] > 0) {
  122. if (!self.privateToggleSwitch.on) {
  123. if ([_recentURLs indexOfObject:self.urlField.text] != NSNotFound)
  124. [_recentURLs removeObject:self.urlField.text];
  125. if (_recentURLs.count >= 15)
  126. [_recentURLs removeLastObject];
  127. [_recentURLs addObject:self.urlField.text];
  128. [self.historyTableView reloadData];
  129. }
  130. [self _openURLStringAndDismiss:self.urlField.text];
  131. }
  132. }
  133. #pragma mark - table view data source
  134. - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
  135. {
  136. return 1;
  137. }
  138. - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
  139. {
  140. return _recentURLs.count;
  141. }
  142. - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
  143. {
  144. static NSString *CellIdentifier = @"StreamingHistoryCell";
  145. UITableViewCell *cell = (UITableViewCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
  146. if (cell == nil) {
  147. cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
  148. cell.textLabel.textColor = [UIColor whiteColor];
  149. cell.textLabel.highlightedTextColor = [UIColor blackColor];
  150. cell.detailTextLabel.textColor = [UIColor VLCLightTextColor];
  151. cell.detailTextLabel.highlightedTextColor = [UIColor blackColor];
  152. }
  153. NSInteger row = indexPath.row;
  154. cell.textLabel.text = [_recentURLs[row] lastPathComponent];
  155. cell.detailTextLabel.text = _recentURLs[row];
  156. return cell;
  157. }
  158. #pragma mark - table view delegate
  159. - (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
  160. {
  161. cell.backgroundColor = (indexPath.row % 2 == 0)? [UIColor blackColor]: [UIColor VLCDarkBackgroundColor];
  162. }
  163. - (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
  164. {
  165. return YES;
  166. }
  167. - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
  168. {
  169. if (editingStyle == UITableViewCellEditingStyleDelete) {
  170. [_recentURLs removeObjectAtIndex:indexPath.row];
  171. [tableView reloadData];
  172. }
  173. }
  174. - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
  175. {
  176. [self _openURLStringAndDismiss:_recentURLs[indexPath.row]];
  177. [self.historyTableView deselectRowAtIndexPath:indexPath animated:NO];
  178. }
  179. - (void)tableView:(UITableView *)tableView
  180. performAction:(SEL)action
  181. forRowAtIndexPath:(NSIndexPath *)indexPath
  182. withSender:(id)sender
  183. {
  184. NSString *actionText = NSStringFromSelector(action);
  185. if ([actionText isEqualToString:@"copy:"])
  186. {
  187. [UIPasteboard generalPasteboard].string = _recentURLs[indexPath.row];
  188. }
  189. }
  190. - (BOOL)tableView:(UITableView *)tableView
  191. canPerformAction:(SEL)action
  192. forRowAtIndexPath:(NSIndexPath *)indexPath
  193. withSender:(id)sender
  194. {
  195. NSString *actionText = NSStringFromSelector(action);
  196. if ([actionText isEqualToString:@"copy:"])
  197. {
  198. return YES;
  199. }
  200. return NO;
  201. }
  202. - (BOOL)tableView:(UITableView *)tableView shouldShowMenuForRowAtIndexPath:(NSIndexPath *)indexPath
  203. {
  204. return YES;
  205. }
  206. #pragma mark - internals
  207. - (void)_openURLStringAndDismiss:(NSString *)url
  208. {
  209. NSURL *URLscheme = [NSURL URLWithString:url];
  210. NSString *URLofSubtitle = nil;
  211. if ([URLscheme.scheme isEqualToString:@"http"])
  212. if (self.ScanSubToggleSwitch.on)
  213. URLofSubtitle = [self _checkURLofSubtitle:url];
  214. [(VLCAppDelegate*)[UIApplication sharedApplication].delegate openMovieWithExternalSubtitleFromURL:[NSURL URLWithString:url] externalSubURL:URLofSubtitle];
  215. }
  216. - (NSString *)_checkURLofSubtitle:(NSString *)url
  217. {
  218. NSString *subtitleFileExtensions = kSupportedSubtitleFileExtensions;
  219. NSCharacterSet *characterFilter = [NSCharacterSet characterSetWithCharactersInString:@"\\.():$"];
  220. subtitleFileExtensions = [[subtitleFileExtensions componentsSeparatedByCharactersInSet:characterFilter] componentsJoinedByString:@""];
  221. NSArray *arraySubtitleFileExtensions = [subtitleFileExtensions componentsSeparatedByString:@"|"];
  222. NSString *urlTemp = [[url stringByDeletingPathExtension] stringByAppendingString:@"."];
  223. for (int cnt = 0; cnt < arraySubtitleFileExtensions.count; cnt++) {
  224. NSString *checkAddress = [urlTemp stringByAppendingString:arraySubtitleFileExtensions[cnt]];
  225. NSURL *checkURL = [NSURL URLWithString:checkAddress];
  226. NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:checkURL];
  227. request.HTTPMethod = @"HEAD";
  228. NSURLResponse *response = nil;
  229. [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:nil];
  230. NSInteger httpStatus = [(NSHTTPURLResponse *)response statusCode];
  231. if (httpStatus == 200) {
  232. NSString *fileSubtitlePath = [self _getFileSubtitleFromServer:checkURL];
  233. return fileSubtitlePath;
  234. }
  235. }
  236. return nil;
  237. }
  238. - (NSString *)_getFileSubtitleFromServer:(NSURL *)url
  239. {
  240. NSString *FileSubtitlePath = nil;
  241. NSString *fileName = [[url path] lastPathComponent];
  242. NSData *receivedSub = [NSData dataWithContentsOfURL:url];
  243. if (receivedSub.length < [[UIDevice currentDevice] freeDiskspace].longLongValue) {
  244. NSArray *searchPaths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
  245. NSString *directoryPath = [searchPaths objectAtIndex:0];
  246. FileSubtitlePath = [directoryPath stringByAppendingPathComponent:fileName];
  247. NSFileManager *fileManager = [NSFileManager defaultManager];
  248. if (![fileManager fileExistsAtPath:FileSubtitlePath]) {
  249. [fileManager createFileAtPath:FileSubtitlePath contents:nil attributes:nil];
  250. if (![fileManager fileExistsAtPath:FileSubtitlePath])
  251. APLog(@"file creation failed, no data was saved");
  252. }
  253. [receivedSub writeToFile:FileSubtitlePath atomically:YES];
  254. } else {
  255. 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];
  256. [alert show];
  257. }
  258. return FileSubtitlePath;
  259. }
  260. #pragma mark - text view delegate
  261. - (BOOL)textFieldShouldReturn:(UITextField *)textField
  262. {
  263. [self.urlField resignFirstResponder];
  264. return NO;
  265. }
  266. @end