VLCLibrarySearchDisplayDataSource.m 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. /*****************************************************************************
  2. * VLCLibrarySearchDisplayDataSource.m
  3. * VLC for iOS
  4. *****************************************************************************
  5. * Copyright (c) 2017 VideoLAN. All rights reserved.
  6. * $Id$
  7. *
  8. * Authors: Carola Nitz <nitz.carola # gmail.com>
  9. *
  10. * Refer to the COPYING file of the official project for license.
  11. *****************************************************************************/
  12. #import "VLCLibrarySearchDisplayDataSource.h"
  13. #import "VLCPlaylistTableViewCell.h"
  14. @interface VLCLibrarySearchDisplayDataSource() <UITableViewDataSource>
  15. {
  16. NSMutableArray *_searchData;
  17. }
  18. @end
  19. @implementation VLCLibrarySearchDisplayDataSource
  20. - (instancetype)init
  21. {
  22. self = [super init];
  23. if (self) {
  24. _searchData = [NSMutableArray new];
  25. }
  26. return self;
  27. }
  28. - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
  29. {
  30. return _searchData.count;
  31. }
  32. - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
  33. {
  34. VLCPlaylistTableViewCell *cell = (VLCPlaylistTableViewCell *)[tableView dequeueReusableCellWithIdentifier:kPlaylistCellIdentifier forIndexPath:indexPath];
  35. NSInteger row = indexPath.row;
  36. if (row < _searchData.count)
  37. cell.mediaObject = _searchData[row];
  38. return cell;
  39. }
  40. - (NSManagedObject *)objectAtIndex:(NSUInteger)index
  41. {
  42. return index < _searchData.count ? _searchData[index] : nil;
  43. }
  44. - (void)shouldReloadTableForSearchString:(NSString *)searchString searchableFiles:(NSArray *)files
  45. {
  46. if (!searchString || [searchString isEqualToString:@""]) {
  47. _searchData = [files mutableCopy];
  48. return;
  49. }
  50. [_searchData removeAllObjects];
  51. NSRange nameRange;
  52. for (NSManagedObject *item in files) {
  53. if ([item isKindOfClass:[MLAlbum class]]) {
  54. nameRange = [self _searchAlbum:(MLAlbum *)item forString:searchString];
  55. } else if ([item isKindOfClass:[MLAlbumTrack class]]) {
  56. nameRange = [self _searchAlbumTrack:(MLAlbumTrack *)item forString:searchString];
  57. } else if ([item isKindOfClass:[MLShowEpisode class]]) {
  58. nameRange = [self _searchShowEpisode:(MLShowEpisode *)item forString:searchString];
  59. } else if ([item isKindOfClass:[MLShow class]]) {
  60. nameRange = [self _searchShow:(MLShow *)item forString:searchString];
  61. } else if ([item isKindOfClass:[MLLabel class]])
  62. nameRange = [self _searchLabel:(MLLabel *)item forString:searchString];
  63. else // simple file
  64. nameRange = [self _searchFile:(MLFile*)item forString:searchString];
  65. if (nameRange.location != NSNotFound)
  66. [_searchData addObject:item];
  67. }
  68. }
  69. - (NSRange)_searchAlbumTrack:(MLAlbumTrack *)albumTrack forString:(NSString *)searchString
  70. {
  71. NSString *trackTitle = albumTrack.title;
  72. NSRange nameRange = [trackTitle rangeOfString:searchString options:NSCaseInsensitiveSearch];
  73. if (nameRange.location != NSNotFound)
  74. return nameRange;
  75. NSMutableArray *stringsToSearch = [[NSMutableArray alloc] initWithObjects:trackTitle, nil];
  76. if ([albumTrack artist])
  77. [stringsToSearch addObject:[albumTrack artist]];
  78. if ([albumTrack genre])
  79. [stringsToSearch addObject:[albumTrack genre]];
  80. NSArray *substrings = [searchString componentsSeparatedByString:@" "];
  81. NSUInteger substringCount = substrings.count;
  82. NSUInteger searchStringCount = stringsToSearch.count;
  83. for (NSUInteger x = 0; x < substringCount; x++) {
  84. for (NSUInteger y = 0; y < searchStringCount; y++) {
  85. nameRange = [stringsToSearch[y] rangeOfString:substrings[x] options:NSCaseInsensitiveSearch];
  86. if (nameRange.location != NSNotFound)
  87. break;
  88. }
  89. if (nameRange.location != NSNotFound)
  90. break;
  91. }
  92. return nameRange;
  93. }
  94. - (NSRange)_searchAlbum:(MLAlbum *)album forString:(NSString *)searchString
  95. {
  96. NSString *albumName = [album name];
  97. NSRange nameRange = [albumName rangeOfString:searchString options:NSCaseInsensitiveSearch];
  98. if (nameRange.location != NSNotFound)
  99. return nameRange;
  100. if ([album releaseYear]) {
  101. nameRange = [[album releaseYear] rangeOfString:searchString options:NSCaseInsensitiveSearch];
  102. if (nameRange.location != NSNotFound)
  103. return nameRange;
  104. }
  105. /* split search string into substrings and try again */
  106. NSArray *substrings = [searchString componentsSeparatedByString:@" "];
  107. NSUInteger substringCount = substrings.count;
  108. if (substringCount > 1) {
  109. for (NSUInteger x = 0; x < substringCount; x++) {
  110. nameRange = [searchString rangeOfString:substrings[x] options:NSCaseInsensitiveSearch];
  111. if (nameRange.location != NSNotFound)
  112. break;
  113. }
  114. }
  115. if (nameRange.location != NSNotFound)
  116. return nameRange;
  117. /* search our tracks if we can't find what the user is looking for */
  118. NSArray *tracks = [album sortedTracks];
  119. NSUInteger trackCount = tracks.count;
  120. for (NSUInteger x = 0; x < trackCount; x++) {
  121. nameRange = [self _searchAlbumTrack:tracks[x] forString:searchString];
  122. if (nameRange.location != NSNotFound)
  123. break;
  124. }
  125. return nameRange;
  126. }
  127. - (NSRange)_searchShowEpisode:(MLShowEpisode *)episode forString:(NSString *)searchString
  128. {
  129. /* basic search first, then try more complex things */
  130. NSString *episodeName = [episode name];
  131. NSRange nameRange;
  132. if (episodeName) {
  133. nameRange = [episodeName rangeOfString:searchString options:NSCaseInsensitiveSearch];
  134. if (nameRange.location != NSNotFound)
  135. return nameRange;
  136. }
  137. /* split search string into substrings and try again */
  138. NSArray *substrings = [searchString componentsSeparatedByString:@" "];
  139. NSUInteger substringCount = substrings.count;
  140. if (substringCount > 1) {
  141. for (NSUInteger x = 0; x < substringCount; x++) {
  142. nameRange = [searchString rangeOfString:substrings[x] options:NSCaseInsensitiveSearch];
  143. if (nameRange.location != NSNotFound)
  144. break;
  145. }
  146. }
  147. return nameRange;
  148. }
  149. - (NSRange)_searchShow:(MLShow *)mediaShow forString:(NSString *)searchString
  150. {
  151. /* basic search first, then try more complex things */
  152. NSRange nameRange = [[mediaShow name] rangeOfString:searchString options:NSCaseInsensitiveSearch];
  153. if (nameRange.location != NSNotFound)
  154. return nameRange;
  155. /* split search string into substrings and try again */
  156. NSArray *substrings = [searchString componentsSeparatedByString:@" "];
  157. NSUInteger substringCount = substrings.count;
  158. if (substringCount > 1) {
  159. for (NSUInteger x = 0; x < substringCount; x++) {
  160. nameRange = [searchString rangeOfString:substrings[x] options:NSCaseInsensitiveSearch];
  161. if (nameRange.location != NSNotFound)
  162. break;
  163. }
  164. }
  165. if (nameRange.location != NSNotFound)
  166. return nameRange;
  167. /* user didn't search for our show name, let's do a deeper search on the episodes */
  168. NSArray *episodes = [mediaShow sortedEpisodes];
  169. NSUInteger episodeCount = episodes.count;
  170. for (NSUInteger x = 0; x < episodeCount; x++)
  171. nameRange = [self _searchShowEpisode:episodes[x] forString:searchString];
  172. return nameRange;
  173. }
  174. - (NSRange)_searchLabel:(MLLabel *)mediaLabel forString:(NSString *)searchString
  175. {
  176. /* basic search first, then try more complex things */
  177. NSRange nameRange = [[mediaLabel name] rangeOfString:searchString options:NSCaseInsensitiveSearch];
  178. if (nameRange.location != NSNotFound)
  179. return nameRange;
  180. /* user didn't search for our label name, let's do a deeper search */
  181. NSArray *files = [mediaLabel sortedFolderItems];
  182. NSUInteger fileCount = files.count;
  183. for (NSUInteger x = 0; x < fileCount; x++) {
  184. nameRange = [self _searchFile:files[x] forString:searchString];
  185. if (nameRange.location != NSNotFound)
  186. break;
  187. }
  188. return nameRange;
  189. }
  190. - (NSRange)_searchFile:(MLFile *)mediaFile forString:(NSString *)searchString
  191. {
  192. /* basic search first, then try more complex things */
  193. NSRange nameRange = [[mediaFile title] rangeOfString:searchString options:NSCaseInsensitiveSearch];
  194. if (nameRange.location != NSNotFound)
  195. return nameRange;
  196. NSMutableArray *stringsToSearch = [[NSMutableArray alloc] initWithObjects:[mediaFile title], nil];
  197. if ([mediaFile artist])
  198. [stringsToSearch addObject:[mediaFile artist]];
  199. if ([mediaFile releaseYear])
  200. [stringsToSearch addObject:[mediaFile releaseYear]];
  201. NSArray *substrings = [searchString componentsSeparatedByString:@" "];
  202. NSUInteger substringCount = substrings.count;
  203. NSUInteger searchStringCount = stringsToSearch.count;
  204. for (NSUInteger x = 0; x < substringCount; x++) {
  205. for (NSUInteger y = 0; y < searchStringCount; y++) {
  206. nameRange = [stringsToSearch[y] rangeOfString:substrings[x] options:NSCaseInsensitiveSearch];
  207. if (nameRange.location != NSNotFound)
  208. break;
  209. }
  210. if (nameRange.location != NSNotFound)
  211. break;
  212. }
  213. return nameRange;
  214. }
  215. @end