1
1
mirror of https://github.com/danbee/persephone synced 2025-03-04 08:39:11 +00:00

WIP: Refactor album art service

We need to make it more flexible and less coupled
This commit is contained in:
Daniel Barber 2019-03-25 21:15:49 -04:00
parent a2706f4e0a
commit 27c0e32e48
Signed by: danbarber
GPG Key ID: 931D8112E0103DD8
32 changed files with 344 additions and 262 deletions

View File

@ -19,6 +19,7 @@
E408D3CB220E341D0006D9BE /* AlbumViewItem.xib in Resources */ = {isa = PBXBuildFile; fileRef = E408D3C9220E341D0006D9BE /* AlbumViewItem.xib */; };
E40F41F3221EDE27004B6CB8 /* Preferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = E40F41F2221EDE27004B6CB8 /* Preferences.swift */; };
E40FE71B221B904300A4223F /* NSEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = E40FE71A221B904300A4223F /* NSEvent.swift */; };
E419E2872249B96600216A8C /* Song.swift in Sources */ = {isa = PBXBuildFile; fileRef = E419E2862249B96600216A8C /* Song.swift */; };
E41B22C021FB6BBA00D544F6 /* libmpdclient.2.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = E41B22BF21FB6BBA00D544F6 /* libmpdclient.2.dylib */; settings = {ATTRIBUTES = (Required, ); }; };
E41B22C121FB6C3300D544F6 /* libmpdclient.2.dylib in Embed Libraries */ = {isa = PBXBuildFile; fileRef = E41B22BF21FB6BBA00D544F6 /* libmpdclient.2.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
E41B22C621FB932700D544F6 /* MPDClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = E41B22C521FB932700D544F6 /* MPDClient.swift */; };
@ -41,7 +42,7 @@
E42A8F3C22176D6400A13ED9 /* README.md in Resources */ = {isa = PBXBuildFile; fileRef = E42A8F3A22176D6400A13ED9 /* README.md */; };
E435E3E2221CD4E200184CFC /* NSFont.swift in Sources */ = {isa = PBXBuildFile; fileRef = E435E3E1221CD4E200184CFC /* NSFont.swift */; };
E435E3E4221CD75D00184CFC /* NSImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = E435E3E3221CD75D00184CFC /* NSImage.swift */; };
E450AD7E222620A10091BED3 /* AlbumItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = E450AD7D222620A10091BED3 /* AlbumItem.swift */; };
E450AD7E222620A10091BED3 /* Album.swift in Sources */ = {isa = PBXBuildFile; fileRef = E450AD7D222620A10091BED3 /* Album.swift */; };
E450AD8622262AE60091BED3 /* SwiftyJSON.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E450AD8522262AE60091BED3 /* SwiftyJSON.framework */; };
E450AD8822262AEC0091BED3 /* SwiftyJSON.framework in Embed Libraries */ = {isa = PBXBuildFile; fileRef = E450AD8522262AE60091BED3 /* SwiftyJSON.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
E450AD8F22262C620091BED3 /* PromiseKit.framework.dSYM in Resources */ = {isa = PBXBuildFile; fileRef = E450AD8E22262C620091BED3 /* PromiseKit.framework.dSYM */; };
@ -54,7 +55,7 @@
E450ADA12229E7C90091BED3 /* PMKFoundation.framework.dSYM in Resources */ = {isa = PBXBuildFile; fileRef = E450AD9F2229E7C90091BED3 /* PMKFoundation.framework.dSYM */; };
E450ADA32229E7E00091BED3 /* PMKFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E450ADA02229E7C90091BED3 /* PMKFoundation.framework */; };
E450ADA42229E7E00091BED3 /* PMKFoundation.framework in Embed Libraries */ = {isa = PBXBuildFile; fileRef = E450ADA02229E7C90091BED3 /* PMKFoundation.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
E45962C62241A78500FC1A1E /* Command.swift in Sources */ = {isa = PBXBuildFile; fileRef = E45962C52241A78500FC1A1E /* Command.swift */; };
E45962C62241A78500FC1A1E /* MPDCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = E45962C52241A78500FC1A1E /* MPDCommand.swift */; };
E465049A21E94DF500A70F4C /* WindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E465049921E94DF500A70F4C /* WindowController.swift */; };
E47E2FCC2220573500F747E6 /* MediaKeyTap.framework.dSYM in Resources */ = {isa = PBXBuildFile; fileRef = E47E2FCB2220573500F747E6 /* MediaKeyTap.framework.dSYM */; };
E47E2FD122205C4600F747E6 /* MainSplitViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E47E2FD022205C4600F747E6 /* MainSplitViewController.swift */; };
@ -64,20 +65,20 @@
E47E2FDD2220A6D100F747E6 /* Time.swift in Sources */ = {isa = PBXBuildFile; fileRef = E47E2FDC2220A6D100F747E6 /* Time.swift */; };
E47E2FE52220AA0700F747E6 /* AlbumViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = E47E2FE42220AA0700F747E6 /* AlbumViewLayout.swift */; };
E4928E0B2218D62A001D4BEA /* CGColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4928E0A2218D62A001D4BEA /* CGColor.swift */; };
E4A642DA22090CBE00067D21 /* Status.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4A642D922090CBE00067D21 /* Status.swift */; };
E4A642DA22090CBE00067D21 /* MPDStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4A642D922090CBE00067D21 /* MPDStatus.swift */; };
E4A83BEF2221F8CF0098FED6 /* AlbumArtPrefsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4A83BEE2221F8CF0098FED6 /* AlbumArtPrefsController.swift */; };
E4A83BF12221FAA00098FED6 /* PreferencesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4A83BF02221FAA00098FED6 /* PreferencesViewController.swift */; };
E4A83BF4222207D50098FED6 /* AlbumArtService.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4A83BF3222207D50098FED6 /* AlbumArtService.swift */; };
E4C8B53C22342005009A20F3 /* PreferencesWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4C8B53B22342005009A20F3 /* PreferencesWindowController.swift */; };
E4C8B53E22349002009A20F3 /* Idle.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4C8B53D22349002009A20F3 /* Idle.swift */; };
E4C8B53E22349002009A20F3 /* MPDIdle.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4C8B53D22349002009A20F3 /* MPDIdle.swift */; };
E4E8CC902204EC7F0024217A /* Delegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4E8CC8F2204EC7F0024217A /* Delegate.swift */; };
E4E8CC922204F4B80024217A /* QueueViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4E8CC912204F4B80024217A /* QueueViewController.swift */; };
E4E8CC942206097F0024217A /* NotificationsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4E8CC932206097F0024217A /* NotificationsController.swift */; };
E4E8CC9A22075D370024217A /* Song.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4E8CC9922075D370024217A /* Song.swift */; };
E4EB2379220F10B8008C70C0 /* Pair.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4EB2378220F10B8008C70C0 /* Pair.swift */; };
E4EB237B220F7CF1008C70C0 /* Album.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4EB237A220F7CF1008C70C0 /* Album.swift */; };
E4E8CC9A22075D370024217A /* MPDSong.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4E8CC9922075D370024217A /* MPDSong.swift */; };
E4EB2379220F10B8008C70C0 /* MPDPair.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4EB2378220F10B8008C70C0 /* MPDPair.swift */; };
E4EB237B220F7CF1008C70C0 /* MPDAlbum.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4EB237A220F7CF1008C70C0 /* MPDAlbum.swift */; };
E4F6B460221E119B00ACF42A /* QueueDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4F6B45F221E119B00ACF42A /* QueueDataSource.swift */; };
E4F6B463221E125900ACF42A /* SongItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4F6B462221E125900ACF42A /* SongItem.swift */; };
E4F6B463221E125900ACF42A /* QueueItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4F6B462221E125900ACF42A /* QueueItem.swift */; };
E4F6B467221E233200ACF42A /* AlbumDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4F6B466221E233200ACF42A /* AlbumDataSource.swift */; };
/* End PBXBuildFile section */
@ -145,6 +146,7 @@
E408D3C9220E341D0006D9BE /* AlbumViewItem.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = AlbumViewItem.xib; sourceTree = "<group>"; };
E40F41F2221EDE27004B6CB8 /* Preferences.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Preferences.swift; sourceTree = "<group>"; };
E40FE71A221B904300A4223F /* NSEvent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSEvent.swift; sourceTree = "<group>"; };
E419E2862249B96600216A8C /* Song.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Song.swift; sourceTree = "<group>"; };
E41B22BF21FB6BBA00D544F6 /* libmpdclient.2.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libmpdclient.2.dylib; path = libmpdclient/output/libmpdclient.2.dylib; sourceTree = "<group>"; };
E41B22C421FB715A00D544F6 /* module.modulemap */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.module-map"; path = module.modulemap; sourceTree = "<group>"; };
E41B22C521FB932700D544F6 /* MPDClient.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MPDClient.swift; sourceTree = "<group>"; };
@ -201,7 +203,7 @@
E42A8F3A22176D6400A13ED9 /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
E435E3E1221CD4E200184CFC /* NSFont.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSFont.swift; sourceTree = "<group>"; };
E435E3E3221CD75D00184CFC /* NSImage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSImage.swift; sourceTree = "<group>"; };
E450AD7D222620A10091BED3 /* AlbumItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlbumItem.swift; sourceTree = "<group>"; };
E450AD7D222620A10091BED3 /* Album.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Album.swift; sourceTree = "<group>"; };
E450AD8522262AE60091BED3 /* SwiftyJSON.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftyJSON.framework; path = Carthage/Build/Mac/SwiftyJSON.framework; sourceTree = "<group>"; };
E450AD8C22262C590091BED3 /* PromiseKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = PromiseKit.framework; path = Carthage/Build/Mac/PromiseKit.framework; sourceTree = "<group>"; };
E450AD8E22262C620091BED3 /* PromiseKit.framework.dSYM */ = {isa = PBXFileReference; lastKnownFileType = wrapper.dsym; name = PromiseKit.framework.dSYM; path = Carthage/Build/Mac/PromiseKit.framework.dSYM; sourceTree = "<group>"; };
@ -213,7 +215,7 @@
E450AD9E2229B9BC0091BED3 /* PersephoneBridgingHeader.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PersephoneBridgingHeader.h; sourceTree = "<group>"; };
E450AD9F2229E7C90091BED3 /* PMKFoundation.framework.dSYM */ = {isa = PBXFileReference; lastKnownFileType = wrapper.dsym; name = PMKFoundation.framework.dSYM; path = Carthage/Build/Mac/PMKFoundation.framework.dSYM; sourceTree = "<group>"; };
E450ADA02229E7C90091BED3 /* PMKFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = PMKFoundation.framework; path = Carthage/Build/Mac/PMKFoundation.framework; sourceTree = "<group>"; };
E45962C52241A78500FC1A1E /* Command.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Command.swift; sourceTree = "<group>"; };
E45962C52241A78500FC1A1E /* MPDCommand.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MPDCommand.swift; sourceTree = "<group>"; };
E465049921E94DF500A70F4C /* WindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WindowController.swift; sourceTree = "<group>"; };
E47E2FCB2220573500F747E6 /* MediaKeyTap.framework.dSYM */ = {isa = PBXFileReference; lastKnownFileType = wrapper.dsym; name = MediaKeyTap.framework.dSYM; path = Carthage/Build/Mac/MediaKeyTap.framework.dSYM; sourceTree = "<group>"; };
E47E2FD022205C4600F747E6 /* MainSplitViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainSplitViewController.swift; sourceTree = "<group>"; };
@ -223,20 +225,20 @@
E47E2FDC2220A6D100F747E6 /* Time.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Time.swift; sourceTree = "<group>"; };
E47E2FE42220AA0700F747E6 /* AlbumViewLayout.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AlbumViewLayout.swift; sourceTree = "<group>"; };
E4928E0A2218D62A001D4BEA /* CGColor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CGColor.swift; sourceTree = "<group>"; };
E4A642D922090CBE00067D21 /* Status.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Status.swift; sourceTree = "<group>"; };
E4A642D922090CBE00067D21 /* MPDStatus.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MPDStatus.swift; sourceTree = "<group>"; };
E4A83BEE2221F8CF0098FED6 /* AlbumArtPrefsController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlbumArtPrefsController.swift; sourceTree = "<group>"; };
E4A83BF02221FAA00098FED6 /* PreferencesViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreferencesViewController.swift; sourceTree = "<group>"; };
E4A83BF3222207D50098FED6 /* AlbumArtService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlbumArtService.swift; sourceTree = "<group>"; };
E4C8B53B22342005009A20F3 /* PreferencesWindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreferencesWindowController.swift; sourceTree = "<group>"; };
E4C8B53D22349002009A20F3 /* Idle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Idle.swift; sourceTree = "<group>"; };
E4C8B53D22349002009A20F3 /* MPDIdle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MPDIdle.swift; sourceTree = "<group>"; };
E4E8CC8F2204EC7F0024217A /* Delegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Delegate.swift; sourceTree = "<group>"; };
E4E8CC912204F4B80024217A /* QueueViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QueueViewController.swift; sourceTree = "<group>"; };
E4E8CC932206097F0024217A /* NotificationsController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationsController.swift; sourceTree = "<group>"; };
E4E8CC9922075D370024217A /* Song.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Song.swift; sourceTree = "<group>"; };
E4EB2378220F10B8008C70C0 /* Pair.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Pair.swift; sourceTree = "<group>"; };
E4EB237A220F7CF1008C70C0 /* Album.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Album.swift; sourceTree = "<group>"; };
E4E8CC9922075D370024217A /* MPDSong.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MPDSong.swift; sourceTree = "<group>"; };
E4EB2378220F10B8008C70C0 /* MPDPair.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MPDPair.swift; sourceTree = "<group>"; };
E4EB237A220F7CF1008C70C0 /* MPDAlbum.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MPDAlbum.swift; sourceTree = "<group>"; };
E4F6B45F221E119B00ACF42A /* QueueDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QueueDataSource.swift; sourceTree = "<group>"; };
E4F6B462221E125900ACF42A /* SongItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SongItem.swift; sourceTree = "<group>"; };
E4F6B462221E125900ACF42A /* QueueItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QueueItem.swift; sourceTree = "<group>"; };
E4F6B466221E233200ACF42A /* AlbumDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlbumDataSource.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */
@ -512,12 +514,12 @@
E4D1B594220BA2490026F233 /* Models */ = {
isa = PBXGroup;
children = (
E4E8CC9922075D370024217A /* Song.swift */,
E4A642D922090CBE00067D21 /* Status.swift */,
E4EB2378220F10B8008C70C0 /* Pair.swift */,
E4EB237A220F7CF1008C70C0 /* Album.swift */,
E4C8B53D22349002009A20F3 /* Idle.swift */,
E45962C52241A78500FC1A1E /* Command.swift */,
E4E8CC9922075D370024217A /* MPDSong.swift */,
E4A642D922090CBE00067D21 /* MPDStatus.swift */,
E4EB2378220F10B8008C70C0 /* MPDPair.swift */,
E4EB237A220F7CF1008C70C0 /* MPDAlbum.swift */,
E4C8B53D22349002009A20F3 /* MPDIdle.swift */,
E45962C52241A78500FC1A1E /* MPDCommand.swift */,
);
path = Models;
sourceTree = "<group>";
@ -564,10 +566,11 @@
E4F6B461221E124700ACF42A /* Models */ = {
isa = PBXGroup;
children = (
E47E2FDC2220A6D100F747E6 /* Time.swift */,
E450AD7D222620A10091BED3 /* Album.swift */,
E40F41F2221EDE27004B6CB8 /* Preferences.swift */,
E4F6B462221E125900ACF42A /* SongItem.swift */,
E450AD7D222620A10091BED3 /* AlbumItem.swift */,
E4F6B462221E125900ACF42A /* QueueItem.swift */,
E419E2862249B96600216A8C /* Song.swift */,
E47E2FDC2220A6D100F747E6 /* Time.swift */,
);
path = Models;
sourceTree = "<group>";
@ -746,36 +749,37 @@
E408D3C2220E134F0006D9BE /* AlbumViewController.swift in Sources */,
E40FE71B221B904300A4223F /* NSEvent.swift in Sources */,
E4928E0B2218D62A001D4BEA /* CGColor.swift in Sources */,
E4C8B53E22349002009A20F3 /* Idle.swift in Sources */,
E4C8B53E22349002009A20F3 /* MPDIdle.swift in Sources */,
E4F6B460221E119B00ACF42A /* QueueDataSource.swift in Sources */,
E4C8B53C22342005009A20F3 /* PreferencesWindowController.swift in Sources */,
E41E5307223C019100173814 /* MPDClient+Status.swift in Sources */,
E41E5310223EF6CE00173814 /* AlbumArtService+Remote.swift in Sources */,
E41E530B223C033700173814 /* MPDClient+Album.swift in Sources */,
E42410B62241B956005ED6DF /* MPDClient+Database.swift in Sources */,
E4A642DA22090CBE00067D21 /* Status.swift in Sources */,
E4A642DA22090CBE00067D21 /* MPDStatus.swift in Sources */,
E47E2FD72220720300F747E6 /* AlbumItemView.swift in Sources */,
E450AD9522262DF10091BED3 /* AlbumArtQueue.swift in Sources */,
E41E52FD223BF87300173814 /* MPDClient+Connection.swift in Sources */,
E450AD7E222620A10091BED3 /* AlbumItem.swift in Sources */,
E450AD7E222620A10091BED3 /* Album.swift in Sources */,
E4E8CC942206097F0024217A /* NotificationsController.swift in Sources */,
E408D3B6220DD8970006D9BE /* Notification.swift in Sources */,
E45962C62241A78500FC1A1E /* Command.swift in Sources */,
E45962C62241A78500FC1A1E /* MPDCommand.swift in Sources */,
E408D3B9220DE98F0006D9BE /* NSUserInterfaceItemIdentifier.swift in Sources */,
E4EB2379220F10B8008C70C0 /* Pair.swift in Sources */,
E4F6B463221E125900ACF42A /* SongItem.swift in Sources */,
E4EB2379220F10B8008C70C0 /* MPDPair.swift in Sources */,
E4F6B463221E125900ACF42A /* QueueItem.swift in Sources */,
E4A83BF12221FAA00098FED6 /* PreferencesViewController.swift in Sources */,
E465049A21E94DF500A70F4C /* WindowController.swift in Sources */,
E41B22C621FB932700D544F6 /* MPDClient.swift in Sources */,
E40F41F3221EDE27004B6CB8 /* Preferences.swift in Sources */,
E47E2FDD2220A6D100F747E6 /* Time.swift in Sources */,
E419E2872249B96600216A8C /* Song.swift in Sources */,
E407861C2110CE6E006887B1 /* AppDelegate.swift in Sources */,
E41E5309223C020400173814 /* MPDClient+Command.swift in Sources */,
E47E2FE52220AA0700F747E6 /* AlbumViewLayout.swift in Sources */,
E41E52FF223BF95E00173814 /* MPDClient+Transport.swift in Sources */,
E47E2FD322205D2500F747E6 /* MainWindow.swift in Sources */,
E47E2FD122205C4600F747E6 /* MainSplitViewController.swift in Sources */,
E4E8CC9A22075D370024217A /* Song.swift in Sources */,
E4E8CC9A22075D370024217A /* MPDSong.swift in Sources */,
E41EA46C221636AF0068EF46 /* GeneralPrefsViewController.swift in Sources */,
E4E8CC902204EC7F0024217A /* Delegate.swift in Sources */,
E4A83BF4222207D50098FED6 /* AlbumArtService.swift in Sources */,
@ -785,7 +789,7 @@
E4E8CC922204F4B80024217A /* QueueViewController.swift in Sources */,
E41E5312223EF74A00173814 /* AlbumArtService+Filesystem.swift in Sources */,
E41E5301223BF99300173814 /* MPDClient+Queue.swift in Sources */,
E4EB237B220F7CF1008C70C0 /* Album.swift in Sources */,
E4EB237B220F7CF1008C70C0 /* MPDAlbum.swift in Sources */,
E450AD9D2229B9050091BED3 /* String.swift in Sources */,
E41E5303223BF9C300173814 /* MPDClient+Idle.swift in Sources */,
E435E3E4221CD75D00184CFC /* NSImage.swift in Sources */,

View File

@ -30,6 +30,7 @@
},
"properties" : {
"template-rendering-intent" : "original",
"preserves-vector-representation" : true
"preserves-vector-representation" : true,
"auto-scaling" : "auto"
}
}

