Merge branch 'main' of https://github.com/ciderapp/Cider into main

This commit is contained in:
Jason Chen 2022-06-17 11:33:32 -07:00
commit 90dcde279a
137 changed files with 8653 additions and 4265 deletions

View file

@ -1,4 +1,4 @@
<div id="app-content" @scroll.passive="setContentScrollPos" :scrollpos="chrome.contentScrollPosY" scrollaxis="y" :style="{'overflow': (chrome.contentAreaScrolling ? '' : 'hidden')}">
<div id="app-content" :scrollpos="chrome.contentScrollPosY" scrollaxis="y" :style="{'overflow': (chrome.contentAreaScrolling ? '' : 'hidden')}">
<div id="navigation-bar" v-if="getThemeDirective('appNavigation') == 'seperate'">
<button class="nav-item" @click="navigateBack()">
<%- include('../svg/chevron-left.svg') %>
@ -24,11 +24,6 @@
</template>
</transition>
<% } %>
<!-- Library - Recently Added -->
<transition :name="chrome.desiredPageTransition" v-on:enter="getLibraryAlbumsFull(null, 0); searchLibraryAlbums(0);">
<%- include('../pages/library-recentlyadded') %>');
</transition>
<!-- Library - Made For You -->
<transition :name="chrome.desiredPageTransition" v-on:enter="getMadeForYou()">
<template v-if="page == 'library-madeforyou'">

View file

@ -1,4 +1,129 @@
<div class="app-navigation" v-cloak>
<transition name="wpfade">
<div class="usermenu-container" v-if="chrome.menuOpened">
<div class="usermenu-body">
<button
class="app-sidebar-button"
style="width: 100%"
@click="appRoute('apple-account-settings')"
>
<img
class="sidebar-user-icon"
loading="lazy"
:src="getMediaItemArtwork(chrome.hideUserInfo ? './assets/logocut.png' : (chrome.userinfo.attributes['artwork'] ? chrome.userinfo.attributes['artwork']['url'] : ''), 26)"
/>
<div class="sidebar-user-text" v-if="!chrome.hideUserInfo">
<template v-if="chrome.userinfo.id || mk.isAuthorized">
<div class="fullname text-overflow-elipsis">
{{
chrome.userinfo != null &&
chrome.userinfo.attributes != null
? chrome.userinfo.attributes.name ?? ""
: ""
}}
</div>
<div class="handle-text text-overflow-elipsis">
{{
chrome.userinfo != null &&
chrome.userinfo.attributes != null
? chrome.userinfo.attributes.handle ?? ""
: ""
}}
</div>
</template>
<template v-else>
<div @click="mk.authorize()">
{{ $root.getLz("term.login") }}
</div>
</template>
</div>
<div class="sidebar-user-text" v-else>
{{ $root.getLz("app.name") }}
</div>
</button>
<!-- Use 20px SVG for usermenu icon -->
<button
class="usermenu-item"
v-if="cfg.general.privateEnabled"
@click="cfg.general.privateEnabled = false"
>
<span class="usermenu-item-icon">
<%- include("../svg/x.svg") %>
</span>
<span class="usermenu-item-name">{{
$root.getLz("term.disablePrivateSession")
}}</span>
</button>
<button class="usermenu-item" @click="appRoute('remote-pair')">
<span class="usermenu-item-icon">
<%- include("../svg/smartphone.svg") %>
</span>
<span class="usermenu-item-name">{{
$root.getLz("action.showWebRemoteQR")
}}</span>
</button>
<button
class="usermenu-item"
@click="cfg.advanced.AudioContext ? modals.castMenu = true : $root.notyf.error($root.getLz('settings.warn.enableAdvancedFunctionality'))"
>
<span class="usermenu-item-icon">
<%- include("../svg/cast.svg") %>
</span>
<span class="usermenu-item-name">{{
$root.getLz("term.cast")
}}</span>
</button>
<button
class="usermenu-item"
@click="cfg.advanced.AudioContext ? modals.audioSettings = true : $root.notyf.error($root.getLz('settings.warn.enableAdvancedFunctionality'))"
>
<span class="usermenu-item-icon">
<%- include("../svg/headphones.svg") %>
</span>
<span class="usermenu-item-name">{{
$root.getLz("term.audioSettings")
}}</span>
</button>
<button
class="usermenu-item"
v-if="pluginInstalled"
@click="modals.pluginMenu = true"
>
<span class="usermenu-item-icon">
<%- include("../svg/grid.svg") %>
</span>
<span class="usermenu-item-name">{{
$root.getLz("term.plugin")
}}</span>
</button>
<button class="usermenu-item" @click="appRoute('about')">
<span class="usermenu-item-icon">
<%- include("../svg/info.svg") %>
</span>
<span class="usermenu-item-name">{{
$root.getLz("term.about")
}}</span>
</button>
<button class="usermenu-item" @click="appRoute('settings')">
<span class="usermenu-item-icon">
<%- include("../svg/settings.svg") %>
</span>
<span class="usermenu-item-name">{{
$root.getLz("term.settings")
}}</span>
</button>
<button class="usermenu-item" @click="unauthorize()">
<span class="usermenu-item-icon" style="right: 2.5px">
<%- include("../svg/log-out.svg") %>
</span>
<span class="usermenu-item-name">{{
$root.getLz("term.logout")
}}</span>
</button>
</div>
</div>
</transition>
<transition name="sidebartransition">
<%- include("sidebar") %>
</transition>

View file

@ -10,10 +10,10 @@
<b-popover custom-class="mediainfo-popover" target="artworkLCD" triggers="hover" placement="right">
<div class="content">
<div class="shadow-artwork">
<mediaitem-artwork :url="currentArtUrl" :url="currentArtUrlRaw"></mediaitem-artwork>
<mediaitem-artwork :url="currentArtUrl"></mediaitem-artwork>
</div>
<div class="popover-artwork">
<mediaitem-artwork :size="210" :url="currentArtUrlRaw"></mediaitem-artwork>
<mediaitem-artwork :url="currentArtUrl"></mediaitem-artwork>
</div>
<div class="song-name">{{ mk.nowPlayingItem["attributes"]["name"] }}</div>
<div class="song-artist" @click="getNowPlayingItemDetailed(`artist`)">{{ mk.nowPlayingItem["attributes"]["artistName"] }}</div>
@ -60,13 +60,27 @@
</div>
</template>
<template v-else>
<div class="app-playback-controls">
<div class="artwork" id="artworkLCD" style="pointer-events: none;">
<mediaitem-artwork :url="currentArtUrl"></mediaitem-artwork>
</div>
<div class="playback-info">
<div class="song-name">
</div>
</div>
</div>
</template>
</div>
</div>
<div class="app-chrome--center">
<div class="app-chrome-playback-duration-bottom">
<b-row>
<b-col sm="auto">{{ convertTime(getSongProgress()) }}</b-col>
<b-row v-if="mkReady()">
<b-col sm="auto" v-if="!mk.nowPlayingItem?.isLiveRadioStation">{{ convertTime(getSongProgress()) }}</b-col>
<b-col sm="auto" v-else>--:--</b-col>
<b-col>
<input type="range" step="0.01" min="0" :style="progressBarStyle()"
@input="playerLCD.desiredDuration = $event.target.value;playerLCD.userInteraction = true"
@ -74,7 +88,8 @@
@touchend="mk.seekToTime($event.target.value);setTimeout(()=>{playerLCD.desiredDuration = 0;playerLCD.userInteraction = false}, 1000);"
:max="mk.currentPlaybackDuration" :value="getSongProgress()">
</b-col>
<b-col sm="auto">{{ convertTime(mk.currentPlaybackDuration) }}</b-col>
<b-col sm="auto" v-if="!mk.nowPlayingItem?.isLiveRadioStation">{{ convertTime(mk.currentPlaybackDuration) }}</b-col>
<b-col sm="auto" v-else>{{ getLz("term.live") }}</b-col>
</b-row>
</div>
<div class="app-chrome-playback-controls">

View file

