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:
parent
a2706f4e0a
commit
27c0e32e48
@ -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 */,
|
||||
|
||||
@ -30,6 +30,7 @@
|
||||
},
|
||||
"properties" : {
|
||||
"template-rendering-intent" : "original",
|
||||
"preserves-vector-representation" : true
|
||||
"preserves-vector-representation" : true,
|
||||
"auto-scaling" : "auto"
|
||||
}
|
||||
}
|
||||
@ -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()
|
||||
}
|
||||
|
||||
|
||||
@ -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!
|
||||
|
||||
@ -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]
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@ -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> = [:]
|
||||
) {
|
||||
|
||||
@ -22,7 +22,7 @@ extension MPDClient {
|
||||
else { return }
|
||||
|
||||
self.connection = connection
|
||||
self.status = Status(status)
|
||||
self.status = MPDStatus(status)
|
||||
|
||||
self.fetchQueue()
|
||||
self.fetchAllAlbums()
|
||||
|
||||
@ -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()
|
||||
|
||||
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@ -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()
|
||||
|
||||
|
||||
@ -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)
|
||||
}
|
||||
}
|
||||
@ -9,7 +9,7 @@
|
||||
import Foundation
|
||||
|
||||
extension MPDClient {
|
||||
struct Album {
|
||||
struct MPDAlbum {
|
||||
let title: String
|
||||
let artist: String
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
27
Persephone/MPDClient/Models/MPDIdle.swift
Normal file
27
Persephone/MPDClient/Models/MPDIdle.swift
Normal 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)
|
||||
}
|
||||
}
|
||||
28
Persephone/MPDClient/Models/MPDPair.swift
Normal file
28
Persephone/MPDClient/Models/MPDPair.swift
Normal 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) }
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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)
|
||||
@ -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
|
||||
}
|
||||
@ -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) }
|
||||
}
|
||||
}
|
||||
@ -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])
|
||||
}
|
||||
|
||||
@ -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 {
|
||||
@ -8,8 +8,8 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
struct SongItem {
|
||||
var song: MPDClient.Song
|
||||
struct QueueItem {
|
||||
var song: Song
|
||||
var queuePos: Int
|
||||
var isPlaying: Bool
|
||||
}
|
||||
25
Persephone/Models/Song.swift
Normal file
25
Persephone/Models/Song.swift
Normal 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)
|
||||
}
|
||||
}
|
||||
@ -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"/>
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user