From 27c0e32e48070dc85cbb8feb20276e51015cfc9e Mon Sep 17 00:00:00 2001 From: Dan Barber Date: Mon, 25 Mar 2019 21:15:49 -0400 Subject: [PATCH] WIP: Refactor album art service We need to make it more flexible and less coupled --- Persephone.xcodeproj/project.pbxproj | 70 +++++---- .../blankAlbum.imageset/Contents.json | 3 +- .../Controllers/AlbumViewController.swift | 4 +- Persephone/Controllers/AlbumViewItem.swift | 6 +- .../Controllers/NotificationsController.swift | 6 +- .../Controllers/QueueViewController.swift | 33 ++-- Persephone/Controllers/WindowController.swift | 4 +- Persephone/DataSources/AlbumDataSource.swift | 14 +- Persephone/DataSources/QueueDataSource.swift | 15 +- .../Extensions/MPDClient+Album.swift | 45 +++--- .../Extensions/MPDClient+Command.swift | 14 +- .../Extensions/MPDClient+Connection.swift | 2 +- .../MPDClient/Extensions/MPDClient+Idle.swift | 2 +- .../Extensions/MPDClient+Queue.swift | 2 +- .../Extensions/MPDClient+Status.swift | 2 +- Persephone/MPDClient/MPDClient.swift | 4 +- Persephone/MPDClient/Models/Idle.swift | 27 ---- .../Models/{Album.swift => MPDAlbum.swift} | 2 +- .../{Command.swift => MPDCommand.swift} | 4 +- Persephone/MPDClient/Models/MPDIdle.swift | 27 ++++ Persephone/MPDClient/Models/MPDPair.swift | 28 ++++ .../Models/{Song.swift => MPDSong.swift} | 21 ++- .../Models/{Status.swift => MPDStatus.swift} | 20 +-- Persephone/MPDClient/Models/Pair.swift | 26 ---- Persephone/MPDClient/Protocols/Delegate.swift | 6 +- .../Models/{AlbumItem.swift => Album.swift} | 8 +- .../{SongItem.swift => QueueItem.swift} | 4 +- Persephone/Models/Song.swift | 25 +++ .../Resources/Base.lproj/Main.storyboard | 142 +++++++++++------- Persephone/Services/AlbumArtService.swift | 8 +- .../Extensions/AlbumArtService+Caching.swift | 4 +- .../AlbumArtService+Filesystem.swift | 28 ++-- 32 files changed, 344 insertions(+), 262 deletions(-) delete mode 100644 Persephone/MPDClient/Models/Idle.swift rename Persephone/MPDClient/Models/{Album.swift => MPDAlbum.swift} (92%) rename Persephone/MPDClient/Models/{Command.swift => MPDCommand.swift} (91%) create mode 100644 Persephone/MPDClient/Models/MPDIdle.swift create mode 100644 Persephone/MPDClient/Models/MPDPair.swift rename Persephone/MPDClient/Models/{Song.swift => MPDSong.swift} (73%) rename Persephone/MPDClient/Models/{Status.swift => MPDStatus.swift} (59%) delete mode 100644 Persephone/MPDClient/Models/Pair.swift rename Persephone/Models/{AlbumItem.swift => Album.swift} (74%) rename Persephone/Models/{SongItem.swift => QueueItem.swift} (82%) create mode 100644 Persephone/Models/Song.swift diff --git a/Persephone.xcodeproj/project.pbxproj b/Persephone.xcodeproj/project.pbxproj index 1cbb508..5721535 100644 --- a/Persephone.xcodeproj/project.pbxproj +++ b/Persephone.xcodeproj/project.pbxproj @@ -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 = ""; }; E40F41F2221EDE27004B6CB8 /* Preferences.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Preferences.swift; sourceTree = ""; }; E40FE71A221B904300A4223F /* NSEvent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSEvent.swift; sourceTree = ""; }; + E419E2862249B96600216A8C /* Song.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Song.swift; sourceTree = ""; }; E41B22BF21FB6BBA00D544F6 /* libmpdclient.2.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libmpdclient.2.dylib; path = libmpdclient/output/libmpdclient.2.dylib; sourceTree = ""; }; E41B22C421FB715A00D544F6 /* module.modulemap */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.module-map"; path = module.modulemap; sourceTree = ""; }; E41B22C521FB932700D544F6 /* MPDClient.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MPDClient.swift; sourceTree = ""; }; @@ -201,7 +203,7 @@ E42A8F3A22176D6400A13ED9 /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; E435E3E1221CD4E200184CFC /* NSFont.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSFont.swift; sourceTree = ""; }; E435E3E3221CD75D00184CFC /* NSImage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSImage.swift; sourceTree = ""; }; - E450AD7D222620A10091BED3 /* AlbumItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlbumItem.swift; sourceTree = ""; }; + E450AD7D222620A10091BED3 /* Album.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Album.swift; sourceTree = ""; }; E450AD8522262AE60091BED3 /* SwiftyJSON.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftyJSON.framework; path = Carthage/Build/Mac/SwiftyJSON.framework; sourceTree = ""; }; E450AD8C22262C590091BED3 /* PromiseKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = PromiseKit.framework; path = Carthage/Build/Mac/PromiseKit.framework; sourceTree = ""; }; E450AD8E22262C620091BED3 /* PromiseKit.framework.dSYM */ = {isa = PBXFileReference; lastKnownFileType = wrapper.dsym; name = PromiseKit.framework.dSYM; path = Carthage/Build/Mac/PromiseKit.framework.dSYM; sourceTree = ""; }; @@ -213,7 +215,7 @@ E450AD9E2229B9BC0091BED3 /* PersephoneBridgingHeader.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PersephoneBridgingHeader.h; sourceTree = ""; }; E450AD9F2229E7C90091BED3 /* PMKFoundation.framework.dSYM */ = {isa = PBXFileReference; lastKnownFileType = wrapper.dsym; name = PMKFoundation.framework.dSYM; path = Carthage/Build/Mac/PMKFoundation.framework.dSYM; sourceTree = ""; }; E450ADA02229E7C90091BED3 /* PMKFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = PMKFoundation.framework; path = Carthage/Build/Mac/PMKFoundation.framework; sourceTree = ""; }; - E45962C52241A78500FC1A1E /* Command.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Command.swift; sourceTree = ""; }; + E45962C52241A78500FC1A1E /* MPDCommand.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MPDCommand.swift; sourceTree = ""; }; E465049921E94DF500A70F4C /* WindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WindowController.swift; sourceTree = ""; }; E47E2FCB2220573500F747E6 /* MediaKeyTap.framework.dSYM */ = {isa = PBXFileReference; lastKnownFileType = wrapper.dsym; name = MediaKeyTap.framework.dSYM; path = Carthage/Build/Mac/MediaKeyTap.framework.dSYM; sourceTree = ""; }; E47E2FD022205C4600F747E6 /* MainSplitViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainSplitViewController.swift; sourceTree = ""; }; @@ -223,20 +225,20 @@ E47E2FDC2220A6D100F747E6 /* Time.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Time.swift; sourceTree = ""; }; E47E2FE42220AA0700F747E6 /* AlbumViewLayout.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AlbumViewLayout.swift; sourceTree = ""; }; E4928E0A2218D62A001D4BEA /* CGColor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CGColor.swift; sourceTree = ""; }; - E4A642D922090CBE00067D21 /* Status.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Status.swift; sourceTree = ""; }; + E4A642D922090CBE00067D21 /* MPDStatus.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MPDStatus.swift; sourceTree = ""; }; E4A83BEE2221F8CF0098FED6 /* AlbumArtPrefsController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlbumArtPrefsController.swift; sourceTree = ""; }; E4A83BF02221FAA00098FED6 /* PreferencesViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreferencesViewController.swift; sourceTree = ""; }; E4A83BF3222207D50098FED6 /* AlbumArtService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlbumArtService.swift; sourceTree = ""; }; E4C8B53B22342005009A20F3 /* PreferencesWindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreferencesWindowController.swift; sourceTree = ""; }; - E4C8B53D22349002009A20F3 /* Idle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Idle.swift; sourceTree = ""; }; + E4C8B53D22349002009A20F3 /* MPDIdle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MPDIdle.swift; sourceTree = ""; }; E4E8CC8F2204EC7F0024217A /* Delegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Delegate.swift; sourceTree = ""; }; E4E8CC912204F4B80024217A /* QueueViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QueueViewController.swift; sourceTree = ""; }; E4E8CC932206097F0024217A /* NotificationsController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationsController.swift; sourceTree = ""; }; - E4E8CC9922075D370024217A /* Song.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Song.swift; sourceTree = ""; }; - E4EB2378220F10B8008C70C0 /* Pair.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Pair.swift; sourceTree = ""; }; - E4EB237A220F7CF1008C70C0 /* Album.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Album.swift; sourceTree = ""; }; + E4E8CC9922075D370024217A /* MPDSong.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MPDSong.swift; sourceTree = ""; }; + E4EB2378220F10B8008C70C0 /* MPDPair.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MPDPair.swift; sourceTree = ""; }; + E4EB237A220F7CF1008C70C0 /* MPDAlbum.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MPDAlbum.swift; sourceTree = ""; }; E4F6B45F221E119B00ACF42A /* QueueDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QueueDataSource.swift; sourceTree = ""; }; - E4F6B462221E125900ACF42A /* SongItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SongItem.swift; sourceTree = ""; }; + E4F6B462221E125900ACF42A /* QueueItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QueueItem.swift; sourceTree = ""; }; E4F6B466221E233200ACF42A /* AlbumDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlbumDataSource.swift; sourceTree = ""; }; /* 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 = ""; @@ -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 = ""; @@ -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 */, diff --git a/Persephone/Assets.xcassets/blankAlbum.imageset/Contents.json b/Persephone/Assets.xcassets/blankAlbum.imageset/Contents.json index 2671449..fdcbd1b 100644 --- a/Persephone/Assets.xcassets/blankAlbum.imageset/Contents.json +++ b/Persephone/Assets.xcassets/blankAlbum.imageset/Contents.json @@ -30,6 +30,7 @@ }, "properties" : { "template-rendering-intent" : "original", - "preserves-vector-representation" : true + "preserves-vector-representation" : true, + "auto-scaling" : "auto" } } \ No newline at end of file diff --git a/Persephone/Controllers/AlbumViewController.swift b/Persephone/Controllers/AlbumViewController.swift index 4689233..40c5f10 100644 --- a/Persephone/Controllers/AlbumViewController.swift +++ b/Persephone/Controllers/AlbumViewController.swift @@ -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() } diff --git a/Persephone/Controllers/AlbumViewItem.swift b/Persephone/Controllers/AlbumViewItem.swift index 1c93150..e43aa04 100644 --- a/Persephone/Controllers/AlbumViewItem.swift +++ b/Persephone/Controllers/AlbumViewItem.swift @@ -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! diff --git a/Persephone/Controllers/NotificationsController.swift b/Persephone/Controllers/NotificationsController.swift index 555712f..c82519e 100644 --- a/Persephone/Controllers/NotificationsController.swift +++ b/Persephone/Controllers/NotificationsController.swift @@ -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] diff --git a/Persephone/Controllers/QueueViewController.swift b/Persephone/Controllers/QueueViewController.swift index b8b9d9f..30a6d52 100644 --- a/Persephone/Controllers/QueueViewController.swift +++ b/Persephone/Controllers/QueueViewController.swift @@ -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 diff --git a/Persephone/Controllers/WindowController.swift b/Persephone/Controllers/WindowController.swift index 28028aa..63d347f 100644 --- a/Persephone/Controllers/WindowController.swift +++ b/Persephone/Controllers/WindowController.swift @@ -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 diff --git a/Persephone/DataSources/AlbumDataSource.swift b/Persephone/DataSources/AlbumDataSource.swift index b672275..0d999e3 100644 --- a/Persephone/DataSources/AlbumDataSource.swift +++ b/Persephone/DataSources/AlbumDataSource.swift @@ -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]) + } } } } diff --git a/Persephone/DataSources/QueueDataSource.swift b/Persephone/DataSources/QueueDataSource.swift index d4cb5a4..c4f8011 100644 --- a/Persephone/DataSources/QueueDataSource.swift +++ b/Persephone/DataSources/QueueDataSource.swift @@ -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 diff --git a/Persephone/MPDClient/Extensions/MPDClient+Album.swift b/Persephone/MPDClient/Extensions/MPDClient+Album.swift index 3acf293..657c422 100644 --- a/Persephone/MPDClient/Extensions/MPDClient+Album.swift +++ b/Persephone/MPDClient/Extensions/MPDClient+Album.swift @@ -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) } } diff --git a/Persephone/MPDClient/Extensions/MPDClient+Command.swift b/Persephone/MPDClient/Extensions/MPDClient+Command.swift index aac1940..7fdac49 100644 --- a/Persephone/MPDClient/Extensions/MPDClient+Command.swift +++ b/Persephone/MPDClient/Extensions/MPDClient+Command.swift @@ -10,7 +10,7 @@ import Foundation extension MPDClient { func sendCommand( - command: Command, + command: MPDCommand, userData: Dictionary = [:] ) { 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 = [:] ) { diff --git a/Persephone/MPDClient/Extensions/MPDClient+Connection.swift b/Persephone/MPDClient/Extensions/MPDClient+Connection.swift index d345863..50f4b27 100644 --- a/Persephone/MPDClient/Extensions/MPDClient+Connection.swift +++ b/Persephone/MPDClient/Extensions/MPDClient+Connection.swift @@ -22,7 +22,7 @@ extension MPDClient { else { return } self.connection = connection - self.status = Status(status) + self.status = MPDStatus(status) self.fetchQueue() self.fetchAllAlbums() diff --git a/Persephone/MPDClient/Extensions/MPDClient+Idle.swift b/Persephone/MPDClient/Extensions/MPDClient+Idle.swift index 68de625..8a03739 100644 --- a/Persephone/MPDClient/Extensions/MPDClient+Idle.swift +++ b/Persephone/MPDClient/Extensions/MPDClient+Idle.swift @@ -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() diff --git a/Persephone/MPDClient/Extensions/MPDClient+Queue.swift b/Persephone/MPDClient/Extensions/MPDClient+Queue.swift index c5aee0e..162586b 100644 --- a/Persephone/MPDClient/Extensions/MPDClient+Queue.swift +++ b/Persephone/MPDClient/Extensions/MPDClient+Queue.swift @@ -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) } } diff --git a/Persephone/MPDClient/Extensions/MPDClient+Status.swift b/Persephone/MPDClient/Extensions/MPDClient+Status.swift index be1e7e4..1008e08 100644 --- a/Persephone/MPDClient/Extensions/MPDClient+Status.swift +++ b/Persephone/MPDClient/Extensions/MPDClient+Status.swift @@ -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) } } diff --git a/Persephone/MPDClient/MPDClient.swift b/Persephone/MPDClient/MPDClient.swift index f22f388..f705f24 100644 --- a/Persephone/MPDClient/MPDClient.swift +++ b/Persephone/MPDClient/MPDClient.swift @@ -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() diff --git a/Persephone/MPDClient/Models/Idle.swift b/Persephone/MPDClient/Models/Idle.swift deleted file mode 100644 index 62781db..0000000 --- a/Persephone/MPDClient/Models/Idle.swift +++ /dev/null @@ -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) - } -} diff --git a/Persephone/MPDClient/Models/Album.swift b/Persephone/MPDClient/Models/MPDAlbum.swift similarity index 92% rename from Persephone/MPDClient/Models/Album.swift rename to Persephone/MPDClient/Models/MPDAlbum.swift index 107adf0..2b87039 100644 --- a/Persephone/MPDClient/Models/Album.swift +++ b/Persephone/MPDClient/Models/MPDAlbum.swift @@ -9,7 +9,7 @@ import Foundation extension MPDClient { - struct Album { + struct MPDAlbum { let title: String let artist: String } diff --git a/Persephone/MPDClient/Models/Command.swift b/Persephone/MPDClient/Models/MPDCommand.swift similarity index 91% rename from Persephone/MPDClient/Models/Command.swift rename to Persephone/MPDClient/Models/MPDCommand.swift index a035729..2631a93 100644 --- a/Persephone/MPDClient/Models/Command.swift +++ b/Persephone/MPDClient/Models/MPDCommand.swift @@ -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 } } diff --git a/Persephone/MPDClient/Models/MPDIdle.swift b/Persephone/MPDClient/Models/MPDIdle.swift new file mode 100644 index 0000000..e52dc31 --- /dev/null +++ b/Persephone/MPDClient/Models/MPDIdle.swift @@ -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) + } +} diff --git a/Persephone/MPDClient/Models/MPDPair.swift b/Persephone/MPDClient/Models/MPDPair.swift new file mode 100644 index 0000000..f720d29 --- /dev/null +++ b/Persephone/MPDClient/Models/MPDPair.swift @@ -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 + + init(_ pair: UnsafeMutablePointer) { + self.pair = pair + } + + var name: String { + get { return String(cString: pair.pointee.name) } + } + + var value: String { + get { return String(cString: pair.pointee.value) } + } + } +} diff --git a/Persephone/MPDClient/Models/Song.swift b/Persephone/MPDClient/Models/MPDSong.swift similarity index 73% rename from Persephone/MPDClient/Models/Song.swift rename to Persephone/MPDClient/Models/MPDSong.swift index 0a4cce2..3a7c93b 100644 --- a/Persephone/MPDClient/Models/Song.swift +++ b/Persephone/MPDClient/Models/MPDSong.swift @@ -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 { - 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) diff --git a/Persephone/MPDClient/Models/Status.swift b/Persephone/MPDClient/Models/MPDStatus.swift similarity index 59% rename from Persephone/MPDClient/Models/Status.swift rename to Persephone/MPDClient/Models/MPDStatus.swift index dc0f913..346c8fe 100644 --- a/Persephone/MPDClient/Models/Status.swift +++ b/Persephone/MPDClient/Models/MPDStatus.swift @@ -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 } diff --git a/Persephone/MPDClient/Models/Pair.swift b/Persephone/MPDClient/Models/Pair.swift deleted file mode 100644 index cc60219..0000000 --- a/Persephone/MPDClient/Models/Pair.swift +++ /dev/null @@ -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 - - init(_ mpdPair: UnsafeMutablePointer) { - self.mpdPair = mpdPair - } - - var name: String { - get { return String(cString: mpdPair.pointee.name) } - } - - var value: String { - get { return String(cString: mpdPair.pointee.value) } - } -} diff --git a/Persephone/MPDClient/Protocols/Delegate.swift b/Persephone/MPDClient/Protocols/Delegate.swift index 90282c5..373a7a6 100644 --- a/Persephone/MPDClient/Protocols/Delegate.swift +++ b/Persephone/MPDClient/Protocols/Delegate.swift @@ -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]) } diff --git a/Persephone/Models/AlbumItem.swift b/Persephone/Models/Album.swift similarity index 74% rename from Persephone/Models/AlbumItem.swift rename to Persephone/Models/Album.swift index dcc5043..d180b60 100644 --- a/Persephone/Models/AlbumItem.swift +++ b/Persephone/Models/Album.swift @@ -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 { diff --git a/Persephone/Models/SongItem.swift b/Persephone/Models/QueueItem.swift similarity index 82% rename from Persephone/Models/SongItem.swift rename to Persephone/Models/QueueItem.swift index f9ef949..a7b6932 100644 --- a/Persephone/Models/SongItem.swift +++ b/Persephone/Models/QueueItem.swift @@ -8,8 +8,8 @@ import Foundation -struct SongItem { - var song: MPDClient.Song +struct QueueItem { + var song: Song var queuePos: Int var isPlaying: Bool } diff --git a/Persephone/Models/Song.swift b/Persephone/Models/Song.swift new file mode 100644 index 0000000..9aed5cc --- /dev/null +++ b/Persephone/Models/Song.swift @@ -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) + } +} diff --git a/Persephone/Resources/Base.lproj/Main.storyboard b/Persephone/Resources/Base.lproj/Main.storyboard index eda9de7..0add0f3 100644 --- a/Persephone/Resources/Base.lproj/Main.storyboard +++ b/Persephone/Resources/Base.lproj/Main.storyboard @@ -349,13 +349,13 @@ - - - - - - - + + + + + + + @@ -389,7 +389,7 @@ - + @@ -406,17 +406,17 @@ - - - - - + + + + + @@ -425,16 +425,15 @@ - - - - - - - - - - + + + + + + + + + @@ -450,18 +449,19 @@ - - - + + + - - + + + - + - + @@ -484,9 +484,11 @@ - - - + + + + + @@ -494,6 +496,10 @@ + + + + @@ -502,7 +508,7 @@ - + @@ -516,12 +522,12 @@ - - - - - - + + + + + + @@ -530,7 +536,7 @@ - + @@ -544,11 +550,11 @@ - + - + @@ -557,9 +563,9 @@ - - - + + + @@ -577,11 +583,11 @@ - - + + + + + + + + + + + + + + + + + + + + + + - - - - - - - + + + + + + - + @@ -654,11 +679,12 @@ - + + diff --git a/Persephone/Services/AlbumArtService.swift b/Persephone/Services/AlbumArtService.swift index 510c19b..a3ccdd5 100644 --- a/Persephone/Services/AlbumArtService.swift +++ b/Persephone/Services/AlbumArtService.swift @@ -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) { diff --git a/Persephone/Services/Extensions/AlbumArtService+Caching.swift b/Persephone/Services/Extensions/AlbumArtService+Caching.swift index ae5c839..52dbf22 100644 --- a/Persephone/Services/Extensions/AlbumArtService+Caching.swift +++ b/Persephone/Services/Extensions/AlbumArtService+Caching.swift @@ -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) + } } } diff --git a/Persephone/Services/Extensions/AlbumArtService+Filesystem.swift b/Persephone/Services/Extensions/AlbumArtService+Filesystem.swift index a835f82..1d6faff 100644 --- a/Persephone/Services/Extensions/AlbumArtService+Filesystem.swift +++ b/Persephone/Services/Extensions/AlbumArtService+Filesystem.swift @@ -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 { - 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 } }