فهرست منبع

VLCMediaLibraryManager: Add new medialibrary manager

Soomin Lee 7 سال پیش
والد
کامیت
6c46ddbeee
3فایلهای تغییر یافته به همراه434 افزوده شده و 0 حذف شده
  1. 429 0
      SharedSources/VLCMediaLibraryManager.swift
  2. 1 0
      VLC-iOS-Bridging-Header.h
  3. 4 0
      VLC.xcodeproj/project.pbxproj

+ 429 - 0
SharedSources/VLCMediaLibraryManager.swift

@@ -0,0 +1,429 @@
+/*****************************************************************************
+ * VLCMediaLibraryManager.swift
+ * VLC for iOS
+ *****************************************************************************
+ * Copyright © 2018 VideoLAN. All rights reserved.
+ * Copyright © 2018 Videolabs
+ *
+ * Authors: Soomin Lee <bubu # mikan.io>
+ *
+ * Refer to the COPYING file of the official project for license.
+ *****************************************************************************/
+
+class VLCMediaLibraryManager: NSObject {
+
+    private static let databaseName: String = "medialibrary.db"
+    private var databasePath: String!
+    private var thumbnailPath: String!
+
+    private lazy var medialibrary: VLCMediaLibrary = {
+        let medialibrary = VLCMediaLibrary()
+        medialibrary.delegate = self
+        return medialibrary
+    }()
+
+    override init() {
+        super.init()
+        setupMediaLibrary()
+    }
+
+    // MARK: Private
+    private func setupMediaLibrary() {
+        guard let documentPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first,
+            let dbPath = NSSearchPathForDirectoriesInDomains(.libraryDirectory, .userDomainMask, true).first else {
+                preconditionFailure("VLCMediaLibraryManager: Unable to init medialibrary.")
+        }
+
+        medialibrary.setVerbosity(.info)
+
+        databasePath = dbPath + "/" + VLCMediaLibraryManager.databaseName
+        thumbnailPath = documentPath
+
+        let medialibraryStatus = medialibrary.setupMediaLibrary(databasePath: databasePath,
+                                                                thumbnailPath: thumbnailPath)
+
+        switch medialibraryStatus {
+        case .success:
+            guard medialibrary.start() else {
+                assertionFailure("VLCMediaLibraryManager: Medialibrary failed to start.")
+                return
+            }
+            medialibrary.reload()
+            medialibrary.discover(onEntryPoint: "file://" + documentPath)
+            break
+        case .alreadyInitialized:
+            assertionFailure("VLCMediaLibraryManager: Medialibrary already initialized.")
+            break
+        case .failed:
+            preconditionFailure("VLCMediaLibraryManager: Failed to setup medialibrary.")
+            break
+        case .dbReset:
+            // should still start and discover but warn the user that the db has been wipped
+            assertionFailure("VLCMediaLibraryManager: The database was resetted, please re-configure.")
+            break
+        }
+    }
+
+    // MARK: Internal
+
+    /// Returns number of *ALL* files(audio and video) present in the medialibrary database
+    func numberOfFiles() -> Int {
+        var media = medialibrary.audioFiles(with: .filename, desc: false)
+
+        media += medialibrary.videoFiles(with: .filename, desc: false)
+        return media.count
+    }
+
+
+    /// Returns *ALL* file found for a specified VLCMLMediaType
+    ///
+    /// - Parameter type: Type of the media
+    /// - Returns: Array of VLCMLMedia
+    func media(ofType type: VLCMLMediaType) -> [VLCMLMedia] {
+        return type == .video ? medialibrary.videoFiles(with: .filename, desc: false) : medialibrary.audioFiles(with: .filename, desc: false)
+    }
+
+    func addMedia(withMrl mrl: URL) {
+        medialibrary.addMedia(withMrl: mrl)
+    }
+}
+
+// MARK: MediaDataSource - Other methods
+
+extension VLCMediaLibraryManager {
+//    @objc enum VLCMediaCategory: Int {
+//        case unknown
+//        case audio
+//        case video
+//    }
+//
+//    @objc enum VLCMediaSubcategory: Int {
+//        case unknown
+//        case movies
+//        case episodes
+//        case artists
+//        case albums
+//        case tracks
+//        case genres
+//        case videoPlaylists
+//        case audioPlaylists
+//        case allVideos
+//    }
+//
+//    struct VLCMediaType {
+//        let category: VLCMediaCategory
+//        var subcategory: VLCMediaSubcategory
+//    }
+//
+//
+//        var foundVideos = [VLCMLMedia]()
+//        var foundAudio = [VLCMLMedia]()
+//
+//        var movies = [VLCMLMedia]()
+//        var episodes = [VLCMLMedia]()
+//        var artists = [String]()
+//        var albums = [MLAlbum]()
+//        var genres = [String]()
+//        var audioPlaylist = [MLLabel]()
+//        var videoPlaylist = [MLLabel]()
+//
+
+//    @objc func numberOfFiles(subcategory: VLCMediaSubcategory) -> Int {
+//        return array(for: subcategory).countSources/MediaViewController.swift
+//    }
+//
+//    private func array(for subcategory: VLCMediaSubcategory) -> [Any] {
+//        switch subcategory {
+//        case .unknown:
+//            preconditionFailure("No")
+//        case .movies:
+//            return movies
+//        case .episodes:
+//            return episodes
+//        case .artists:
+//            return artists
+//        case .albums:
+//            return albums
+//        case .tracks:
+//            return foundAudio
+//        case .genres:
+//            return genres
+//        case .audioPlaylists:
+//            return audioPlaylist
+//        case .videoPlaylists:
+//            return videoPlaylist
+//        case .allVideos:
+//            return foundVideos
+//        }
+//    }
+//
+//    func indicatorInfo(for subcategory: VLCMediaSubcategory) -> IndicatorInfo {
+//        switch subcategory {
+//        case .unknown:
+//            preconditionFailure("No")
+//        case .movies:
+//            return IndicatorInfo(title: NSLocalizedString("MOVIES", comment: ""))
+//        case .episodes:
+//            return IndicatorInfo(title: NSLocalizedString("EPISODES", comment: ""))
+//        case .artists:
+//            return IndicatorInfo(title: NSLocalizedString("ARTISTS", comment: ""))
+//        case .albums:
+//            return IndicatorInfo(title: NSLocalizedString("ALBUMS", comment: ""))
+//        case .tracks:
+//            return IndicatorInfo(title: NSLocalizedString("SONGS", comment: ""))
+//        case .genres:
+//            return IndicatorInfo(title: NSLocalizedString("GENRES", comment: ""))
+//        case .audioPlaylists:
+//            return IndicatorInfo(title: NSLocalizedString("AUDIO_PLAYLISTS", comment: ""))
+//        case .videoPlaylists:
+//            return IndicatorInfo(title: NSLocalizedString("VIDEO_PLAYLISTS", comment: ""))
+//        case .allVideos:
+//            return IndicatorInfo(title: NSLocalizedString("VIDEOS", comment: ""))
+//        }
+//
+//    }
+//
+//    @objc func object(at index: Int, subcategory: VLCMediaSubcategory) -> Any {
+//
+//        guard index >= 0 else {
+//            preconditionFailure("a negative value ? I don't think so!")
+//        }
+//
+//        let categoryArray = array(for: subcategory)
+//        if index < categoryArray.count {
+//            return categoryArray[Int(index)]
+//        }
+//        preconditionFailure("index is taller than count")
+//    }
+//
+//    func allObjects(for subcategory: VLCMediaSubcategory) -> [Any] {
+//        return array(for:subcategory)
+//    }
+//
+//    func removeObject(at index: Int, subcategory: VLCMediaSubcategory) {
+//        guard index >= 0 else {
+//            preconditionFailure("a negative value ? I don't think so!")
+//        }
+//        var categoryArray = array(for: subcategory)
+//        if index < categoryArray.count {
+//            categoryArray.remove(at: index)
+//        }
+//        preconditionFailure("index is taller than count")
+//    }
+//
+//    func insert(_ item: MLFile, at index: Int, subcategory: VLCMediaSubcategory) {
+//        guard index >= 0 else {
+//            preconditionFailure("a negative value ? I don't think so!")
+//        }
+//        var categoryArray = array(for: subcategory)
+//        if index < categoryArray.count {
+//            categoryArray.insert(item, at: index)
+//        }
+//        categoryArray.append(item)
+//    }
+}
+
+// MARK: MediaDataSource - Audio methods
+
+extension VLCMediaLibraryManager {
+    private func getAllAudio() {
+//        foundAudio = medialibrary.media(ofType: .audio)
+//        artistsFromAudio()
+//        albumsFromAudio()
+//        audioPlaylistsFromAudio()
+//        genresFromAudio()
+    }
+
+    private func getArtists() {
+//        let albumtracks = MLAlbumTrack.allTracks() as! [MLAlbumTrack]
+//        let tracksWithArtist = albumtracks.filter { $0.artist != nil && $0.artist != "" }
+//        artists = tracksWithArtist.map { $0.artist }
+    }
+
+    private func getAlbums() {
+//        albums = MLAlbum.allAlbums() as! [MLAlbum]
+    }
+
+    private func getAudioPlaylists() {
+//        let labels = MLLabel.allLabels() as! [MLLabel]
+//        audioPlaylist = labels.filter {
+//            let audioFiles = $0.files.filter {
+//                if let file = $0 as? MLFile {
+//                    return file.isSupportedAudioFile()
+//                }
+//                return false
+//            }
+//            return !audioFiles.isEmpty
+//        }
+    }
+
+    private func genresFromAudio() {
+//        let albumtracks = MLAlbumTrack.allTracks() as! [MLAlbumTrack]
+//        let tracksWithArtist = albumtracks.filter { $0.genre != nil && $0.genre != "" }
+//        genres = tracksWithArtist.map { $0.genre }
+    }
+}
+
+// MARK: MediaDataSource - Video methods
+
+extension VLCMediaLibraryManager {
+    private func getAllVideos() {
+//        foundVideos = medialibrary.media(ofType: .video)
+//        moviesFromVideos()
+//        episodesFromVideos()
+        //        videoPlaylistsFromVideos()
+    }
+
+    private func getMovies() {
+//        movies = foundVideos.filter { $0.subtype() == .movie }
+    }
+
+    private func getShowEpisodes() {
+//        episodes = foundVideos.filter { $0.subtype() == .showEpisode }
+    }
+
+    private func getVideoPlaylists() {
+//        let labels = MLLabel.allLabels() as! [MLLabel]
+//        audioPlaylist = labels.filter {
+//            let audioFiles = $0.files.filter {
+//                if let file = $0 as? MLFile {
+//                    return file.isShowEpisode() || file.isMovie() || file.isClip()
+//                }
+//                return false
+//            }
+//            return !audioFiles.isEmpty
+//        }
+    }
+}
+
+// MARK: VLCMediaLibraryDelegate
+extension VLCMediaLibraryManager: VLCMediaLibraryDelegate {
+    func medialibrary(_ medialibrary: VLCMediaLibrary, didAddMedia media: [VLCMLMedia]) {
+        NotificationCenter.default.post(name: .VLCVideosDidChangeNotification, object: media)
+    }
+
+    func medialibrary(_ medialibrary: VLCMediaLibrary, didStartDiscovery entryPoint: String) {
+    }
+
+    func medialibrary(_ medialibrary: VLCMediaLibrary, didCompleteDiscovery entryPoint: String) {
+    }
+
+    func medialibrary(_ medialibrary: VLCMediaLibrary, didProgressDiscovery entryPoint: String) {
+    }
+
+    func medialibrary(_ medialibrary: VLCMediaLibrary, didUpdateParsingStatsWithPercent percent: UInt32) {
+    }
+}
+
+// MARK: Future MediaDataSource extension
+
+// Todo: implement the remove
+//    - (void)removeMediaObjectFromFolder:(NSManagedObject *)managedObject
+// {
+//    NSAssert(([managedObject isKindOfClass:[MLFile class]] && ((MLFile *)managedObject).labels.count > 0), @"All media in a folder should be of type MLFile and it should be in a folder");
+//
+//    if (![managedObject isKindOfClass:[MLFile class]]) return;
+//
+//    MLFile *mediaFile = (MLFile *)managedObject;
+//    [self rearrangeFolderTrackNumbersForRemovedItem:mediaFile];
+//    mediaFile.labels = nil;
+//    mediaFile.folderTrackNumber = nil;
+//    }
+//
+//    - (void)removeMediaObject:(NSManagedObject *)managedObject
+// {
+//    if ([managedObject isKindOfClass:[MLAlbum class]]) {
+//        MLAlbum *album = (MLAlbum *)managedObject;
+//        NSSet *iterAlbumTrack = [NSSet setWithSet:album.tracks];
+//
+//        for (MLAlbumTrack *track in iterAlbumTrack) {
+//            NSSet *iterFiles = [NSSet setWithSet:track.files];
+//
+//            for (MLFile *file in iterFiles)
+//                [self _deleteMediaObject:file];
+//        }
+//        [[MLMediaLibrary sharedMediaLibrary] removeObject: album];
+//        // delete all episodes from a show
+//    } else if ([managedObject isKindOfClass:[MLShow class]]) {
+//        MLShow *show = (MLShow *)managedObject;
+//        NSSet *iterShowEpisodes = [NSSet setWithSet:show.episodes];
+//
+//        for (MLShowEpisode *episode in iterShowEpisodes) {
+//            NSSet *iterFiles = [NSSet setWithSet:episode.files];
+//
+//            for (MLFile *file in iterFiles)
+//                [self _deleteMediaObject:file];
+//        }
+//        [[MLMediaLibrary sharedMediaLibrary] removeObject: show];
+//        // delete all files from an episode
+//    } else if ([managedObject isKindOfClass:[MLShowEpisode class]]) {
+//        MLShowEpisode *episode = (MLShowEpisode *)managedObject;
+//        NSSet *iterFiles = [NSSet setWithSet:episode.files];
+//
+//        for (MLFile *file in iterFiles)
+//            [self _deleteMediaObject:file];
+//        // delete all files from a track
+//        [[MLMediaLibrary sharedMediaLibrary] removeObject: episode];
+//    } else if ([managedObject isKindOfClass:[MLAlbumTrack class]]) {
+//        MLAlbumTrack *track = (MLAlbumTrack *)managedObject;
+//        NSSet *iterFiles = [NSSet setWithSet:track.files];
+//
+//        for (MLFile *file in iterFiles)
+//            [self _deleteMediaObject:file];
+//    } else if ([managedObject isKindOfClass:[MLLabel class]]) {
+//        MLLabel *folder = (MLLabel *)managedObject;
+//        NSSet *iterFiles = [NSSet setWithSet:folder.files];
+//        [folder removeFiles:folder.files];
+//        for (MLFile *file in iterFiles)
+//            [self _deleteMediaObject:file];
+//        [[MLMediaLibrary sharedMediaLibrary] removeObject:folder];
+//    }
+//    else
+//    [self _deleteMediaObject:(MLFile *)managedObject];
+//    }
+//
+//    - (void)_deleteMediaObject:(MLFile *)mediaObject
+// {
+//    [self rearrangeFolderTrackNumbersForRemovedItem:mediaObject];
+//
+//    /* stop playback if needed */
+//    VLCPlaybackController *vpc = [VLCPlaybackController sharedInstance];
+//    VLCMedia *media = [vpc currentlyPlayingMedia];
+//    MLFile *currentlyPlayingFile = [MLFile fileForURL:media.url].firstObject;
+//    if (currentlyPlayingFile && currentlyPlayingFile == mediaObject) {
+//        [vpc stopPlayback];
+//    }
+//
+//    NSFileManager *fileManager = [NSFileManager defaultManager];
+//    NSString *folderLocation = [[mediaObject.url path] stringByDeletingLastPathComponent];
+//    NSArray *allfiles = [fileManager contentsOfDirectoryAtPath:folderLocation error:nil];
+//    NSString *fileName = [mediaObject.path.lastPathComponent stringByDeletingPathExtension];
+//    if (!fileName)
+//    return;
+//    NSIndexSet *indexSet = [allfiles indexesOfObjectsPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) {
+//        return ([obj rangeOfString:fileName].location != NSNotFound);
+//        }];
+//    NSUInteger count = indexSet.count;
+//    NSString *additionalFilePath;
+//    NSUInteger currentIndex = [indexSet firstIndex];
+//    for (unsigned int x = 0; x < count; x++) {
+//        additionalFilePath = allfiles[currentIndex];
+//        if ([additionalFilePath isSupportedSubtitleFormat])
+//        [fileManager removeItemAtPath:[folderLocation stringByAppendingPathComponent:additionalFilePath] error:nil];
+//        currentIndex = [indexSet indexGreaterThanIndex:currentIndex];
+//    }
+//    [fileManager removeItemAtURL:mediaObject.url error:nil];
+//    }
+//
+//    - (void)rearrangeFolderTrackNumbersForRemovedItem:(MLFile *) mediaObject
+// {
+//    MLLabel *label = [mediaObject.labels anyObject];
+//    NSSet *allFiles = label.files;
+//    for (MLFile *file in allFiles) {
+//        if (file.folderTrackNumber > mediaObject.folderTrackNumber) {
+//            int value = [file.folderTrackNumber intValue];
+//            file.folderTrackNumber = [NSNumber numberWithInt:value - 1];
+//        }
+//    }
+// }
+// @end