@ -1,217 +1,118 @@
<div
class="app-chrome"
:style="{'display': chrome.topChromeVisible ? '' : 'none'}"
>
<div class="app-chrome" :style="{'display': chrome.topChromeVisible ? '' : 'none'}">
<div class="app-chrome--left">
<div
class="app-chrome-item full-height"
v-if="chrome.windowControlPosition == 'left' && !chrome.nativeControls"
>
<div class="app-chrome-item full-height" v-if="chrome.windowControlPosition == 'left' && !chrome.nativeControls">
<div class="window-controls-macos">
<div class="close" @click="ipcRenderer.send('close')"></div>
<div class="minimize" @click="ipcRenderer.send('minimize')"></div>
<div
class="minmax restore"
v-if="chrome.maximized"
@click="ipcRenderer.send('maximize')"
></div>
<div class="minmax restore" v-if="chrome.maximized" @click="ipcRenderer.send('maximize')"></div>
<div class="minmax" v-else @click="ipcRenderer.send('maximize')"></div>
</div>
</div>
<div class="app-chrome-item full-height" v-else>
<button
class="app-mainmenu"
@blur="mainMenuVisibility(false)"
@click="mainMenuVisibility(true)"
:class="{active: chrome.menuOpened}"
:aria-label="$root.getLz('term.quickNav')"
></button>
<button class="app-mainmenu" @blur="mainMenuVisibility(false, true)" @click="mainMenuVisibility(true, false)"
@contextmenu="mainMenuVisibility(true, true)" :class="{active: chrome.menuOpened}"
:aria-label="$root.getLz('term.quickNav')"></button>
</div>
<template v-if="getThemeDirective('appNavigation') != 'seperate'">
<div
class="vdiv"
v-if="getThemeDirective('windowLayout') == 'twopanel'"
></div>
<div class="vdiv" v-if="getThemeDirective('windowLayout') == 'twopanel'"></div>
<div class="app-chrome-item">
<button
class="playback-button navigation"
@click="navigateBack()"
:title="$root.getLz('term.navigateBack')"
v-b-tooltip.hover
>
<button class="playback-button navigation" @click="navigateBack()" :title="$root.getLz('term.navigateBack')"
v-b-tooltip.hover>
<%- include('../svg/chevron-left.svg') %>
</button>
</div>
<div class="app-chrome-item">
<button
class="playback-button navigation"
@click="navigateForward()"
:title="$root.getLz('term.navigateForward')"
v-b-tooltip.hover
>
<button class="playback-button navigation" @click="navigateForward()"
:title="$root.getLz('term.navigateForward')" v-b-tooltip.hover>
<%- include('../svg/chevron-right.svg') %>
</button>
</div>
<div
class="vdiv display--large"
v-if="getThemeDirective('windowLayout') != 'twopanel'"
></div>
<div class="app-chrome-item" v-if="getThemeDirective('windowLayout') == 'twopanel'">
<button class="playback-button collapseLibrary" v-b-tooltip.hover
:title="chrome.sidebarCollapsed ? getLz('action.showLibrary') : getLz('action.hideLibrary')"
@click="chrome.sidebarCollapsed = !chrome.sidebarCollapsed">
<transition name="fade">
<span v-if="chrome.sidebarCollapsed"></span>
</transition>
<transition name="fade">
<span v-if="!chrome.sidebarCollapsed"></span>
</transition>
</button>
</div>
<div class="vdiv display--large" v-if="getThemeDirective('windowLayout') != 'twopanel'"></div>
</template>
<template v-if="getThemeDirective('windowLayout') != 'twopanel'">
<div class="app-chrome-item display--large">
<button
class="playback-button--small shuffle"
v-if="mk.shuffleMode == 0"
:class="isDisabled() && 'disabled'"
@click="mk.shuffleMode = 1"
:title="$root.getLz('term.enableShuffle')"
v-b-tooltip.hover
></button>
<button
class="playback-button--small shuffle active"
v-else
:class="isDisabled() && 'disabled'"
@click="mk.shuffleMode = 0"
:title="$root.getLz('term.disableShuffle')"
v-b-tooltip.hover
></button>
<button class="playback-button--small shuffle" v-if="mk.shuffleMode == 0" :class="isDisabled() && 'disabled'"
@click="mk.shuffleMode = 1" :title="$root.getLz('term.enableShuffle')" v-b-tooltip.hover></button>
<button class="playback-button--small shuffle active" v-else :class="isDisabled() && 'disabled'"
@click="mk.shuffleMode = 0" :title="$root.getLz('term.disableShuffle')" v-b-tooltip.hover></button>
</div>
<div class="app-chrome-item display--large">
<button
class="playback-button previous"
@click="prevButton()"
:class="isPrevDisabled() && 'disabled'"
:title="$root.getLz('term.previous')"
v-b-tooltip.hover
></button>
<button class="playback-button previous" @click="prevButton()" :class="isPrevDisabled() && 'disabled'"
:title="$root.getLz('term.previous')" v-b-tooltip.hover></button>
</div>
<div class="app-chrome-item display--large">
<button
class="playback-button stop"
@click="mk.stop()"
<button class="playback-button stop" @click="mk.stop()"
v-if="mk.isPlaying && mk.nowPlayingItem.attributes.playParams.kind == 'radioStation'"
:title="$root.getLz('term.stop')"
v-b-tooltip.hover
></button>
<button
class="playback-button pause"
@click="mk.pause()"
v-else-if="mk.isPlaying"
:title="$root.getLz('term.pause')"
v-b-tooltip.hover
></button>
<button
class="playback-button play"
@click="mk.play()"
v-else
:title="$root.getLz('term.play')"
v-b-tooltip.hover
></button>
:title="$root.getLz('term.stop')" v-b-tooltip.hover></button>
<button class="playback-button pause" @click="mk.pause()" v-else-if="mk.isPlaying"
:title="$root.getLz('term.pause')" v-b-tooltip.hover></button>
<button class="playback-button play" @click="mk.play()" v-else :title="$root.getLz('term.play')"
v-b-tooltip.hover></button>
</div>
<div class="app-chrome-item display--large">
<button
class="playback-button next"
@click="skipToNextItem()"
:class="isNextDisabled() && 'disabled'"
:title="$root.getLz('term.next')"
v-b-tooltip.hover
></button>
<button class="playback-button next" @click="skipToNextItem()" :class="isNextDisabled() && 'disabled'"
:title="$root.getLz('term.next')" v-b-tooltip.hover></button>
</div>
<div class="app-chrome-item display--large">
<button
class="playback-button--small repeat"
v-if="mk.repeatMode == 0"
:class="isDisabled() && 'disabled'"
@click="mk.repeatMode = 1"
:title="$root.getLz('term.enableRepeatOne')"
v-b-tooltip.hover
></button>
<button
class="playback-button--small repeat repeatOne"
@click="mk.repeatMode = 2"
:class="isDisabled() && 'disabled'"
v-else-if="mk.repeatMode == 1"
:title="$root.getLz('term.disableRepeatOne')"
v-b-tooltip.hover
></button>
<button
class="playback-button--small repeat active"
@click="mk.repeatMode = 0"
:class="isDisabled() && 'disabled'"
v-else-if="mk.repeatMode == 2"
:title="$root.getLz('term.disableRepeat')"
v-b-tooltip.hover
></button>
<button class="playback-button--small repeat" v-if="mk.repeatMode == 0" :class="isDisabled() && 'disabled'"
@click="mk.repeatMode = 1" :title="$root.getLz('term.enableRepeatOne')" v-b-tooltip.hover></button>
<button class="playback-button--small repeat repeatOne" @click="mk.repeatMode = 2"
:class="isDisabled() && 'disabled'" v-else-if="mk.repeatMode == 1"
:title="$root.getLz('term.disableRepeatOne')" v-b-tooltip.hover></button>
<button class="playback-button--small repeat active" @click="mk.repeatMode = 0"
:class="isDisabled() && 'disabled'" v-else-if="mk.repeatMode == 2" :title="$root.getLz('term.disableRepeat')"
v-b-tooltip.hover></button>
</div>
</template>
</div>
<div class="app-chrome--center">
<div
class="app-chrome-item playback-controls"
v-if="getThemeDirective('windowLayout') != 'twopanel'"
>
<div class="app-chrome-item playback-controls" v-if="getThemeDirective('windowLayout') != 'twopanel'">
<template v-if="mkReady()">
<div
class="app-playback-controls"
@mouseover="chrome.progresshover = true"
@mouseleave="chrome.progresshover = false"
@contextmenu="nowPlayingContextMenu"
>
<div class="app-playback-controls" @mouseover="chrome.progresshover = true"
@mouseleave="chrome.progresshover = false" @contextmenu="nowPlayingContextMenu">
<div class="artwork" id="artworkLCD">
<mediaitem-artwork :url="currentArtUrl"></mediaitem-artwork>
</div>
<b-popover
custom-class="mediainfo-popover"
target="artworkLCD"
triggers="hover"
placement="bottom"
>
<b-popover custom-class="mediainfo-popover" target="artworkLCD" triggers="hover" placement="bottom">
<div class="content">
<div class="shadow-artwork">
<mediaitem-artwork
:url="currentArtUrl"
:url="currentArtUrlRaw"
></mediaitem-artwork>
<mediaitem-artwork :url="currentArtUrl"></mediaitem-artwork>
</div>
<div class="popover-artwork">
<mediaitem-artwork
:size="210"
:url="currentArtUrlRaw"
></mediaitem-artwork>
<mediaitem-artwork :size="210" :url="currentArtUrl"></mediaitem-artwork>
</div>
<div class="song-name">
{{ mk.nowPlayingItem["attributes"]["name"] }}
</div>
<div
class="song-artist"
@click="getNowPlayingItemDetailed(`artist`)"
>
<div class="song-artist" @click="getNowPlayingItemDetailed(`artist`)">
{{ mk.nowPlayingItem["attributes"]["artistName"] }}
</div>
<div
class="song-album"
@click="getNowPlayingItemDetailed(`album`)"
>
<div class="song-album" @click="getNowPlayingItemDetailed(`album`)">
{{
mk.nowPlayingItem["attributes"]["albumName"]
? mk.nowPlayingItem["attributes"]["albumName"]
: ""
mk.nowPlayingItem["attributes"]["albumName"]
? mk.nowPlayingItem["attributes"]["albumName"]
: ""
}}
</div>
<hr />
<div class="btn-group" style="width: 100%">
<button
class="md-btn md-btn-small"
style="width: 100%"
@click="drawer.open = false; miniPlayer(true)"
>
<button class="md-btn md-btn-small" style="width: 100%" @click="drawer.open = false; miniPlayer(true)">
{{ $root.getLz("term.miniplayer") }}
</button>
<button
class="md-btn md-btn-small"
style="width: 100%"
@click="drawer.open = false; fullscreen(true)"
>
<button class="md-btn md-btn-small" style="width: 100%" @click="drawer.open = false; fullscreen(true)">
{{ $root.getLz("term.fullscreenView") }}
</button>
</div>
@ -219,183 +120,121 @@
</b-popover>
<div class="playback-info">
<div class="chrome-icon-container">
<div
class="audio-type private-icon"
v-if="cfg.general.privateEnabled === true"
></div>
<div
class="audio-type ppe-icon"
v-if="cfg.audio.maikiwiAudio.ciderPPE === true"
></div>
<div class="audio-type private-icon" v-if="cfg.general.privateEnabled === true"></div>
<div class="audio-type ppe-icon" v-if="cfg.audio.maikiwiAudio.ciderPPE === true"></div>
</div>
<div
class="song-name"
:class="[isElementOverflowing('#app-main > div.app-chrome > div.app-chrome--center > div > div > div.playback-info > div.song-name') ? 'marquee' : '']"
>
{{ mk.nowPlayingItem["attributes"]["name"] }}
<div
class="explicit-icon"
v-if="mk.nowPlayingItem['attributes']['contentRating'] == 'explicit'"
style="display: inline-block"
></div>
</div>
<div class="song-artist-album">
<div
class="song-artist-album-content"
:class="[isElementOverflowing('#app-main > .app-chrome .app-chrome-item > .app-playback-controls > div >.song-artist-album > .song-artist-album-content') ? 'marquee' : '']"
style="
<div class="info-rect">
<div class="song-name"
:class="[isElementOverflowing('#app-main > div.app-chrome > div.app-chrome--center > div > div > div.playback-info > div.song-name') ? 'marquee' : '']">
{{ mk.nowPlayingItem["attributes"]["name"] }}
<div class="explicit-icon" v-if="mk.nowPlayingItem['attributes']['contentRating'] == 'explicit'"
style="display: inline-block"></div>
</div>
<div class="song-artist-album">
<div class="song-artist-album-content"
:class="[isElementOverflowing('#app-main > .app-chrome .app-chrome-item > .app-playback-controls > div >.song-artist-album > .song-artist-album-content') ? 'marquee' : '']"
style="
display: inline-block;
-webkit-box-orient: horizontal;
white-space: nowrap;
"
>
<div
class="item-navigate song-artist"
style="display: inline-block"
@click="getNowPlayingItemDetailed(`artist`)"
>
{{ mk.nowPlayingItem["attributes"]["artistName"] }}
</div>
<div
class="song-artist item-navigate"
style="display: inline-block"
@click="getNowPlayingItemDetailed('album')"
v-if="mk.nowPlayingItem['attributes']['albumName'] != ''"
>
<div class="separator" style="display: inline-block">
{{ "—" }}
">
<div class="item-navigate song-artist" style="display: inline-block"
@click="getNowPlayingItemDetailed(`artist`)">
{{ mk.nowPlayingItem["attributes"]["artistName"] }}
</div>
{{
<div class="song-artist item-navigate" style="display: inline-block"
@click="getNowPlayingItemDetailed('album')"
v-if="mk.nowPlayingItem['attributes']['albumName'] != ''">
<div class="separator" style="display: inline-block">
{{ "—" }}
</div>
{{
mk.nowPlayingItem["attributes"]["albumName"]
? mk.nowPlayingItem["attributes"]["albumName"]
: ""
}}
? mk.nowPlayingItem["attributes"]["albumName"]
: ""
}}
</div>
</div>
</div>
</div>
<div class="song-progress">
<div
class="song-duration"
style="justify-content: space-between; height: 1px"
:style="[chrome.progresshover ? {'display': 'flex'} : {'display' : 'none'} ]"
>
<div class="song-duration" style="justify-content: space-between; height: 1px"
:style="[chrome.progresshover ? {'display': 'flex'} : {'display' : 'none'} ]">
<p style="width: auto">{{ convertTime(getSongProgress()) }}</p>
<p style="width: auto">
{{ convertTime(mk.currentPlaybackDuration) }}
</p>
</div>
<input
type="range"
step="0.01"
min="0"
:style="progressBarStyle()"
<input type="range" step="0.01" min="0" :style="progressBarStyle()"
@input="playerLCD.desiredDuration = $event.target.value;playerLCD.userInteraction = true"
@mouseup="mk.seekToTime($event.target.value);setTimeout(()=>{playerLCD.desiredDuration = 0;playerLCD.userInteraction = false}, 1000);"
@touchend="mk.seekToTime($event.target.value);setTimeout(()=>{playerLCD.desiredDuration = 0;playerLCD.userInteraction = false}, 1000);"
:max="mk.currentPlaybackDuration"
:value="getSongProgress()"
/>
:max="mk.currentPlaybackDuration" :value="getSongProgress()" />
</div>
</div>
<template v-if="mk.nowPlayingItem['attributes']['playParams']">
<div class="actions">
<button
class="lcdMenu"
@click="nowPlayingContextMenu"
:title="$root.getLz('term.more')"
v-b-tooltip.hover
>
<button class="lcdMenu" @click="nowPlayingContextMenu" :title="$root.getLz('term.more')"
v-b-tooltip.hover>
<div class="svg-icon"></div>
</button>
</div>
</template>
</div>
</template>
<template v-else>
<div class="app-playback-controls">
<div class="artwork" id="artworkLCD" style="pointer-events: none;">
<mediaitem-artwork :url="currentArtUrl"></mediaitem-artwork>
</div>
<div class="playback-info">
<div class="info-rect">
</div>
</div>
</div>
</template>
</div>
<div class="app-chrome-item" v-else>
<div class="top-nav-group">
<sidebar-library-item
:name="$root.getLz('home.title')"
svg-icon="./assets/feather/home.svg"
page="home"
>
<sidebar-library-item :name="$root.getLz('home.title')" svg-icon="./assets/feather/home.svg" page="home">
</sidebar-library-item>
<sidebar-library-item
:name="$root.getLz('term.listenNow')"
svg-icon="./assets/feather/play-circle.svg"
page="listen_now"
></sidebar-library-item>
<sidebar-library-item
:name="$root.getLz('term.browse')"
svg-icon="./assets/feather/globe.svg"
page="browse"
>
<sidebar-library-item :name="$root.getLz('term.listenNow')" svg-icon="./assets/feather/play-circle.svg"
page="listen_now"></sidebar-library-item>
<sidebar-library-item :name="$root.getLz('term.browse')" svg-icon="./assets/feather/globe.svg" page="browse">
</sidebar-library-item>
<sidebar-library-item :name="$root.getLz('term.radio')" svg-icon="./assets/feather/radio.svg" page="radio">
</sidebar-library-item>
<sidebar-library-item
:name="$root.getLz('term.radio')"
svg-icon="./assets/feather/radio.svg"
page="radio"
></sidebar-library-item>
</div>
</div>
</div>
<div class="app-chrome--right">
<template v-if="getThemeDirective('windowLayout') != 'twopanel'">
<div class="app-chrome-item volume display--large">
<button
class="volume-button--small volume"
@click="muteButtonPressed()"
<button class="volume-button--small volume" @click="muteButtonPressed()"
:class="{'active': this.cfg.audio.volume == 0}"
:title="cfg.audio.muted ? $root.getLz('term.unmute') : $root.getLz('term.mute')"
v-b-tooltip.hover
></button>
<input
type="range"
@wheel="volumeWheel"
:step="cfg.audio.volumeStep"
min="0"
:max="cfg.audio.maxVolume"
v-model="mk.volume"
v-if="typeof mk.volume != 'undefined'"
@change="checkMuteChange()"
v-b-tooltip.hover
:title="formatVolumeTooltip()"
/>
:title="cfg.audio.muted ? $root.getLz('term.unmute') : $root.getLz('term.mute')" v-b-tooltip.hover></button>
<input type="range" @wheel="volumeWheel" :step="cfg.audio.volumeStep" min="0" :max="cfg.audio.maxVolume"
v-model="mk.volume" v-if="typeof mk.volume != 'undefined'" @change="checkMuteChange()" v-b-tooltip.hover
:title="formatVolumeTooltip()" />
</div>
<div class="app-chrome-item generic">
<button
class="playback-button--small cast"
:title="$root.getLz('term.cast')"
<button class="playback-button--small cast" :title="$root.getLz('term.cast')"
@click="cfg.advanced.AudioContext ? modals.castMenu = true : $root.notyf.error($root.getLz('settings.warn.enableAdvancedFunctionality'))"
v-b-tooltip.hover
></button>
v-b-tooltip.hover></button>
</div>
<div class="app-chrome-item generic">
<button
class="playback-button--small queue"
:title="$root.getLz('term.queue')"
v-b-tooltip.hover
:class="{'active': drawer.panel == 'queue'}"
@click="invokeDrawer('queue')"
></button>
<button class="playback-button--small queue" :title="$root.getLz('term.queue')" v-b-tooltip.hover
:class="{'active': drawer.panel == 'queue'}" @click="invokeDrawer('queue')"></button>
</div>
<div class="app-chrome-item generic">
<template v-if="lyrics && lyrics != [] && lyrics.length > 0">
<button
class="playback-button--small lyrics"
:title="$root.getLz('term.lyrics')"
v-b-tooltip.hover
:class="{'active': drawer.panel == 'lyrics'}"
@click="invokeDrawer('lyrics')"
></button>
<button class="playback-button--small lyrics" :title="$root.getLz('term.lyrics')" v-b-tooltip.hover
:class="{'active': drawer.panel == 'lyrics'}" @click="invokeDrawer('lyrics')"></button>
</template>
<template v-else>
<button
class="playback-button--small lyrics"
:style="{'opacity': 0.3, 'pointer-events': 'none'}"
></button>
<button class="playback-button--small lyrics" :style="{'opacity': 0.3, 'pointer-events': 'none'}"></button>
</template>
</div>
</template>
@ -403,31 +242,16 @@
<div class="app-chrome-item search">
<div class="search-input-container">
<div class="search-input--icon"></div>
<input
type="search"
spellcheck="false"
@click="showSearch()"
@focus="search.showHints = true"
<input type="search" spellcheck="false" @click="showSearch()" @focus="search.showHints = true"
@blur="setTimeout(()=>{search.showHints = false}, 300)"
v-on:keyup.enter="searchQuery();search.showHints = false"
@change="showSearch();"
@input="getSearchHints()"
:placeholder="$root.getLz('term.search') + '...'"
v-model="search.term"
ref="searchInput"
class="search-input"
/>
v-on:keyup.enter="searchQuery();search.showHints = false" @change="showSearch();" @input="getSearchHints()"
:placeholder="$root.getLz('term.search') + '...'" v-model="search.term" ref="searchInput"
class="search-input" />
<div
class="search-hints-container"
v-if="search.showHints && search.hints.length != 0"
>
<div class="search-hints-container" v-if="search.showHints && search.hints.length != 0">
<div class="search-hints">
<button
class="search-hint text-overflow-elipsis"
v-for="hint in search.hints"
@click="search.term = hint;search.showHints = false;searchQuery(hint)"
>
<button class="search-hint text-overflow-elipsis" v-for="hint in search.hints"
@click="search.term = hint;search.showHints = false;searchQuery(hint)">
{{ hint }}
</button>
</div>
@ -435,32 +259,18 @@
</div>
</div>
</template>
<div
class="app-chrome-item full-height"
id="window-controls-container"
v-if="chrome.windowControlPosition == 'right' && !chrome.nativeControls"
>
<div class="app-chrome-item full-height" id="window-controls-container"
v-if="chrome.windowControlPosition == 'right' && !chrome.nativeControls">
<div class="window-controls">
<div class="minimize" @click="ipcRenderer.send('minimize')"></div>
<div
class="minmax restore"
v-if="chrome.maximized"
@click="ipcRenderer.send('maximize')"
></div>
<div class="minmax restore" v-if="chrome.maximized" @click="ipcRenderer.send('maximize')"></div>
<div class="minmax" v-else @click="ipcRenderer.send('maximize')"></div>
<div class="close" @click="ipcRenderer.send('close')"></div>
</div>
</div>
<div
class="app-chrome-item full-height"
v-else-if="platform != 'darwin' && !chrome.nativeControls"
>
<button
class="app-mainmenu"
@blur="mainMenuVisibility(false)"
@click="mainMenuVisibility(true)"
:class="{active: chrome.menuOpened}"
></button>
<div class="app-chrome-item full-height" v-else-if="platform != 'darwin' && !chrome.nativeControls">
<button class="app-mainmenu" @blur="mainMenuVisibility(false, true)" @click="mainMenuVisibility(true, false)"
@contextmenu="mainMenuVisibility(true, true)" :class="{active: chrome.menuOpened}"></button>
</div>
</div>
</div>
</div>

View file

@ -13,9 +13,6 @@
<transition name="modal">
<add-to-playlist :playlists="playlists.listing" v-if="modals.addToPlaylist"></add-to-playlist>
</transition>
<transition name="modal">
<spatial-properties v-if="modals.spatialProperties"></spatial-properties>
</transition>
<transition name="modal">
<audio-controls v-if="modals.audioControls"></audio-controls>
</transition>

View file

@ -183,136 +183,6 @@
</sidebar-playlist>
</template>
</div>
<transition name="wpfade">
<div class="usermenu-container" v-if="chrome.menuOpened">
<div class="usermenu-body">
<button
class="app-sidebar-button"
style="width: 100%"
@click="appRoute('apple-account-settings')"
>
<img
class="sidebar-user-icon"
loading="lazy"
:src="getMediaItemArtwork(chrome.hideUserInfo ? 'http://localhost:9000/assets/logocut.png' : (chrome.userinfo.attributes['artwork'] ? chrome.userinfo.attributes['artwork']['url'] : ''), 26)"
/>
<div class="sidebar-user-text" v-if="!chrome.hideUserInfo">
<template v-if="chrome.userinfo.id || mk.isAuthorized">
<div class="fullname text-overflow-elipsis">
{{
chrome.userinfo != null &&
chrome.userinfo.attributes != null
? chrome.userinfo.attributes.name ?? ""
: ""
}}
</div>
<div class="handle-text text-overflow-elipsis">
{{
chrome.userinfo != null &&
chrome.userinfo.attributes != null
? chrome.userinfo.attributes.handle ?? ""
: ""
}}
</div>
</template>
<template v-else>
<div @click="mk.authorize()">
{{ $root.getLz("term.login") }}
</div>
</template>
</div>
<div class="sidebar-user-text" v-else>
{{ $root.getLz("app.name") }}
</div>
</button>
<!-- Use 20px SVG for usermenu icon -->
<button
class="usermenu-item"
v-if="cfg.general.privateEnabled"
@click="cfg.general.privateEnabled = false"
>
<span class="usermenu-item-icon">
<%- include("../svg/x.svg") %>
</span>
<span class="usermenu-item-name">{{
$root.getLz("term.disablePrivateSession")
}}</span>
</button>
<button class="usermenu-item" @click="appRoute('remote-pair')">
<span class="usermenu-item-icon">
<%- include("../svg/smartphone.svg") %>
</span>
<span class="usermenu-item-name">{{
$root.getLz("action.showWebRemoteQR")
}}</span>
</button>
<button
class="usermenu-item"
@click="cfg.advanced.AudioContext ? modals.castMenu = true : $root.notyf.error($root.getLz('settings.warn.enableAdvancedFunctionality'))"
>
<span class="usermenu-item-icon">
<%- include("../svg/cast.svg") %>
</span>
<span class="usermenu-item-name">{{
$root.getLz("term.cast")
}}</span>
</button>
<button
class="usermenu-item"
@click="cfg.advanced.AudioContext ? modals.audioSettings = true : $root.notyf.error($root.getLz('settings.warn.enableAdvancedFunctionality'))"
>
<span class="usermenu-item-icon">
<%- include("../svg/headphones.svg") %>
</span>
<span class="usermenu-item-name">{{
$root.getLz("term.audioSettings")
}}</span>
</button>
<button
class="usermenu-item"
v-if="pluginInstalled"
@click="modals.pluginMenu = true"
>
<span class="usermenu-item-icon">
<%- include("../svg/grid.svg") %>
</span>
<span class="usermenu-item-name">{{
$root.getLz("term.plugin")
}}</span>
</button>
<button class="usermenu-item" @click="appRoute('about')">
<span class="usermenu-item-icon">
<%- include("../svg/info.svg") %>
</span>
<span class="usermenu-item-name">{{
$root.getLz("term.about")
}}</span>
</button>
<button class="usermenu-item" @click="appRoute('settings')">
<span class="usermenu-item-icon">
<%- include("../svg/settings.svg") %>
</span>
<span class="usermenu-item-name">{{
$root.getLz("term.settings")
}}</span>
</button>
<button class="usermenu-item" @click="unauthorize()">
<span class="usermenu-item-icon" style="right: 2.5px">
<%- include("../svg/log-out.svg") %>
</span>
<span class="usermenu-item-name">{{
$root.getLz("term.logout")
}}</span>
</button>
</div>
</div>
</transition>
<div class="app-sidebar-footer collapseTab" v-if="cfg.advanced.experiments.includes('collapseSidebar')">
<button @click="chrome.sidebarCollapsed = !chrome.sidebarCollapsed">
Collapse
</button>
</div>
<div class="app-sidebar-footer display--small app-sidebar-footer--controls">
<div
class="app-playback-controls"
@ -326,6 +196,7 @@
v-if="mk.shuffleMode == 0"
@click="mk.shuffleMode = 1"
:title="$root.getLz('term.enableShuffle')"
:class="$root.isDisabled() && 'disabled'"
v-b-tooltip.hover.righttop
></button>
<button
@ -333,6 +204,7 @@
v-else
@click="mk.shuffleMode = 0"
:title="$root.getLz('term.disableShuffle')"
:class="$root.isDisabled() && 'disabled'"
v-b-tooltip.hover.righttop
></button>
</div>
@ -340,31 +212,26 @@
<button
class="playback-button previous"
@click="prevButton()"
:class="$root.isPrevDisabled() && 'disabled'"
:title="$root.getLz('term.previous')"
v-b-tooltip.hover
></button>
</div>
<div class="app-chrome-item">
<button
class="playback-button pause"
@click="mk.pause()"
v-if="mk.isPlaying"
:title="$root.getLz('term.pause')"
v-b-tooltip.hover
></button>
<button
class="playback-button play"
@click="mk.play()"
v-else
:title="$root.getLz('term.play')"
v-b-tooltip.hover
></button>
<button class="playback-button stop" @click="$root.mk.stop()"
v-if="$root.mk.isPlaying && $root.mk.nowPlayingItem.attributes.playParams.kind == 'radioStation'"
:title="$root.getLz('term.stop')" v-b-tooltip.hover></button>
<button class="playback-button pause" @click="$root.mk.pause()" v-else-if="$root.mk.isPlaying"
:title="$root.getLz('term.pause')" v-b-tooltip.hover></button>
<button class="playback-button play" @click="$root.mk.play()" v-else :title="$root.getLz('term.play')"
v-b-tooltip.hover></button>
</div>
<div class="app-chrome-item">
<button
class="playback-button next"
@click="skipToNextItem()"
:title="$root.getLz('term.next')"
:class="$root.isNextDisabled() && 'disabled'"
v-b-tooltip.hover
></button>
</div>
@ -373,6 +240,7 @@
class="playback-button--small repeat"
v-if="mk.repeatMode == 0"
@click="mk.repeatMode = 1"
:class="$root.isDisabled() && 'disabled'"
:title="$root.getLz('term.enableRepeatOne')"
v-b-tooltip.hover
></button>
@ -381,6 +249,7 @@
@click="mk.repeatMode = 2"
v-else-if="mk.repeatMode == 1"
:title="$root.getLz('term.disableRepeatOne')"
:class="$root.isDisabled() && 'disabled'"
v-b-tooltip.hover
></button>
<button
@ -388,6 +257,7 @@
@click="mk.repeatMode = 0"
v-else-if="mk.repeatMode == 2"
:title="$root.getLz('term.disableRepeat')"
:class="$root.isDisabled() && 'disabled'"
v-b-tooltip.hover
></button>
</div>

