diff --git a/Amperfy.xcodeproj/project.pbxproj b/Amperfy.xcodeproj/project.pbxproj index a743ae97..6b68181c 100644 --- a/Amperfy.xcodeproj/project.pbxproj +++ b/Amperfy.xcodeproj/project.pbxproj @@ -155,6 +155,9 @@ 509121032625EF14008C57EC /* MarqueeLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 509121022625EF14008C57EC /* MarqueeLabel.swift */; }; 5095F98C23C8389E008B0805 /* MusicPlayerTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5095F98B23C8389E008B0805 /* MusicPlayerTest.swift */; }; 50973ADD2636E4C4005497CA /* SsGenreParserDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50973ADC2636E4C4005497CA /* SsGenreParserDelegate.swift */; }; + 50A12F432739239800E7B2AA /* EmbeddedArtworkMO+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50A12F412739239800E7B2AA /* EmbeddedArtworkMO+CoreDataClass.swift */; }; + 50A12F442739239800E7B2AA /* EmbeddedArtworkMO+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50A12F422739239800E7B2AA /* EmbeddedArtworkMO+CoreDataProperties.swift */; }; + 50A12F4627392B2400E7B2AA /* EmbeddedArtwork.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50A12F4527392B2400E7B2AA /* EmbeddedArtwork.swift */; }; 50A738812244B03700D3F2D4 /* SsPlayableParserDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50A738802244B03700D3F2D4 /* SsPlayableParserDelegate.swift */; }; 50A7388322451ED200D3F2D4 /* SsPlaylistParserDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50A7388222451ED200D3F2D4 /* SsPlaylistParserDelegate.swift */; }; 50A7388522452C1900D3F2D4 /* SsPlaylistSongsParserDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50A7388422452C1900D3F2D4 /* SsPlaylistSongsParserDelegate.swift */; }; @@ -511,6 +514,10 @@ 5095F98B23C8389E008B0805 /* MusicPlayerTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MusicPlayerTest.swift; sourceTree = ""; }; 50964D5723B54BBA00B685B2 /* Amperfy v3.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "Amperfy v3.xcdatamodel"; sourceTree = ""; }; 50973ADC2636E4C4005497CA /* SsGenreParserDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SsGenreParserDelegate.swift; sourceTree = ""; }; + 50A12F402739203E00E7B2AA /* Amperfy v15.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "Amperfy v15.xcdatamodel"; sourceTree = ""; }; + 50A12F412739239800E7B2AA /* EmbeddedArtworkMO+CoreDataClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "EmbeddedArtworkMO+CoreDataClass.swift"; sourceTree = ""; }; + 50A12F422739239800E7B2AA /* EmbeddedArtworkMO+CoreDataProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "EmbeddedArtworkMO+CoreDataProperties.swift"; sourceTree = ""; }; + 50A12F4527392B2400E7B2AA /* EmbeddedArtwork.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmbeddedArtwork.swift; sourceTree = ""; }; 50A738802244B03700D3F2D4 /* SsPlayableParserDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SsPlayableParserDelegate.swift; sourceTree = ""; }; 50A7388222451ED200D3F2D4 /* SsPlaylistParserDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SsPlaylistParserDelegate.swift; sourceTree = ""; }; 50A7388422452C1900D3F2D4 /* SsPlaylistSongsParserDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SsPlaylistSongsParserDelegate.swift; sourceTree = ""; }; @@ -774,6 +781,8 @@ 50F81ED723BF6B1E00EAAC3E /* PlaylistItemMO+CoreDataProperties.swift */, 50F81ED823BF6B1E00EAAC3E /* ArtworkMO+CoreDataClass.swift */, 50F81ED923BF6B1E00EAAC3E /* ArtworkMO+CoreDataProperties.swift */, + 50A12F412739239800E7B2AA /* EmbeddedArtworkMO+CoreDataClass.swift */, + 50A12F422739239800E7B2AA /* EmbeddedArtworkMO+CoreDataProperties.swift */, 50F81EDA23BF6B1E00EAAC3E /* SongMO+CoreDataClass.swift */, 50F81EDB23BF6B1E00EAAC3E /* SongMO+CoreDataProperties.swift */, 501A7D442681C11C0055A51B /* PodcastEpisodeMO+CoreDataClass.swift */, @@ -999,6 +1008,7 @@ 50DEEE1A265ED65B0073FF20 /* MusicFolder.swift */, 501858F7265F779B00F2E13A /* Directory.swift */, 501A7D3C2680A9AE0055A51B /* Podcast.swift */, + 50A12F4527392B2400E7B2AA /* EmbeddedArtwork.swift */, ); path = EntityWrappers; sourceTree = ""; @@ -1597,6 +1607,7 @@ 501858F8265F779C00F2E13A /* Directory.swift in Sources */, 502C0045224C0B1400DA0D1E /* SubsonicArtworkDownloadDelegate.swift in Sources */, 5013E68626834F450020D8B5 /* PodcastDetailTableHeader.swift in Sources */, + 50A12F442739239800E7B2AA /* EmbeddedArtworkMO+CoreDataProperties.swift in Sources */, 50BA930021CFDEBD00E5901D /* LibraryVC.swift in Sources */, 505A45F4268B53D30031B08B /* MappingModelV10toV11.xcmappingmodel in Sources */, 50BA92FA21CC37F800E5901D /* SongsVC.swift in Sources */, @@ -1610,6 +1621,7 @@ 5088A8A526A955AD00B4C8C6 /* DownloadProtocols.swift in Sources */, 50763F1A22AD942A00D062A0 /* AlbumDetailTableHeader.swift in Sources */, 5083861A21C827E600C4BB32 /* AuthParserDelegate.swift in Sources */, + 50A12F432739239800E7B2AA /* EmbeddedArtworkMO+CoreDataClass.swift in Sources */, 50DEEE1B265ED65B0073FF20 /* MusicFolder.swift in Sources */, 50BA930221D1019B00E5901D /* AmpacheLibrarySyncer.swift in Sources */, 500B7D4321ECFCDD0083ED6F /* LibraryElementEnum.swift in Sources */, @@ -1650,6 +1662,7 @@ 50C16C3221EA77C700F086F0 /* AmpacheArtworkDownloadDelegate.swift in Sources */, 5029288E2657B78B00DA3A8F /* UserStatisticsMO+CoreDataClass.swift in Sources */, 50C16C1021E5463E00F086F0 /* ArtistsVC.swift in Sources */, + 50A12F4627392B2400E7B2AA /* EmbeddedArtwork.swift in Sources */, 50065EB421F0584D0066FC32 /* PlaylistSelectorVC.swift in Sources */, 500B7D4121EC893B0083ED6F /* SongActionSheetView.swift in Sources */, 50F81EDC23BF6B1E00EAAC3E /* ArtistMO+CoreDataClass.swift in Sources */, @@ -2075,6 +2088,7 @@ 500BB49521CAAA2700D367CF /* Amperfy.xcdatamodeld */ = { isa = XCVersionGroup; children = ( + 50A12F402739203E00E7B2AA /* Amperfy v15.xcdatamodel */, 509001BD2717120900A8056D /* Amperfy v14.xcdatamodel */, 50FE808B26A55A8300CB434D /* Amperfy v13.xcdatamodel */, 5040B2C2269C451A00911451 /* Amperfy v12.xcdatamodel */, @@ -2090,7 +2104,7 @@ 506B3A3823B4539D00E31F21 /* Amperfy v2.xcdatamodel */, 500BB49621CAAA2700D367CF /* Amperfy.xcdatamodel */, ); - currentVersion = 509001BD2717120900A8056D /* Amperfy v14.xcdatamodel */; + currentVersion = 50A12F402739203E00E7B2AA /* Amperfy v15.xcdatamodel */; path = Amperfy.xcdatamodeld; sourceTree = ""; versionGroupType = wrapper.xcdatamodel; diff --git a/Amperfy/Common/AppDelegate.swift b/Amperfy/Common/AppDelegate.swift index 24736bfd..814df3bb 100644 --- a/Amperfy/Common/AppDelegate.swift +++ b/Amperfy/Common/AppDelegate.swift @@ -35,7 +35,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate { }() lazy var player: MusicPlayer = { let backendAudioPlayer = BackendAudioPlayer(mediaPlayer: AVPlayer(), eventLogger: eventLogger, backendApi: backendApi, playableDownloader: playableDownloadManager, cacheProxy: library, userStatistics: userStatistics) - let curPlayer = MusicPlayer(coreData: library.getPlayerData(), playableDownloadManager: playableDownloadManager, backendAudioPlayer: backendAudioPlayer, userStatistics: userStatistics) + let curPlayer = MusicPlayer(coreData: library.getPlayerData(), library: library, playableDownloadManager: playableDownloadManager, backendAudioPlayer: backendAudioPlayer, userStatistics: userStatistics) curPlayer.isOfflineMode = persistentStorage.settings.isOfflineMode return curPlayer }() diff --git a/Amperfy/Common/Utilities.swift b/Amperfy/Common/Utilities.swift index c5c3c75c..758e36c6 100644 --- a/Amperfy/Common/Utilities.swift +++ b/Amperfy/Common/Utilities.swift @@ -239,6 +239,12 @@ extension Data { var sizeInByte: Int64 { return Int64(count) } + func createLocalUrl(fileName: String? = nil) -> URL { + let tempDirectoryURL = NSURL.fileURL(withPath: NSTemporaryDirectory(), isDirectory: true) + let url = tempDirectoryURL.appendingPathComponent(fileName ?? UUID().uuidString) + try! self.write(to: url, options: Data.WritingOptions.atomic) + return url + } } extension Date { diff --git a/Amperfy/Player/BackendAudioPlayer.swift b/Amperfy/Player/BackendAudioPlayer.swift index 31202049..9842483c 100644 --- a/Amperfy/Player/BackendAudioPlayer.swift +++ b/Amperfy/Player/BackendAudioPlayer.swift @@ -1,5 +1,6 @@ import Foundation import AVFoundation +import UIKit import os.log protocol BackendAudioPlayerNotifiable { @@ -125,8 +126,8 @@ class BackendAudioPlayer { guard let playable = playlistItem.playable, let playableData = cacheProxy.getFile(forPlayable: playable)?.data else { return } os_log(.default, "Play item: %s", playable.displayString) if playable.isSong { userStatistics.playedSong(isPlayedFromCache: true) } - let url = createLocalUrl(forFileData: playableData) - insert(playable: playable, withUrl: url) + let itemUrl = playableData.createLocalUrl(fileName: "curPlayItem.mp3") + insert(playable: playable, withUrl: itemUrl) } private func insertStreamPlayable(playlistItem: PlaylistItem) { @@ -155,11 +156,15 @@ class BackendAudioPlayer { self.responder?.notifyItemPreparationFinished() } - private func createLocalUrl(forFileData fileData: Data) -> URL { - let tempDirectoryURL = NSURL.fileURL(withPath: NSTemporaryDirectory(), isDirectory: true) - let url = tempDirectoryURL.appendingPathComponent("curPlayItem.mp3") - try! fileData.write(to: url, options: Data.WritingOptions.atomic) - return url + func getEmbeddedArtworkFromID3Tag() -> UIImage? { + guard let item = player.currentItem else { return nil } + let metadataList = item.asset.metadata + guard let artworkAsset = metadataList.filter({ $0.commonKey == .commonKeyArtwork }).first, + let artworkData = artworkAsset.dataValue, + let artworkImage = UIImage(data: artworkData) else { + return nil + } + return artworkImage } } diff --git a/Amperfy/Player/MusicPlayer.swift b/Amperfy/Player/MusicPlayer.swift index ce1a0b75..f2a3119e 100644 --- a/Amperfy/Player/MusicPlayer.swift +++ b/Amperfy/Player/MusicPlayer.swift @@ -9,6 +9,7 @@ protocol MusicPlayable { func didStopPlaying(playlistItem: PlaylistItem?) func didElapsedTimeChange() func didPlaylistChange() + func didArtworkChange() } enum RepeatMode: Int16 { @@ -88,6 +89,7 @@ class MusicPlayer: NSObject, BackendAudioPlayerNotifiable { } private var coreData: PlayerData + private let library: LibraryStorage private var playableDownloadManager: DownloadManageable private let backendAudioPlayer: BackendAudioPlayer private let userStatistics: UserStatistics @@ -95,8 +97,9 @@ class MusicPlayer: NSObject, BackendAudioPlayerNotifiable { private let replayInsteadPlayPreviousTimeInSec = 5.0 private var remoteCommandCenter: MPRemoteCommandCenter? - init(coreData: PlayerData, playableDownloadManager: DownloadManageable, backendAudioPlayer: BackendAudioPlayer, userStatistics: UserStatistics) { + init(coreData: PlayerData, library: LibraryStorage, playableDownloadManager: DownloadManageable, backendAudioPlayer: BackendAudioPlayer, userStatistics: UserStatistics) { self.coreData = coreData + self.library = library self.playableDownloadManager = playableDownloadManager self.backendAudioPlayer = backendAudioPlayer self.backendAudioPlayer.isAutoCachePlayedItems = coreData.isAutoCachePlayedItems @@ -154,10 +157,21 @@ class MusicPlayer: NSObject, BackendAudioPlayerNotifiable { let playlistItem = playlist.items[playlistIndex] userStatistics.playedItem(repeatMode: repeatMode, isShuffle: isShuffle) backendAudioPlayer.requestToPlay(playlistItem: playlistItem) + extractEmbeddedArtwork(playlistItem: playlistItem) coreData.currentIndex = playlistIndex preDownloadNextItems(playlistIndex: playlistIndex) } + private func extractEmbeddedArtwork(playlistItem: PlaylistItem) { + if let embeddedImage = backendAudioPlayer.getEmbeddedArtworkFromID3Tag(), playlistItem.playable?.embeddedArtwork == nil { + let embeddedArtwork = library.createEmbeddedArtwork() + embeddedArtwork.setImage(fromData: embeddedImage.pngData()) + embeddedArtwork.owner = playlistItem.playable + library.saveContext() + notifyArtworkChanged() + } + } + private func preDownloadNextItems(playlistIndex: Int) { guard coreData.isAutoCachePlayedItems else { return } var upcomingItemsCount = (playlist.playables.count-1) - playlistIndex @@ -349,6 +363,12 @@ class MusicPlayer: NSObject, BackendAudioPlayerNotifiable { } } + func notifyArtworkChanged() { + for notifier in notifierList { + notifier.didArtworkChange() + } + } + func notifyElapsedTimeChanged() { for notifier in notifierList { notifier.didElapsedTimeChange() diff --git a/Amperfy/Screens/View/PlayerView.swift b/Amperfy/Screens/View/PlayerView.swift index 29f6e06e..3a34e475 100644 --- a/Amperfy/Screens/View/PlayerView.swift +++ b/Amperfy/Screens/View/PlayerView.swift @@ -368,6 +368,7 @@ class PlayerView: UIView { } func refreshCurrentlyPlayingInfo() { + refreshArtwork() if player.playlist.playables.count > 0 { let playableIndex = player.currentlyPlaying?.index ?? 0 let playableInfo = player.playlist.playables[playableIndex] @@ -375,10 +376,8 @@ class PlayerView: UIView { titleLargeLabel.text = playableInfo.title artistNameCompactLabel.text = playableInfo.creatorName artistNameLargeLabel.text = playableInfo.creatorName - artworkImage.image = playableInfo.image rootView?.popupItem.title = playableInfo.title rootView?.popupItem.subtitle = playableInfo.creatorName - rootView?.popupItem.image = playableInfo.image rootView?.changeBackgroundGradient(forPlayable: playableInfo) lastDisplayedPlayable = playableInfo } else { @@ -386,13 +385,23 @@ class PlayerView: UIView { titleLargeLabel.text = "Not playing" artistNameCompactLabel.text = "" artistNameLargeLabel.text = "" - artworkImage.image = Artwork.defaultImage rootView?.popupItem.title = "Not playing" rootView?.popupItem.subtitle = "" - rootView?.popupItem.image = Artwork.defaultImage lastDisplayedPlayable = nil } } + + func refreshArtwork() { + if player.playlist.playables.count > 0 { + let playableIndex = player.currentlyPlaying?.index ?? 0 + let playableInfo = player.playlist.playables[playableIndex] + artworkImage.image = playableInfo.image + rootView?.popupItem.image = playableInfo.image + } else { + artworkImage.image = Artwork.defaultImage + rootView?.popupItem.image = Artwork.defaultImage + } + } func refreshTimeInfo() { if player.currentlyPlaying != nil { @@ -479,5 +488,9 @@ extension PlayerView: MusicPlayable { func didPlaylistChange() { refreshPlayer() } + + func didArtworkChange() { + refreshArtwork() + } } diff --git a/Amperfy/Screens/ViewController/PopupPlayerVC.swift b/Amperfy/Screens/ViewController/PopupPlayerVC.swift index cf62f2f6..676f03d4 100644 --- a/Amperfy/Screens/ViewController/PopupPlayerVC.swift +++ b/Amperfy/Screens/ViewController/PopupPlayerVC.swift @@ -304,6 +304,9 @@ extension PopupPlayerVC: MusicPlayable { self.reloadData() } + func didArtworkChange() { + } + func closePopupPlayerAndDisplayInLibraryTab(vc: UIViewController) { guard let hostingTabBarVC = hostingTabBarVC else { return } hostingTabBarVC.closePopup(animated: true, completion: { () in diff --git a/Amperfy/Storage/EntityWrappers/AbstractPlayable.swift b/Amperfy/Storage/EntityWrappers/AbstractPlayable.swift index 24eaab89..f4a07a45 100644 --- a/Amperfy/Storage/EntityWrappers/AbstractPlayable.swift +++ b/Amperfy/Storage/EntityWrappers/AbstractPlayable.swift @@ -1,6 +1,7 @@ import Foundation import CoreData import UIKit +import AVFoundation public class AbstractPlayable: AbstractLibraryEntity, Downloadable { /* @@ -16,6 +17,23 @@ public class AbstractPlayable: AbstractLibraryEntity, Downloadable { super.init(managedObject: managedObject) } + override var image: UIImage { + guard let embeddedArtwork = playableManagedObject.embeddedArtwork, + let embeddedArtworkImageData = embeddedArtwork.imageData, + let embeddedArtworkImage = UIImage(data: embeddedArtworkImageData) else { + return super.image + } + return embeddedArtworkImage + } + var embeddedArtwork: EmbeddedArtwork? { + get { + guard let embeddedArtworkMO = playableManagedObject.embeddedArtwork else { return nil } + return EmbeddedArtwork(managedObject: embeddedArtworkMO) + } + set { + if playableManagedObject.embeddedArtwork != newValue?.managedObject { playableManagedObject.embeddedArtwork = newValue?.managedObject } + } + } var objectID: NSManagedObjectID { return playableManagedObject.objectID } diff --git a/Amperfy/Storage/EntityWrappers/EmbeddedArtwork.swift b/Amperfy/Storage/EntityWrappers/EmbeddedArtwork.swift new file mode 100644 index 00000000..83f46227 --- /dev/null +++ b/Amperfy/Storage/EntityWrappers/EmbeddedArtwork.swift @@ -0,0 +1,29 @@ +import Foundation +import UIKit + +public class EmbeddedArtwork: NSObject { + + let managedObject: EmbeddedArtworkMO + + init(managedObject: EmbeddedArtworkMO) { + self.managedObject = managedObject + } + + var image: UIImage? { + guard let imageData = managedObject.imageData else { return nil } + return UIImage(data: imageData) + } + + func setImage(fromData: Data?) { + managedObject.imageData = fromData + } + + var owner: AbstractPlayable? { + get { + guard let ownerMO = managedObject.owner else { return nil } + return AbstractPlayable(managedObject: ownerMO) + } + set { if managedObject.owner != newValue?.playableManagedObject { managedObject.owner = newValue?.playableManagedObject } } + } + +} diff --git a/Amperfy/Storage/LibraryStorage.swift b/Amperfy/Storage/LibraryStorage.swift index 918bd200..9db13219 100644 --- a/Amperfy/Storage/LibraryStorage.swift +++ b/Amperfy/Storage/LibraryStorage.swift @@ -17,7 +17,7 @@ enum PlaylistSearchCategory: Int { class LibraryStorage: PlayableFileCachable { - static let entitiesToDelete = [Genre.typeName, Artist.typeName, Album.typeName, Song.typeName, PlayableFile.typeName, Artwork.typeName, SyncWave.typeName, Playlist.typeName, PlaylistItem.typeName, PlayerData.entityName, LogEntry.typeName, MusicFolder.typeName, Directory.typeName, Podcast.typeName, PodcastEpisode.typeName, Download.typeName] + static let entitiesToDelete = [Genre.typeName, Artist.typeName, Album.typeName, Song.typeName, PlayableFile.typeName, Artwork.typeName, EmbeddedArtwork.typeName, SyncWave.typeName, Playlist.typeName, PlaylistItem.typeName, PlayerData.entityName, LogEntry.typeName, MusicFolder.typeName, Directory.typeName, Podcast.typeName, PodcastEpisode.typeName, Download.typeName] private let log = OSLog(subsystem: AppDelegate.name, category: "LibraryStorage") private var context: NSManagedObjectContext @@ -211,6 +211,18 @@ class LibraryStorage: PlayableFileCachable { clearStorage(ofType: PlayableFile.typeName) } + func createEmbeddedArtwork() -> EmbeddedArtwork { + return EmbeddedArtwork(managedObject: EmbeddedArtworkMO(context: context)) + } + + func deleteEmbeddedArtworks() { + let fetchRequest = EmbeddedArtworkMO.fetchRequest() + guard let artworks = try? context.fetch(fetchRequest) else { return } + for artwork in artworks { + context.delete(artwork) + } + } + func createArtwork() -> Artwork { return Artwork(managedObject: ArtworkMO(context: context)) } diff --git a/Amperfy/Storage/ManagedObjects/AbstractPlayableMO+CoreDataProperties.swift b/Amperfy/Storage/ManagedObjects/AbstractPlayableMO+CoreDataProperties.swift index ef9704d8..19319de3 100644 --- a/Amperfy/Storage/ManagedObjects/AbstractPlayableMO+CoreDataProperties.swift +++ b/Amperfy/Storage/ManagedObjects/AbstractPlayableMO+CoreDataProperties.swift @@ -23,6 +23,7 @@ extension AbstractPlayableMO { @NSManaged public var download: DownloadMO? @NSManaged public var file: PlayableFileMO? @NSManaged public var playlistItems: NSOrderedSet? + @NSManaged public var embeddedArtwork: EmbeddedArtworkMO? } diff --git a/Amperfy/Storage/ManagedObjects/Amperfy.xcdatamodeld/.xccurrentversion b/Amperfy/Storage/ManagedObjects/Amperfy.xcdatamodeld/.xccurrentversion index 1ef7c4b3..89fcec67 100644 --- a/Amperfy/Storage/ManagedObjects/Amperfy.xcdatamodeld/.xccurrentversion +++ b/Amperfy/Storage/ManagedObjects/Amperfy.xcdatamodeld/.xccurrentversion @@ -3,6 +3,6 @@ _XCCurrentVersionName - Amperfy v14.xcdatamodel + Amperfy v15.xcdatamodel diff --git a/Amperfy/Storage/ManagedObjects/Amperfy.xcdatamodeld/Amperfy v15.xcdatamodel/contents b/Amperfy/Storage/ManagedObjects/Amperfy.xcdatamodeld/Amperfy v15.xcdatamodel/contents new file mode 100644 index 00000000..8d345f22 --- /dev/null +++ b/Amperfy/Storage/ManagedObjects/Amperfy.xcdatamodeld/Amperfy v15.xcdatamodel/contents @@ -0,0 +1,228 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Amperfy/Storage/ManagedObjects/EmbeddedArtworkMO+CoreDataClass.swift b/Amperfy/Storage/ManagedObjects/EmbeddedArtworkMO+CoreDataClass.swift new file mode 100644 index 00000000..a741af4e --- /dev/null +++ b/Amperfy/Storage/ManagedObjects/EmbeddedArtworkMO+CoreDataClass.swift @@ -0,0 +1,7 @@ +import Foundation +import CoreData + +@objc(EmbeddedArtworkMO) +public class EmbeddedArtworkMO: NSManagedObject { + +} diff --git a/Amperfy/Storage/ManagedObjects/EmbeddedArtworkMO+CoreDataProperties.swift b/Amperfy/Storage/ManagedObjects/EmbeddedArtworkMO+CoreDataProperties.swift new file mode 100644 index 00000000..e1d10717 --- /dev/null +++ b/Amperfy/Storage/ManagedObjects/EmbeddedArtworkMO+CoreDataProperties.swift @@ -0,0 +1,14 @@ +import Foundation +import CoreData + + +extension EmbeddedArtworkMO { + + @nonobjc public class func fetchRequest() -> NSFetchRequest { + return NSFetchRequest(entityName: "EmbeddedArtwork") + } + + @NSManaged public var imageData: Data? + @NSManaged public var owner: AbstractPlayableMO? + +} diff --git a/Amperfy/Storage/ManagedObjects/Migration/CoreDataMigrationVersion.swift b/Amperfy/Storage/ManagedObjects/Migration/CoreDataMigrationVersion.swift index 25f37108..7a259679 100644 --- a/Amperfy/Storage/ManagedObjects/Migration/CoreDataMigrationVersion.swift +++ b/Amperfy/Storage/ManagedObjects/Migration/CoreDataMigrationVersion.swift @@ -24,6 +24,7 @@ enum CoreDataMigrationVersion: String, CaseIterable { case v12 = "Amperfy v12" case v13 = "Amperfy v13" case v14 = "Amperfy v14" + case v15 = "Amperfy v15" // MARK: - Current @@ -67,6 +68,8 @@ enum CoreDataMigrationVersion: String, CaseIterable { case .v13: return .v14 case .v14: + return .v15 + case .v15: return nil } } diff --git a/AmperfyTests/Cases/Player/MusicPlayerTest.swift b/AmperfyTests/Cases/Player/MusicPlayerTest.swift index f04b2687..ef701bd8 100644 --- a/AmperfyTests/Cases/Player/MusicPlayerTest.swift +++ b/AmperfyTests/Cases/Player/MusicPlayerTest.swift @@ -146,7 +146,7 @@ class MusicPlayerTest: XCTestCase { backendApi = MOCK_BackendApi() backendPlayer = BackendAudioPlayer(mediaPlayer: mockAVPlayer, eventLogger: eventLogger, backendApi: backendApi, playableDownloader: songDownloader, cacheProxy: library, userStatistics: userStatistics) playerData = library.getPlayerData() - testPlayer = MusicPlayer(coreData: playerData, playableDownloadManager: songDownloader, backendAudioPlayer: backendPlayer, userStatistics: userStatistics) + testPlayer = MusicPlayer(coreData: playerData, library: library, playableDownloadManager: songDownloader, backendAudioPlayer: backendPlayer, userStatistics: userStatistics) guard let songCachedFetched = library.getSong(id: "36") else { XCTFail(); return } songCached = songCachedFetched