+ 1 - 0
VLC-iOS-Bridging-Header.h

@@ -2,6 +2,7 @@
 #import <MediaLibraryKit/MediaLibraryKit.h>
 #import <MobileVLCKit/MobileVLCKit.h>
 #import <ObjectiveDropboxOfficial/ObjectiveDropboxOfficial.h>
+#import <VLCMediaLibraryKit/VLCMediaLibraryKit.h>
 #import <PAPasscode/PAPasscodeViewController.h>
 #import <XKKeychain/XKKeychain.h>
 #import "VLCExternalDisplayController.h"

+ 4 - 0
VLC.xcodeproj/project.pbxproj

@@ -250,6 +250,7 @@
 		7DF9352F1958AB0600E60FD4 /* UIColor+Presets.m in Sources */ = {isa = PBXBuildFile; fileRef = 7DF9352E1958AB0600E60FD4 /* UIColor+Presets.m */; };
 		8D43712D2056AF1600F36458 /* VLCRendererDiscovererManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D43712C2056AF1600F36458 /* VLCRendererDiscovererManager.swift */; };
 		8D437154205808FF00F36458 /* VLCActionSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D437153205808FF00F36458 /* VLCActionSheet.swift */; };
+		8D66A47320AC61B900FA5B92 /* VLCMediaLibraryManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D66A47220AC61B900FA5B92 /* VLCMediaLibraryManager.swift */; };
 		8DD6516F208C89BC0052EE68 /* VLCAccessibilityIdentifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8DD6516E208C89BC0052EE68 /* VLCAccessibilityIdentifier.swift */; };
 		8DD651BA208F6AF00052EE68 /* VLCActionSheetCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8DD651B9208F6AF00052EE68 /* VLCActionSheetCell.swift */; };
 		8DD651C4208F786F0052EE68 /* VLCActionSheetSectionHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8DD651C3208F786F0052EE68 /* VLCActionSheetSectionHeader.swift */; };