View file

@ -1,13 +1,15 @@
<script type="text/x-template" id="artist-chip">
<div class="artist-chip" @click.self="route" tabindex="0">
<div class="artist-chip__image">
<mediaitem-artwork v-if="artist.id != null" :url="artist.attributes.artwork.url" :size="32"></mediaitem-artwork>
<div class="artist-chip__image" v-if="image" :style="{backgroundColor: '#' + (artist.attributes.artwork?.bgColor ?? '000')}">
<mediaitem-artwork v-if="artist.id != null" :url="artist.attributes.artwork.url" :size="80"></mediaitem-artwork>
</div>
<div class="artist-chip__image" v-else>
</div>
<div class="artist-chip__name">
<span>{{ item.attributes.name }}</span>
</div>
<button @click="$root.followArtistById(artist.id, true)" title="Follow" v-if="!$root.followingArtist(artist.id)" class="artist-chip__follow codicon codicon-add"></button>
<button @click="$root.followArtistById(artist.id, false)" title="Following" v-else class="artist-chip__follow codicon codicon-check"></button>
<button @click="$root.setArtistFavorite(artist.id, true)" title="Follow" v-if="!$root.followingArtist(artist.id)" class="artist-chip__follow codicon codicon-add"></button>
<button @click="$root.setArtistFavorite(artist.id, false)" title="Following" v-else class="artist-chip__follow codicon codicon-check"></button>
</div>
</script>
@ -21,6 +23,7 @@
},
data: function() {
return {
image: false,
artist: {
id: null
}
@ -34,6 +37,7 @@
}
app.mk.api.v3.music(`/v1/catalog/${app.mk.storefrontId}/artists/${artistId}`).then(response => {
this.artist = response.data.data[0];
this.image = true;
});
},
methods: {

View file

@ -1,6 +1,6 @@
<script type="text/x-template" id="artwork-material">
<div class="artworkMaterial">
<img :src="src" v-for="image in images"/>
<mediaitem-artwork :url="src" :size="500" v-for="image in images"/>
</div>
</script>

View file

@ -35,6 +35,16 @@
v-model="maxVolume"/>
</div>
</div>
<div class="md-option-line">
<div class="md-option-segment">
{{$root.getLz('settings.option.audio.advanced')}}
</div>
<div class="md-option-segment md-option-segment_auto">
<label>
<input type="checkbox" v-model="app.cfg.audio.advanced" switch/>
</label>
</div>
</div>
</div>
</div>
</div>

View file

@ -298,7 +298,7 @@
try {
for (var i = 0; i < 21; i++) {
CiderAudio.audioNodes.vibrantbassNode[i].gain.value = app.cfg.audio.maikiwiAudio.vibrantBass.gain[i] * (app.cfg.audio.equalizer.vibrantBass / 10);
} CiderAudio.intelliGainComp_h0_0();
} CiderAudio.intelliGainComp_n0_0();
}
catch (e) {
CiderAudio.hierarchical_loading();
@ -315,7 +315,7 @@
for (var i = 0; i < 10; i++) {
CiderAudio.audioNodes.audioBands[i].gain.value = app.cfg.audio.equalizer.gain[i] * app.cfg.audio.equalizer.mix
}
CiderAudio.intelliGainComp_h0_0();
CiderAudio.intelliGainComp_n0_0();
} catch (e) { CiderAudio.hierarchical_loading(); }
}
},
@ -323,7 +323,7 @@
if (Math.max(...app.cfg.audio.equalizer.gain) != 0) {
try {
CiderAudio.audioNodes.audioBands[i].gain.value = app.cfg.audio.equalizer.gain[i] * app.cfg.audio.equalizer.mix
CiderAudio.intelliGainComp_h0_0();
CiderAudio.intelliGainComp_n0_0();
}
catch (e) { CiderAudio.hierarchical_loading(); }
}
@ -413,7 +413,7 @@
CiderAudio.audioNodes.audioBands[i].frequency.value = app.cfg.audio.equalizer.frequencies[i]
CiderAudio.audioNodes.audioBands[i].Q.value = app.cfg.audio.equalizer.Q[i]
}
CiderAudio.intelliGainComp_h0_0();
CiderAudio.intelliGainComp_n0_0();
},
changePreset(id) {
let userPresets = app.cfg.audio.equalizer.presets

View file

@ -14,7 +14,9 @@
<div class="artwork" @click="app.fullscreen(false)">
<mediaitem-artwork
:size="600"
:url="(image ?? '').replace('{w}','600').replace('{h}','600') "
:video="video"
:videoPriority="true"
:url="(image ?? '').replace('{w}','600').replace('{h}','600')"
></mediaitem-artwork>
</div>
<div class="controls-parents">
@ -52,39 +54,40 @@
</div>
</div>
<div class="control-buttons">
<div class="app-chrome-item">
<button class="playback-button--small shuffle" v-if="app.mk.shuffleMode == 0"
@click="app.mk.shuffleMode = 1" :title="$root.getLz('term.enableShuffle')"
v-b-tooltip.hover></button>
<button class="playback-button--small shuffle active" v-else
@click="app.mk.shuffleMode = 0" :title="$root.getLz('term.disableShuffle')"
v-b-tooltip.hover></button>
</div>
<div class="app-chrome-item">
<button class="playback-button previous" @click="app.prevButton()"
:title="$root.getLz('term.previous')" v-b-tooltip.hover></button>
</div>
<div class="app-chrome-item">
<button class="playback-button pause" @click="app.mk.pause()" v-if="app.mk.isPlaying"
:title="$root.getLz('term.pause')" v-b-tooltip.hover></button>
<button class="playback-button play" @click="app.mk.play()" v-else
:title="$root.getLz('term.play')" v-b-tooltip.hover></button>
</div>
<div class="app-chrome-item">
<button class="playback-button next" @click="app.skipToNextItem()"
:title="$root.getLz('term.next')" v-b-tooltip.hover></button>
</div>
<div class="app-chrome-item">
<button class="playback-button--small repeat" v-if="app.mk.repeatMode == 0"
@click="app.mk.repeatMode = 1" :title="$root.getLz('term.enableRepeatOne')"
v-b-tooltip.hover></button>
<button class="playback-button--small repeat repeatOne" @click="app.mk.repeatMode = 2"
v-else-if="app.mk.repeatMode == 1" :title="$root.getLz('term.disableRepeatOne')"
v-b-tooltip.hover></button>
<button class="playback-button--small repeat active" @click="app.mk.repeatMode = 0"
v-else-if="app.mk.repeatMode == 2" :title="$root.getLz('term.disableRepeat')"
v-b-tooltip.hover></button>
</div>
<div class="app-chrome-item display--large">
<button class="playback-button--small shuffle" v-if="$root.mk.shuffleMode == 0" :class="$root.isDisabled() && 'disabled'"
@click="$root.mk.shuffleMode = 1" :title="$root.getLz('term.enableShuffle')" v-b-tooltip.hover></button>
<button class="playback-button--small shuffle active" v-else :class="$root.isDisabled() && 'disabled'"
@click="$root.mk.shuffleMode = 0" :title="$root.getLz('term.disableShuffle')" v-b-tooltip.hover></button>
</div>
<div class="app-chrome-item display--large">
<button class="playback-button previous" @click="$root.prevButton()" :class="$root.isPrevDisabled() && 'disabled'"
:title="$root.getLz('term.previous')" v-b-tooltip.hover></button>
</div>
<div class="app-chrome-item display--large">
<button class="playback-button stop" @click="$root.mk.stop()"
v-if="$root.mk.isPlaying && $root.mk.nowPlayingItem.attributes.playParams.kind == 'radioStation'"
:title="$root.getLz('term.stop')" v-b-tooltip.hover></button>
<button class="playback-button pause" @click="$root.mk.pause()" v-else-if="$root.mk.isPlaying"
:title="$root.getLz('term.pause')" v-b-tooltip.hover></button>
<button class="playback-button play" @click="$root.mk.play()" v-else :title="$root.getLz('term.play')"
v-b-tooltip.hover></button>
</div>
<div class="app-chrome-item display--large">
<button class="playback-button next" @click="$root.skipToNextItem()" :class="$root.isNextDisabled() && 'disabled'"
:title="$root.getLz('term.next')" v-b-tooltip.hover></button>
</div>
<div class="app-chrome-item display--large">
<button class="playback-button--small repeat" v-if="$root.mk.repeatMode == 0" :class="$root.isDisabled() && 'disabled'"
@click="$root.mk.repeatMode = 1" :title="$root.getLz('term.enableRepeatOne')" v-b-tooltip.hover></button>
<button class="playback-button--small repeat repeatOne" @click="mk.repeatMode = 2"
:class="$root.isDisabled() && 'disabled'" v-else-if="$root.mk.repeatMode == 1"
:title="$root.getLz('term.disableRepeatOne')" v-b-tooltip.hover></button>
<button class="playback-button--small repeat active" @click="$root.mk.repeatMode = 0"
:class="$root.isDisabled() && 'disabled'" v-else-if="$root.mk.repeatMode == 2" :title="$root.getLz('term.disableRepeat')"
v-b-tooltip.hover></button>
</div>
</div>
</div>
<div class="app-chrome-item volume display--large">
<div class="input-container">
@ -149,6 +152,37 @@
return {
app: this.$root,
tabMode: "lyrics",
video: null
}
},
async mounted() {
if (app.mk.nowPlayingItem._container.type == "albums") {
try {
const result = (await app.mk.api.v3.music(`/v1/catalog/${app.mk.storefrontId}/${app.mk.nowPlayingItem._container.type}/${app.mk.nowPlayingItem._container.id}`, {
"fields": "editorialArtwork,editorialVideo",
})).data.data[0].attributes?.editorialVideo?.motionDetailSquare?.video
if (result) {
this.video = result
} else {
this.video = null
}
} catch (e) {
this.video = null
e = null
}
} else if (app.mk.nowPlayingItem._container.type == "library-albums") {
try {
const result = (await app.mk.api.v3.music(`/v1/me/library/albums/${app.mk.nowPlayingItem._container.id}/catalog`
, { "fields": "editorialArtwork,editorialVideo" })).data.data[0].attributes?.editorialVideo?.motionDetailSquare?.video
if (result) {
this.video = result
} else {
this.video = null
}
} catch (e) {
e = null
this.video = null
}
}
},
beforeMount() {

View file

@ -4,8 +4,7 @@
class="cd-mediaitem-list-item"
:class="{'mediaitem-selected': app.select_hasMediaItem(guid)}"
@contextmenu="contextMenu">
<template v-if="isVisible">
<div class="artwork" v-if="showArtwork == true">
<div class="artwork" v-show="isVisible" v-if="showArtwork == true">
<mediaitem-artwork
:url="getArtwork()"
size="50"
@ -17,7 +16,6 @@
{{ item.attributes.name }}
</div>
</div>
</template>
</div>
</script>

View file

@ -6,10 +6,10 @@
<h3>{{ recom.attributes.title ? recom.attributes.title.stringForDisplay : " "}}</h3>
</div>
<div class="col-auto flex-center" v-if="recom.relationships.contents.data.length >= 10">
<button class="cd-btn-seeall" @click="app.showCollection(recom.relationships.contents, recom.attributes.title ? recom.attributes.title.stringForDisplay : '', 'listen_now')" >{{app.getLz('term.seeAll')}}</button>
<button class="cd-btn-seeall" @click="showCollection(recom)" >{{app.getLz('term.seeAll')}}</button>
</div>
</div>
<template v-if="recom.attributes.display.kind == 'MusicCoverShelf'">
<template v-if="recom.attributes.display.kind == 'MusicCoverShelf' || recom.attributes.display.kind == 'MusicCircleCoverShelf'">
<mediaitem-scroller-horizontal-large
:items="recom.relationships.contents.data.limit(10)"></mediaitem-scroller-horizontal-large>
</template>
@ -39,6 +39,10 @@
visibilityChanged: function (isVisible, entry) {
// this.isVisible = isVisible
},
showCollection: function (recom) {
console.debug(recom)
app.showCollection(recom.relationships.contents, recom.attributes.title ? recom.attributes.title.stringForDisplay : '', 'listen_now')
}
}
})
</script>

View file

