VLCMediaDataSource.m 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281
  1. //
  2. // VLCMediaDatasource.m
  3. // VLC
  4. //
  5. // Created by Carola Nitz on 8/15/17.
  6. // Copyright © 2017 VideoLAN. All rights reserved.
  7. //
  8. #import "VLCMediaDataSource.h"
  9. #import "VLCPlaybackController.h"
  10. #import "NSString+SupportedMedia.h"
  11. @interface VLCMediaDataSource ()
  12. {
  13. NSMutableArray *_foundMedia;
  14. }
  15. @end
  16. @implementation VLCMediaDataSource
  17. - (void)updateContentsForSelection:(NSManagedObject *)selection
  18. {
  19. NSArray *array;
  20. if ([selection isKindOfClass:[MLAlbum class]]) {
  21. array = [(MLAlbum *)selection sortedTracks];
  22. } else if ([selection isKindOfClass:[MLShow class]]) {
  23. array = [(MLShow *)selection sortedEpisodes];
  24. } else if ([selection isKindOfClass:[MLLabel class]]) {
  25. array = [(MLLabel *)selection sortedFolderItems];
  26. }
  27. @synchronized(_foundMedia) {
  28. _foundMedia = [NSMutableArray arrayWithArray:array];
  29. }
  30. }
  31. - (NSUInteger)numberOfFiles
  32. {
  33. @synchronized (_foundMedia) {
  34. return [_foundMedia count];
  35. }
  36. }
  37. - (NSManagedObject *)objectAtIndex:(NSUInteger)index
  38. {
  39. @synchronized (_foundMedia) {
  40. if (index < _foundMedia.count)
  41. return _foundMedia[index];
  42. }
  43. return nil;
  44. }
  45. - (NSUInteger)indexOfObject:(NSManagedObject *)object
  46. {
  47. @synchronized(_foundMedia) {
  48. return [_foundMedia indexOfObject:object];
  49. }
  50. }
  51. - (void)insertObject:(NSManagedObject *)object atIndex:(NSUInteger)index
  52. {
  53. @synchronized(_foundMedia) {
  54. [_foundMedia insertObject:object atIndex:index];
  55. }
  56. }
  57. - (void)removeObjectAtIndex:(NSUInteger)index
  58. {
  59. @synchronized(_foundMedia) {
  60. [_foundMedia removeObjectAtIndex:index];
  61. }
  62. }
  63. - (void)moveObjectFromIndex:(NSUInteger)fromIdx toIndex:(NSUInteger)toIdx
  64. {
  65. @synchronized(_foundMedia) {
  66. MLFile* object = _foundMedia[fromIdx];
  67. if (![object isKindOfClass:[MLFile class]])
  68. return;
  69. [_foundMedia removeObjectAtIndex:fromIdx];
  70. [_foundMedia insertObject:object atIndex:toIdx];
  71. object.folderTrackNumber = @(toIdx - 1);
  72. object = [_foundMedia objectAtIndex:fromIdx];
  73. if (![object isKindOfClass:[MLFile class]])
  74. return;
  75. object.folderTrackNumber = @(fromIdx - 1);
  76. }
  77. }
  78. - (void)removeAllObjects
  79. {
  80. @synchronized(_foundMedia) {
  81. _foundMedia = [NSMutableArray new];
  82. }
  83. }
  84. - (NSArray *)allObjects
  85. {
  86. @synchronized(_foundMedia) {
  87. return [_foundMedia copy];
  88. }
  89. }
  90. - (void)addObject:(NSManagedObject *)object
  91. {
  92. @synchronized (_foundMedia) {
  93. [_foundMedia addObject:object];
  94. }
  95. }
  96. - (void)addAlbumsInAllAlbumMode:(BOOL)isAllAlbumMode;
  97. {
  98. for (MLAlbum *album in [MLAlbum allAlbums]) {
  99. if (album.name.length > 0) {
  100. if (isAllAlbumMode) {
  101. [self addObject:album];
  102. } else if ( album.tracks.count > 1) {
  103. [self addObject:album];
  104. }
  105. }
  106. }
  107. }
  108. - (void)addAllShows
  109. {
  110. for (MLShow *show in [MLShow allShows]) {
  111. if (show.name.length > 0 && show.episodes.count > 1) {
  112. [self addObject:show];
  113. }
  114. }
  115. }
  116. - (void)addAllFolders
  117. {
  118. for (MLLabel *folder in [MLLabel allLabels]) {
  119. [self addObject:folder];
  120. }
  121. }
  122. - (void)addRemainingFiles
  123. {
  124. for (MLFile *file in [MLFile allFiles]) {
  125. if (file.labels != nil) {
  126. @synchronized(file.labels) {
  127. if (file.labels.count > 0)
  128. continue;
  129. }
  130. }
  131. if (!file.isShowEpisode && !file.isAlbumTrack) {
  132. [self addObject:file];
  133. } else if (file.isShowEpisode) {
  134. if (file.showEpisode.show.episodes.count < 2) {
  135. [self addObject:file];
  136. }
  137. /* older MediaLibraryKit versions don't send a show name in a popular
  138. * corner case. hence, we need to work-around here and force a reload
  139. * afterwards as this could lead to the 'all my shows are gone'
  140. * syndrome (see #10435, #10464, #10432 et al) */
  141. if (file.showEpisode.show.name.length == 0) {
  142. file.showEpisode.show.name = NSLocalizedString(@"UNTITLED_SHOW", nil);
  143. [self performSelector:@selector(updateViewContents) withObject:nil afterDelay:0.1];
  144. }
  145. } else if (file.isAlbumTrack && file.albumTrack.album.tracks.count < 2) {
  146. [self addObject:file];
  147. }
  148. }
  149. }
  150. - (void)removeMediaObjectFromFolder:(NSManagedObject *)managedObject
  151. {
  152. NSAssert([managedObject isKindOfClass:[MLFile class]], @"All media in a folder should be of type MLFile");
  153. if (![managedObject isKindOfClass:[MLFile class]]) return;
  154. MLFile *mediaFile = (MLFile *)managedObject;
  155. [self rearrangeFolderTrackNumbersForRemovedItem:mediaFile];
  156. mediaFile.labels = nil;
  157. mediaFile.folderTrackNumber = nil;
  158. }
  159. - (void)removeMediaObject:(NSManagedObject *)managedObject
  160. {
  161. if ([managedObject isKindOfClass:[MLAlbum class]]) {
  162. MLAlbum *album = (MLAlbum *)managedObject;
  163. NSSet *iterAlbumTrack = [NSSet setWithSet:album.tracks];
  164. for (MLAlbumTrack *track in iterAlbumTrack) {
  165. NSSet *iterFiles = [NSSet setWithSet:track.files];
  166. for (MLFile *file in iterFiles)
  167. [self _deleteMediaObject:file];
  168. }
  169. [[MLMediaLibrary sharedMediaLibrary] removeObject: album];
  170. // delete all episodes from a show
  171. } else if ([managedObject isKindOfClass:[MLShow class]]) {
  172. MLShow *show = (MLShow *)managedObject;
  173. NSSet *iterShowEpisodes = [NSSet setWithSet:show.episodes];
  174. for (MLShowEpisode *episode in iterShowEpisodes) {
  175. NSSet *iterFiles = [NSSet setWithSet:episode.files];
  176. for (MLFile *file in iterFiles)
  177. [self _deleteMediaObject:file];
  178. }
  179. [[MLMediaLibrary sharedMediaLibrary] removeObject: show];
  180. // delete all files from an episode
  181. } else if ([managedObject isKindOfClass:[MLShowEpisode class]]) {
  182. MLShowEpisode *episode = (MLShowEpisode *)managedObject;
  183. NSSet *iterFiles = [NSSet setWithSet:episode.files];
  184. for (MLFile *file in iterFiles)
  185. [self _deleteMediaObject:file];
  186. // delete all files from a track
  187. [[MLMediaLibrary sharedMediaLibrary] removeObject: episode];
  188. } else if ([managedObject isKindOfClass:[MLAlbumTrack class]]) {
  189. MLAlbumTrack *track = (MLAlbumTrack *)managedObject;
  190. NSSet *iterFiles = [NSSet setWithSet:track.files];
  191. for (MLFile *file in iterFiles)
  192. [self _deleteMediaObject:file];
  193. } else if ([managedObject isKindOfClass:[MLLabel class]]) {
  194. MLLabel *folder = (MLLabel *)managedObject;
  195. NSSet *iterFiles = [NSSet setWithSet:folder.files];
  196. [folder removeFiles:folder.files];
  197. for (MLFile *file in iterFiles)
  198. [self _deleteMediaObject:file];
  199. [[MLMediaLibrary sharedMediaLibrary] removeObject:folder];
  200. }
  201. else
  202. [self _deleteMediaObject:(MLFile *)managedObject];
  203. }
  204. - (void)_deleteMediaObject:(MLFile *)mediaObject
  205. {
  206. [self rearrangeFolderTrackNumbersForRemovedItem:mediaObject];
  207. /* stop playback if needed */
  208. VLCPlaybackController *vpc = [VLCPlaybackController sharedInstance];
  209. if (vpc.isPlaying) {
  210. MLFile *currentlyPlayingFile = [[MLFile fileForURL:vpc.mediaPlayer.media.url] firstObject];
  211. if (currentlyPlayingFile) {
  212. if (currentlyPlayingFile == mediaObject)
  213. [vpc stopPlayback];
  214. }
  215. }
  216. NSFileManager *fileManager = [NSFileManager defaultManager];
  217. NSString *folderLocation = [[mediaObject.url path] stringByDeletingLastPathComponent];
  218. NSArray *allfiles = [fileManager contentsOfDirectoryAtPath:folderLocation error:nil];
  219. NSString *fileName = [mediaObject.path.lastPathComponent stringByDeletingPathExtension];
  220. if (!fileName)
  221. return;
  222. NSIndexSet *indexSet = [allfiles indexesOfObjectsPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) {
  223. return ([obj rangeOfString:fileName].location != NSNotFound);
  224. }];
  225. NSUInteger count = indexSet.count;
  226. NSString *additionalFilePath;
  227. NSUInteger currentIndex = [indexSet firstIndex];
  228. for (unsigned int x = 0; x < count; x++) {
  229. additionalFilePath = allfiles[currentIndex];
  230. if ([additionalFilePath isSupportedSubtitleFormat])
  231. [fileManager removeItemAtPath:[folderLocation stringByAppendingPathComponent:additionalFilePath] error:nil];
  232. currentIndex = [indexSet indexGreaterThanIndex:currentIndex];
  233. }
  234. [fileManager removeItemAtURL:mediaObject.url error:nil];
  235. }
  236. - (void)rearrangeFolderTrackNumbersForRemovedItem:(MLFile *) mediaObject
  237. {
  238. MLLabel *label = [mediaObject.labels anyObject];
  239. NSSet *allFiles = label.files;
  240. for (MLFile *file in allFiles) {
  241. if (file.folderTrackNumber > mediaObject.folderTrackNumber) {
  242. int value = [file.folderTrackNumber intValue];
  243. file.folderTrackNumber = [NSNumber numberWithInt:value - 1];
  244. }
  245. }
  246. }
  247. @end