@@ -937,6 +938,7 @@
 		8C707B9BB2C5681D50CC9B99 /* Pods-VLC-tvOS-Debug.distribution.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-VLC-tvOS-Debug.distribution.xcconfig"; path = "Pods/Target Support Files/Pods-VLC-tvOS-Debug/Pods-VLC-tvOS-Debug.distribution.xcconfig"; sourceTree = "<group>"; };
 		8D43712C2056AF1600F36458 /* VLCRendererDiscovererManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = VLCRendererDiscovererManager.swift; path = Sources/VLCRendererDiscovererManager.swift; sourceTree = "<group>"; };
 		8D437153205808FF00F36458 /* VLCActionSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VLCActionSheet.swift; sourceTree = "<group>"; };
+		8D66A47220AC61B900FA5B92 /* VLCMediaLibraryManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VLCMediaLibraryManager.swift; sourceTree = "<group>"; };
 		8DD6516E208C89BC0052EE68 /* VLCAccessibilityIdentifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VLCAccessibilityIdentifier.swift; sourceTree = "<group>"; };
 		8DD651B9208F6AF00052EE68 /* VLCActionSheetCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VLCActionSheetCell.swift; sourceTree = "<group>"; };
 		8DD651C3208F786F0052EE68 /* VLCActionSheetSectionHeader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VLCActionSheetSectionHeader.swift; sourceTree = "<group>"; };
@@ -1950,6 +1952,7 @@
 				7D37849D183A98DD009EE944 /* VLCThumbnailsCache.m */,
 				DD7110EE1AF38B2B00854776 /* MLMediaLibrary+playlist.h */,
 				DD7110EF1AF38B2B00854776 /* MLMediaLibrary+playlist.m */,
+				8D66A47220AC61B900FA5B92 /* VLCMediaLibraryManager.swift */,
 			);
 			name = Library;
 			sourceTree = "<group>";
@@ -3228,6 +3231,7 @@
 				DD3EFF4D1BDEBCE500B68579 /* VLCNetworkServerBrowserPlex.m in Sources */,
 				8D437154205808FF00F36458 /* VLCActionSheet.swift in Sources */,
 				DDF908E41CFCD97400108B70 /* VLCNetworkLoginDataSourceProtocol.m in Sources */,
+				8D66A47320AC61B900FA5B92 /* VLCMediaLibraryManager.swift in Sources */,
 				7D378492183A98BF009EE944 /* VLCExternalDisplayController.m in Sources */,
 				4170152C209A1D3600802E44 /* MediaViewController.swift in Sources */,
 				41F9BC7C1F4F20E400268461 /* VLCTrackSelectorView.m in Sources */,