@ -1,9 +1,10 @@
<script type="text/x-template" id="mediaitem-artwork">
<div class="mediaitem-artwork" @contextmenu="contextMenu" :class="[{'rounded': (type == 'artists')}, classes]" :key="url">
<div class="mediaitem-artwork" :style="awStyle" @contextmenu="contextMenu" :class="[{'rounded': (type == 'artists')}, classes]" :key="url">
<img :src="app.getMediaItemArtwork(url, size, width)"
decoding="async"
loading="lazy"
:style="{background: bgcolor}"
:style="imgStyle"
@load="imgLoaded()"
class="mediaitem-artwork--img">
<div v-if="video && getVideoPriority()" class="animatedartwork-view-box">
<animatedartwork-view :priority="getVideoPriority()" :video="video"></animatedartwork-view>
@ -50,11 +51,18 @@
},
data: function () {
return {
app:this.$root,
app: this.$root,
isVisible: false,
style: {
"box-shadow": ""
},
awStyle: {
background: this.bgcolor
},
imgStyle: {
opacity: 0,
transition: "opacity .25s linear"
},
classes: []
}
},
@ -62,6 +70,10 @@
this.getClasses()
},
methods: {
imgLoaded() {
this.imgStyle.opacity = 1
// this.awStyle.background = ""
},
contextMenu(event) {
let self = this
app.showMenuPanel({

View file

@ -16,7 +16,7 @@
@controller-click="route()"
tabindex="0"
:class="[{'mediaitem-selected': app.select_hasMediaItem(guid)}, addClasses]">
<template v-if="isVisible">
<div v-show="isVisible" class="listitem-content">
<div class="popular" v-if="!showInLibrary && item?.meta?.popularity != null && item?.meta?.popularity > 0.7"></div>
<div class="isLibrary" v-if="showLibraryStatus == true">
<div v-if="showInLibrary" :style="{display: (showInLibrary ? 'block' : 'none'), 'margin-left':'11px'}">
@ -87,7 +87,7 @@
<div class="duration" v-if="item.attributes.playCount" @dblclick="route()">
{{ item.attributes.playCount }}
</div>
</template>
</div>
</div>
</script>

View file

@ -8,8 +8,7 @@
<div v-if="reasonShown" class="reasonSP ">{{item?.meta?.reason?.stringForDisplay ?? ''}}</div>
<div style="{'--spcolor': getBgColor()}"
class="cd-mediaitem-square" :class="getClasses()" @contextmenu="getContextMenu">
<template>
<div class="artwork-container">
<div class="artwork-container" v-show="isVisible">
<div class="unavailable-overlay" v-if="unavailable">
<div class="codicon codicon-circle-slash"></div>
</div>
@ -40,6 +39,7 @@
</div>
</div>
<div class="info-rect" :class="{'info-rect-card': kind == 'card'}"
v-show="isVisible"
:style="{'--bgartwork': getArtworkUrl(size, true)}">
<div class="title"
:title="item.attributes?.name ?? (item.relationships?.contents?.data[0]?.attributes?.name ?? (item.attributes?.editorialNotes?.name ?? ''))"
@ -58,7 +58,6 @@
</div>
<div class="subtitle" v-if="getSubtitle() == '' && kind != 'card'">&nbsp;</div>
</div>
</template>
</div>
</div>
</script>
@ -88,6 +87,11 @@
default: false,
required: false
},
noScale: {
type: Boolean,
default: false,
required: false
},
'contextExt': { type: Object, required: false },
},
data: function () {
@ -252,6 +256,10 @@
},
getClasses() {
let type = []
let classes = []
if(this.noScale) {
classes.push("noscale")
}
try {
type = this.item.type
@ -264,25 +272,26 @@
}
switch (type) {
default:
return []
break;
case "editorial-elements":
case "card":
return ["mediaitem-card"]
classes.push("mediaitem-card")
break;
case "385": // editorial
return ["mediaitem-brick"]
classes.push("mediaitem-brick")
break;
case "small":
return ["mediaitem-small"]
classes.push("mediaitem-small")
break;
case "music-videos":
case "uploadedVideo":
case "uploaded-videos":
case "library-music-videos":
return "mediaitem-video";
classes.push("mediaitem-video")
break;
}
return classes
},
visibilityChanged: function (isVisible, entry) {
this.isVisible = isVisible
@ -534,19 +543,16 @@
let followActions = {
follow: {
icon: "./assets/feather/plus-circle.svg",
name: app.getLz('action.follow'),
name: app.getLz('action.favorite'),
action: () => {
self.app.cfg.home.followedArtists.push(this.item.id)
self.$root.setArtistFavorite(this.item.id, true)
}
},
unfollow: {
icon: "./assets/feather/x-circle.svg",
name: app.getLz('action.unfollow'),
name: app.getLz('action.removeFavorite'),
action: () => {
let index = self.app.cfg.home.followedArtists.indexOf(this.item.id)
if (index > -1) {
self.app.cfg.home.followedArtists.splice(index, 1)
}
self.$root.setArtistFavorite(this.item.id, false)
}
}
}

View file

@ -66,30 +66,40 @@
</div>
</div>
<div class="control-buttons">
<div class="app-chrome-item">
<button class="playback-button--small shuffle" v-if="app.mk.shuffleMode == 0"
@click="app.mk.shuffleMode = 1"></button>
<button class="playback-button--small shuffle active" v-else
@click="app.mk.shuffleMode = 0"></button>
</div>
<div class="app-chrome-item">
<button class="playback-button previous" @click="app.prevButton()"></button>
</div>
<div class="app-chrome-item">
<button class="playback-button pause" @click="app.mk.pause()" v-if="app.mk.isPlaying"></button>
<button class="playback-button play" @click="app.mk.play()" v-else></button>
</div>
<div class="app-chrome-item">
<button class="playback-button next" @click="app.skipToNextItem()"></button>
</div>
<div class="app-chrome-item">
<button class="playback-button--small repeat" v-if="app.mk.repeatMode == 0"
@click="app.mk.repeatMode = 1"></button>
<button class="playback-button--small repeat repeatOne" @click="app.mk.repeatMode = 2"
v-else-if="app.mk.repeatMode == 1"></button>
<button class="playback-button--small repeat active" @click="app.mk.repeatMode = 0"
v-else-if="app.mk.repeatMode == 2"></button>
</div>
<div class="app-chrome-item display--large">
<button class="playback-button--small shuffle" v-if="$root.mk.shuffleMode == 0" :class="$root.isDisabled() && 'disabled'"
@click="$root.mk.shuffleMode = 1" :title="$root.getLz('term.enableShuffle')" v-b-tooltip.hover></button>
<button class="playback-button--small shuffle active" v-else :class="$root.isDisabled() && 'disabled'"
@click="$root.mk.shuffleMode = 0" :title="$root.getLz('term.disableShuffle')" v-b-tooltip.hover></button>
</div>
<div class="app-chrome-item display--large">
<button class="playback-button previous" @click="$root.prevButton()" :class="$root.isPrevDisabled() && 'disabled'"
:title="$root.getLz('term.previous')" v-b-tooltip.hover></button>
</div>
<div class="app-chrome-item display--large">
<button class="playback-button stop" @click="$root.mk.stop()"
v-if="$root.mk.isPlaying && $root.mk.nowPlayingItem.attributes.playParams.kind == 'radioStation'"
:title="$root.getLz('term.stop')" v-b-tooltip.hover></button>
<button class="playback-button pause" @click="$root.mk.pause()" v-else-if="$root.mk.isPlaying"
:title="$root.getLz('term.pause')" v-b-tooltip.hover></button>
<button class="playback-button play" @click="$root.mk.play()" v-else :title="$root.getLz('term.play')"
v-b-tooltip.hover></button>
</div>
<div class="app-chrome-item display--large">
<button class="playback-button next" @click="$root.skipToNextItem()" :class="$root.isNextDisabled() && 'disabled'"
:title="$root.getLz('term.next')" v-b-tooltip.hover></button>
</div>
<div class="app-chrome-item display--large">
<button class="playback-button--small repeat" v-if="$root.mk.repeatMode == 0" :class="$root.isDisabled() && 'disabled'"
@click="$root.mk.repeatMode = 1" :title="$root.getLz('term.enableRepeatOne')" v-b-tooltip.hover></button>
<button class="playback-button--small repeat repeatOne" @click="mk.repeatMode = 2"
:class="$root.isDisabled() && 'disabled'" v-else-if="$root.mk.repeatMode == 1"
:title="$root.getLz('term.disableRepeatOne')" v-b-tooltip.hover></button>
<button class="playback-button--small repeat active" @click="$root.mk.repeatMode = 0"
:class="$root.isDisabled() && 'disabled'" v-else-if="$root.mk.repeatMode == 2" :title="$root.getLz('term.disableRepeat')"
v-b-tooltip.hover></button>
</div>
</div>
</div>
<div class="app-chrome-item volume display--large">
<div class="input-container">

View file

@ -1,355 +0,0 @@
<script type="text/x-template" id="spatial-properties">
<div class="modal-fullscreen spatialproperties-panel" @click.self="close()" @contextmenu.self="close()">
<div class="modal-window" v-if="ready">
<div class="modal-header">
<div class="modal-title">{{$root.getLz('spatial.spatialProperties')}}</div>
<button class="close-btn" @click="close()" :aria-label="$root.getLz('action.close')"></button>
</div>
<div class="modal-content">
<template v-if="roomEditType == 'dimensions'">
<div class="row">
<div class="col"><h3>{{$root.getLz('spatial.roomDimensions')}}</h3></div>
<div class="col-auto flex-center">
<button class="md-btn" @click="roomEditType = 'positions'">{{$root.getLz('spatial.setPositions')}}</button>
</div>
</div>
<div class="row">
<div class="col">
<div class="row">
<div class="col-3 flex-center">
{{$root.getLz('spatial.width')}}
</div>
<div class="col flex-center">
<input type="range" class="md-slider" min="0" max="100" @change="setRoom()" style="width: 100%;"
v-model="room_dimensions.width" step="1"/>
</div>
<div class="col-3 flex-center">
<input type="number" min="0" @change="setRoom()" style="width: 100%;text-align: center"
v-model="room_dimensions.width" step="1"/>
</div>
</div>
<div class="row">
<div class="col-3 flex-center">
{{$root.getLz('spatial.height')}}
</div>
<div class="col flex-center">
<input type="range" class="md-slider" min="0" max="100" @change="setRoom()" style="width: 100%;"
v-model="room_dimensions.height" step="1"/>
</div>
<div class="col-3 flex-center">
<input type="number" min="0" @change="setRoom()" style="width: 100%;text-align: center"
v-model="room_dimensions.height" step="1"/>
</div>
</div>
<div class="row">
<div class="col-3 flex-center">
{{$root.getLz('spatial.depth')}}
</div>
<div class="col flex-center">
<input type="range" class="md-slider" min="0" max="100" @change="setRoom()" style="width: 100%;"
v-model="room_dimensions.depth" step="1"/>
</div>
<div class="col-3 flex-center">
<input type="number" min="0" @change="setRoom()" style="width: 100%;text-align: center"
v-model="room_dimensions.depth" step="1"/>
</div>
</div>
<label v-if="!app.cfg.audio.normalization">
{{$root.getLz('spatial.gain')}}
<input type="number" min="0" @change="setRoom()" style="width: 100%;"
v-model="app.cfg.audio.spatial_properties.gain" step="0.1"/>
</label>
</div>
<div class="col visual-container">
<div class="visual" :style="objectContainerStyle()">
<div class="face" :style="[faceStyle()]"></div>
<div class="face" :style="[faceStyle(), topFaceStyle()]"></div>
</div>
</div>
</div>
</template>
<template v-if="roomEditType == 'positions'">
<div class="row">
<div class="col"><h3>{{$root.getLz('spatial.roomPositions')}}</h3></div>
<div class="col-auto flex-center">
<button class="md-btn" @click="roomEditType = 'dimensions'">{{$root.getLz('spatial.setDimensions')}}</button>
</div>
</div>
<div class="row">
<div class="col">
<div class="row">
<div class="col-3 flex-center">
X ({{$root.getLz('spatial.listener')}})
</div>
<div class="col flex-center">
<input type="range" class="md-slider" min="0" max="100" @change="setRoom()" style="width: 100%;"
v-model="listener_position[0]" step="1"/>
</div>
<div class="col-3 flex-center">
<input type="number" min="0" @change="setRoom()" style="width: 100%;text-align: center"
v-model="listener_position[0]" step="1"/>
</div>
</div>
<div class="row">
<div class="col-3 flex-center">
Y ({{$root.getLz('spatial.listener')}})
</div>
<div class="col flex-center">
<input type="range" class="md-slider" min="0" max="100" @change="setRoom()" style="width: 100%;"
v-model="listener_position[1]" step="1"/>
</div>
<div class="col-3 flex-center">
<input type="number" min="0" @change="setRoom()" style="width: 100%;text-align: center"
v-model="listener_position[1]" step="1"/>
</div>
</div>
<div class="row">
<div class="col-3 flex-center">
Z ({{$root.getLz('spatial.listener')}})
</div>
<div class="col flex-center">
<input type="range" class="md-slider" min="0" max="100" @change="setRoom()" style="width: 100%;"
v-model="listener_position[2]" step="1"/>
</div>
<div class="col-3 flex-center">
<input type="number" min="0" @change="setRoom()" style="width: 100%;text-align: center"
v-model="listener_position[2]" step="1"/>
</div>
</div>
<div class="row">
<div class="col-3 flex-center">
X ({{$root.getLz('spatial.audioSource')}})
</div>
<div class="col flex-center">
<input type="range" class="md-slider" min="0" max="100" @change="setRoom()" style="width: 100%;"
v-model="audio_position[0]" step="1"/>
</div>
<div class="col-3 flex-center">
<input type="number" min="0" @change="setRoom()" style="width: 100%;text-align: center"
v-model="audio_position[0]" step="1"/>
</div>
</div>
<div class="row">
<div class="col-3 flex-center">
Y ({{$root.getLz('spatial.audioSource')}})
</div>
<div class="col flex-center">
<input type="range" class="md-slider" min="0" max="100" @change="setRoom()" style="width: 100%;"
v-model="audio_position[1]" step="1"/>
</div>
<div class="col-3 flex-center">
<input type="number" min="0" @change="setRoom()" style="width: 100%;text-align: center"
v-model="audio_position[1]" step="1"/>
</div>
</div>
<div class="row">
<div class="col-3 flex-center">
Z ({{$root.getLz('spatial.audioSource')}})
</div>
<div class="col flex-center">
<input type="range" class="md-slider" min="0" max="100" @change="setRoom()" style="width: 100%;"
v-model="audio_position[2]" step="1"/>
</div>
<div class="col-3 flex-center">
<input type="number" min="0" @change="setRoom()" style="width: 100%;text-align: center"
v-model="audio_position[2]" step="1"/>
</div>
</div>
</div>
<div class="col visual-container">
<div class="visual">
<div class="face" :style="[faceStyle()]"></div>
<div class="face" :style="[faceStyle(), topFaceStyle()]"></div>
<!-- <div class="listener" :style="[listenerStyle()]">L</div> -->
<!-- <div class="audiosource" :style="[audioSourceStyle()]">A</div> -->
</div>
</div>
</div>
</template>
<div class="row">
<div class="col"><h3>{{$root.getLz('spatial.roomMaterials')}}</h3></div>
</div>
<div class="row">
<div class="col"></div>
<div class="col flex-center">
<label>
{{$root.getLz('spatial.up')}}
<select class="md-select" @change="setRoom()"
v-model="room_materials.up">
<option v-for="prop in roomProps" :value="prop">{{ prop }}</option>
</select>
</label>
</div>
<div class="col"></div>
</div>
<div class="row">
<div class="col flex-center">
<label>
{{$root.getLz('spatial.left')}}
<select class="md-select" @change="setRoom()"
v-model="room_materials.left">
<option v-for="prop in roomProps" :value="prop">{{ prop }}</option>
</select>
</label>
</div>
<div class="col flex-center">
<label>
{{$root.getLz('spatial.front')}}
<select class="md-select" @change="setRoom()"
v-model="room_materials.front">
<option v-for="prop in roomProps" :value="prop">{{ prop }}</option>
</select>
</label>
<label>
{{$root.getLz('spatial.back')}}
<select class="md-select" @change="setRoom()"
v-model="room_materials.back">
<option v-for="prop in roomProps" :value="prop">{{ prop }}</option>
</select>
</label>
</div>
<div class="col flex-center">
<label>
{{$root.getLz('spatial.right')}}
<select class="md-select" @change="setRoom()"
v-model="room_materials.right">
<option v-for="prop in roomProps" :value="prop">{{ prop }}</option>
</select>
</label>
</div>
</div>
<div class="row">
<div class="col"></div>
<div class="col flex-center">
<label>
{{$root.getLz('spatial.down')}}
<select class="md-select" @change="setRoom()"
v-model="room_materials.down">
<option v-for="prop in roomProps" :value="prop">{{ prop }}</option>
</select>
</label>
</div>
<div class="col"></div>
</div>
</div>
</div>
</div>
</script>
<script>
Vue.component('spatial-properties', {
template: '#spatial-properties',
data: function () {
return {
app: this.$root,
room_dimensions: null,
room_materials: null,
listener_position: null,
audio_position: null,
roomEditType: "dimensions",
roomProps: [
'transparent',
'acoustic-ceiling-tiles',
'brick-bare',
'brick-painted',
'concrete-block-coarse',
'concrete-block-painted',
'curtain-heavy',
'fiber-glass-insulation',
'glass-thin',
'glass-thick',
'grass',
'linoleum-on-concrete',
'marble',
'metal',
'parquet-on-concrete',
'plaster-smooth',
'plywood-panel',
'polished-concrete-or-tile',
'sheetrock',
'water-or-ice-surface',
'wood-ceiling',
'wood-panel',
'uniform'
],
visualMultiplier: 4,
ready: false
}
},
props: {},
mounted() {
this.room_dimensions = JSON.parse(JSON.stringify(this.$root.cfg.audio.spatial_properties.room_dimensions))
this.room_materials = JSON.parse(JSON.stringify(this.$root.cfg.audio.spatial_properties.room_materials))
this.audio_position = JSON.parse(JSON.stringify(this.$root.cfg.audio.spatial_properties.audio_position))
this.listener_position = JSON.parse(JSON.stringify(this.$root.cfg.audio.spatial_properties.listener_position))
if (typeof this.app.mk.nowPlayingItem != "undefined") {
this.setRoom()
}
this.ready = true
},
methods: {
listenerStyle() {
let style = {
transform: `rotateX(60deg) rotateZ(-45deg) translateX(${this.listener_position[0]}px) translateY(${this.listener_position[2]}px) translateZ(${100 + +this.listener_position[1]}px)`
}
return style
},
audioSourceStyle() {
let style = {
transform: `rotateX(60deg) rotateZ(-45deg) translateX(${this.audio_position[0]}px) translateY(${this.audio_position[2]}px) translateZ(${100 + +this.audio_position[1]}px)`
}
return style
},
topFaceStyle() {
let style = {
transform: `rotateX(60deg) rotateZ(-45deg) translateZ(${this.room_dimensions.height * this.visualMultiplier}px)`
}
return style
},
objectContainerStyle() {
let scale = 1
if (this.room_dimensions.width * this.visualMultiplier > 300) {
scale = 300 / (this.room_dimensions.width * this.visualMultiplier)
}
let style = {
transform: `scale(${scale})`
}
return style
},
faceStyle() {
let style = {
width: `${this.room_dimensions.width * this.visualMultiplier}px`,
height: `${this.room_dimensions.depth * this.visualMultiplier}px`,
}
return style
},
close() {
this.$root.cfg.audio.spatial_properties.room_dimensions = this.room_dimensions
this.$root.cfg.audio.spatial_properties.room_materials = this.room_materials
this.$root.cfg.audio.spatial_properties.audio_position = this.audio_position
this.$root.cfg.audio.spatial_properties.listener_position = this.listener_position
app.resetState()
},
setRoom() {
window.CiderAudio.audioNodes.spatialNode.setRoomProperties(this.room_dimensions, this.room_materials);
CiderAudio.audioNodes.spatialInput.setPosition(...this.audio_position)
CiderAudio.audioNodes.spatialNode.setListenerPosition(...this.listener_position)
if (!this.app.cfg.audio.normalization) {
window.CiderAudio.audioNodes.gainNode.gain.value = app.cfg.audio.spatial_properties.gain
}
}
}
});
</script>

View file

@ -58,6 +58,12 @@
#LOADER>svg {
width: 128px;
}
@media (prefers-color-scheme: light) {
#LOADER {
background-color: #eee;
}
}
</style>
</head>
@ -65,7 +71,7 @@
<div id="LOADER">
<%- include("../assets/cider-round.svg") %>
</div>
<div id="app" :class="getAppClasses()" :window-style="cfg.visual.directives.windowLayout">
<div id="app" :class="getAppClasses()" :style="getAppStyle()" :library-visbile="(chrome.sidebarCollapsed ? 0 : 1)" :window-style="cfg.visual.directives.windowLayout">
<transition name="fsModeSwitch">
<div id="app-main" v-show="appMode == 'player'">
<%- include('app/chrome-top'); %>
@ -85,6 +91,11 @@
</mini-view>
</div>
</transition>
<transition name="fsModeSwitch">
<div class="fullscreen-view-container oobe" v-if="appMode == 'oobe'">
<cider-oobe></cider-oobe>
</div>
</transition>
<%- include('app/panels'); %>
<div class="cursor" v-if="chrome.showCursor"></div>
</div>
@ -94,7 +105,8 @@
<% } %>
<script async src="https://js-cdn.music.apple.com/musickit/v2/amp/musickit.js"></script>
<script async src="<%- (env.useV3 ? "https://js-cdn.music.apple.com/musickit/v3/amp/musickit.js" : "https://js-cdn.music.apple.com/musickit/v2/amp/musickit.js" ) %>" data-web-components>
</script>
<script src="index.js?v=1"></script>
<script type="text/x-template" id="am-musiccovershelf">
@ -104,7 +116,7 @@
<!-- Sidebar Item -->
<script type="text/x-template" id="sidebar-library-item">
<button class="app-sidebar-item"
:class="$parent.getSidebarItemClass(page)" @click="$root.appRoute(page)">
:class="$parent.getSidebarItemClass(page)" @click="$root.setWindowHash(page)">
<div class="sidebar-icon" v-html="svgIconData" v-if="svgIconData != ''"></div>
{{ name }}
</button>

