mirror of
https://github.com/danbee/persephone
synced 2025-03-04 08:39:11 +00:00
Compare commits
No commits in common. "01371db6cbab2cb284d2a254cecbe5232de08d5e" and "812af07c1ace4885d8b1ea9bc9f91bc2dda73b1f" have entirely different histories.
01371db6cb
...
812af07c1a
@ -298,23 +298,23 @@
|
|||||||
E407861A2110CE6E006887B1 /* Persephone */ = {
|
E407861A2110CE6E006887B1 /* Persephone */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
E407861B2110CE6E006887B1 /* AppDelegate.swift */,
|
E450AD9E2229B9BC0091BED3 /* PersephoneBridgingHeader.h */,
|
||||||
E407861F2110CE70006887B1 /* Assets.xcassets */,
|
E450AD8922262B420091BED3 /* Operations */,
|
||||||
E4D1B597220BA3A20026F233 /* Controllers */,
|
E4A83BF2222207BE0098FED6 /* Services */,
|
||||||
E4F6B45E221E117600ACF42A /* DataSources */,
|
E4A83BEC2221F5DD0098FED6 /* Preferences */,
|
||||||
E408D3B7220DE8CC0006D9BE /* Extensions */,
|
|
||||||
E41B22C721FB966C00D544F6 /* include */,
|
|
||||||
E40786242110CE70006887B1 /* Info.plist */,
|
|
||||||
E47E2FE32220AA0700F747E6 /* Layouts */,
|
E47E2FE32220AA0700F747E6 /* Layouts */,
|
||||||
E4F6B461221E124700ACF42A /* Models */,
|
E4F6B461221E124700ACF42A /* Models */,
|
||||||
E4A642DB220912FA00067D21 /* MPDClient */,
|
E4F6B45E221E117600ACF42A /* DataSources */,
|
||||||
E450AD8922262B420091BED3 /* Operations */,
|
E407861F2110CE70006887B1 /* Assets.xcassets */,
|
||||||
E40786252110CE70006887B1 /* Persephone.entitlements */,
|
E408D3B7220DE8CC0006D9BE /* Extensions */,
|
||||||
E450AD9E2229B9BC0091BED3 /* PersephoneBridgingHeader.h */,
|
|
||||||
E4A83BEC2221F5DD0098FED6 /* Preferences */,
|
|
||||||
E4D1B598220BA3C90026F233 /* Resources */,
|
E4D1B598220BA3C90026F233 /* Resources */,
|
||||||
E4A83BF2222207BE0098FED6 /* Services */,
|
E4D1B597220BA3A20026F233 /* Controllers */,
|
||||||
E408D3C3220E138B0006D9BE /* Views */,
|
E408D3C3220E138B0006D9BE /* Views */,
|
||||||
|
E41B22C721FB966C00D544F6 /* include */,
|
||||||
|
E407861B2110CE6E006887B1 /* AppDelegate.swift */,
|
||||||
|
E40786242110CE70006887B1 /* Info.plist */,
|
||||||
|
E40786252110CE70006887B1 /* Persephone.entitlements */,
|
||||||
|
E4A642DB220912FA00067D21 /* MPDClient */,
|
||||||
);
|
);
|
||||||
path = Persephone;
|
path = Persephone;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -342,10 +342,10 @@
|
|||||||
children = (
|
children = (
|
||||||
E4928E0A2218D62A001D4BEA /* CGColor.swift */,
|
E4928E0A2218D62A001D4BEA /* CGColor.swift */,
|
||||||
E408D3B5220DD8970006D9BE /* Notification.swift */,
|
E408D3B5220DD8970006D9BE /* Notification.swift */,
|
||||||
|
E408D3B8220DE98F0006D9BE /* NSUserInterfaceItemIdentifier.swift */,
|
||||||
E40FE71A221B904300A4223F /* NSEvent.swift */,
|
E40FE71A221B904300A4223F /* NSEvent.swift */,
|
||||||
E435E3E1221CD4E200184CFC /* NSFont.swift */,
|
E435E3E1221CD4E200184CFC /* NSFont.swift */,
|
||||||
E435E3E3221CD75D00184CFC /* NSImage.swift */,
|
E435E3E3221CD75D00184CFC /* NSImage.swift */,
|
||||||
E408D3B8220DE98F0006D9BE /* NSUserInterfaceItemIdentifier.swift */,
|
|
||||||
E450AD9C2229B9050091BED3 /* String.swift */,
|
E450AD9C2229B9050091BED3 /* String.swift */,
|
||||||
);
|
);
|
||||||
path = Extensions;
|
path = Extensions;
|
||||||
@ -354,15 +354,15 @@
|
|||||||
E408D3BC220E03D20006D9BE /* Extensions */ = {
|
E408D3BC220E03D20006D9BE /* Extensions */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
E41E530A223C033700173814 /* MPDClient+Album.swift */,
|
|
||||||
E41E5308223C020400173814 /* MPDClient+Command.swift */,
|
|
||||||
E41E52FC223BF87300173814 /* MPDClient+Connection.swift */,
|
E41E52FC223BF87300173814 /* MPDClient+Connection.swift */,
|
||||||
E42410B52241B956005ED6DF /* MPDClient+Database.swift */,
|
E42410B52241B956005ED6DF /* MPDClient+Database.swift */,
|
||||||
E41E5304223BFB0700173814 /* MPDClient+Error.swift */,
|
|
||||||
E41E5302223BF9C300173814 /* MPDClient+Idle.swift */,
|
|
||||||
E41E5300223BF99300173814 /* MPDClient+Queue.swift */,
|
|
||||||
E41E5306223C019100173814 /* MPDClient+Status.swift */,
|
|
||||||
E41E52FE223BF95E00173814 /* MPDClient+Transport.swift */,
|
E41E52FE223BF95E00173814 /* MPDClient+Transport.swift */,
|
||||||
|
E41E5300223BF99300173814 /* MPDClient+Queue.swift */,
|
||||||
|
E41E5302223BF9C300173814 /* MPDClient+Idle.swift */,
|
||||||
|
E41E5304223BFB0700173814 /* MPDClient+Error.swift */,
|
||||||
|
E41E5306223C019100173814 /* MPDClient+Status.swift */,
|
||||||
|
E41E5308223C020400173814 /* MPDClient+Command.swift */,
|
||||||
|
E41E530A223C033700173814 /* MPDClient+Album.swift */,
|
||||||
E408D3BD220E03EE0006D9BE /* RawRepresentable.swift */,
|
E408D3BD220E03EE0006D9BE /* RawRepresentable.swift */,
|
||||||
);
|
);
|
||||||
path = Extensions;
|
path = Extensions;
|
||||||
@ -450,8 +450,8 @@
|
|||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
E41E530D223EF4CF00173814 /* AlbumArtService+Caching.swift */,
|
E41E530D223EF4CF00173814 /* AlbumArtService+Caching.swift */,
|
||||||
E41E5311223EF74A00173814 /* AlbumArtService+Filesystem.swift */,
|
|
||||||
E41E530F223EF6CE00173814 /* AlbumArtService+Remote.swift */,
|
E41E530F223EF6CE00173814 /* AlbumArtService+Remote.swift */,
|
||||||
|
E41E5311223EF74A00173814 /* AlbumArtService+Filesystem.swift */,
|
||||||
);
|
);
|
||||||
path = Extensions;
|
path = Extensions;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -475,10 +475,10 @@
|
|||||||
E4A642DB220912FA00067D21 /* MPDClient */ = {
|
E4A642DB220912FA00067D21 /* MPDClient */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
E408D3BC220E03D20006D9BE /* Extensions */,
|
|
||||||
E4D1B594220BA2490026F233 /* Models */,
|
|
||||||
E41B22C521FB932700D544F6 /* MPDClient.swift */,
|
E41B22C521FB932700D544F6 /* MPDClient.swift */,
|
||||||
|
E408D3BC220E03D20006D9BE /* Extensions */,
|
||||||
E4D1B595220BA27C0026F233 /* Protocols */,
|
E4D1B595220BA27C0026F233 /* Protocols */,
|
||||||
|
E4D1B594220BA2490026F233 /* Models */,
|
||||||
);
|
);
|
||||||
path = MPDClient;
|
path = MPDClient;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -494,8 +494,8 @@
|
|||||||
E4A83BED2221F5E60098FED6 /* Controllers */ = {
|
E4A83BED2221F5E60098FED6 /* Controllers */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
E4A83BEE2221F8CF0098FED6 /* AlbumArtPrefsController.swift */,
|
|
||||||
E41EA46B221636AF0068EF46 /* GeneralPrefsViewController.swift */,
|
E41EA46B221636AF0068EF46 /* GeneralPrefsViewController.swift */,
|
||||||
|
E4A83BEE2221F8CF0098FED6 /* AlbumArtPrefsController.swift */,
|
||||||
E4A83BF02221FAA00098FED6 /* PreferencesViewController.swift */,
|
E4A83BF02221FAA00098FED6 /* PreferencesViewController.swift */,
|
||||||
E4C8B53B22342005009A20F3 /* PreferencesWindowController.swift */,
|
E4C8B53B22342005009A20F3 /* PreferencesWindowController.swift */,
|
||||||
);
|
);
|
||||||
@ -505,8 +505,8 @@
|
|||||||
E4A83BF2222207BE0098FED6 /* Services */ = {
|
E4A83BF2222207BE0098FED6 /* Services */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
E4A83BF3222207D50098FED6 /* AlbumArtService.swift */,
|
|
||||||
E41E530C223EF4BA00173814 /* Extensions */,
|
E41E530C223EF4BA00173814 /* Extensions */,
|
||||||
|
E4A83BF3222207D50098FED6 /* AlbumArtService.swift */,
|
||||||
);
|
);
|
||||||
path = Services;
|
path = Services;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -514,12 +514,12 @@
|
|||||||
E4D1B594220BA2490026F233 /* Models */ = {
|
E4D1B594220BA2490026F233 /* Models */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
E4EB237A220F7CF1008C70C0 /* MPDAlbum.swift */,
|
|
||||||
E45962C52241A78500FC1A1E /* MPDCommand.swift */,
|
|
||||||
E4C8B53D22349002009A20F3 /* MPDIdle.swift */,
|
|
||||||
E4EB2378220F10B8008C70C0 /* MPDPair.swift */,
|
|
||||||
E4E8CC9922075D370024217A /* MPDSong.swift */,
|
E4E8CC9922075D370024217A /* MPDSong.swift */,
|
||||||
E4A642D922090CBE00067D21 /* MPDStatus.swift */,
|
E4A642D922090CBE00067D21 /* MPDStatus.swift */,
|
||||||
|
E4EB2378220F10B8008C70C0 /* MPDPair.swift */,
|
||||||
|
E4EB237A220F7CF1008C70C0 /* MPDAlbum.swift */,
|
||||||
|
E4C8B53D22349002009A20F3 /* MPDIdle.swift */,
|
||||||
|
E45962C52241A78500FC1A1E /* MPDCommand.swift */,
|
||||||
);
|
);
|
||||||
path = Models;
|
path = Models;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -535,12 +535,12 @@
|
|||||||
E4D1B597220BA3A20026F233 /* Controllers */ = {
|
E4D1B597220BA3A20026F233 /* Controllers */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
E408D3C1220E134F0006D9BE /* AlbumViewController.swift */,
|
|
||||||
E47E2FD4222071FD00F747E6 /* AlbumViewItem.swift */,
|
E47E2FD4222071FD00F747E6 /* AlbumViewItem.swift */,
|
||||||
E47E2FD022205C4600F747E6 /* MainSplitViewController.swift */,
|
E408D3C1220E134F0006D9BE /* AlbumViewController.swift */,
|
||||||
E4E8CC932206097F0024217A /* NotificationsController.swift */,
|
E4E8CC932206097F0024217A /* NotificationsController.swift */,
|
||||||
E4E8CC912204F4B80024217A /* QueueViewController.swift */,
|
E4E8CC912204F4B80024217A /* QueueViewController.swift */,
|
||||||
E465049921E94DF500A70F4C /* WindowController.swift */,
|
E465049921E94DF500A70F4C /* WindowController.swift */,
|
||||||
|
E47E2FD022205C4600F747E6 /* MainSplitViewController.swift */,
|
||||||
);
|
);
|
||||||
path = Controllers;
|
path = Controllers;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -557,8 +557,8 @@
|
|||||||
E4F6B45E221E117600ACF42A /* DataSources */ = {
|
E4F6B45E221E117600ACF42A /* DataSources */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
E4F6B466221E233200ACF42A /* AlbumDataSource.swift */,
|
|
||||||
E4F6B45F221E119B00ACF42A /* QueueDataSource.swift */,
|
E4F6B45F221E119B00ACF42A /* QueueDataSource.swift */,
|
||||||
|
E4F6B466221E233200ACF42A /* AlbumDataSource.swift */,
|
||||||
);
|
);
|
||||||
path = DataSources;
|
path = DataSources;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
|
|||||||
@ -7,7 +7,6 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
import Cocoa
|
import Cocoa
|
||||||
import PromiseKit
|
|
||||||
|
|
||||||
class QueueViewController: NSViewController,
|
class QueueViewController: NSViewController,
|
||||||
NSOutlineViewDelegate {
|
NSOutlineViewDelegate {
|
||||||
@ -67,18 +66,8 @@ class QueueViewController: NSViewController,
|
|||||||
}
|
}
|
||||||
|
|
||||||
func updateAlbumArt() {
|
func updateAlbumArt() {
|
||||||
if let playingQueueItem = dataSource.queue.first(where: { $0.isPlaying }) {
|
if let playingSong = dataSource.queue.first(where: { $0.isPlaying }) {
|
||||||
let albumArtService = AlbumArtService(song: playingQueueItem.song)
|
|
||||||
|
|
||||||
albumArtService.fetchBigAlbumArt()
|
|
||||||
.done() {
|
|
||||||
guard let image = $0 else { return }
|
|
||||||
|
|
||||||
self.queueAlbumArtImage.image = image.toFitBox(
|
|
||||||
size: NSSize(width: 500, height: 500)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
.cauterize()
|
|
||||||
} else {
|
} else {
|
||||||
queueAlbumArtImage.image = NSImage.defaultCoverArt
|
queueAlbumArtImage.image = NSImage.defaultCoverArt
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,7 +7,6 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
import Cocoa
|
import Cocoa
|
||||||
import PromiseKit
|
|
||||||
|
|
||||||
class AlbumDataSource: NSObject, NSCollectionViewDataSource {
|
class AlbumDataSource: NSObject, NSCollectionViewDataSource {
|
||||||
var albums: [Album] = []
|
var albums: [Album] = []
|
||||||
@ -27,9 +26,7 @@ class AlbumDataSource: NSObject, NSCollectionViewDataSource {
|
|||||||
AppDelegate.mpdClient.getAlbumFirstSong(for: albums[indexPath.item].mpdAlbum) {
|
AppDelegate.mpdClient.getAlbumFirstSong(for: albums[indexPath.item].mpdAlbum) {
|
||||||
guard let song = $0 else { return }
|
guard let song = $0 else { return }
|
||||||
|
|
||||||
AlbumArtService(song: Song(mpdSong: song))
|
AlbumArtService(song: Song(mpdSong: song)).fetchAlbumArt { image in
|
||||||
.fetchAlbumArt()
|
|
||||||
.done { image in
|
|
||||||
self.albums[indexPath.item].coverArt = image
|
self.albums[indexPath.item].coverArt = image
|
||||||
|
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<document type="com.apple.InterfaceBuilder3.Cocoa.Storyboard.XIB" version="3.0" toolsVersion="14490.70" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" initialViewController="B8D-0N-5wS">
|
<document type="com.apple.InterfaceBuilder3.Cocoa.Storyboard.XIB" version="3.0" toolsVersion="14460.31" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" initialViewController="B8D-0N-5wS">
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<deployment identifier="macosx"/>
|
<deployment identifier="macosx"/>
|
||||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="14490.70"/>
|
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="14460.31"/>
|
||||||
<capability name="System colors introduced in macOS 10.14" minToolsVersion="10.0"/>
|
<capability name="System colors introduced in macOS 10.14" minToolsVersion="10.0"/>
|
||||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
@ -315,11 +315,11 @@
|
|||||||
<objects>
|
<objects>
|
||||||
<viewController title="Album Art" id="3C9-vU-zjZ" customClass="AlbumArtPrefsController" customModule="Persephone" customModuleProvider="target" sceneMemberID="viewController">
|
<viewController title="Album Art" id="3C9-vU-zjZ" customClass="AlbumArtPrefsController" customModule="Persephone" customModuleProvider="target" sceneMemberID="viewController">
|
||||||
<view key="view" id="PyK-v2-kus">
|
<view key="view" id="PyK-v2-kus">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="524" height="168"/>
|
<rect key="frame" x="0.0" y="0.0" width="524" height="100"/>
|
||||||
<autoresizingMask key="autoresizingMask"/>
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
<subviews>
|
<subviews>
|
||||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="zZn-Rm-e1f">
|
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="zZn-Rm-e1f">
|
||||||
<rect key="frame" x="53" y="130" width="104" height="17"/>
|
<rect key="frame" x="53" y="62" width="104" height="17"/>
|
||||||
<textFieldCell key="cell" lineBreakMode="clipping" title="Music Directory:" id="sPn-V6-CfK">
|
<textFieldCell key="cell" lineBreakMode="clipping" title="Music Directory:" id="sPn-V6-CfK">
|
||||||
<font key="font" usesAppearanceFont="YES"/>
|
<font key="font" usesAppearanceFont="YES"/>
|
||||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||||
@ -327,7 +327,7 @@
|
|||||||
</textFieldCell>
|
</textFieldCell>
|
||||||
</textField>
|
</textField>
|
||||||
<textField verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="gDk-ca-eOa">
|
<textField verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="gDk-ca-eOa">
|
||||||
<rect key="frame" x="162" y="126" width="288" height="22"/>
|
<rect key="frame" x="162" y="58" width="288" height="22"/>
|
||||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" borderStyle="bezel" placeholderString="~/Music" drawsBackground="YES" id="7WZ-b7-GUs">
|
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" borderStyle="bezel" placeholderString="~/Music" drawsBackground="YES" id="7WZ-b7-GUs">
|
||||||
<font key="font" metaFont="system"/>
|
<font key="font" metaFont="system"/>
|
||||||
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||||
@ -338,7 +338,7 @@
|
|||||||
</connections>
|
</connections>
|
||||||
</textField>
|
</textField>
|
||||||
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="pRL-MG-1Be">
|
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="pRL-MG-1Be">
|
||||||
<rect key="frame" x="160" y="95" width="264" height="18"/>
|
<rect key="frame" x="160" y="27" width="265" height="18"/>
|
||||||
<buttonCell key="cell" type="check" title="Fetch missing artwork from MusicBrainz" bezelStyle="regularSquare" imagePosition="left" inset="2" id="LpD-Ew-HMd">
|
<buttonCell key="cell" type="check" title="Fetch missing artwork from MusicBrainz" bezelStyle="regularSquare" imagePosition="left" inset="2" id="LpD-Ew-HMd">
|
||||||
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
|
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
|
||||||
<font key="font" metaFont="system"/>
|
<font key="font" metaFont="system"/>
|
||||||
@ -347,51 +347,15 @@
|
|||||||
<action selector="updateFetchMissingArtworkFromInternet:" target="3C9-vU-zjZ" id="I7x-9V-xJr"/>
|
<action selector="updateFetchMissingArtworkFromInternet:" target="3C9-vU-zjZ" id="I7x-9V-xJr"/>
|
||||||
</connections>
|
</connections>
|
||||||
</button>
|
</button>
|
||||||
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="z1g-nP-ksw">
|
|
||||||
<rect key="frame" x="160" y="64" width="264" height="18"/>
|
|
||||||
<constraints>
|
|
||||||
<constraint firstAttribute="width" constant="260" id="gK0-aW-CJy"/>
|
|
||||||
</constraints>
|
|
||||||
<buttonCell key="cell" type="check" title="Save fetched artwork to music directory" bezelStyle="regularSquare" imagePosition="left" inset="2" id="ZeZ-O4-vjS">
|
|
||||||
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
|
|
||||||
<font key="font" metaFont="system"/>
|
|
||||||
</buttonCell>
|
|
||||||
</button>
|
|
||||||
<textField verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="xgS-Kg-8KR">
|
|
||||||
<rect key="frame" x="162" y="26" width="144" height="22"/>
|
|
||||||
<constraints>
|
|
||||||
<constraint firstAttribute="width" constant="144" id="DSX-th-Wn1"/>
|
|
||||||
</constraints>
|
|
||||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" borderStyle="bezel" placeholderString="folder.jpg" drawsBackground="YES" id="nKF-YI-xBL">
|
|
||||||
<font key="font" metaFont="system"/>
|
|
||||||
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
|
||||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
|
||||||
</textFieldCell>
|
|
||||||
</textField>
|
|
||||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="SmH-w6-5QI">
|
|
||||||
<rect key="frame" x="37" y="30" width="119" height="17"/>
|
|
||||||
<textFieldCell key="cell" lineBreakMode="clipping" alignment="right" title="Cover art filename:" id="b4u-u7-iWD">
|
|
||||||
<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>
|
|
||||||
</subviews>
|
</subviews>
|
||||||
<constraints>
|
<constraints>
|
||||||
<constraint firstItem="pRL-MG-1Be" firstAttribute="centerX" secondItem="z1g-nP-ksw" secondAttribute="centerX" id="0Ev-Ia-XBO"/>
|
|
||||||
<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="pRL-MG-1Be" secondAttribute="leading" id="1jd-wZ-a4Q"/>
|
||||||
<constraint firstItem="pRL-MG-1Be" firstAttribute="leading" secondItem="z1g-nP-ksw" secondAttribute="leading" id="3tZ-Ub-RaT"/>
|
|
||||||
<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="leading" secondItem="zZn-Rm-e1f" secondAttribute="trailing" constant="7" id="C0m-yx-gXh"/>
|
||||||
<constraint firstItem="z1g-nP-ksw" firstAttribute="leading" secondItem="xgS-Kg-8KR" secondAttribute="leading" id="Dkv-ai-X2G"/>
|
<constraint firstItem="gDk-ca-eOa" firstAttribute="top" secondItem="PyK-v2-kus" secondAttribute="top" constant="20" symbolic="YES" id="HZD-uf-Mhl"/>
|
||||||
<constraint firstItem="xgS-Kg-8KR" firstAttribute="leading" secondItem="SmH-w6-5QI" secondAttribute="trailing" constant="8" symbolic="YES" id="KQk-nr-H8y"/>
|
|
||||||
<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="leading" secondItem="PyK-v2-kus" secondAttribute="leading" constant="55" id="OzK-MR-zuB"/>
|
||||||
<constraint firstAttribute="bottom" secondItem="SmH-w6-5QI" secondAttribute="bottom" constant="30" id="aBY-Ny-jPe"/>
|
<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 firstItem="pRL-MG-1Be" firstAttribute="top" secondItem="gDk-ca-eOa" secondAttribute="bottom" constant="15" id="dKy-uC-r43"/>
|
||||||
<constraint firstItem="xgS-Kg-8KR" firstAttribute="top" secondItem="z1g-nP-ksw" secondAttribute="bottom" constant="18" id="lfR-Im-bd4"/>
|
|
||||||
<constraint firstAttribute="trailing" secondItem="gDk-ca-eOa" secondAttribute="trailing" constant="74" id="n8X-T2-tXA"/>
|
<constraint firstAttribute="trailing" secondItem="gDk-ca-eOa" secondAttribute="trailing" constant="74" id="n8X-T2-tXA"/>
|
||||||
<constraint firstAttribute="bottom" secondItem="xgS-Kg-8KR" secondAttribute="bottom" constant="26" id="oXZ-qo-HwX"/>
|
|
||||||
<constraint firstItem="SmH-w6-5QI" firstAttribute="top" secondItem="zZn-Rm-e1f" secondAttribute="bottom" constant="83" id="qhC-mD-Bvw"/>
|
|
||||||
<constraint firstItem="z1g-nP-ksw" firstAttribute="top" secondItem="pRL-MG-1Be" secondAttribute="bottom" constant="17" id="sTP-hk-zfU"/>
|
|
||||||
</constraints>
|
</constraints>
|
||||||
</view>
|
</view>
|
||||||
<connections>
|
<connections>
|
||||||
@ -401,7 +365,7 @@
|
|||||||
</viewController>
|
</viewController>
|
||||||
<customObject id="KzD-E3-lpA" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
|
<customObject id="KzD-E3-lpA" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
|
||||||
</objects>
|
</objects>
|
||||||
<point key="canvasLocation" x="1626" y="373"/>
|
<point key="canvasLocation" x="1626" y="339"/>
|
||||||
</scene>
|
</scene>
|
||||||
<!--General-->
|
<!--General-->
|
||||||
<scene sceneID="xTC-Y5-Agk">
|
<scene sceneID="xTC-Y5-Agk">
|
||||||
@ -463,13 +427,13 @@
|
|||||||
<constraints>
|
<constraints>
|
||||||
<constraint firstItem="kvB-99-zwY" firstAttribute="centerX" secondItem="AU9-wN-kbU" secondAttribute="centerX" id="6bm-yZ-rJu"/>
|
<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="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 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="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="wPm-sJ-e9E" firstAttribute="leading" secondItem="kvB-99-zwY" secondAttribute="trailing" constant="8" symbolic="YES" id="NAc-1j-JEH"/>
|
||||||
<constraint firstAttribute="bottom" secondItem="IbX-oV-soD" secondAttribute="bottom" constant="26" id="QHJ-ID-D3L"/>
|
<constraint firstItem="IbX-oV-soD" firstAttribute="top" secondItem="wPm-sJ-e9E" secondAttribute="bottom" constant="10" symbolic="YES" id="gT9-JL-dW0"/>
|
||||||
<constraint firstAttribute="bottom" secondItem="AU9-wN-kbU" secondAttribute="bottom" constant="30" id="j5r-By-kiE"/>
|
|
||||||
<constraint firstItem="wPm-sJ-e9E" firstAttribute="leading" secondItem="IbX-oV-soD" secondAttribute="leading" id="lz4-7S-QQb"/>
|
<constraint firstItem="wPm-sJ-e9E" firstAttribute="leading" secondItem="IbX-oV-soD" secondAttribute="leading" id="lz4-7S-QQb"/>
|
||||||
<constraint firstItem="IbX-oV-soD" firstAttribute="top" secondItem="wPm-sJ-e9E" secondAttribute="bottom" constant="10" id="sZA-01-JAS"/>
|
|
||||||
</constraints>
|
</constraints>
|
||||||
</view>
|
</view>
|
||||||
<connections>
|
<connections>
|
||||||
@ -635,7 +599,7 @@
|
|||||||
<rect key="frame" x="0.0" y="220" width="328" height="328"/>
|
<rect key="frame" x="0.0" y="220" width="328" height="328"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||||
<subviews>
|
<subviews>
|
||||||
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" horizontalCompressionResistancePriority="250" verticalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="Dw3-M5-tWY">
|
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="Dw3-M5-tWY">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="328" height="328"/>
|
<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"/>
|
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyUpOrDown" image="blankAlbum" id="IoN-3N-TCb"/>
|
||||||
</imageView>
|
</imageView>
|
||||||
|
|||||||
@ -17,68 +17,39 @@ class AlbumArtService {
|
|||||||
let cachedArtworkSize = 180
|
let cachedArtworkSize = 180
|
||||||
let cachedArtworkQuality: CGFloat = 0.5
|
let cachedArtworkQuality: CGFloat = 0.5
|
||||||
|
|
||||||
let bigArtworkSize = 600
|
|
||||||
|
|
||||||
var session = URLSession(configuration: .default)
|
var session = URLSession(configuration: .default)
|
||||||
let artworkQueue = DispatchQueue(label: "albumArtQueue", qos: .background)
|
let cacheQueue = DispatchQueue(label: "albumArtCacheQueue")
|
||||||
|
|
||||||
init(song: Song) {
|
init(song: Song) {
|
||||||
self.song = song
|
self.song = song
|
||||||
self.album = song.album
|
self.album = song.album
|
||||||
}
|
}
|
||||||
|
|
||||||
func fetchBigAlbumArt() -> Promise<NSImage?> {
|
func fetchAlbumArt(callback: @escaping (_ image: NSImage?) -> Void) {
|
||||||
return firstly {
|
cacheQueue.async {
|
||||||
self.getArtworkFromFilesystem()
|
firstly {
|
||||||
}.then { (image: NSImage?) -> Promise<NSImage?> in
|
|
||||||
image.map(Promise.value) ?? self.getRemoteArtwork()
|
|
||||||
}.compactMap(on :artworkQueue) { image in
|
|
||||||
if self.fileSystemArtworkFilePath() != nil {
|
|
||||||
let sizedImage = image?.toFitBox(
|
|
||||||
size: NSSize(width: self.bigArtworkSize, height: self.bigArtworkSize)
|
|
||||||
)
|
|
||||||
self.saveArtworkToFilesystem(data: sizedImage?.jpegData(compressionQuality: self.cachedArtworkQuality))
|
|
||||||
return sizedImage
|
|
||||||
} else {
|
|
||||||
return image
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func fetchAlbumArt() -> Guarantee<NSImage?> {
|
|
||||||
return firstly {
|
|
||||||
self.getCachedArtwork()
|
self.getCachedArtwork()
|
||||||
}.then { (artwork: NSImage?) -> Promise<NSImage?> in
|
}.then { artwork -> Promise<NSImage?> in
|
||||||
artwork.map(Promise.value) ?? self.getArtworkFromFilesystem()
|
artwork.map { Promise.value($0 as NSImage?) } ?? self.cacheIfNecessary(self.getArtworkFromFilesystem())
|
||||||
}.then { (artwork: NSImage?) -> Promise<NSImage?> in
|
}.then { artwork -> Promise<NSImage?> in
|
||||||
artwork.map(Promise.value) ?? self.getRemoteArtwork()
|
artwork.map { Promise.value($0 as NSImage?) } ?? self.cacheIfNecessary(self.getArtworkFromMusicBrainz().map(Optional.some))
|
||||||
}.compactMap(on: artworkQueue) {
|
}.tap { result in
|
||||||
return self.sizeAndCacheImage($0).map(Optional.some)
|
switch result {
|
||||||
}.recover { error in
|
case .fulfilled(nil), .rejected(MusicBrainzError.noArtworkAvailable):
|
||||||
switch error {
|
|
||||||
case RemoteArtworkError.noArtworkAvailable:
|
|
||||||
self.cacheArtwork(data: Data())
|
self.cacheArtwork(data: Data())
|
||||||
default:
|
default:
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
return .value(nil)
|
}.recover { error in
|
||||||
|
.value(nil)
|
||||||
|
}.done(callback)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func sizeAndCacheImage(_ image: NSImage?) -> NSImage? {
|
func cacheIfNecessary(_ promise: Promise<NSImage?>) -> Promise<NSImage?> {
|
||||||
switch image {
|
return promise.get { image in
|
||||||
case nil:
|
if let data = image?.jpegData(compressionQuality: self.cachedArtworkQuality) {
|
||||||
self.cacheArtwork(data: Data())
|
self.cacheArtwork(data: data)
|
||||||
return image
|
|
||||||
case let image:
|
|
||||||
if self.isArtworkCached() {
|
|
||||||
return image
|
|
||||||
} else {
|
|
||||||
let sizedImage = image?.toFitBox(
|
|
||||||
size: NSSize(width: self.cachedArtworkSize, height: self.cachedArtworkSize)
|
|
||||||
)
|
|
||||||
self.cacheArtwork(data: sizedImage?.jpegData(compressionQuality: self.cachedArtworkQuality))
|
|
||||||
return sizedImage
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,38 +14,24 @@ extension AlbumArtService {
|
|||||||
|
|
||||||
func getCachedArtwork() -> Promise<NSImage?> {
|
func getCachedArtwork() -> Promise<NSImage?> {
|
||||||
return Promise { seal in
|
return Promise { seal in
|
||||||
artworkQueue.async {
|
let cacheFilePath = AlbumArtService.cacheDir.appendingPathComponent(album.hash).path
|
||||||
if self.isArtworkCached() {
|
|
||||||
let cacheFilePath = AlbumArtService.cacheDir.appendingPathComponent(self.album.hash).path
|
|
||||||
let data = FileManager.default.contents(atPath: cacheFilePath)
|
let data = FileManager.default.contents(atPath: cacheFilePath)
|
||||||
let image = NSImage(data: data ?? Data()) ?? NSImage.defaultCoverArt
|
let image = data.flatMap(NSImage.init(data:))
|
||||||
|
|
||||||
seal.fulfill(image)
|
seal.fulfill(image)
|
||||||
} else {
|
|
||||||
seal.fulfill(nil)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func cacheArtwork(data: Data?) {
|
func cacheArtwork(data: Data?) {
|
||||||
artworkQueue.async {
|
|
||||||
guard let bundleIdentifier = Bundle.main.bundleIdentifier,
|
guard let bundleIdentifier = Bundle.main.bundleIdentifier,
|
||||||
let cacheDir = try? FileManager.default.url(for: .cachesDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
|
let cacheDir = try? FileManager.default.url(for: .cachesDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
|
||||||
.appendingPathComponent(bundleIdentifier)
|
.appendingPathComponent(bundleIdentifier)
|
||||||
else { return }
|
else { return }
|
||||||
|
|
||||||
let cacheFilePath = cacheDir.appendingPathComponent(self.album.hash).path
|
let cacheFilePath = cacheDir.appendingPathComponent(album.hash).path
|
||||||
|
|
||||||
if !self.isArtworkCached() {
|
if !FileManager.default.fileExists(atPath: cacheFilePath) {
|
||||||
FileManager.default.createFile(atPath: cacheFilePath, contents: data, attributes: nil)
|
FileManager.default.createFile(atPath: cacheFilePath, contents: data, attributes: nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
func isArtworkCached() -> Bool {
|
|
||||||
let cacheFilePath = AlbumArtService.cacheDir.appendingPathComponent(album.hash).path
|
|
||||||
|
|
||||||
return FileManager.default.fileExists(atPath: cacheFilePath)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,57 +10,29 @@ import Cocoa
|
|||||||
import PromiseKit
|
import PromiseKit
|
||||||
|
|
||||||
extension AlbumArtService {
|
extension AlbumArtService {
|
||||||
var coverArtFilenames: [String] {
|
func getArtworkFromFilesystem() -> Promise<NSImage?> {
|
||||||
return [
|
let coverArtFilenames = [
|
||||||
"folder.jpg",
|
"folder.jpg",
|
||||||
"cover.jpg",
|
"cover.jpg",
|
||||||
"\(album.artist) - \(album.title).jpg"
|
"\(album.artist) - \(album.title).jpg"
|
||||||
]
|
]
|
||||||
}
|
|
||||||
|
|
||||||
var musicDir: String {
|
let musicDir = self.preferences.expandedMpdLibraryDir
|
||||||
return self.preferences.expandedMpdLibraryDir
|
let songPath = self.songPath()
|
||||||
}
|
|
||||||
|
|
||||||
func getArtworkFromFilesystem() -> Promise<NSImage?> {
|
|
||||||
return Promise { seal in
|
return Promise { seal in
|
||||||
artworkQueue.async {
|
let image = coverArtFilenames
|
||||||
guard let artworkPath = self.fileSystemArtworkFilePath()
|
.lazy
|
||||||
else { seal.fulfill(nil); return }
|
.map { "\(musicDir)/\(songPath)/\($0)" }
|
||||||
|
.compactMap(self.tryImage)
|
||||||
let image = self.tryImage(artworkPath)
|
.first
|
||||||
|
|
||||||
seal.fulfill(image)
|
seal.fulfill(image)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
func saveArtworkToFilesystem(data: Data?) {
|
func songPath() -> String {
|
||||||
let artworkFileName = coverArtFilenames.first!
|
return song.mpdSong
|
||||||
|
|
||||||
if self.fileSystemArtworkFilePath() == nil {
|
|
||||||
FileManager.default.createFile(
|
|
||||||
atPath: "\(self.musicDir)/\(self.songPath)/\(artworkFileName)",
|
|
||||||
contents: data,
|
|
||||||
attributes: nil
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func fileSystemArtworkFilePath() -> String? {
|
|
||||||
let musicDir = self.preferences.expandedMpdLibraryDir
|
|
||||||
|
|
||||||
return self.coverArtFilenames
|
|
||||||
.lazy
|
|
||||||
.map { "\(musicDir)/\(self.songPath)/\($0)" }
|
|
||||||
.first {
|
|
||||||
FileManager.default.fileExists(atPath: $0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var songPath: String {
|
|
||||||
return song
|
|
||||||
.mpdSong
|
|
||||||
.uriString
|
.uriString
|
||||||
.split(separator: "/")
|
.split(separator: "/")
|
||||||
.dropLast()
|
.dropLast()
|
||||||
|
|||||||
@ -12,34 +12,26 @@ import PromiseKit
|
|||||||
import PMKFoundation
|
import PMKFoundation
|
||||||
|
|
||||||
extension AlbumArtService {
|
extension AlbumArtService {
|
||||||
enum RemoteArtworkError: Error {
|
enum MusicBrainzError: Error {
|
||||||
case noArtworkAvailable
|
case noArtworkAvailable
|
||||||
case notConfigured
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func getRemoteArtwork() -> Promise<NSImage?> {
|
func getRemoteArtwork() -> Promise<NSImage> {
|
||||||
return Promise { seal in
|
return Promise { seal in
|
||||||
if preferences.fetchMissingArtworkFromInternet {
|
|
||||||
artworkQueue.async {
|
|
||||||
let albumArtWorkItem = DispatchWorkItem {
|
let albumArtWorkItem = DispatchWorkItem {
|
||||||
self.getArtworkFromMusicBrainz().map(Optional.some).pipe(to: seal.resolve)
|
self.getArtworkFromMusicBrainz().pipe(to: seal.resolve)
|
||||||
}
|
}
|
||||||
|
|
||||||
AlbumArtQueue.shared.addToQueue(workItem: albumArtWorkItem)
|
AlbumArtQueue.shared.addToQueue(workItem: albumArtWorkItem)
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
throw RemoteArtworkError.notConfigured
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func getArtworkFromMusicBrainz() -> Promise<NSImage> {
|
func getArtworkFromMusicBrainz() -> Promise<NSImage> {
|
||||||
var search = URLComponents(string: "https://musicbrainz.org/ws/2/release/")!
|
var search = URLComponents(string: "https://musicbrainz.org/ws/2/release/")!
|
||||||
search.query = "query=artist:\(album.artist) AND release:\(album.title) AND country:US&limit=1&fmt=json"
|
search.query = "query=artist:\(album.artist) AND release:\(album.title) AND country:US&limit=1&fmt=json"
|
||||||
|
|
||||||
return firstly {
|
return URLSession.shared.dataTask(.promise, with: search.url!).validate()
|
||||||
URLSession.shared.dataTask(.promise, with: search.url!).validate()
|
.compactMap {
|
||||||
}.compactMap {
|
|
||||||
JSON($0.data)
|
JSON($0.data)
|
||||||
}.compactMap {
|
}.compactMap {
|
||||||
$0["releases"][0]["id"].string
|
$0["releases"][0]["id"].string
|
||||||
@ -53,7 +45,7 @@ extension AlbumArtService {
|
|||||||
)
|
)
|
||||||
}.recover { error -> Promise<NSImage> in
|
}.recover { error -> Promise<NSImage> in
|
||||||
if case PMKHTTPError.badStatusCode(404, _, _) = error {
|
if case PMKHTTPError.badStatusCode(404, _, _) = error {
|
||||||
throw RemoteArtworkError.noArtworkAvailable
|
throw MusicBrainzError.noArtworkAvailable
|
||||||
} else {
|
} else {
|
||||||
throw error
|
throw error
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user