VLCNetworkServerBrowserFTP.m 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. /*****************************************************************************
  2. * VLCNetworkServerBrowserFTP.m
  3. * VLC for iOS
  4. *****************************************************************************
  5. * Copyright (c) 2015 VideoLAN. All rights reserved.
  6. * $Id$
  7. *
  8. * Authors: Tobias Conradi <videolan # tobias-conradi.de>
  9. *
  10. * Refer to the COPYING file of the official project for license.
  11. *****************************************************************************/
  12. #import "VLCNetworkServerBrowserFTP.h"
  13. #import "WhiteRaccoon.h"
  14. #import "NSString+SupportedMedia.h"
  15. @interface VLCNetworkServerBrowserFTP () <WRRequestDelegate>
  16. @property (nonatomic) NSURL *url;
  17. @property (nonatomic) WRRequestListDirectory *FTPListDirRequest;
  18. @end
  19. @implementation VLCNetworkServerBrowserFTP
  20. @synthesize delegate = _delegate, items = _items, mediaList = _mediaList;
  21. #pragma mark - Protocol conformance
  22. - (NSString *)title {
  23. if ([_url.path isEqualToString:@"/"])
  24. return _url.host;
  25. else
  26. return [_url.path lastPathComponent];
  27. }
  28. - (void)update {
  29. if (_FTPListDirRequest)
  30. return;
  31. _FTPListDirRequest = [[WRRequestListDirectory alloc] init];
  32. _FTPListDirRequest.delegate = self;
  33. _FTPListDirRequest.hostname = _url.host;
  34. _FTPListDirRequest.username = _url.user;
  35. _FTPListDirRequest.password = [_url.password stringByRemovingPercentEncoding];
  36. _FTPListDirRequest.path = _url.path;
  37. _FTPListDirRequest.passive = YES;
  38. [_FTPListDirRequest start];
  39. }
  40. #pragma mark -
  41. - (instancetype)initWithLogin:(VLCNetworkServerLoginInformation *)login
  42. {
  43. return [self initWithFTPServer:login.address
  44. userName:login.username
  45. andPassword:login.password
  46. atPath:@"/"];
  47. }
  48. - (instancetype)initWithFTPServer:(NSString *)serverAddress userName:(NSString *)username andPassword:(NSString *)password atPath:(NSString *)path
  49. {
  50. NSURLComponents *components = [[NSURLComponents alloc] init];
  51. components.scheme = @"ftp";
  52. components.host = serverAddress;
  53. components.user = username.length ? username : @"anonymous";
  54. components.password = password.length ? password : nil;
  55. components.path = path;
  56. return [self initWithURL:components.URL];
  57. }
  58. - (instancetype)initWithURL:(NSURL *)url
  59. {
  60. self = [super init];
  61. if (self) {
  62. _url = url;
  63. }
  64. return self;
  65. }
  66. - (VLCMediaList *)buildMediaList
  67. {
  68. VLCMediaList *mediaList = [[VLCMediaList alloc] init];
  69. @synchronized(_items) {
  70. for (id<VLCNetworkServerBrowserItem> browseritem in _items) {
  71. VLCMedia *media = [browseritem media];
  72. if (media)
  73. [mediaList addMedia:media];
  74. }
  75. }
  76. return mediaList;
  77. }
  78. #pragma mark - white raccoon delegation
  79. - (NSURL*)searchSubtitleForFile:(NSString *)filename inSubtitleList:(NSArray *)subtitleList
  80. {
  81. NSString *filenameNoExt = [[filename lastPathComponent] stringByDeletingPathExtension];
  82. for (NSString *subtitle in subtitleList) {
  83. if ([[[subtitle lastPathComponent] stringByDeletingPathExtension] isEqualToString:filenameNoExt])
  84. return [self.url URLByAppendingPathComponent:subtitle];
  85. }
  86. return nil;
  87. }
  88. - (void)requestCompleted:(WRRequest *)request
  89. {
  90. if (request == _FTPListDirRequest) {
  91. NSMutableArray *subtitleList = [[NSMutableArray alloc] init];
  92. NSMutableArray *filteredList = [[NSMutableArray alloc] init];
  93. NSArray *rawList = [(WRRequestListDirectory*)request filesInfo];
  94. NSUInteger count = rawList.count;
  95. for (NSUInteger x = 0; x < count; x++) {
  96. NSDictionary *dict = rawList[x];
  97. if ([[dict objectForKey:(id)kCFFTPResourceName] isSupportedSubtitleFormat])
  98. [subtitleList addObject:[dict objectForKey:(id)kCFFTPResourceName]];
  99. }
  100. for (NSUInteger x = 0; x < count; x++) {
  101. NSDictionary *dict = rawList[x];
  102. NSString *filename = [dict objectForKey:(id)kCFFTPResourceName];
  103. BOOL container = [[dict objectForKey:(id)kCFFTPResourceType] intValue] == 4;
  104. if (![filename hasPrefix:@"."])
  105. {
  106. NSURL *subtitleURL = nil;
  107. if ([filename isSupportedAudioMediaFormat] || [filename isSupportedMediaFormat])
  108. subtitleURL = [self searchSubtitleForFile:filename inSubtitleList:subtitleList];
  109. else if ((!container) && ![filename isSupportedSubtitleFormat])
  110. continue;
  111. [filteredList addObject:[[VLCNetworkServerBrowserItemFTP alloc] initWithDictionary:dict baseURL:self.url subtitleURL:subtitleURL]];
  112. }
  113. }
  114. __weak typeof(self) weakSelf = self;
  115. [[NSOperationQueue mainQueue] addOperationWithBlock:^{
  116. __strong __typeof(weakSelf)strongSelf = weakSelf;
  117. @synchronized(strongSelf.items) {
  118. strongSelf->_items = [NSArray arrayWithArray:filteredList];
  119. }
  120. strongSelf->_mediaList = [self buildMediaList];
  121. [self.delegate networkServerBrowserDidUpdate:self];
  122. }];
  123. } else
  124. APLog(@"unknown request %@ completed", request);
  125. }
  126. - (void)requestFailed:(WRRequest *)request
  127. {
  128. [[NSOperationQueue mainQueue] addOperationWithBlock:^{
  129. NSDictionary *userInfo = nil;
  130. if (request.error.message) {
  131. userInfo = @{ NSLocalizedDescriptionKey : request.error.message };
  132. }
  133. NSError *error = [NSError errorWithDomain:@"org.videolan.whiteracoon" code:request.error.errorCode userInfo:userInfo];
  134. [self.delegate networkServerBrowser:self requestDidFailWithError:error];
  135. APLog(@"request %@ failed with error %i", request, request.error.errorCode);
  136. }];
  137. }
  138. @end
  139. @implementation VLCNetworkServerBrowserItemFTP
  140. @synthesize name = _name, container = _container, fileSizeBytes = _fileSizeBytes, URL = _URL;
  141. - (instancetype)initWithDictionary:(NSDictionary *)dict baseURL:(NSURL *)baseURL subtitleURL:(NSURL *)subtitleURL
  142. {
  143. self = [super init];
  144. if (self) {
  145. NSString *rawFileName = [dict objectForKey:(id)kCFFTPResourceName];
  146. NSData *flippedData = [rawFileName dataUsingEncoding:[[[NSUserDefaults standardUserDefaults] objectForKey:kVLCSettingFTPTextEncoding] intValue] allowLossyConversion:YES];
  147. if (flippedData != nil) {
  148. _name = [[NSString alloc] initWithData:flippedData encoding:NSUTF8StringEncoding];
  149. if (_name == nil) {
  150. /* this can happen if our string conversation failed */
  151. _name = rawFileName;
  152. }
  153. _container = [dict[(id)kCFFTPResourceType] intValue] == 4;
  154. _fileSizeBytes = dict[(id)kCFFTPResourceSize];
  155. _URL = [baseURL URLByAppendingPathComponent:_name];
  156. _subtitleURL = subtitleURL;
  157. }
  158. }
  159. return self;
  160. }
  161. - (id<VLCNetworkServerBrowser>)containerBrowser {
  162. return [[VLCNetworkServerBrowserFTP alloc] initWithURL:self.URL];
  163. }
  164. - (BOOL)isDownloadable
  165. {
  166. //VLC also needs an extension in the filename for this to work.
  167. return YES;
  168. }
  169. - (VLCMedia *)media
  170. {
  171. if (_URL)
  172. return [VLCMedia mediaWithURL:_URL];
  173. return [VLCMedia mediaAsNodeWithName:self.name];
  174. }
  175. @end