View file

@ -7,6 +7,10 @@
<div class="col nopadding">
<h3>{{app.getLz('home.followedArtists')}}</h3>
</div>
<div class="col-auto nopadding flex-center">
<button class="cd-btn-seeall" @click="syncFavorites()" v-if="!syncingFavs">{{app.getLz('home.syncFavorites')}}</button>
<div class="spinner" style="height: 26px;" v-else></div>
</div>
</div>
<vue-horizontal>
<div v-for="artist in artists" style="margin: 6px;">
@ -14,7 +18,7 @@
<button @click="unfollow(artist.id)" class="md-btn md-btn-glyph" style="display:flex;">
<div class="sidebar-icon">
<div class="svg-icon" :style="{'--url': 'url(./assets/feather/x-circle.svg)'}"></div>
</div> {{app.getLz('action.unfollow')}}
</div> {{app.getLz('action.removeFavorite')}}
</button>
</div>
</vue-horizontal>
@ -53,7 +57,8 @@
app: this.$root,
followedArtists: this.$root.cfg.home.followedArtists,
artistFeed: [],
artists: []
artists: [],
syncingFavs: false
}
},
async mounted() {
@ -61,7 +66,13 @@
await this.getArtistFeed()
},
methods: {
unfollow(id) {
async syncFavorites() {
this.syncingFavs = true
await app.syncFavorites()
await this.getArtistFeed()
this.syncingFavs = false
},
async unfollow(id) {
let index = this.followedArtists.indexOf(id)
if (index > -1) {
this.followedArtists.splice(index, 1)
@ -71,6 +82,16 @@
if (index2 > -1) {
this.artists.splice(index2, 1)
}
await app.mk.api.v3.music(`/v1/me/favorites`, {
"art[url]": "f",
"ids[artists]": id,
"l": app.mklang,
"platform": "web"
}, {
fetchOptions: {
method: "DELETE"
}
})
this.getArtistFeed()
},
async getArtistFeed() {
@ -78,7 +99,7 @@
let self = this
this.artists = []
this.artistFeed = []
// Apple limits the number of IDs we can provide in a single API call to 50.
// Divide it into groups of 50 and send parallel requests
let chunks = []

View file

@ -1,20 +1,22 @@
<script type="text/x-template" id="cider-artist">
<div class="content-inner artist-page" :class="[data.attributes.editorialVideo && (data.attributes.editorialVideo.motionArtistWide16x9 || data.attributes.editorialVideo.motionArtistFullscreen16x9) ? 'animated' : '']">
<div class="content-inner artist-page"
:class="[(data.attributes.editorialVideo && (data.attributes.editorialVideo.motionArtistWide16x9 || data.attributes.editorialVideo.motionArtistFullscreen16x9) || hasHero()) ? 'animated' : '']">
<div class="artist-header" :key="data.id" v-observe-visibility="{callback: isHeaderVisible}">
<animatedartwork-view
:priority="true"
v-if="data.attributes.editorialVideo && (data.attributes.editorialVideo.motionArtistWide16x9 || data.attributes.editorialVideo.motionArtistFullscreen16x9)"
v-if="hasAnimated()"
:video="data.attributes.editorialVideo.motionArtistWide16x9.video ?? (data.attributes.editorialVideo.motionArtistFullscreen16x9.video ?? '')">
</animatedartwork-view>
<div class="header-content" style="pointer-events: all;">
<div class="row">
<div class="col-sm" style="width: auto;">
<div class="artist-image" v-if="!(data.attributes.editorialVideo && (data.attributes.editorialVideo.motionArtistWide16x9 || data.attributes.editorialVideo.motionArtistFullscreen16x9))">
<div class="artist-image"
v-if="!(data.attributes.editorialVideo && (data.attributes.editorialVideo.motionArtistWide16x9 || data.attributes.editorialVideo.motionArtistFullscreen16x9))&& !hasHero()">
<mediaitem-artwork
shadow="large"
:url="data.attributes.artwork ? data.attributes.artwork.url : ''"
size="190" type="artists"></mediaitem-artwork>
<button class="overlay-play" @click="app.mk.setStationQueue({artist:'a-'+data.id}).then(()=>{
<button class="overlay-play" @click="app.mk.setStationQueue({artist:'a-'+data.id}).then(()=>{
app.mk.play()
})" :aria-label="app.getLz('term.play')">
<%- include("../svg/play.svg") %>
@ -22,7 +24,7 @@
</div>
</div>
<div class="col flex-center artist-title"
:class="{'artist-animation-on': (data.attributes.editorialVideo && (data.attributes.editorialVideo.motionArtistWide16x9 || data.attributes.editorialVideo.motionArtistFullscreen16x9)) }"
:class="{'artist-animation-on': (data.attributes.editorialVideo && (data.attributes.editorialVideo.motionArtistWide16x9 || data.attributes.editorialVideo.motionArtistFullscreen16x9)) || hasHero() }"
>
<button class="artist-play" @click="app.mk.setStationQueue({artist:'a-'+data.id}).then(()=>{
app.mk.play()
@ -30,15 +32,25 @@
<h1>{{ data.attributes.name }}</h1>
</div>
</div>
<button class="more-btn-round" @click="artistMenu" style="pointer-events: all;" :aria-label="app.getLz('term.more')">
<button class="more-btn-round favorite" @click="artistMenu" style="pointer-events: all;"
:aria-label="app.getLz('term.more')">
<div class="svg-icon"></div>
</button>
<button class="more-btn-round menu" @click="artistMenu" style="pointer-events: all;"
:aria-label="app.getLz('term.more')">
<div class="svg-icon"></div>
</button>
</div>
<div class="artworkContainer" v-if="!(data.attributes.editorialVideo && (data.attributes.editorialVideo.motionArtistWide16x9 || data.attributes.editorialVideo.motionArtistFullscreen16x9))">
<artwork-material :url="data.attributes.artwork.url" size="190" images="1"></artwork-material>
<div class="artworkContainer"
v-if="!(data.attributes.editorialVideo && (data.attributes.editorialVideo.motionArtistWide16x9 || data.attributes.editorialVideo.motionArtistFullscreen16x9)) && !hasHero()">
<artwork-material :url="data.attributes.artwork.url" size="190" images="1"></artwork-material>
</div>
<div class="artist-hero" v-if="hasHero() && !hasAnimated()">
<mediaitem-artwork shadow="none" :url="hasHero()" size="2048" />
</div>
</div>
<div class="floating-header" :style="{opacity: (headerVisible ? 0 : 1),'pointer-events': (headerVisible ? 'none' : '')}">
<div class="floating-header"
:style="{opacity: (headerVisible ? 0 : 1),'pointer-events': (headerVisible ? 'none' : '')}">
<div class="row">
<div class="col-auto flex-center">
<button class="artist-play" style="display:block;" @click="app.mk.setStationQueue({artist:'a-'+data.id}).then(()=>{
@ -49,7 +61,7 @@
<h3>{{ data.attributes.name }}</h3>
</div>
<div class="col-auto flex-center">
<button class="more-btn-round" @click="artistMenu" :aria-label="app.getLz('term.more')">
<button class="more-btn-round menu" @click="artistMenu" :aria-label="app.getLz('term.more')">
<div class="svg-icon"></div>
</button>
</div>
@ -60,8 +72,8 @@
<div class="latestRelease" v-if="data.views['latest-release'].data.length != 0">
<h3>{{app.getLz('term.latestReleases')}}</h3>
<div style="width: auto;margin: 0 auto;">
<mediaitem-square kind="card" v-for="song in data.views['latest-release'].data"
:item="song">
<mediaitem-square kind="card" :no-scale="true" v-for="song in data.views['latest-release'].data"
:item="song">
</mediaitem-square>
</div>
</div>
@ -70,8 +82,12 @@
<div class="col" style="padding:0;">
<h3>{{app.getLz('term.topSongs')}}</h3>
</div>
<div class="col-auto flex-center" v-if="data.views['top-songs'].data.length >= 20" style="padding:0;">
<button class="cd-btn-seeall" @click="app.showArtistView(data.id, data.attributes.name + ' - Top Songs', 'top-songs')">{{app.getLz('term.seeAll')}}</button>
<div class="col-auto flex-center" v-if="data.views['top-songs'].data.length >= 20"
style="padding:0;">
<button class="cd-btn-seeall"
@click="app.showArtistView(data.id, data.attributes.name + ' - Top Songs', 'top-songs')">
{{app.getLz('term.seeAll')}}
</button>
</div>
</div>
<div class="row">
@ -96,23 +112,27 @@
</h3>
</div>
<div class="col-auto flex-center" v-if="data.views[view].data.length >= 10">
<button class="cd-btn-seeall" @click="app.showArtistView(data.id, data.attributes.name + ' - ' + data.views[view].attributes.title, view)">{{app.getLz('term.seeAll')}}</button>
<button class="cd-btn-seeall"
@click="app.showArtistView(data.id, data.attributes.name + ' - ' + data.views[view].attributes.title, view)">
{{app.getLz('term.seeAll')}}
</button>
</div>
</div>
<template v-if="!((data.views[view].attributes.title ?
data.views[view].attributes.title : '???').includes('Video') || (data.views[view].attributes.title ?
data.views[view].attributes.title : '???').includes('More To See'))">
<mediaitem-scroller-horizontal-large :items="data.views[view].data.limit(10)">
</mediaitem-scroller-horizontal-large>
<mediaitem-scroller-horizontal-large :items="data.views[view].data.limit(10)">
</mediaitem-scroller-horizontal-large>
</template>
<template v-else>
<mediaitem-scroller-horizontal-mvview
:items="data.views[view].data.limit(10)"></mediaitem-scroller-horizontal-mvview>
:items="data.views[view].data.limit(10)"></mediaitem-scroller-horizontal-mvview>
</template>
</template>
<div class="row">
<div class="col" v-if="data.attributes.artistBio">
<h3>{{ $root.stringTemplateParser($root.getLz('term.aboutArtist'), {"artistName": data.attributes.name}) }}</h3>
<h3>{{ $root.stringTemplateParser($root.getLz('term.aboutArtist'), {"artistName":
data.attributes.name}) }}</h3>
<p v-html="data.attributes.artistBio"></p>
</div>
<div class="col">
@ -147,24 +167,40 @@
}
},
methods: {
hasAnimated() {
if(this.data.attributes?.editorialVideo && (this.data.attributes?.editorialVideo?.motionArtistWide16x9 || this.data.attributes?.editorialVideo?.motionArtistFullscreen16x9)) {
return true;
}
return false;
},
hasHero() {
if(this.data.attributes?.editorialArtwork?.centeredFullscreenBackground){
return this.data.attributes?.editorialArtwork?.centeredFullscreenBackground.url
} else if(this.data.attributes?.editorialArtwork?.bannerUber) {
return this.data.attributes?.editorialArtwork?.bannerUber.url
}else if(this.data.attributes?.editorialArtwork?.subscriptionHero){
return this.data.attributes?.editorialArtwork?.subscriptionHero.url
}
return false;
},
isHeaderVisible(visible) {
this.headerVisible = visible
},
artistMenu (event) {
async artistMenu(event) {
let self = this
let followAction = "follow"
let followActions = {
follow: {
icon: "./assets/feather/plus-circle.svg",
name: app.getLz('action.follow'),
action: ()=>{
action: () => {
self.app.cfg.home.followedArtists.push(self.data.id)
}
},
unfollow: {
icon: "./assets/feather/x-circle.svg",
name: app.getLz('action.unfollow'),
action: ()=>{
action: () => {
let index = self.app.cfg.home.followedArtists.indexOf(self.data.id)
if (index > -1) {
self.app.cfg.home.followedArtists.splice(index, 1)
@ -172,25 +208,45 @@
}
}
}
let favoriteActions = {
favorite: {
icon: "./assets/star.svg",
name: app.getLz('action.favorite'),
action: () => {
app.setArtistFavorite(app.artistPage.data.id, true)
}
},
removeFavorite: {
icon: "./assets/star.svg",
name: app.getLz('action.removeFavorite'),
action: () => {
app.setArtistFavorite(app.artistPage.data.id, false)
}
}
}
if (this.app.cfg.home.followedArtists.includes(self.data.id)) {
followAction = "unfollow"
}
const inFavorites = (await app.mk.api.v3.music(`/v1/catalog/${app.mk.storefrontId}/artists/${app.artistPage.data.id}`, {
"fields[artists]": "inFavorites"
})).data.data[0].attributes?.inFavorites
app.showMenuPanel({
items: [
{
icon: "./assets/feather/play.svg",
name: app.getLz('action.startRadio'),
action: ()=>{
app.mk.setStationQueue({artist:self.data.id}).then(()=>{
action: () => {
app.mk.setStationQueue({artist: self.data.id}).then(() => {
app.mk.play()
})
}
},
followActions[followAction],
favoriteActions[inFavorites ? "removeFavorite" : "favorite"],
// followActions[followAction],
{
icon: "./assets/feather/share.svg",
name: app.getLz('term.share'),
action: ()=>{
action: () => {
self.app.copyToClipboard(self.data.attributes.url)
}
}

View file

@ -35,10 +35,12 @@
<select class="md-select" style="width:180px;"
v-model="app.cfg.audio.maikiwiAudio.ciderPPE_value"
v-on:change="CiderAudio.hierarchical_loading()">
<option value="MAIKIWI">Maikiwi</option>
<option value="MAIKIWI">Maikiwi ({{$root.getLz('settings.option.audio.enableAdvancedFunctionality.ciderPPEStrength.adaptive')}})</option>
<option value="MAIKIWI_LEGACY">Maikiwi ({{$root.getLz('settings.option.audio.enableAdvancedFunctionality.ciderPPEStrength.legacy')}})</option>
<option value="NATURAL">
{{$root.getLz('settings.option.audio.enableAdvancedFunctionality.ciderPPEStrength.standard')}}
</option>
<option value="LEGACY">{{$root.getLz('settings.option.audio.enableAdvancedFunctionality.ciderPPEStrength.legacy')}}</option>
</select>
</div>
</div>
@ -100,7 +102,7 @@
</div>
<div class="md-option-segment md-option-segment_auto">
<input type="checkbox" v-model="app.cfg.audio.maikiwiAudio.spatial"
v-on:change="toggleMaikiwiSpatial" switch/>
v-on:change="CiderAudio.hierarchical_loading();" switch/>
</div>
</div>
<div class="md-option-line"
@ -113,7 +115,7 @@
<div class="md-option-segment md-option-segment_auto">
<select class="md-select" style="width:180px;"
v-model="$root.cfg.audio.maikiwiAudio.spatialProfile"
v-on:change="toggleMaikiwiSpatial">
v-on:change="CiderAudio.hierarchical_loading();">
<option v-for="profile in spprofiles" :value="profile.id">{{ getProfileLz("CTS", profile.name) }}</option>
</select>
</div>
@ -170,11 +172,10 @@
},
methods: {
getProfileLz(type, name) {
let result = "";
// Hard-coded shiz
switch (name) {
case "CRYPTO":
return "Cryptofyre";
break;
case "Maikiwi":
return "Maikiwi";
break;
@ -183,43 +184,33 @@
return "Maikiwi+";
break;
case "Minimal+":
return this.$root.getLz('settings.option.audio.enableAdvancedFunctionality.tunedAudioSpatialization.profile.minimal') + "+";
break;
case "live":
return "LIVE";
break;
}
}
switch (type) {
case "CAR":
return this.$root.getLz('settings.option.audio.enableAdvancedFunctionality.atmosphereRealizerMode.' + name);
result = this.$root.getLz('settings.option.audio.enableAdvancedFunctionality.atmosphereRealizerMode.' + name);
if (result === "settings.option.audio.enableAdvancedFunctionality.atmosphereRealizerMode." + name) {
return name;
}
else {return result;}
break;
case "CTS":
return this.$root.getLz('settings.option.audio.enableAdvancedFunctionality.tunedAudioSpatialization.profile.' + name.toLowerCase());
result = this.$root.getLz('settings.option.audio.enableAdvancedFunctionality.tunedAudioSpatialization.profile.' + name.toLowerCase());
if (result === "settings.option.audio.enableAdvancedFunctionality.tunedAudioSpatialization.profile." + name.toLowerCase()) {
return name;
}
else {return result;}
break;
default:
return name;
}
},
toggleSpatial: function () {
if (app.cfg.audio.maikiwiAudio.spatial) {
CiderAudio.spatialOn()
CiderAudio.hierarchical_loading();
} else {
CiderAudio.spatialOff()
}
},
toggleMaikiwiSpatial: function () {
if (app.cfg.audio.maikiwiAudio.spatial === true) {
CiderAudio.spatialOn()
CiderAudio.hierarchical_loading();
//let normalized = Math.pow(10, (((Math.log10(app.mk.volume) * 20) - 14) / 20));
//app.mk.volume = normalized
// -13dBFS Target
} else {
//let normalized = Math.pow(10, (((Math.log10(app.mk.volume) * 20) + 14) / 20));
//app.mk.volume = normalized
CiderAudio.spatialOn()
CiderAudio.hierarchical_loading();
}
},
}
}
})
</script>

View file

@ -0,0 +1,133 @@
<script type="text/x-template" id="cider-charts">
<div class="content-inner">
<h1 class="header-text">{{$root.getLz("term.charts")}}</h1>
<template v-if="songs != []">
<div class="row">
<div class="col">
<h3>{{ songs.name ?? ""}}</h3>
</div>
<div class="col-auto flex-center" v-if="songs.data.length > 12">
<button class="cd-btn-seeall" @click="app.showCollection((songs ?? []), songs.name ?? '', 'default')" >{{app.getLz('term.seeAll')}}</button>
</div>
</div>
<div class="mediaitem-list-item__grid">
<listitem-horizontal :items="(songs?.data ?? []).limit(12)">
</listitem-horizontal>
</div>
</template>
<template v-if="albums != []">
<div class="row">
<div class="col">
<h3>{{ albums.name ?? ""}}</h3>
</div>
<div class="col-auto flex-center" v-if="songs.data.length > 12">
<button class="cd-btn-seeall" @click="app.showCollection((albums ?? []), albums.name ?? '', 'default')" >{{app.getLz('term.seeAll')}}</button>
</div>
</div>
<mediaitem-scroller-horizontal-large
:items="(albums?.data ?? []).limit(10)"></mediaitem-scroller-horizontal-large>
</template>
<template v-if="playlists != []">
<div class="row">
<div class="col">
<h3>{{ playlists.name ?? ""}}</h3>
</div>
<div class="col-auto flex-center" v-if="playlists.data.length > 12">
<button class="cd-btn-seeall" @click="app.showCollection((playlists ?? []), playlists.name ?? '', 'default')" >{{app.getLz('term.seeAll')}}</button>
</div>
</div>
<mediaitem-scroller-horizontal-large
:items="(playlists?.data ?? []).limit(10)"></mediaitem-scroller-horizontal-large>
</template>
<template v-if="musicvideos != []">
<div class="row">
<div class="col">
<h3>{{ musicvideos.name ?? ""}}</h3>
</div>
<div class="col-auto flex-center" v-if="musicvideos.data.length > 12">
<button class="cd-btn-seeall" @click="app.showCollection((musicvideos ?? []), musicvideos.name ?? '', 'default')" >{{app.getLz('term.seeAll')}}</button>
</div>
</div>
<mediaitem-scroller-horizontal-large
:items="(musicvideos?.data ?? []).limit(10)"></mediaitem-scroller-horizontal-large>
</template>
<template v-if="globalcharts != []">
<div class="row">
<div class="col">
<h3>{{ globalcharts.name ?? ""}}</h3>
</div>
<div class="col-auto flex-center" v-if="globalcharts.data.length > 12">
<button class="cd-btn-seeall" @click="app.showCollection((globalcharts ?? []), globalcharts.name ?? '', 'default')" >{{app.getLz('term.seeAll')}}</button>
</div>
</div>
<mediaitem-scroller-horizontal-large
:items="(globalcharts?.data ?? []).limit(10)"></mediaitem-scroller-horizontal-large>
</template>
<template v-if="citycharts != []">
<div class="row">
<div class="col">
<h3>{{ citycharts.name ?? ""}}</h3>
</div>
<div class="col-auto flex-center" v-if="citycharts.data.length > 12">
<button class="cd-btn-seeall" @click="app.showCollection((citycharts ?? []), citycharts.name ?? '', 'default')" >{{app.getLz('term.seeAll')}}</button>
</div>
</div>
<mediaitem-scroller-horizontal-large
:items="(citycharts?.data ?? []).limit(10)"></mediaitem-scroller-horizontal-large>
</template>
</div>
</script>
<script>
Vue.component('cider-charts', {
template: "#cider-charts",
data: function () {
return {
app: this.$root,
songs: [],
albums: [],
playlists: [],
musicvideos: [],
citycharts: [],
globalcharts: [],
categories: [],
}
},
mounted() {
this.getData();
},
methods: {
getData() {
let self = this;
app.mk.api.v3.music(`/v1/catalog/${app.mk.storefrontId}/charts`, {
types: 'albums,songs,music-videos,playlists',
l: 'en-gb',
platform: 'auto',
limit: '50',
genre: '34',
include: 'tracks',
with: 'cityCharts,dailyGlobalTopCharts',
extend: 'artistUrl',
'fields[albums]': 'artistName,artistUrl,artwork,contentRating,editorialArtwork,name,playParams,releaseDate,url',
'fields[playlists]': 'artistName,artistUrl,artwork,contentRating,editorialArtwork,name,playParams,releaseDate,url,curatorName'
}).then(res => {
let page = res.data?.results ?? [];
self.songs = page.songs[0] ?? [];
self.albums = page.albums[0] ?? [];
self.playlists = page.playlists[0] ?? [];
self.musicvideos = page['music-videos'][0] ?? [];
self.citycharts = page.cityCharts[0] ?? [];
self.globalcharts = page.dailyGlobalTopCharts[0] ?? [];
})
// let self = this;
// app.mk.api.music(`/v1/catalog/${app.mk.storefrontId}/charts?types=songs%2Calbums%2Cplaylists&limit=36`).then(res => {
// let page = res.data?.results ?? [];
// self.songs = page.songs[0] ?? [];
// self.albums = page.albums[0] ?? [];
// self.playlists = page.playlists[0] ?? [];
// })
}
}
})
</script>

View file

@ -80,7 +80,7 @@
</button>
</div>
</template>
<div class="playlist-controls" v-observe-visibility="{callback: isHeaderVisible}">
<div class="playlist-controls" v-observe-visibility="{callback: isHeaderVisible}" style="z-index: 20;">
<button class="md-btn md-btn-primary md-btn-icon" style="min-width: 100px;"
@click="app.mk.shuffleMode = 0; play()"><img class="md-ico-play">
{{app.getLz('term.play')}}
@ -121,7 +121,7 @@
</div>
</div>
<div class="artworkContainer" v-if="data.attributes.artwork != null">
<artwork-material :url="data.attributes.artwork.url" size="260" images="1"></artwork-material>
<artwork-material :url="data.attributes.artwork.url" size="500" images="1"></artwork-material>
</div>
<button class="md-btn md-btn-small editTracksBtn" v-if="(data.attributes.canEdit && data.type == 'library-playlists')" @click="editing = !editing">
<span v-if="!editing">
@ -648,39 +648,11 @@
app.copyToClipboard(res.data.data[0].attributes.url)
})
}
},
"follow": {
name: app.getLz('action.follow'),
icon: "./assets/feather/plus-circle.svg",
hidden: false,
action: () => {
app.followArtistById(artistId, true)
}
},
"unfollow": {
name: app.getLz('action.unfollow'),
icon: "./assets/feather/x-circle.svg",
hidden: true,
action: () => {
app.followArtistById(artistId, false)
}
},
}
}
}
app.showMenuPanel(menuItems, event)
if (artistId != null) {
if (app.followingArtist(artistId)) {
menuItems.items.follow.hidden = true
menuItems.items.unfollow.hidden = false
} else {
menuItems.items.follow.hidden = false
menuItems.items.unfollow.hidden = true
}
} else {
menuItems.items.follow.hidden = true
menuItems.items.unfollow.hidden = true
}
try {
let rating = await app.getRating(self.data)
if (rating == 0) {

View file

@ -58,19 +58,33 @@
},
methods: {
getClasses() {
if(this.commonKind != "song") {
return "collection-list-square";
}else{
if ((this.data?.data?.length ?? 0) > 0) {
let item = this.data.data[0]
if (typeof item.kind != "undefined") {
this.commonKind = item.kind;
return item.kind
}
if (typeof item.attributes.playParams != "undefined") {
this.commonKind = item.attributes.playParams.kind
return item.attributes.playParams.kind
}
if (this.commonKind != "song") {
return "collection-list-square";
} else {
return "";
}
} else {
return "";
}
},
getKind(item) {
if (typeof item.kind != "undefined") {
this.commonKind = item.kind;
// this.commonKind = item.kind;
return item.kind
}
if (typeof item.attributes.playParams != "undefined") {
this.commonKind = item.attributes.playParams.kind
// this.commonKind = item.attributes.playParams.kind
return item.attributes.playParams.kind
}
return this.commonKind

View file

@ -61,18 +61,28 @@
};
},
async mounted() {
const queryDefaults = `?platform=web&l=en-us&extend=editorialArtwork%2CartistUrl&omit%5Bresource%3Aartists%5D=relationships&include[groupings]=curator&include[albums]=artists&include[songs]=artists&include[music-videos]=artists&fields%5Bartists%5D=name%2Curl%2Cartwork%2CeditorialArtwork%2CgenreNames%2CeditorialNotes`
const queryDefaults = {
"platform": "web",
"l" : this.$root.mklang,
"extend": "editorialArtwork,artistUrl",
"omit[resource:artists]": "relationships",
"include[groupings]": "curator",
"include[albums]": "artists",
"include[songs]": "artists",
"include[music-videos]": "artists",
"fields[artists]": "name,url,artwork,editorialArtwork,genreNames,editorialNotes",
}
const hash = window.location.hash;
// get everything after the first / character but keep everything afterwards
const query = hash.substring(hash.indexOf("/") + 1);
const query = hash.substring(hash.indexOf("/") + 1, hash.indexOf("&") > 0 ? hash.indexOf("&") : hash.length);
this.query = query;
if(!this.query.includes("?")) {
this.query += queryDefaults;
}
// if(!this.query.includes("?")) {
// this.query += queryDefaults;
// }
console.debug(query);
const result = await this.$root.mk.api.v3.music(
`/v1/editorial/${this.$root.mk.storefrontId}/groupings/${this.query}`
);
,!this.query.includes("&") ? queryDefaults : {"platform": "web"});
this.data = result.data.data[0];
console.log(this.data);

View file

@ -26,6 +26,8 @@
<h3>{{app.getLz('home.artistsFeed')}}</h3>
</div>
<div class="col-auto nopadding flex-center">
<button class="cd-btn-seeall" @click="syncFavorites()" v-if="!syncingFavs">{{app.getLz('home.syncFavorites')}}</button>
<div class="spinner" style="height: 26px;" v-else></div>
<button class="cd-btn-seeall" @click="app.appRoute('artist-feed')">{{app.getLz('term.seeAll')}}</button>
</div>
</div>
@ -113,7 +115,8 @@
page: "main",
sectionsReady: [],
year: new Date().getFullYear(),
seenReplay: localStorage.getItem('seenReplay')
seenReplay: localStorage.getItem('seenReplay'),
syncingFavs: false
}
},
async mounted() {
@ -128,6 +131,12 @@
}
},
methods: {
async syncFavorites() {
this.syncingFavs = true
await app.syncFavorites()
await this.getArtistFeed()
this.syncingFavs = false
},
async seeAllRecentlyPlayed() {
let hist = await app.mk.api.v3.music(`/v1/me/recent/played`, {
l: this.$root.mklang,
@ -188,7 +197,7 @@
async getArtistFeed() {
let artists = this.followedArtists
let self = this
this.artistFeed = []
let chunks = []
for (let artistIdx = 0; artistIdx < artists.length; artistIdx += 50) {
chunks.push(artists.slice(artistIdx, artistIdx + 50));

View file

@ -226,10 +226,10 @@
name: "Reduce Visuals",
file: "reduce_visuals.less"
})
themes.unshift({
name: "Inline Drawer",
file: "inline_drawer.less"
})
// themes.unshift({
// name: "Inline Drawer",
// file: "inline_drawer.less"
// })
themes.unshift({
name: "Dark",
file: "dark.less"

View file

@ -170,6 +170,11 @@
Vue.component('keybinds-settings', {
template: "#keybinds-settings",
props: [],
data: function () {
return {
app: this.$root
}
},
methods: {
keyBindUpdate: function (action) {
const blur = document.createElement('div');
@ -230,14 +235,14 @@
app.cfg.general.keybindings.browse = [app.platform == "darwin" ? "Command" : "Control", "B"];
app.cfg.general.keybindings.recentAdd = [app.platform == "darwin" ? "Command" : "Control", "G"];
app.cfg.general.keybindings.songs = [app.platform == "darwin" ? "Command" : "Control", "J"];
app.cfg.general.keybindings.albums = [app.platform == "darwin" ? "Command" : "Control", "S"];
app.cfg.general.keybindings.albums = [app.platform == "darwin" ? "Command" : "Control", "A"];
app.cfg.general.keybindings.artists = [app.platform == "darwin" ? "Command" : "Control", "D"];
app.cfg.general.keybindings.togglePrivateSession = [app.platform == "darwin" ? "Command" : "Control", "P"];
app.cfg.general.keybindings.webRemote = [app.platform == "darwin" ? "Command" : "Control", "W"];
app.cfg.general.keybindings.audioSettings = [app.platform == "darwin" ? "Option" : "Alt", "A"];
app.cfg.general.keybindings.pluginMenu = [app.platform == "darwin" ? "Option" : "Alt", "P"];
app.cfg.general.keybindings.castToDevices = [app.platform == "darwin" ? "Option" : "Alt", "C"];
app.cfg.general.keybindings.settings = [app.platform == "darwin" ? "Option" : "Alt", "S"];
app.cfg.general.keybindings.webRemote = [app.platform == "darwin" ? "Command" : "Control",app.platform == "darwin" ? "Option" : (app.platform == "linux" ? "Shift" : "Alt"), "W"];
app.cfg.general.keybindings.audioSettings = [app.platform == "darwin" ? "Command" : "Control",app.platform == "darwin" ? "Option" : (app.platform == "linux" ? "Shift" : "Alt"), "A"];
app.cfg.general.keybindings.pluginMenu = [app.platform == "darwin" ? "Command" : "Control",app.platform == "darwin" ? "Option" : (app.platform == "linux" ? "Shift" : "Alt"), "P"];
app.cfg.general.keybindings.castToDevices = [app.platform == "darwin" ? "Command" : "Control",app.platform == "darwin" ? "Option" : (app.platform == "linux" ? "Shift" : "Alt"), "C"];
app.cfg.general.keybindings.settings = [app.platform == "darwin" ? "Command" : "Control", ","];
app.cfg.general.keybindings.openDeveloperTools = [app.platform == "darwin" ? "Command" : "Control", app.platform == "darwin" ? "Option" : "Shift", "I"];
notyf.success(app.getLz('settings.notyf.general.keybindings.update.success'));
bootbox.confirm(app.getLz("settings.prompt.general.keybindings.update.success"), (ok) => {

View file

@ -1,58 +1,70 @@
<template v-if="page == 'library-recentlyadded'">
<script type="text/x-template" id="cider-recentlyadded">
<div class="content-inner">
<div class="row">
<div class="col" style="padding:0;">
<h1 class="header-text">{{$root.getLz('term.recentlyAdded')}}</h1>
</div>
<div class="col-auto">
<button v-if="library.albums.downloadState == 2" @click="getLibraryAlbumsFull(true, 0)"
class="reload-btn" :aria-label="app.getLz('menubar.options.reload')"><%- include('../svg/redo.svg') %></button>
</div>
<h1 class="header-text">{{$root.getLz('term.recentlyAdded')}}</h1>
<div class="well itemContainer" v-if="itemSize == 'normal'">
<mediaitem-square v-for="item in items" :item="item"></mediaitem-square>
</div>
<div class="row">
<div class="col" style="padding:0;">
<div class="search-input-container" style="width:100%;margin: 16px 0;">
<div class="search-input--icon"></div>
<input type="search"
style="width:100%;"
spellcheck="false"
:placeholder="$root.getLz('term.search') + '...'"
@input="searchLibraryAlbums"
v-model="library.albums.search" class="search-input">
</div>
</div>
<div class="col-auto flex-center">
<div class="row">
<div class="col">
<select class="md-select" v-model="library.albums.sortOrder[0]"
@change="searchLibraryAlbums(0)">
<optgroup :label="$root.getLz('term.sortOrder')">
<option value="asc">{{$root.getLz('term.sortOrder.ascending')}}</option>
<option value="desc">{{$root.getLz('term.sortOrder.descending')}}</option>
</optgroup>
</select>
</div>
<div class="col">
<select class="md-select" v-model="library.albums.viewAs">
<optgroup :label="$root.getLz('term.viewAs')">
<option value="covers">{{$root.getLz('term.viewAs.coverArt')}}</option>
<option value="list">{{$root.getLz('term.viewAs.list')}}</option>
</optgroup>
</select>
</div>
</div>
</div>
<div class="well itemContainer" v-else="itemSize == 'compact'">
<mediaitem-list-item :show-meta-data="true" :show-library-status="false" v-for="item in items" :item="item"></mediaitem-list-item>
</div>
<div class="well">
<div class="albums-square-container">
<mediaitem-square v-if="library.albums.viewAs == 'covers'" :item="item"
v-for="item in library.albums.displayListing">
</mediaitem-square>
</div>
<mediaitem-list-item v-if="library.albums.viewAs == 'list'" :show-duration="false" :show-meta-data="true"
:show-library-status="false" :item="item"
v-for="item in library.albums.displayListing">
</mediaitem-list-item>
<div class="well itemContainer" v-show="loading">
<div class="spinner"></div>
</div>
<button v-if="nextUrl && !loading" style="opacity:0;height: 32px;" v-observe-visibility="{callback: visibilityChanged}">{{$root.getLz('term.showMore')}}
</button>
</div>
</template>
</script>
<script>
Vue.component("cider-recentlyadded", {
template: "#cider-recentlyadded",
computed: {
items() {
return this.$store.state.pageState['recentlyAdded'].items;
},
nextUrl() {
return this.$store.state.pageState['recentlyAdded'].nextUrl;
},
itemSize() {
return this.$store.state.pageState['recentlyAdded'].size
}
},
data: function () {
return {
loading: false,
firstRoute: `/v1/me/library/recently-added?l=${app.mklang}&platform=web&include[library-albums]=artists&include[library-artists]=catalog&fields[artists]=url&fields%5Balbums%5D=artistName%2CartistUrl%2Cartwork%2CcontentRating%2CeditorialArtwork%2Cname%2CplayParams%2CreleaseDate%2Curl&includeOnly=catalog%2Cartists&limit=25`
}
},
async mounted() {
if(this.$store.state.pageState['recentlyAdded'].items.length !== 0) return
const firstResult = await app.mk.api.v3.music(this.firstRoute)
this.$store.state.pageState["recentlyAdded"].items = firstResult.data.data
this.$store.state.pageState["recentlyAdded"].nextUrl = firstResult.data.next
},
beforeDestroy() {
// this.$store.state.pageState["recently-added"].scrollPosY = $("#app-content").scrollTop()
},
methods: {
visibilityChanged: function(isVisible, entry) {
if (isVisible && !this.loading) {
this.getNextData();
}
},
async getNextData() {
if (this.$store.state.pageState["recentlyAdded"].nextUrl) {
this.loading = true;
const nextResult = await app.mk.api.v3.music(this.$store.state.pageState["recentlyAdded"].nextUrl)
this.$store.state.pageState["recentlyAdded"].items = this.$store.state.pageState["recentlyAdded"].items.concat(nextResult.data.data)
if (nextResult.data.next) {
this.$store.state.pageState["recentlyAdded"].nextUrl = nextResult.data.next
} else {
this.$store.state.pageState["recentlyAdded"].nextUrl = null
}
this.loading = false;
}
return
}
}
});
</script>

View file

@ -0,0 +1,179 @@
<script type="text/x-template" id="cider-oobe">
<div class="content-inner oobe">
<!-- before_we_start-->
<!-- <transition name=""> -->
<div class="oobe-view" v-if="screen == 'before_we_start'">
<div class="oobe-header">
{{ getLz("oobe.amupsell.title") }}
</div>
<div class="oobe-body text">{{ getLz("oobe.amupsell.text") }}</div>
<div class="oobe-footer">
<div class="btn-group">
<div class="md-btn" @click="screen = 'welcome'">{{ getLz("oobe.next") }}</div>
</div>
</div>
</div>
<!-- </transition> -->
<!-- Welcome -->
<!-- <transition name=""> -->
<div class="oobe-view" v-if="screen == 'welcome'">
<div class="oobe-header">
{{ getLz("oobe.intro.title") }}
</div>
<div class="oobe-body text">{{ getLz("oobe.intro.text") }}</div>
<div class="oobe-footer">
<div class="btn-group">
<div class="md-btn" @click="screen = 'before_we_start'">{{ getLz("oobe.previous") }}</div>
<div class="md-btn" @click="screen = 'general'">{{ getLz("oobe.next") }}</div>
</div>
</div>
</div>
<!-- </transition> -->
<!-- General -->
<!-- <transition name=""> -->
<div class="oobe-view" v-if="screen == 'general'">
<div class="oobe-header">
{{ getLz("oobe.general.title") }}
</div>
<div class="oobe-body text">{{ getLz("oobe.general.text") }}</div>
<div class="oobe-footer">
<div class="btn-group">
<div class="md-btn" @click="screen = 'welcome'">{{ getLz("oobe.previous") }}</div>
<div class="md-btn" @click="screen = 'visual'">{{ getLz("oobe.next") }}</div>
</div>
</div>
</div>
<!-- </transition> -->
<!-- Visual -->
<!-- <transition name=""> -->
<div class="oobe-view" v-if="screen == 'visual'">
<div class="oobe-header">
{{ getLz("oobe.visual.title") }}
</div>
<div class="oobe-body visual">
<b-row>
<b-col>
<div class="card bg-dark text-white stylePicker" @click="$root.cfg.visual.directives.windowLayout = 'twopanel'" :class="{'style-active': ($root.cfg.visual.directives.windowLayout == 'twopanel')}">
<div class="card-body">
<img class="visualPreview" src="./assets/oobe/mojave.png" alt="TEMP">
</div>
<div class="card-footer">
Mojave
</div>
</div>
</b-col>
<b-col>
<div class="card bg-dark text-white stylePicker" @click="$root.cfg.visual.directives.windowLayout = 'default'" :class="{'style-active': ($root.cfg.visual.directives.windowLayout == 'default')}">
<div class="card-body">
<img class="visualPreview" src="./assets/oobe/maverick.png" alt="TEMP">
</div>
<div class="card-footer">
Maverick
</div>
</div>
</b-col>
</b-row>
<div class="blurb">{{getLz("oobe.visual.layout.text")}}</div>
</div>
<div class="oobe-footer">
<div class="btn-group">
<div class="md-btn" @click="screen = 'general'">{{ getLz("oobe.previous") }}</div>
<div class="md-btn" @click="screen = 'audio'">{{ getLz("oobe.next") }}</div>
</div>
</div>
</div>
<!-- </transition> -->
<!-- Audio -->
<!-- <transition name=""> -->
<div class="oobe-view" v-if="screen == 'audio'">
<div class="oobe-header">
{{ getLz("oobe.audio.title") }}
</div>
<div class="oobe-body">
<div class="blurb">{{ getLz("oobe.audio.text") }}</div>
<div class="md-option-container">
<div class="settings-option-body">
<div class="md-option-line">
<div class="md-option-segment">
{{getLz('settings.option.audio.enableAdvancedFunctionality')}}
<br>
<small>{{getLz('settings.option.audio.enableAdvancedFunctionality.description')}}</small>
</div>
<div class="md-option-segment md-option-segment_auto">
<label>
<input type="checkbox" v-model="$root.cfg.advanced.AudioContext"
switch/>
</label>
</div>
</div>
<div class="md-option-line" v-show="$root.cfg.advanced.AudioContext === true">
<div class="md-option-segment">
{{$root.getLz('settings.option.audio.enableAdvancedFunctionality.ciderPPE')}}
<br>
<small>{{$root.getLz('settings.option.audio.enableAdvancedFunctionality.ciderPPE.description')}}</small>
</div>
<div class="md-option-segment md-option-segment_auto">
<input type="checkbox" v-model="$root.cfg.audio.maikiwiAudio.ciderPPE"
switch/>
</div>
</div>
</div>
</div>
</div>
<div class="oobe-footer">
<div class="btn-group">
<div class="md-btn" @click="screen = 'visual'">{{ getLz("oobe.previous") }}</div>
<div class="md-btn" @click="signIn()">{{ getLz("oobe.next") }}</div>
</div>
</div>
</div>
<!-- </transition> -->
<div class="oobe-view" v-if="screen == 'signin'">
<div class="oobe-header">
Sign in with Apple Music
</div>
<div class="oobe-body">
<div class="blurb"></div>
</div>
<div class="oobe-footer">
</div>
</div>
<div class="oobe-titlebar">
<div class="button-group" v-if="$root.platform !== 'darwin'">
<button class="min" @click="$root.ipcRenderer.send('minimize')"></button>
<button class="close" @click="$root.ipcRenderer.send('close')"></button>
</div>
</div>
</div>
</script>
<script>
Vue.component('cider-oobe', {
template: '#cider-oobe',
data: function () {
return {
screen: "before_we_start"
}
},
async mounted() {
},
methods: {
signIn() {
if (localStorage.getItem("music.ampwebplay.media-user-token")) {
localStorage.setItem("seenOOBE", 1)
window.location.reload()
}
this.screen = "signin"
capiInit()
},
getLz() {
return this.$root.getLz.apply(this.$root, arguments);
}
}
});
</script>

View file

@ -539,7 +539,7 @@
icon: "./assets/feather/plus-circle.svg",
hidden: false,
action: () => {
app.followArtistById(artistId, true)
app.setArtistFavorite(artistId, true)
}
},
"unfollow": {
@ -547,7 +547,7 @@
icon: "./assets/feather/x-circle.svg",
hidden: true,
action: () => {
app.followArtistById(artistId, false)
app.setArtistFavorite(artistId, false)
}
},
}

View file

@ -176,7 +176,7 @@
redirect: 'follow'
};
fetch("https://api.github.com/search/repositories?q=topic:cidermusicplugin fork:true", requestOptions)
fetch("https://api.github.com/search/repositories?q=topic:cidermusicplugin fork:true&per_page=100", requestOptions)
.then(response => response.text())
.then(result => {
self.repos = JSON.parse(result).items
@ -185,4 +185,4 @@
}
}
})
</script>
</script>

View file

@ -68,7 +68,7 @@
<transition name="wpfade">
<div class="podcasts-details" v-if="selected.id != -1">
<div class="podcasts-details-header">
<button class="close-btn" @click="selected.id = -1" :aria-label="app.getLz('action.close')"></button>
<button class="close-btn" @click="selected.id = -1" :aria-label="$root.getLz('action.close')"></button>
</div>
<div class="podcast-artwork">
<mediaitem-artwork shadow="large" :url="selected.attributes.artwork.url" size="300"></mediaitem-artwork>

View file

@ -28,7 +28,7 @@
<h4>{{ loaded.attributes.uniqueSongCount }} {{$root.getLz('term.uniqueSongs')}}</h4>
</div>
<div class="col-auto replay-playlist-container">
<mediaitem-square kind="card" :force-video="true" :item="loaded.playlist"></mediaitem-square>
<mediaitem-square kind="card" :no-scale="true" :force-video="true" :item="loaded.playlist"></mediaitem-square>
</div>
</div>
<!-- Top Artists-->

View file

@ -1,82 +1,105 @@
<script type="text/x-template" id="cider-search">
<div class="content-inner search-page">
<div class="btn-group searchToggle">
<button
@click="searchType = 'catalog'"
class="md-btn md-btn-small" :class="{'md-btn-primary': searchType == 'catalog'}">{{ $root.getLz("term.appleMusic") }}</button>
<button
@click="searchType = 'library';"
class="md-btn md-btn-small" :class="{'md-btn-primary': searchType == 'library'}">{{ $root.getLz("term.library") }}</button>
</div>
<div v-if="search != null && search != [] && search.term != ''">
<h3>{{app.getLz('term.topResult')}}</h3>
<mediaitem-scroller-horizontal
:items="search.results[search.results.meta.results.order[0]]['data']"></mediaitem-scroller-horizontal>
<div class="row">
<div v-else style="text-align: center">
<h3>{{app.getLz('error.noResults')}}</h3>
<p>{{app.getLz('error.noResults.description')}}</p>
</div>
<div class="col" v-if="search.results.song">
<div class="row">
<div class="col">
<h3>{{app.getLz('term.songs')}}</h3>
<template v-if="searchType == 'catalog'">
<h3>{{app.getLz('term.topResult')}}</h3>
<mediaitem-scroller-horizontal
:items="search.results[search.results.meta.results.order[0]]['data']"></mediaitem-scroller-horizontal>
<div class="row">
<div v-else style="text-align: center">
<h3>{{app.getLz('error.noResults')}}</h3>
<p>{{app.getLz('error.noResults.description')}}</p>
</div>
<div class="col" v-if="search.results.song">
<div class="row">
<div class="col">
<h3>{{app.getLz('term.songs')}}</h3>
</div>
<div class="col-auto flex-center"
@click="app.showSearchView(app.search.term, 'song', app.friendlyTypes('song'))"
v-if="search.results.song.data.length >= 12">
<button class="cd-btn-seeall">{{app.getLz('term.seeAll')}}</button>
</div>
</div>
<div class="col-auto flex-center"
@click="app.showSearchView(app.search.term, 'song', app.friendlyTypes('song'))"
v-if="search.results.song.data.length >= 12">
<button class="cd-btn-seeall">{{app.getLz('term.seeAll')}}</button>
<div class="mediaitem-list-item__grid">
<listitem-horizontal :items="search.results.song.data.limit(12)">
</listitem-horizontal>
</div>
</div>
<div class="mediaitem-list-item__grid">
<listitem-horizontal :items="search.results.song.data.limit(12)">
</listitem-horizontal>
</div>
</div>
</div>
<template v-if="search.results['meta'] != null">
<template
v-for="section in search.results.meta.results.order" v-if="section != 'song' && section != 'top'">
<template v-if="search.results['meta'] != null">
<template
v-for="section in search.results.meta.results.order" v-if="section != 'song' && section != 'top'">
<div class="row">
<div class="col">
<h3>{{ app.friendlyTypes(section) }}</h3>
</div>
<div class="col-auto flex-center" v-if="search.results[section].data.length >= 10">
<button class="cd-btn-seeall"
@click="app.showSearchView(app.search.term, section, app.friendlyTypes(section))">{{app.getLz('term.seeAll')}}
</button>
</div>
</div>
<template v-if="!app.friendlyTypes(section).includes('Video')">
<mediaitem-scroller-horizontal-large
:items="search.results[section].data.limit(10)"></mediaitem-scroller-horizontal-large>
</template>
<template v-else>
<mediaitem-scroller-horizontal-mvview
:items="search.results[section].data.limit(10)"></mediaitem-scroller-horizontal-mvview>
</template>
</template>
</template>
<template v-if="search.resultsSocial.playlist">
<div class="row">
<div class="col">
<h3>{{ app.friendlyTypes(section) }}</h3>
<h3>{{app.getLz('term.sharedPlaylists')}}</h3>
</div>
<div class="col-auto flex-center" v-if="search.results[section].data.length >= 10">
<div class="col-auto flex-center" v-if="search.resultsSocial.playlist.data.length >= 10">
<button class="cd-btn-seeall"
@click="app.showSearchView(app.search.term, section, app.friendlyTypes(section))">{{app.getLz('term.seeAll')}}
@click="app.showCollection(search.resultsSocial.playlist, 'Shared Playlists', 'default')">{{app.getLz('term.seeAll')}}
</button>
</div>
</div>
<template v-if="!app.friendlyTypes(section).includes('Video')">
<mediaitem-scroller-horizontal-large
:items="search.results[section].data.limit(10)"></mediaitem-scroller-horizontal-large>
</template>
<template v-else>
<mediaitem-scroller-horizontal-mvview
:items="search.results[section].data.limit(10)"></mediaitem-scroller-horizontal-mvview>
</template>
<mediaitem-scroller-horizontal-large
:items="search.resultsSocial.playlist.data.limit(10)"></mediaitem-scroller-horizontal-large>
</template>
<template v-if="search.resultsSocial.profile">
<div class="row">
<div class="col">
<h3>{{app.getLz('term.people')}}</h3>
</div>
<div class="col-auto flex-center" v-if="search.resultsSocial.profile.data.length >= 10">
<button class="cd-btn-seeall"
@click="app.showCollection(search.resultsSocial.profile, 'People', 'default')">{{app.getLz('term.seeAll')}}
</button>
</div>
</div>
<mediaitem-scroller-horizontal-large
:items="search.resultsSocial.profile.data.limit(10)"></mediaitem-scroller-horizontal-large>
</template>
</template>
<template v-if="search.resultsSocial.playlist">
<div class="row">
<div class="col">
<h3>{{app.getLz('term.sharedPlaylists')}}</h3>
<template v-else>
<h1>{{ $root.getLz("term.library") }}</h1>
<div v-for="(section, key) in $root.search.resultsLibrary">
<h3>{{app.friendlyTypes(key)}}</h3>
<div class="mediaitem-list-item__grid" v-if="key.includes('songs')">
<listitem-horizontal :items="section.data"></listitem-horizontal>
</div>
<div class="col-auto flex-center" v-if="search.resultsSocial.playlist.data.length >= 10">
<button class="cd-btn-seeall"
@click="app.showCollection(search.resultsSocial.playlist, 'Shared Playlists', 'default')">{{app.getLz('term.seeAll')}}
</button>
<div class="well" v-else>
<mediaitem-scroller-horizontal-large
:items="section.data"></mediaitem-scroller-horizontal-large>
</div>
</div>
<mediaitem-scroller-horizontal-large
:items="search.resultsSocial.playlist.data.limit(10)"></mediaitem-scroller-horizontal-large>
</template>
<template v-if="search.resultsSocial.profile">
<div class="row">
<div class="col">
<h3>{{app.getLz('term.people')}}</h3>
</div>
<div class="col-auto flex-center" v-if="search.resultsSocial.profile.data.length >= 10">
<button class="cd-btn-seeall"
@click="app.showCollection(search.resultsSocial.profile, 'People', 'default')">{{app.getLz('term.seeAll')}}
</button>
</div>
</div>
<mediaitem-scroller-horizontal-large
:items="search.resultsSocial.profile.data.limit(10)"></mediaitem-scroller-horizontal-large>
</template>
</div>
<div v-else>
@ -111,6 +134,7 @@
recentlyPlayed: [],
categoriesView: [],
categoriesReady: false,
searchType: "catalog",
}
},
methods: {

View file

@ -96,7 +96,8 @@
<option value="listen_now">{{$root.getLz('term.listenNow')}}</option>
<option value="browse">{{$root.getLz('term.browse')}}</option>
<option value="radio">{{$root.getLz('term.radio')}}</option>
<option value="library-recentlyadded">{{$root.getLz('term.recentlyAdded')}}</option>
<option value="library-recentlyadded">{{$root.getLz('term.recentlyAdded')}}
</option>
<option value="library-songs">{{$root.getLz('term.songs')}}</option>
<option value="library-albums">{{$root.getLz('term.albums')}}</option>
<option value="library-artists">{{$root.getLz('term.artists')}}</option>
@ -124,7 +125,8 @@
</div>
<div class="md-option-segment md-option-segment_auto">
<label>
<input type="checkbox" v-model="app.cfg.general.sidebarItems.recentlyAdded"
<input type="checkbox"
v-model="app.cfg.general.sidebarItems.recentlyAdded"
switch/>
</label>
</div>
@ -135,7 +137,8 @@
</div>
<div class="md-option-segment md-option-segment_auto">
<label>
<input type="checkbox" v-model="app.cfg.general.sidebarItems.songs" switch/>
<input type="checkbox" v-model="app.cfg.general.sidebarItems.songs"
switch/>
</label>
</div>
</div>
@ -185,17 +188,17 @@
</div>
</div>
</b-modal>
</div>
</div>
<div class="md-option-line">
<div class="md-option-segment">
{{$root.getLz('settings.option.general.keybindings')}}
</div>
<div class="md-option-segment md-option-segment_auto">
<button class="md-btn" @click="app.appRoute('keybinds-settings')" >
<button class="md-btn" @click="app.appRoute('keybinds-settings')">
{{$root.getLz('settings.option.general.keybindings.open')}}
</button>
</div>
</div>
</div>
<div class="md-option-line">
<div class="md-option-segment">
{{$root.getLz('settings.option.general.themeUpdateNotification')}}
@ -206,7 +209,7 @@
switch/>
</label>
</div>
</div>
</div>
<div class="md-option-line">
<div class="md-option-segment">
{{$root.getLz('settings.option.general.showLovedTracksInline')}}
@ -217,7 +220,7 @@
switch/>
</label>
</div>
</div>
</div>
</div>
</div>
</b-tab>
@ -241,7 +244,8 @@
<option value="HIGH">{{$root.getLz('settings.header.audio.quality.high')}}
({{$root.getLz('settings.header.audio.quality.high.description')}})
</option>
<option value="STANDARD">{{$root.getLz('settings.header.audio.quality.standard')}}
<option value="STANDARD">
{{$root.getLz('settings.header.audio.quality.standard')}}
({{$root.getLz('settings.header.audio.quality.standard.description')}})
</option>
</select>
@ -329,12 +333,13 @@
<label>
<input type="checkbox" v-model="app.cfg.audio.normalization"
v-on:change="toggleNormalization"
:disabled="app.cfg.audio.spatial === true || app.cfg.audio.maikiwiAudio.spatial === true || app.cfg.audio.maikiwiAudio.ciderPPE === true || app.cfg.audio.maikiwiAudio.atmosphereRealizer1 === true || app.cfg.audio.maikiwiAudio.atmosphereRealizer2 === true"
:disabled="app.cfg.audio.maikiwiAudio.spatial === true || app.cfg.audio.maikiwiAudio.ciderPPE === true || app.cfg.audio.maikiwiAudio.atmosphereRealizer1 === true || app.cfg.audio.maikiwiAudio.atmosphereRealizer2 === true"
switch/>
</label>
</div>
</div>
<div class="md-option-line" v-show="app.cfg.advanced.AudioContext && app.cfg.audio.normalization">
<div class="md-option-line"
v-show="app.cfg.advanced.AudioContext && app.cfg.audio.normalization">
<div class="md-option-segment">
{{$root.getLz('settings.option.audio.dbspl.display')}}
<br>
@ -408,13 +413,131 @@
<option value="image">
{{$root.getLz('settings.header.visual.windowBackgroundStyle.image')}}
</option>
<option value="mica">
<option value="color">
{{$root.getLz('settings.header.visual.windowBackgroundStyle.color')}}
</option>
<option v-if="$root.platform == 'win32'" value="mica">
Mica (Beta)
</option>
</select>
</label>
</div>
</div>
<div class="md-option-line child" v-if="app.cfg.visual.window_background_style == 'color'">
<div class="md-option-segment">
{{$root.getLz('settings.option.visual.windowColor')}}
</div>
<div class="md-option-segment_auto">
<input type="color" v-model="app.cfg.visual.windowColor"/>
</div>
</div>
<div class="md-option-line">
<div class="md-option-segment">
{{$root.getLz('settings.option.visual.customAccentColor')}}
</div>
<div class="md-option-segment_auto">
<input type="checkbox" v-model="app.cfg.visual.customAccentColor" :disabled="app.cfg.visual.purplePodcastPlaybackBar" switch/>
</div>
</div>
<div class="md-option-line child" v-if="app.cfg.visual.customAccentColor">
<div class="md-option-segment">
{{$root.getLz('settings.option.visual.accentColor')}}
</div>
<div class="md-option-segment_auto">
<input type="color" v-model="app.cfg.visual.accentColor"/>
</div>
</div>
<div class="md-option-line">
<div class="md-option-segment">
{{$root.getLz('settings.option.visual.purplePodcastPlaybackBar')}}
</div>
<div class="md-option-segment_auto">
<input type="checkbox" v-model="app.cfg.visual.purplePodcastPlaybackBar" :disabled="app.cfg.visual.customAccentColor" switch/>
</div>
</div>
<div class="md-option-line">
<div class="md-option-segment">
{{$root.getLz('settings.option.visual.hardwareAcceleration')}}<br>
<small>({{$root.getLz('settings.option.visual.hardwareAcceleration.description')}})</small>
</div>
<div class="md-option-segment md-option-segment_auto">
<label>
<select class="md-select" style="width:180px;"
v-model="app.cfg.visual.hw_acceleration" @change="promptForRelaunch()">
<option value="default">
{{$root.getLz('settings.header.visual.hardwareAcceleration.default')}}
</option>
<option value="webgpu">
{{$root.getLz('settings.header.visual.hardwareAcceleration.webGPU')}}
</option>
<option value="disabled">{{$root.getLz('term.disabled')}}</option>
</select>
</label>
</div>
</div>
<div class="md-option-line">
<div class="md-option-segment">
{{$root.getLz('settings.option.visual.showPersonalInfo')}}
</div>
<div class="md-option-segment md-option-segment_auto">
<label>
<input type="checkbox" v-model="app.cfg.visual.showuserinfo"
v-on:change="toggleUserInfo"
switch/>
</label>
</div>
</div>
</div>
<!-- Window Settings -->
<div class="md-option-header">
<span>{{$root.getLz('settings.header.window')}}</span>
</div>
<div class="settings-option-body">
<div class="md-option-line" v-show="app.platform !== 'darwin'">
<div class="md-option-segment">
{{$root.getLz("settings.option.window.close_button_hide")}}
</div>
<div class="md-option-segment md-option-segment_auto">
<label>
<input type="checkbox" v-model="app.cfg.general.close_button_hide" switch/>
</label>
</div>
</div>
<div class="md-option-line" v-show="app.platform !== 'darwin'">
<div class="md-option-segment">
{{$root.getLz("settings.option.window.useNativeTitleBar")}}<br>
<small>({{$root.getLz("settings.option.visual.hardwareAcceleration.description")}})</small>
</div>
<div class="md-option-segment md-option-segment_auto">
<label>
<input type="checkbox" v-model="app.cfg.visual.nativeTitleBar" switch
@change="promptForRelaunch()"/>
</label>
</div>
</div>
<div class="md-option-line" v-show="app.platform !== 'darwin'">
<div class="md-option-segment">
{{$root.getLz("settings.option.window.windowControlStyle")}}
</div>
<div class="md-option-segment md-option-segment_auto">
<label>
<select class="md-select" v-model="app.cfg.visual.windowControlPosition">
<option value="0">
{{$root.getLz("settings.option.window.windowControlStyle.right")}}
</option>
<option value="1">
{{$root.getLz("settings.option.window.windowControlStyle.left")}}
</option>
</select>
</label>
</div>
</div>
</div>
<!-- Advanced Visual -->
<div class="md-option-header">
<span>{{$root.getLz('settings.header.advanced')}}</span>
</div>
<div class="settings-option-body">
<div class="md-option-line">
<div class="md-option-segment">
{{$root.getLz('settings.option.visual.animatedArtwork')}}
@ -483,83 +606,8 @@
</label>
</div>
</div>
<div class="md-option-line">
<div class="md-option-segment">
{{$root.getLz('settings.option.visual.hardwareAcceleration')}}<br>
<small>({{$root.getLz('settings.option.visual.hardwareAcceleration.description')}})</small>
</div>
<div class="md-option-segment md-option-segment_auto">
<label>
<select class="md-select" style="width:180px;" v-model="app.cfg.visual.hw_acceleration" @change="promptForRelaunch()">
<option value="default">
{{$root.getLz('settings.header.visual.hardwareAcceleration.default')}}
</option>
<option value="webgpu">
{{$root.getLz('settings.header.visual.hardwareAcceleration.webGPU')}}
</option>
<option value="disabled">{{$root.getLz('term.disabled')}}</option>
</select>
</label>
</div>
</div>
<div class="md-option-line">
<div class="md-option-segment">
{{$root.getLz('settings.option.visual.showPersonalInfo')}}
</div>
<div class="md-option-segment md-option-segment_auto">
<label>
<input type="checkbox" v-model="app.cfg.visual.showuserinfo"
v-on:change="toggleUserInfo"
switch/>
</label>
</div>
</div>
</div>
<!-- Window Settings -->
<div class="md-option-header">
<span>{{$root.getLz('settings.header.window')}}</span>
</div>
<div class="settings-option-body">
<div class="md-option-line" v-show="app.platform !== 'darwin'">
<div class="md-option-segment">
{{$root.getLz("settings.option.window.close_button_hide")}}
</div>
<div class="md-option-segment md-option-segment_auto">
<label>
<input type="checkbox" v-model="app.cfg.general.close_button_hide" switch/>
</label>
</div>
</div>
<div class="md-option-line" v-show="app.platform !== 'darwin'">
<div class="md-option-segment">
{{$root.getLz("settings.option.window.useNativeTitleBar")}}<br>
<small>({{$root.getLz("settings.option.visual.hardwareAcceleration.description")}})</small>
</div>
<div class="md-option-segment md-option-segment_auto">
<label>
<input type="checkbox" v-model="app.cfg.visual.nativeTitleBar" switch
@change="promptForRelaunch()"/>
</label>
</div>
</div>
<div class="md-option-line" v-show="app.platform !== 'darwin'">
<div class="md-option-segment">
{{$root.getLz("settings.option.window.windowControlStyle")}}
</div>
<div class="md-option-segment md-option-segment_auto">
<label>
<select class="md-select" v-model="app.cfg.visual.windowControlPosition">
<option value="0">
{{$root.getLz("settings.option.window.windowControlStyle.right")}}
</option>
<option value="1">
{{$root.getLz("settings.option.window.windowControlStyle.left")}}
</option>
</select>
</label>
</div>
</div>
</div>
</div>
</b-tab>
<b-tab :title="$root.getLz('settings.header.lyrics')">
@ -998,6 +1046,17 @@
</div>
</div>
<div class="md-option-line" v-show="app.cfg.general.discordrpc.enabled != false">
<div class="md-option-segment">
{{$root.getLz('settings.option.connectivity.discordRPC.reload')}}
</div>
<div class="md-option-segment md-option-segment_auto">
<button class="md-btn" @click="reloadDiscordRPC()">
{{$root.getLz('menubar.options.reload')}}
</button>
</div>
</div>
<!-- LastFM -->
<div class="md-option-line">
<div class="md-option-segment">
@ -1005,7 +1064,7 @@
</div>
<div class="md-option-segment md-option-segment_auto">
<button class="md-btn" id="lfmConnect" ref="lfmConnect"
onclick="app.LastFMAuthenticate()">
@click="app.LastFMAuthenticate()">
{{$root.getLz('term.connect')}}
</button>
</div>
@ -1036,7 +1095,8 @@
</div>
<div class="md-option-segment md-option-segment_auto">
<label>
<input type="checkbox" v-model="app.cfg.lastfm.enabledRemoveFeaturingArtists" switch/>
<input type="checkbox" v-model="app.cfg.lastfm.enabledRemoveFeaturingArtists"
switch/>
</label>
</div>
</div>
@ -1125,6 +1185,20 @@
</div>
</div>
<div class="md-option-line">
<div class="md-option-segment">
Use MusicKit V3
<small>Requires relaunch</small>
</div>
<div class="md-option-segment md-option-segment_auto">
<label>
<input type="checkbox" v-model="app.cfg.advanced.experiments.includes('ampv3')"
@click="app.cfg.advanced.experiments.includes('ampv3') ? removeExperiment('ampv3') : addExperiment('ampv3')"
switch/>
</label>
</div>
</div>
<div class="md-option-line">
<div class="md-option-segment">
{{$root.getLz('settings.option.advanced.playlistTrackMapping')}}
@ -1138,28 +1212,16 @@
</div>
</div>
<div class="md-option-line">
<div class="md-option-segment">
Collapsable Sidebar
</div>
<div class="md-option-segment md-option-segment_auto">
<label>
<input type="checkbox" v-model="app.cfg.advanced.experiments.includes('collapseSidebar')"
@click="app.cfg.advanced.experiments.includes('collapseSidebar') ? removeExperiment('collapseSidebar') : addExperiment('collapseSidebar')"
switch/>
</label>
</div>
</div>
<div class="md-option-line">
<div class="md-option-segment">
{{$root.getLz('settings.option.experimental.compactUI')}}
<small v-if="!!app.getThemeDirective('forceUI')">{{$root.getLz('term.themeManaged')}}</small>
</div>
<div class="md-option-segment md-option-segment_auto">
<label>
<input type="checkbox" v-model="app.cfg.advanced.experiments.includes('compactui')"
@click="app.cfg.advanced.experiments.includes('compactui') ? removeExperiment('compactui') : addExperiment('compactui')"
switch/>
switch :disabled="!!app.getThemeDirective('forceUI')"/>
</label>
</div>
</div>
@ -1187,7 +1249,8 @@
<select class="md-select" @change="$root.setLz('');$root.setLzManual()"
v-model="app.cfg.general.language">
<optgroup :label="index" v-for="(categories, index) in getLanguages()">
<option v-for="lang in categories" :value="lang.code">{{lang.nameNative}} ({{
<option v-for="lang in categories" :value="lang.code">{{lang.nameNative}}
({{
lang.nameEnglish }})
</option>
</optgroup>
@ -1211,9 +1274,10 @@
</div>
</b-tab>
<!-- Connect Settings -->
<!-- Not Prod Ready
<b-tab :title="$root.getLz('settings.header.connect')">
<div class="md-option-container">
<!-- Cider Connect / Linking Settings -->
<!!!!!-- Cider Connect / Linking Settings -!->
<div class="md-option-header">
<span>{{$root.getLz('settings.header.connect')}}</span>
</div>
@ -1295,6 +1359,7 @@
</div>
</div>
</b-tab>
-->
</b-tabs>
</div>
</script>
@ -1393,8 +1458,7 @@
if (app.cfg.audio.normalization === true) {
CiderAudio.normalizerOn()
}
if (app.cfg.audio.spatial === true) {
CiderAudio.spatialOn()
if (app.cfg.audio.maikiwiAudio.spatial === true) {
CiderAudio.hierarchical_loading();
}
}
@ -1404,8 +1468,7 @@
if (app.cfg.audio.normalization === true) {
CiderAudio.normalizerOn()
}
if (app.cfg.audio.spatial === true) {
CiderAudio.spatialOn()
if (app.cfg.audio.maikiwiAudio.spatial === true) {
CiderAudio.hierarchical_loading();
}
}
@ -1421,7 +1484,6 @@
}
},
changeAudioQuality: function () {
1
app.mk.bitrate = MusicKit.PlaybackBitrate[app.cfg.audio.quality];
},
toggleUserInfo: function () {
@ -1455,6 +1517,9 @@
logoutCC() {
ipcRenderer.send('cc-logout')
},
reloadDiscordRPC() {
ipcRenderer.send('reloadRPC')
}
}
})
</script>

View file

@ -184,7 +184,7 @@
redirect: 'follow'
};
fetch("https://api.github.com/search/repositories?q=topic:cidermusictheme fork:true", requestOptions)
fetch("https://api.github.com/search/repositories?q=topic:cidermusictheme fork:true&per_page=100", requestOptions)
.then(response => response.text())
.then(result => {
let items = JSON.parse(result).items
@ -194,4 +194,4 @@
}
}
})
</script>
</script>

View file

@ -9,6 +9,20 @@
v-if="artistLoaded"
:item="artist"
></artist-chip>
<amp-chrome-player/>
<!-- <amp-footer-player/> -->
<hr>
<amp-lcd-progress/>
<hr>
<amp-playback-controls-shuffle/>
<apple-music-playback-controls theme="dark" />
<apple-music-progress theme="dark"></apple-music-progress>
<apple-music-volume theme="dark"></apple-music-volume>
<amp-user-menu/>
<amp-tv-overlay/>
<amp-podcast-playback-controls/>
<amp-lcd/>
</div>
</script>
<script>

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-external-link"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path><polyline points="15 3 21 3 21 9"></polyline><line x1="10" y1="14" x2="21" y2="3"></line></svg>

After

Width:  |  Height:  |  Size: 388 B