View File

@ -72,10 +72,10 @@ class AlbumViewController: NSViewController,
}
@objc func updateAlbums(_ notification: Notification) {
guard let albums = notification.userInfo?[Notification.albumsKey] as? [MPDClient.Album]
guard let albums = notification.userInfo?[Notification.albumsKey] as? [MPDClient.MPDAlbum]
else { return }
dataSource.albums = albums.map { AlbumItem(album: $0, coverArt: nil) }
dataSource.albums = albums.map { Album(mpdAlbum: $0, coverArt: nil) }
albumCollectionView.reloadData()
}

View File

@ -10,7 +10,7 @@ import Cocoa
class AlbumViewItem: NSCollectionViewItem {
var observer: NSKeyValueObservation?
var album: AlbumItem?
var album: Album?
override func viewDidLoad() {
super.viewDidLoad()
@ -27,7 +27,7 @@ class AlbumViewItem: NSCollectionViewItem {
}
}
func setAlbum(_ album: AlbumItem) {
func setAlbum(_ album: Album) {
self.album = album
albumTitle.stringValue = album.title
albumArtist.stringValue = album.artist
@ -53,7 +53,7 @@ class AlbumViewItem: NSCollectionViewItem {
@IBAction func playAlbum(_ sender: Any) {
guard let album = album else { return }
AppDelegate.mpdClient.playAlbum(album.album)
AppDelegate.mpdClient.playAlbum(album.mpdAlbum)
}
@IBOutlet var albumCoverView: NSImageView!

View File

@ -19,7 +19,7 @@ class NotificationsController: MPDClientDelegate {
sendNotification(name: Notification.willDisconnect)
}
func didUpdateState(mpdClient: MPDClient, state: MPDClient.Status.State) {
func didUpdateState(mpdClient: MPDClient, state: MPDClient.MPDStatus.State) {
sendNotification(
name: Notification.stateChanged,
userInfo: [Notification.stateKey: state]
@ -44,7 +44,7 @@ class NotificationsController: MPDClientDelegate {
sendNotification(name: Notification.databaseUpdateFinished)
}
func didUpdateQueue(mpdClient: MPDClient, queue: [MPDClient.Song]) {
func didUpdateQueue(mpdClient: MPDClient, queue: [MPDClient.MPDSong]) {
sendNotification(
name: Notification.queueChanged,
userInfo: [Notification.queueKey: queue]
@ -58,7 +58,7 @@ class NotificationsController: MPDClientDelegate {
)
}
func didLoadAlbums(mpdClient: MPDClient, albums: [MPDClient.Album]) {
func didLoadAlbums(mpdClient: MPDClient, albums: [MPDClient.MPDAlbum]) {
sendNotification(
name: Notification.loadedAlbums,
userInfo: [Notification.albumsKey: albums]

View File

@ -13,6 +13,7 @@ class QueueViewController: NSViewController,
var dataSource = QueueDataSource()
@IBOutlet var queueView: NSOutlineView!
@IBOutlet var queueAlbumArtImage: NSImageView!
override func viewDidLoad() {
super.viewDidLoad()
@ -41,14 +42,14 @@ class QueueViewController: NSViewController,
}
@objc func stateChanged(_ notification: Notification) {
guard let state = notification.userInfo?[Notification.stateKey] as? MPDClient.Status.State
guard let state = notification.userInfo?[Notification.stateKey] as? MPDClient.MPDStatus.State
else { return }
dataSource.setQueueIcon(state)
}
@objc func queueChanged(_ notification: Notification) {
guard let queue = notification.userInfo?[Notification.queueKey] as? [MPDClient.Song]
guard let queue = notification.userInfo?[Notification.queueKey] as? [MPDClient.MPDSong]
else { return }
dataSource.updateQueue(queue)
@ -60,8 +61,16 @@ class QueueViewController: NSViewController,
else { return }
dataSource.setQueuePos(queuePos)
queueView.reloadData()
updateAlbumArt()
}
func updateAlbumArt() {
if let playingSong = dataSource.queue.first(where: { $0.isPlaying }) {
} else {
queueAlbumArtImage.image = NSImage.defaultCoverArt
}
}
func outlineView(
@ -76,12 +85,12 @@ class QueueViewController: NSViewController,
}
func outlineView(_ outlineView: NSOutlineView, viewFor tableColumn: NSTableColumn?, item: Any) -> NSView? {
if let songItem = item as? SongItem {
if let queueItem = item as? QueueItem {
switch tableColumn?.identifier.rawValue {
case "songTitleColumn":
return cellForSongTitle(outlineView, with: songItem)
return cellForSongTitle(outlineView, with: queueItem)
case "songArtistColumn":
return cellForSongArtist(outlineView, with: songItem)
return cellForSongArtist(outlineView, with: queueItem)
default:
return nil
}
@ -92,14 +101,14 @@ class QueueViewController: NSViewController,
}
}
func cellForSongTitle(_ outlineView: NSOutlineView, with songItem: SongItem) -> NSView {
func cellForSongTitle(_ outlineView: NSOutlineView, with queueItem: QueueItem) -> NSView {
let cellView = outlineView.makeView(
withIdentifier: .queueSongTitle,
owner: self
) as! NSTableCellView
cellView.textField?.stringValue = songItem.song.getTag(.title)
if songItem.isPlaying {
cellView.textField?.stringValue = queueItem.song.title
if queueItem.isPlaying {
cellView.textField?.font = .systemFontBold
cellView.imageView?.image = dataSource.queueIcon
} else {
@ -110,14 +119,14 @@ class QueueViewController: NSViewController,
return cellView
}
func cellForSongArtist(_ outlineView: NSOutlineView, with songItem: SongItem) -> NSView {
func cellForSongArtist(_ outlineView: NSOutlineView, with queueItem: QueueItem) -> NSView {
let cellView = outlineView.makeView(
withIdentifier: .queueSongArtist,
owner: self
) as! NSTableCellView
cellView.textField?.stringValue = songItem.song.getTag(.artist)
if songItem.isPlaying {
cellView.textField?.stringValue = queueItem.song.artist
if queueItem.isPlaying {
cellView.textField?.font = .systemFontBold
} else {
cellView.textField?.font = .systemFontRegular

View File

@ -13,7 +13,7 @@ class WindowController: NSWindowController {
case prevTrack, playPause, stop, nextTrack
}
var state: MPDClient.Status.State?
var state: MPDClient.MPDStatus.State?
var totalTime: UInt?
var elapsedTimeMs: UInt?
var trackTimer: Timer?
@ -64,7 +64,7 @@ class WindowController: NSWindowController {
}
@objc func stateChanged(_ notification: Notification) {
guard let state = notification.userInfo?[Notification.stateKey] as? MPDClient.Status.State
guard let state = notification.userInfo?[Notification.stateKey] as? MPDClient.MPDStatus.State
else { return }
self.state = state

View File

@ -9,7 +9,7 @@
import Cocoa
class AlbumDataSource: NSObject, NSCollectionViewDataSource {
var albums: [AlbumItem] = []
var albums: [Album] = []
func collectionView(_ collectionView: NSCollectionView, numberOfItemsInSection section: Int) -> Int {
return albums.count
@ -23,11 +23,15 @@ class AlbumDataSource: NSObject, NSCollectionViewDataSource {
albumViewItem.setAlbum(albums[indexPath.item])
if albums[indexPath.item].coverArt == nil {
AlbumArtService(album: albums[indexPath.item]).fetchAlbumArt { image in
self.albums[indexPath.item].coverArt = image
AppDelegate.mpdClient.albumFirstSong(for: albums[indexPath.item].mpdAlbum) {
guard let song = $0 else { return }
AlbumArtService(song: Song(mpdSong: song)).fetchAlbumArt { image in
self.albums[indexPath.item].coverArt = image
DispatchQueue.main.async {
collectionView.reloadItems(at: [indexPath])
DispatchQueue.main.async {
collectionView.reloadItems(at: [indexPath])
}
}
}
}

View File

@ -9,16 +9,21 @@
import Cocoa
class QueueDataSource: NSObject, NSOutlineViewDataSource {
var queue: [SongItem] = []
var queue: [QueueItem] = []
var queuePos: Int = -1
var queueIcon: NSImage? = nil
func updateQueue(_ queue: [MPDClient.Song]) {
func updateQueue(_ queue: [MPDClient.MPDSong]) {
queuePos = -1
self.queue = queue.enumerated().map { index, song in
SongItem(song: song, queuePos: index, isPlaying: index == queuePos)
self.queue = queue.enumerated().map { index, mpdSong in
let song = Song(mpdSong: mpdSong)
return QueueItem(
song: song,
queuePos: index,
isPlaying: index == queuePos
)
}
}
@ -35,7 +40,7 @@ class QueueDataSource: NSObject, NSOutlineViewDataSource {
}
}
func setQueueIcon(_ state: MPDClient.Status.State) {
func setQueueIcon(_ state: MPDClient.MPDStatus.State) {
switch state {
case .playing:
queueIcon = .playIcon

View File

@ -14,28 +14,28 @@ extension MPDClient {
enqueueCommand(command: .fetchAllAlbums)
}
func playAlbum(_ album: Album) {
func playAlbum(_ album: MPDAlbum) {
enqueueCommand(command: .playAlbum, userData: ["album": album])
}
func getAlbumURI(for album: Album, callback: @escaping (String?) -> Void) {
func getAlbumFirstSong(for album: MPDAlbum, callback: @escaping (String?) -> Void) {
enqueueCommand(
command: .getAlbumURI,
command: .getAlbumFirstSong,
priority: .low,
userData: ["album": album, "callback": callback]
)
}
func sendPlayAlbum(_ album: Album) {
var songs: [Song] = []
func sendPlayAlbum(_ album: MPDAlbum) {
var songs: [MPDSong] = []
mpd_run_clear(self.connection)
mpd_search_db_songs(self.connection, true)
mpd_search_add_tag_constraint(self.connection, MPD_OPERATOR_DEFAULT, MPD_TAG_ALBUM, album.title)
mpd_search_add_tag_constraint(self.connection, MPD_OPERATOR_DEFAULT, MPD_TAG_ALBUM_ARTIST, album.artist)
mpd_search_commit(self.connection)
while let mpdSong = mpd_recv_song(self.connection) {
songs.append(Song(mpdSong))
while let song = mpd_recv_song(self.connection) {
songs.append(MPDSong(song))
}
for song in songs {
mpd_run_add(self.connection, song.uri)
@ -44,36 +44,36 @@ extension MPDClient {
}
func allAlbums() {
var albums: [Album] = []
var albums: [MPDAlbum] = []
var artist: String = ""
mpd_search_db_tags(self.connection, MPD_TAG_ALBUM)
mpd_search_add_group_tag(self.connection, MPD_TAG_ALBUM_ARTIST)
mpd_search_commit(self.connection)
while let mpdPair = mpd_recv_pair(self.connection) {
let pair = Pair(mpdPair)
while let pair = mpd_recv_pair(self.connection) {
let pair = MPDPair(pair)
switch pair.name {
case "AlbumArtist":
artist = pair.value
case "Album":
albums.append(Album(title: pair.value, artist: artist))
albums.append(MPDAlbum(title: pair.value, artist: artist))
default:
break
}
mpd_return_pair(self.connection, pair.mpdPair)
mpd_return_pair(self.connection, pair.pair)
}
self.delegate?.didLoadAlbums(mpdClient: self, albums: albums)
}
func albumURI(for album: Album, callback: (String?) -> Void) {
var songURI: String?
func albumFirstSong(for album: MPDAlbum, callback: @escaping (MPDSong?) -> Void) {
guard isConnected else { return }
var firstSong: MPDSong?
mpd_search_db_songs(self.connection, true)
mpd_search_add_tag_constraint(self.connection, MPD_OPERATOR_DEFAULT, MPD_TAG_ALBUM, album.title)
mpd_search_add_tag_constraint(self.connection, MPD_OPERATOR_DEFAULT, MPD_TAG_ALBUM_ARTIST, album.artist)
@ -81,19 +81,14 @@ extension MPDClient {
mpd_search_commit(self.connection)
while let mpdSong = mpd_recv_song(self.connection) {
let song = Song(mpdSong)
while let song = mpd_recv_song(self.connection) {
let song = MPDSong(song)
if songURI == nil {
songURI = song.uriString
if firstSong == nil {
firstSong = song
}
}
callback(
songURI?
.split(separator: "/")
.dropLast()
.joined(separator: "/")
)
callback(firstSong)
}
}

View File

@ -10,7 +10,7 @@ import Foundation
extension MPDClient {
func sendCommand(
command: Command,
command: MPDCommand,
userData: Dictionary<String, Any> = [:]
) {
switch command {
@ -49,18 +49,18 @@ extension MPDClient {
case .fetchAllAlbums:
allAlbums()
case .playAlbum:
guard let album = userData["album"] as? Album else { return }
guard let album = userData["album"] as? MPDAlbum else { return }
sendPlayAlbum(album)
case .getAlbumURI:
guard let album = userData["album"] as? Album,
let callback = userData["callback"] as? (String?) -> Void
case .getAlbumFirstSong:
guard let album = userData["album"] as? MPDAlbum,
let callback = userData["callback"] as? (MPDSong?) -> Void
else { return }
albumURI(for: album, callback: callback)
albumFirstSong(for: album, callback: callback)
}
}
func enqueueCommand(
command: Command,
command: MPDCommand,
priority: BlockOperation.QueuePriority = .normal,
userData: Dictionary<String, Any> = [:]
) {

View File

@ -22,7 +22,7 @@ extension MPDClient {
else { return }
self.connection = connection
self.status = Status(status)
self.status = MPDStatus(status)
self.fetchQueue()
self.fetchAllAlbums()

View File

@ -30,7 +30,7 @@ extension MPDClient {
func handleIdleResult(_ result: mpd_idle) {
isIdle = false
let mpdIdle = Idle(rawValue: result.rawValue)
let mpdIdle = MPDIdle(rawValue: result.rawValue)
if mpdIdle.contains(.database) {
self.fetchAllAlbums()

View File

@ -27,7 +27,7 @@ extension MPDClient {
mpd_send_list_queue_meta(connection)
while let mpdSong = mpd_recv_song(connection) {
let song = Song(mpdSong)
let song = MPDSong(mpdSong)
self.queue.append(song)
}
}

View File

@ -16,6 +16,6 @@ extension MPDClient {
func sendRunStatus() {
guard let status = mpd_run_status(connection) else { return }
self.status = Status(status)
self.status = MPDStatus(status)
}
}

View File

@ -15,8 +15,8 @@ class MPDClient {
var connection: OpaquePointer?
var isConnected: Bool = false
var isIdle: Bool = false
var status: Status?
var queue: [Song] = []
var status: MPDStatus?
var queue: [MPDSong] = []
let commandQueue = OperationQueue()

View File

@ -1,27 +0,0 @@
//
// Idle.swift
// Persephone
//
// Created by Daniel Barber on 2019/3/09.
// Copyright © 2019 Dan Barber. All rights reserved.
//
import Foundation
extension MPDClient {
struct Idle: OptionSet {
let rawValue: UInt32
static let database = Idle(rawValue: 0x1)
static let storedPlaylist = Idle(rawValue: 0x2)
static let queue = Idle(rawValue: 0x4)
static let player = Idle(rawValue: 0x8)
static let mixer = Idle(rawValue: 0x10)
static let output = Idle(rawValue: 0x20)
static let options = Idle(rawValue: 0x40)
static let update = Idle(rawValue: 0x80)
static let sticker = Idle(rawValue: 0x100)
static let subscription = Idle(rawValue: 0x200)
static let message = Idle(rawValue: 0x400)
}
}

View File

@ -9,7 +9,7 @@
import Foundation
extension MPDClient {
struct Album {
struct MPDAlbum {
let title: String
let artist: String
}

View File

@ -9,7 +9,7 @@
import Foundation
extension MPDClient {
enum Command {
enum MPDCommand {
// Transport commands
case prevTrack
case nextTrack
@ -30,6 +30,6 @@ extension MPDClient {
// Album commands
case fetchAllAlbums
case playAlbum
case getAlbumURI
case getAlbumFirstSong
}
}

View File

@ -0,0 +1,27 @@
//
// Idle.swift
// Persephone
//
// Created by Daniel Barber on 2019/3/09.
// Copyright © 2019 Dan Barber. All rights reserved.
//
import Foundation
extension MPDClient {
struct MPDIdle: OptionSet {
let rawValue: UInt32
static let database = MPDIdle(rawValue: 0x1)
static let storedPlaylist = MPDIdle(rawValue: 0x2)
static let queue = MPDIdle(rawValue: 0x4)
static let player = MPDIdle(rawValue: 0x8)
static let mixer = MPDIdle(rawValue: 0x10)
static let output = MPDIdle(rawValue: 0x20)
static let options = MPDIdle(rawValue: 0x40)
static let update = MPDIdle(rawValue: 0x80)
static let sticker = MPDIdle(rawValue: 0x100)
static let subscription = MPDIdle(rawValue: 0x200)
static let message = MPDIdle(rawValue: 0x400)
}
}

View File

@ -0,0 +1,28 @@
//
// Pair.swift
// Persephone
//
// Created by Daniel Barber on 2019/2/09.
// Copyright © 2019 Dan Barber. All rights reserved.
//
import Foundation
import mpdclient
extension MPDClient {
class MPDPair {
let pair: UnsafeMutablePointer<mpd_pair>
init(_ pair: UnsafeMutablePointer<mpd_pair>) {
self.pair = pair
}
var name: String {
get { return String(cString: pair.pointee.name) }
}
var value: String {
get { return String(cString: pair.pointee.value) }
}
}
}

View File

@ -10,8 +10,8 @@ import Foundation
import mpdclient
extension MPDClient {
class Song {
let mpdSong: OpaquePointer
class MPDSong {
let song: OpaquePointer
enum TagType: Int {
case unknown = -1
@ -33,26 +33,33 @@ extension MPDClient {
case tagCount
}
init(_ mpdSong: OpaquePointer) {
self.mpdSong = mpdSong
init(_ song: OpaquePointer) {
self.song = song
}
deinit {
mpd_song_free(mpdSong)
mpd_song_free(song)
}
var uri: UnsafePointer<Int8> {
return mpd_song_get_uri(mpdSong)
return mpd_song_get_uri(song)
}
var uriString: String {
return String(cString: uri)
}
var album: MPDAlbum {
return MPDAlbum(
title: getTag(.album),
artist: getTag(.albumArtist)
)
}
func getTag(_ tagType: TagType) -> String {
let mpdTagType = mpd_tag_type(rawValue: Int32(tagType.rawValue))
guard let tag = mpd_song_get_tag(mpdSong, mpdTagType, 0)
guard let tag = mpd_song_get_tag(song, mpdTagType, 0)
else { return "" }
return String(cString: tag)

View File

@ -10,8 +10,8 @@ import Foundation
import mpdclient
extension MPDClient {
class Status {
private let mpdStatus: OpaquePointer
class MPDStatus {
private let status: OpaquePointer
enum State: UInt {
case unknown = 0
@ -20,38 +20,38 @@ extension MPDClient {
case paused = 3
}
init(_ mpdStatus: OpaquePointer) {
self.mpdStatus = mpdStatus
init(_ status: OpaquePointer) {
self.status = status
}
deinit {
mpd_status_free(mpdStatus)
mpd_status_free(status)
}
var state: State {
let mpdState = mpd_status_get_state(mpdStatus)
let mpdState = mpd_status_get_state(status)
return State(rawValue: UInt(mpdState.rawValue))!
}
var totalTime: UInt {
let mpdTotalTime = mpd_status_get_total_time(mpdStatus)
let mpdTotalTime = mpd_status_get_total_time(status)
return UInt(mpdTotalTime)
}
var elapsedTimeMs: UInt {
let mpdElapsedTimeMs = mpd_status_get_elapsed_ms(mpdStatus)
let mpdElapsedTimeMs = mpd_status_get_elapsed_ms(status)
return UInt(mpdElapsedTimeMs)
}
var song: Int {
return Int(mpd_status_get_song_pos(mpdStatus))
return Int(mpd_status_get_song_pos(status))
}
var updating: Bool {
let updating = mpd_status_get_update_id(mpdStatus)
let updating = mpd_status_get_update_id(status)
return updating > 0
}

View File

@ -1,26 +0,0 @@
//
// Pair.swift
// Persephone
//
// Created by Daniel Barber on 2019/2/09.
// Copyright © 2019 Dan Barber. All rights reserved.
//
import Foundation
import mpdclient
class Pair {
let mpdPair: UnsafeMutablePointer<mpd_pair>
init(_ mpdPair: UnsafeMutablePointer<mpd_pair>) {
self.mpdPair = mpdPair
}
var name: String {
get { return String(cString: mpdPair.pointee.name) }
}
var value: String {
get { return String(cString: mpdPair.pointee.value) }
}
}

View File

@ -12,14 +12,14 @@ protocol MPDClientDelegate {
func didConnect(mpdClient: MPDClient)
func willDisconnect(mpdClient: MPDClient)
func didUpdateState(mpdClient: MPDClient, state: MPDClient.Status.State)
func didUpdateState(mpdClient: MPDClient, state: MPDClient.MPDStatus.State)
func didUpdateTime(mpdClient: MPDClient, total: UInt, elapsedMs: UInt)
func willStartDatabaseUpdate(mpdClient: MPDClient)
func didFinishDatabaseUpdate(mpdClient: MPDClient)
func didUpdateQueue(mpdClient: MPDClient, queue: [MPDClient.Song])
func didUpdateQueue(mpdClient: MPDClient, queue: [MPDClient.MPDSong])
func didUpdateQueuePos(mpdClient: MPDClient, song: Int)
func didLoadAlbums(mpdClient: MPDClient, albums: [MPDClient.Album])
func didLoadAlbums(mpdClient: MPDClient, albums: [MPDClient.MPDAlbum])
}

View File

@ -8,16 +8,16 @@
import Cocoa
struct AlbumItem {
var album: MPDClient.Album
struct Album {
var mpdAlbum: MPDClient.MPDAlbum
var coverArt: NSImage?
var title: String {
return album.title
return mpdAlbum.title
}
var artist: String {
return album.artist
return mpdAlbum.artist
}
var hash: String {

View File

@ -8,8 +8,8 @@
import Foundation
struct SongItem {
var song: MPDClient.Song
struct QueueItem {
var song: Song
var queuePos: Int
var isPlaying: Bool
}

View File

@ -0,0 +1,25 @@
//
// SongItem.swift
// Persephone
//
// Created by Daniel Barber on 2019/3/25.
// Copyright © 2019 Dan Barber. All rights reserved.
//
import Foundation
struct Song {
var mpdSong: MPDClient.MPDSong
var title: String {
return mpdSong.getTag(.title)
}
var artist: String {
return mpdSong.getTag(.artist)
}
var album: Album {
return Album(mpdAlbum: mpdSong.album, coverArt: nil)
}
}

View File

@ -349,13 +349,13 @@
</button>
</subviews>
<constraints>
<constraint firstItem="zZn-Rm-e1f" firstAttribute="leading" secondItem="PyK-v2-kus" secondAttribute="leading" constant="55" id="F9T-mO-lMa"/>
<constraint firstItem="gDk-ca-eOa" firstAttribute="top" secondItem="PyK-v2-kus" secondAttribute="top" constant="20" symbolic="YES" id="NSz-Xf-KZS"/>
<constraint firstAttribute="trailing" secondItem="gDk-ca-eOa" secondAttribute="trailing" constant="74" id="QMb-TP-IdQ"/>
<constraint firstItem="pRL-MG-1Be" firstAttribute="top" secondItem="gDk-ca-eOa" secondAttribute="bottom" constant="15" id="bD6-hA-Wz5"/>
<constraint firstItem="gDk-ca-eOa" firstAttribute="leading" secondItem="zZn-Rm-e1f" secondAttribute="trailing" constant="7" id="oZ5-45-Pe5"/>
<constraint firstItem="gDk-ca-eOa" firstAttribute="leading" secondItem="pRL-MG-1Be" secondAttribute="leading" id="sBG-Yb-ii6"/>
<constraint firstItem="zZn-Rm-e1f" firstAttribute="top" secondItem="PyK-v2-kus" secondAttribute="top" constant="21" id="wHW-jd-TaG"/>
<constraint firstItem="gDk-ca-eOa" firstAttribute="leading" secondItem="pRL-MG-1Be" secondAttribute="leading" id="1jd-wZ-a4Q"/>
<constraint firstItem="gDk-ca-eOa" firstAttribute="leading" secondItem="zZn-Rm-e1f" secondAttribute="trailing" constant="7" id="C0m-yx-gXh"/>
<constraint firstItem="gDk-ca-eOa" firstAttribute="top" secondItem="PyK-v2-kus" secondAttribute="top" constant="20" symbolic="YES" id="HZD-uf-Mhl"/>
<constraint firstItem="zZn-Rm-e1f" firstAttribute="leading" secondItem="PyK-v2-kus" secondAttribute="leading" constant="55" id="OzK-MR-zuB"/>
<constraint firstItem="zZn-Rm-e1f" firstAttribute="top" secondItem="PyK-v2-kus" secondAttribute="top" constant="21" id="RpF-wL-4nE"/>
<constraint firstItem="pRL-MG-1Be" firstAttribute="top" secondItem="gDk-ca-eOa" secondAttribute="bottom" constant="15" id="dKy-uC-r43"/>
<constraint firstAttribute="trailing" secondItem="gDk-ca-eOa" secondAttribute="trailing" constant="74" id="n8X-T2-tXA"/>
</constraints>
</view>
<connections>
@ -389,7 +389,7 @@
<textField verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="IbX-oV-soD">
<rect key="frame" x="162" y="26" width="80" height="22"/>
<constraints>
<constraint firstAttribute="width" constant="80" id="WAb-PB-Z1Y"/>
<constraint firstAttribute="width" constant="80" id="vW2-G6-2vi"/>
</constraints>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" placeholderString="6600" drawsBackground="YES" id="i9j-nB-bqq">
<numberFormatter key="formatter" formatterBehavior="custom10_4" numberStyle="decimal" usesGroupingSeparator="NO" minimumIntegerDigits="1" maximumIntegerDigits="2000000000" maximumFractionDigits="3" id="UiQ-gi-Hbp">
@ -406,17 +406,17 @@
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="kvB-99-zwY">
<rect key="frame" x="76" y="62" width="80" height="17"/>
<constraints>
<constraint firstAttribute="width" constant="76" id="4VR-n5-bGr"/>
</constraints>
<textFieldCell key="cell" lineBreakMode="clipping" alignment="right" title="Server Host:" id="AVi-g9-Irz">
<font key="font" metaFont="system"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" misplaced="YES" translatesAutoresizingMaskIntoConstraints="NO" id="AU9-wN-kbU">
<rect key="frame" x="77" y="30" width="77" height="17"/>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="AU9-wN-kbU">
<rect key="frame" x="78" y="30" width="76" height="17"/>
<constraints>
<constraint firstAttribute="width" constant="72" id="Of6-Ls-knP"/>
</constraints>
<textFieldCell key="cell" lineBreakMode="clipping" alignment="right" title="Server Port:" id="DgA-xT-2ir">
<font key="font" metaFont="system"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
@ -425,16 +425,15 @@
</textField>
</subviews>
<constraints>
<constraint firstItem="wPm-sJ-e9E" firstAttribute="top" secondItem="Uwt-Lw-ILP" secondAttribute="top" constant="20" symbolic="YES" id="1u9-dh-XrA"/>
<constraint firstItem="wPm-sJ-e9E" firstAttribute="leading" secondItem="kvB-99-zwY" secondAttribute="trailing" constant="8" symbolic="YES" id="655-3c-mJH"/>
<constraint firstItem="AU9-wN-kbU" firstAttribute="top" secondItem="kvB-99-zwY" secondAttribute="bottom" constant="15" id="FPR-mZ-SUo"/>
<constraint firstItem="IbX-oV-soD" firstAttribute="top" secondItem="wPm-sJ-e9E" secondAttribute="bottom" constant="10" symbolic="YES" id="G7a-VX-OLJ"/>
<constraint firstItem="kvB-99-zwY" firstAttribute="top" secondItem="Uwt-Lw-ILP" secondAttribute="top" constant="21" id="ITg-Ag-wpl"/>
<constraint firstItem="kvB-99-zwY" firstAttribute="leading" secondItem="Uwt-Lw-ILP" secondAttribute="leading" constant="78" id="Kw0-2i-oST"/>
<constraint firstItem="IbX-oV-soD" firstAttribute="leading" secondItem="AU9-wN-kbU" secondAttribute="trailing" constant="10" id="Y6y-25-qRM"/>
<constraint firstAttribute="trailing" secondItem="wPm-sJ-e9E" secondAttribute="trailing" constant="74" id="cX3-Sz-RXR"/>
<constraint firstItem="kvB-99-zwY" firstAttribute="centerX" secondItem="AU9-wN-kbU" secondAttribute="centerX" id="fdg-fL-UzL"/>
<constraint firstItem="wPm-sJ-e9E" firstAttribute="leading" secondItem="IbX-oV-soD" secondAttribute="leading" id="qBw-Ri-Z4l"/>
<constraint firstItem="kvB-99-zwY" firstAttribute="centerX" secondItem="AU9-wN-kbU" secondAttribute="centerX" id="6bm-yZ-rJu"/>
<constraint firstItem="AU9-wN-kbU" firstAttribute="top" secondItem="kvB-99-zwY" secondAttribute="bottom" constant="15" id="6qh-zn-2xt"/>
<constraint firstItem="kvB-99-zwY" firstAttribute="top" secondItem="Uwt-Lw-ILP" secondAttribute="top" constant="21" id="AyL-F9-VTD"/>
<constraint firstAttribute="trailing" secondItem="wPm-sJ-e9E" secondAttribute="trailing" constant="74" id="B0v-nc-2aA"/>
<constraint firstItem="wPm-sJ-e9E" firstAttribute="top" secondItem="Uwt-Lw-ILP" secondAttribute="top" constant="20" symbolic="YES" id="F0N-Yn-jbd"/>
<constraint firstItem="kvB-99-zwY" firstAttribute="leading" secondItem="Uwt-Lw-ILP" secondAttribute="leading" constant="78" id="Hvc-Wt-Uha"/>
<constraint firstItem="wPm-sJ-e9E" firstAttribute="leading" secondItem="kvB-99-zwY" secondAttribute="trailing" constant="8" symbolic="YES" id="NAc-1j-JEH"/>
<constraint firstItem="IbX-oV-soD" firstAttribute="top" secondItem="wPm-sJ-e9E" secondAttribute="bottom" constant="10" symbolic="YES" id="gT9-JL-dW0"/>
<constraint firstItem="wPm-sJ-e9E" firstAttribute="leading" secondItem="IbX-oV-soD" secondAttribute="leading" id="lz4-7S-QQb"/>
</constraints>
</view>
<connections>
@ -450,18 +449,19 @@
<scene sceneID="QcX-dC-cTZ">
<objects>
<viewController id="KIP-rq-4dM" customClass="QueueViewController" customModule="Persephone" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" id="2su-YT-hba">
<rect key="frame" x="0.0" y="0.0" width="350" height="300"/>
<autoresizingMask key="autoresizingMask"/>
<splitView key="view" wantsLayer="YES" dividerStyle="thin" id="84I-w3-Mxl">
<rect key="frame" x="0.0" y="0.0" width="328" height="548"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<subviews>
<scrollView borderType="none" autohidesScrollers="YES" horizontalLineScroll="19" horizontalPageScroll="10" verticalLineScroll="19" verticalPageScroll="10" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="S3o-nF-NN7">
<rect key="frame" x="0.0" y="0.0" width="350" height="300"/>
<scrollView borderType="none" autohidesScrollers="YES" horizontalLineScroll="19" horizontalPageScroll="10" verticalLineScroll="19" verticalPageScroll="10" usesPredominantAxisScrolling="NO" id="S3o-nF-NN7">
<rect key="frame" x="0.0" y="0.0" width="328" height="219"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<clipView key="contentView" drawsBackground="NO" id="WI8-Pw-03L">
<rect key="frame" x="0.0" y="0.0" width="350" height="300"/>
<rect key="frame" x="0.0" y="0.0" width="328" height="219"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<outlineView verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="lastColumnOnly" selectionHighlightStyle="sourceList" multipleSelection="NO" autosaveColumns="NO" rowSizeStyle="automatic" viewBased="YES" indentationPerLevel="16" outlineTableColumn="0Co-uF-CCB" id="jEJ-jg-fll">
<rect key="frame" x="0.0" y="0.0" width="350" height="300"/>
<rect key="frame" x="0.0" y="0.0" width="328" height="219"/>
<autoresizingMask key="autoresizingMask"/>
<size key="intercellSpacing" width="3" height="2"/>
<color key="backgroundColor" name="_sourceListBackgroundColor" catalog="System" colorSpace="catalog"/>
@ -484,9 +484,11 @@
<rect key="frame" x="1" y="1" width="200" height="17"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<textField verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="xgd-Cz-np3">
<rect key="frame" x="0.0" y="1" width="447" height="14"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textField verticalHuggingPriority="750" misplaced="YES" translatesAutoresizingMaskIntoConstraints="NO" id="xgd-Cz-np3">
<rect key="frame" x="0.0" y="1" width="329" height="14"/>
<constraints>
<constraint firstAttribute="width" constant="443" id="mkA-ng-q8a"/>
</constraints>
<textFieldCell key="cell" lineBreakMode="truncatingTail" sendsActionOnEndEditing="YES" title="QUEUE" id="Mqf-uh-ibl">
<font key="font" metaFont="smallSystemBold"/>
<color key="textColor" name="controlAccentColor" catalog="System" colorSpace="catalog"/>
@ -494,6 +496,10 @@
</textFieldCell>
</textField>
</subviews>
<constraints>
<constraint firstItem="xgd-Cz-np3" firstAttribute="leading" secondItem="GOd-cg-juD" secondAttribute="leading" constant="2" id="iOU-E2-K47"/>
<constraint firstItem="xgd-Cz-np3" firstAttribute="centerY" secondItem="GOd-cg-juD" secondAttribute="centerY" id="uxd-zs-s33"/>
</constraints>
</tableCellView>
<tableCellView identifier="songTitleCell" id="5rR-Gz-AcP">
<rect key="frame" x="1" y="20" width="200" height="17"/>
@ -502,7 +508,7 @@
<imageView translatesAutoresizingMaskIntoConstraints="NO" id="o8i-cz-hIP">
<rect key="frame" x="3" y="0.0" width="17" height="17"/>
<constraints>
<constraint firstAttribute="width" constant="17" id="UFf-Fg-9Qg"/>
<constraint firstAttribute="width" constant="17" id="v6R-Dd-a1y"/>
</constraints>
<imageCell key="cell" refusesFirstResponder="YES" imageScaling="proportionallyDown" id="ckK-gW-Vhx"/>
</imageView>
@ -516,12 +522,12 @@
</textField>
</subviews>
<constraints>
<constraint firstAttribute="trailing" secondItem="i0h-bn-auJ" secondAttribute="trailing" constant="2" id="0bp-mw-2mz"/>
<constraint firstItem="i0h-bn-auJ" firstAttribute="leading" secondItem="o8i-cz-hIP" secondAttribute="trailing" constant="7" id="GUh-cd-QQx"/>
<constraint firstItem="o8i-cz-hIP" firstAttribute="centerY" secondItem="5rR-Gz-AcP" secondAttribute="centerY" id="QT8-Zj-AGK"/>
<constraint firstItem="o8i-cz-hIP" firstAttribute="leading" secondItem="5rR-Gz-AcP" secondAttribute="leading" constant="3" id="VCd-sT-dmS"/>
<constraint firstItem="o8i-cz-hIP" firstAttribute="bottom" secondItem="i0h-bn-auJ" secondAttribute="bottom" id="ud8-g2-OYn"/>
<constraint firstItem="o8i-cz-hIP" firstAttribute="top" secondItem="i0h-bn-auJ" secondAttribute="top" id="yN0-Pp-adE"/>
<constraint firstItem="o8i-cz-hIP" firstAttribute="bottom" secondItem="i0h-bn-auJ" secondAttribute="bottom" id="3PU-pE-aEs"/>
<constraint firstItem="o8i-cz-hIP" firstAttribute="leading" secondItem="5rR-Gz-AcP" secondAttribute="leading" constant="3" id="6gY-cP-87e"/>
<constraint firstItem="o8i-cz-hIP" firstAttribute="top" secondItem="i0h-bn-auJ" secondAttribute="top" id="Aju-r7-8gb"/>
<constraint firstItem="o8i-cz-hIP" firstAttribute="centerY" secondItem="5rR-Gz-AcP" secondAttribute="centerY" id="POX-ni-OdT"/>
<constraint firstItem="i0h-bn-auJ" firstAttribute="leading" secondItem="o8i-cz-hIP" secondAttribute="trailing" constant="7" id="QIl-PH-2Ox"/>
<constraint firstAttribute="trailing" secondItem="i0h-bn-auJ" secondAttribute="trailing" constant="2" id="S2f-3u-olm"/>
</constraints>
<connections>
<outlet property="imageView" destination="o8i-cz-hIP" id="4In-Lr-QcL"/>
@ -530,7 +536,7 @@
</tableCellView>
</prototypeCellViews>
</tableColumn>
<tableColumn identifier="songArtistColumn" width="144" minWidth="64" maxWidth="1000" id="SPM-QP-DX8">
<tableColumn identifier="songArtistColumn" width="122" minWidth="64" maxWidth="1000" id="SPM-QP-DX8">
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" alignment="left" title="Artist">
<font key="font" metaFont="smallSystem"/>
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
@ -544,11 +550,11 @@
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES"/>
<prototypeCellViews>
<tableCellView identifier="songArtistCell" id="JSk-Vc-Y7e">
<rect key="frame" x="204" y="1" width="144" height="17"/>
<rect key="frame" x="204" y="1" width="122" height="17"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="tBe-Q9-3Rw">
<rect key="frame" x="0.0" y="0.0" width="149" height="17"/>
<rect key="frame" x="0.0" y="0.0" width="127" height="17"/>
<textFieldCell key="cell" lineBreakMode="truncatingTail" sendsActionOnEndEditing="YES" title="Table View Cell" id="Ceb-ec-ydU">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
@ -557,9 +563,9 @@
</textField>
</subviews>
<constraints>
<constraint firstItem="tBe-Q9-3Rw" firstAttribute="centerY" secondItem="JSk-Vc-Y7e" secondAttribute="centerY" id="Tkg-cb-Bg6"/>
<constraint firstAttribute="trailing" secondItem="tBe-Q9-3Rw" secondAttribute="trailing" constant="-3" id="VhZ-ua-QQX"/>
<constraint firstItem="tBe-Q9-3Rw" firstAttribute="leading" secondItem="JSk-Vc-Y7e" secondAttribute="leading" constant="2" id="cTy-tR-Grg"/>
<constraint firstAttribute="trailing" secondItem="tBe-Q9-3Rw" secondAttribute="trailing" constant="-3" id="E6a-sY-dne"/>
<constraint firstItem="tBe-Q9-3Rw" firstAttribute="leading" secondItem="JSk-Vc-Y7e" secondAttribute="leading" constant="2" id="Gm4-l1-WRz"/>
<constraint firstItem="tBe-Q9-3Rw" firstAttribute="centerY" secondItem="JSk-Vc-Y7e" secondAttribute="centerY" id="KhJ-nn-rh5"/>
</constraints>
<connections>
<outlet property="textField" destination="tBe-Q9-3Rw" id="2e6-zi-tKj"/>
@ -577,11 +583,11 @@
<nil key="backgroundColor"/>
</clipView>
<constraints>
<constraint firstAttribute="width" relation="lessThanOrEqual" constant="500" id="tgW-46-U0V"/>
<constraint firstAttribute="width" relation="greaterThanOrEqual" constant="200" id="ynf-58-b0B"/>
<constraint firstAttribute="width" relation="greaterThanOrEqual" constant="200" id="Kqx-7n-cws"/>
<constraint firstAttribute="width" relation="lessThanOrEqual" constant="500" id="zuT-k9-w8d"/>
</constraints>
<scroller key="horizontalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" horizontal="YES" id="7mx-v9-DSr">
<rect key="frame" x="0.0" y="284" width="350" height="16"/>
<rect key="frame" x="0.0" y="237" width="328" height="16"/>
<autoresizingMask key="autoresizingMask"/>
</scroller>
<scroller key="verticalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" horizontal="NO" id="p5z-C0-FUJ">
@ -589,21 +595,40 @@
<autoresizingMask key="autoresizingMask"/>
</scroller>
</scrollView>
<customView id="iUb-eV-Qws">
<rect key="frame" x="0.0" y="220" width="328" height="328"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<subviews>
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="Dw3-M5-tWY">
<rect key="frame" x="0.0" y="0.0" width="328" height="328"/>
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyUpOrDown" image="blankAlbum" id="IoN-3N-TCb"/>
</imageView>
</subviews>
<constraints>
<constraint firstItem="Dw3-M5-tWY" firstAttribute="leading" secondItem="iUb-eV-Qws" secondAttribute="leading" id="ERf-Kd-Q7L"/>
<constraint firstAttribute="bottom" secondItem="Dw3-M5-tWY" secondAttribute="bottom" id="GGz-uh-bzq"/>
<constraint firstAttribute="trailing" secondItem="Dw3-M5-tWY" secondAttribute="trailing" id="c91-AQ-BT2"/>
<constraint firstAttribute="width" secondItem="iUb-eV-Qws" secondAttribute="height" multiplier="1:1" id="f4L-V4-5x2"/>
<constraint firstItem="Dw3-M5-tWY" firstAttribute="top" secondItem="iUb-eV-Qws" secondAttribute="top" id="ue4-Gb-CaX"/>
</constraints>
<shadow key="shadow">
<color key="color" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</shadow>
</customView>
</subviews>
<constraints>
<constraint firstItem="S3o-nF-NN7" firstAttribute="leading" secondItem="2su-YT-hba" secondAttribute="leading" id="B7i-Su-Rgr"/>
<constraint firstItem="S3o-nF-NN7" firstAttribute="top" secondItem="2su-YT-hba" secondAttribute="top" id="EZN-ac-0xk"/>
<constraint firstAttribute="bottom" secondItem="S3o-nF-NN7" secondAttribute="bottom" id="OTS-yj-4am"/>
<constraint firstAttribute="trailing" secondItem="S3o-nF-NN7" secondAttribute="trailing" id="Yis-ZS-y2w"/>
</constraints>
</view>
<holdingPriorities>
<real value="250"/>
<real value="250"/>
</holdingPriorities>
</splitView>
<connections>
<outlet property="queueAlbumArtImage" destination="Dw3-M5-tWY" id="3hQ-Gu-XqM"/>
<outlet property="queueView" destination="jEJ-jg-fll" id="cwo-E8-deo"/>
</connections>
</viewController>
<customObject id="du4-e9-TfX" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="834" y="679"/>
<point key="canvasLocation" x="820" y="749"/>
</scene>
<!--Album View Controller-->
<scene sceneID="7Ua-Hj-zWt">
@ -654,11 +679,12 @@
</viewController>
<customObject id="uex-Ws-5X4" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="744" y="1077"/>
<point key="canvasLocation" x="531" y="1358"/>
</scene>
</scenes>
<resources>
<image name="NSPreferencesGeneral" width="32" height="32"/>
<image name="blankAlbum" width="128" height="128"/>
<image name="coverArtPreferencesIcon" width="32" height="32"/>
<image name="nextTrackButton" width="17" height="17"/>
<image name="playButton" width="17" height="17"/>

View File

@ -11,7 +11,8 @@ import PromiseKit
class AlbumArtService {
var preferences = Preferences()
let album: AlbumItem
let song: Song
let album: Album
let cachedArtworkSize = 180
let cachedArtworkQuality: CGFloat = 0.5
@ -19,8 +20,9 @@ class AlbumArtService {
var session = URLSession(configuration: .default)
let cacheQueue = DispatchQueue(label: "albumArtCacheQueue")
init(album: AlbumItem) {
self.album = album
init(song: Song) {
self.song = song
self.album = song.album
}
func fetchAlbumArt(callback: @escaping (_ image: NSImage?) -> Void) {

View File

@ -30,6 +30,8 @@ extension AlbumArtService {
let cacheFilePath = cacheDir.appendingPathComponent(album.hash).path
FileManager.default.createFile(atPath: cacheFilePath, contents: data, attributes: nil)
if !FileManager.default.fileExists(atPath: cacheFilePath) {
FileManager.default.createFile(atPath: cacheFilePath, contents: data, attributes: nil)
}
}
}

View File

@ -17,22 +17,26 @@ extension AlbumArtService {
"\(album.artist) - \(album.title).jpg"
]
return getAlbumURI().map { albumURI in
let musicDir = self.preferences.expandedMpdLibraryDir
let musicDir = self.preferences.expandedMpdLibraryDir
let songPath = self.songPath()
return coverArtFilenames
return Promise { seal in
let image = coverArtFilenames
.lazy
.map { "\(musicDir)/\(albumURI)/\($0)" }
.map { "\(musicDir)/\(songPath)/\($0)" }
.compactMap(self.tryImage)
.first
seal.fulfill(image)
}
}
func getAlbumURI() -> Promise<String> {
return Promise { seal in
AppDelegate.mpdClient.getAlbumURI(for: album.album, callback: seal.fulfill)
}
.compactMap { $0 }
func songPath() -> String {
return song.mpdSong
.uriString
.split(separator: "/")
.dropLast()
.joined(separator: "/")
}
func tryImage(_ filePath: String) -> NSImage? {
@ -40,10 +44,6 @@ extension AlbumArtService {
let image = NSImage(data: data)
else { return nil }
let imageThumb = image.toFitBox(
size: NSSize(width: self.cachedArtworkSize, height: self.cachedArtworkSize)
)
return imageThumb
return image
}
}