CHONKY BOY
|
@ -1,136 +1,136 @@
|
|||
<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="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"
|
||||
>
|
||||
<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">{{
|
||||
<span class="usermenu-item-name">{{
|
||||
$root.getLz("term.disablePrivateSession")
|
||||
}}</span>
|
||||
</button>
|
||||
<button class="usermenu-item" @click="appRoute('remote-pair')">
|
||||
</button>
|
||||
<button class="usermenu-item" @click="appRoute('remote-pair')">
|
||||
<span class="usermenu-item-icon">
|
||||
<%- include("../svg/smartphone.svg") %>
|
||||
</span>
|
||||
<span class="usermenu-item-name">{{
|
||||
<span class="usermenu-item-name">{{
|
||||
$root.getLz("action.showWebRemoteQR")
|
||||
}}</span>
|
||||
</button>
|
||||
<button
|
||||
class="usermenu-item"
|
||||
@click="modals.castMenu = true"
|
||||
>
|
||||
</button>
|
||||
<button
|
||||
class="usermenu-item"
|
||||
@click="modals.castMenu = true"
|
||||
>
|
||||
<span class="usermenu-item-icon">
|
||||
<%- include("../svg/cast.svg") %>
|
||||
</span>
|
||||
<span class="usermenu-item-name">{{
|
||||
<span class="usermenu-item-name">{{
|
||||
$root.getLz("term.cast")
|
||||
}}</span>
|
||||
</button>
|
||||
<button
|
||||
class="usermenu-item"
|
||||
@click="modals.audioSettings = true"
|
||||
>
|
||||
</button>
|
||||
<button
|
||||
class="usermenu-item"
|
||||
@click="modals.audioSettings = true"
|
||||
>
|
||||
<span class="usermenu-item-icon">
|
||||
<%- include("../svg/headphones.svg") %>
|
||||
</span>
|
||||
<span class="usermenu-item-name">{{
|
||||
<span class="usermenu-item-name">{{
|
||||
$root.getLz("term.audioSettings")
|
||||
}}</span>
|
||||
</button>
|
||||
<button
|
||||
class="usermenu-item"
|
||||
v-if="pluginInstalled"
|
||||
@click="modals.pluginMenu = true"
|
||||
>
|
||||
</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">{{
|
||||
<span class="usermenu-item-name">{{
|
||||
$root.getLz("term.plugin")
|
||||
}}</span>
|
||||
</button>
|
||||
<button class="usermenu-item" @click="appRoute('about')">
|
||||
</button>
|
||||
<button class="usermenu-item" @click="appRoute('about')">
|
||||
<span class="usermenu-item-icon">
|
||||
<%- include("../svg/info.svg") %>
|
||||
</span>
|
||||
<span class="usermenu-item-name">{{
|
||||
<span class="usermenu-item-name">{{
|
||||
$root.getLz("term.about")
|
||||
}}</span>
|
||||
</button>
|
||||
<button class="usermenu-item" @click="modals.settings = true">
|
||||
</button>
|
||||
<button class="usermenu-item" @click="modals.settings = true">
|
||||
<span class="usermenu-item-icon">
|
||||
<%- include("../svg/settings.svg") %>
|
||||
</span>
|
||||
<span class="usermenu-item-name">{{
|
||||
<span class="usermenu-item-name">{{
|
||||
$root.getLz("term.settings")
|
||||
}}</span>
|
||||
</button>
|
||||
<button class="usermenu-item" @click="unauthorize()">
|
||||
</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">{{
|
||||
<span class="usermenu-item-name">{{
|
||||
$root.getLz("term.logout")
|
||||
}}</span>
|
||||
</button>
|
||||
<button class="usermenu-item" @click="quit()">
|
||||
</button>
|
||||
<button class="usermenu-item" @click="quit()">
|
||||
<span class="usermenu-item-icon" style="right: 2.5px">
|
||||
<%- include("../svg/x.svg") %>
|
||||
</span>
|
||||
<span class="usermenu-item-name">{{
|
||||
<span class="usermenu-item-name">{{
|
||||
$root.getLz("term.quit")
|
||||
}}</span>
|
||||
</button>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
<transition name="sidebartransition">
|
||||
<cider-app-sidebar v-if="!chrome.sidebarCollapsed"></cider-app-sidebar>
|
||||
|
@ -141,9 +141,12 @@
|
|||
v-if="drawer.open && drawer.panel == 'lyrics' && lyrics && lyrics != [] && lyrics.length > 0">
|
||||
<div class="bgArtworkMaterial">
|
||||
<div class="bg-artwork-container">
|
||||
<img v-if="(cfg.visual.bg_artwork_rotation && animateBackground)" class="bg-artwork a" :src="$store.state.artwork.playerLCD">
|
||||
<img v-if="(cfg.visual.bg_artwork_rotation && animateBackground)" class="bg-artwork b" :src="$store.state.artwork.playerLCD">
|
||||
<img v-if="!(cfg.visual.bg_artwork_rotation && animateBackground)" class="bg-artwork no-animation" :src="$store.state.artwork.playerLCD">
|
||||
<img v-if="(cfg.visual.bg_artwork_rotation && animateBackground)" class="bg-artwork a"
|
||||
:src="$store.state.artwork.playerLCD">
|
||||
<img v-if="(cfg.visual.bg_artwork_rotation && animateBackground)" class="bg-artwork b"
|
||||
:src="$store.state.artwork.playerLCD">
|
||||
<img v-if="!(cfg.visual.bg_artwork_rotation && animateBackground)" class="bg-artwork no-animation"
|
||||
:src="$store.state.artwork.playerLCD">
|
||||
</div>
|
||||
</div>
|
||||
<lyrics-view v-if="drawer.panel == 'lyrics'" :time="mk.currentPlaybackTime - lyricOffset" :lyrics="lyrics"
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
<div class="app-chrome chrome-bottom" v-if="getThemeDirective('windowLayout') == 'twopanel'" :style="{'display': chrome.topChromeVisible ? '' : 'none'}">
|
||||
<div class="app-chrome chrome-bottom" v-if="getThemeDirective('windowLayout') == 'twopanel'"
|
||||
:style="{'display': chrome.topChromeVisible ? '' : 'none'}">
|
||||
<div class="app-chrome--left">
|
||||
<div class="app-chrome-item playback-controls">
|
||||
<template v-if="mkReady()">
|
||||
|
@ -16,15 +17,23 @@
|
|||
<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>
|
||||
<div class="song-artist" @click="getNowPlayingItemDetailed(`artist`)">{{
|
||||
mk.nowPlayingItem["attributes"]["artistName"] }}
|
||||
</div>
|
||||
<div class="song-album" @click="getNowPlayingItemDetailed(`album`)">
|
||||
{{(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)">{{ $root.getLz("term.miniplayer") }}</button>
|
||||
<button class="md-btn md-btn-small" style="width: 100%;" @click="drawer.open = false; fullscreen(true)">{{ $root.getLz("term.fullscreenView") }}</button>
|
||||
<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)">{{
|
||||
$root.getLz("term.fullscreenView") }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</b-popover>
|
||||
|
@ -39,20 +48,26 @@
|
|||
<div class="song-artist" @click="getNowPlayingItemDetailed(`artist`)">
|
||||
{{ mk.nowPlayingItem["attributes"]["artistName"] }}
|
||||
</div>
|
||||
<div class="song-album" @click="getNowPlayingItemDetailed('album')" v-if='mk.nowPlayingItem["attributes"]["albumName"]'>
|
||||
<div class="song-album" @click="getNowPlayingItemDetailed('album')"
|
||||
v-if='mk.nowPlayingItem["attributes"]["albumName"]'>
|
||||
{{(mk.nowPlayingItem["attributes"]["albumName"]) ?
|
||||
(mk.nowPlayingItem["attributes"]["albumName"]) : "" }}
|
||||
</div>
|
||||
<div class="chrome-icon-container">
|
||||
<div class="audio-type private-icon" v-if="cfg.general.privateEnabled === true"></div>
|
||||
<div class="audio-type spatial-icon" v-if="cfg.audio.maikiwiAudio.spatial === true"
|
||||
:title="$root.getLz('settings.option.audio.enableAdvancedFunctionality.tunedAudioSpatialization') + ' (' + getProfileLz('CTS', cfg.audio.maikiwiAudio.spatialProfile) + ')'" v-b-tooltip.hover
|
||||
<div class="audio-type spatial-icon" v-if="cfg.audio.maikiwiAudio.spatial === true"
|
||||
:title="$root.getLz('settings.option.audio.enableAdvancedFunctionality.tunedAudioSpatialization') + ' (' + getProfileLz('CTS', cfg.audio.maikiwiAudio.spatialProfile) + ')'"
|
||||
v-b-tooltip.hover
|
||||
></div>
|
||||
<div class="audio-type lossless-icon" v-if="(mk.nowPlayingItem?.localFilesMetadata?.lossless ?? false) === true"
|
||||
:title="mk.nowPlayingItem?.localFilesMetadata?.bitDepth +'-bit / '+ mk.nowPlayingItem?.localFilesMetadata?.sampleRate/1000 + ' kHz ' + mk.nowPlayingItem.localFilesMetadata.container" v-b-tooltip.hover
|
||||
></div>
|
||||
<div class="audio-type ppe-icon" v-if="mk.nowPlayingItem.localFilesMetadata == null && cfg.audio.maikiwiAudio.ciderPPE === true"
|
||||
:title="$root.getLz('settings.option.audio.enableAdvancedFunctionality.ciderPPE')" v-b-tooltip.hover
|
||||
<div class="audio-type lossless-icon"
|
||||
v-if="(mk.nowPlayingItem?.localFilesMetadata?.lossless ?? false) === true"
|
||||
:title="mk.nowPlayingItem?.localFilesMetadata?.bitDepth +'-bit / '+ mk.nowPlayingItem?.localFilesMetadata?.sampleRate/1000 + ' kHz ' + mk.nowPlayingItem.localFilesMetadata.container"
|
||||
v-b-tooltip.hover
|
||||
></div>
|
||||
<div class="audio-type ppe-icon"
|
||||
v-if="mk.nowPlayingItem.localFilesMetadata == null && cfg.audio.maikiwiAudio.ciderPPE === true"
|
||||
:title="$root.getLz('settings.option.audio.enableAdvancedFunctionality.ciderPPE')"
|
||||
v-b-tooltip.hover
|
||||
></div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -75,7 +90,7 @@
|
|||
</div>
|
||||
<div class="playback-info">
|
||||
<div class="song-name">
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -86,8 +101,9 @@
|
|||
</div>
|
||||
<div class="app-chrome--center">
|
||||
<div class="app-chrome-playback-duration-bottom">
|
||||
<b-row v-if="mkReady()">
|
||||
<b-col sm="auto" v-if="!mk.nowPlayingItem?.isLiveRadioStation">{{ 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()"
|
||||
|
@ -96,13 +112,16 @@
|
|||
@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" v-if="!mk.nowPlayingItem?.isLiveRadioStation">{{ 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">
|
||||
<div class="app-chrome-item">
|
||||
<button class="playback-button--small shuffle" v-if="mk.shuffleMode == 0" :class="isDisabled() && 'disabled'"
|
||||
<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'"
|
||||
|
@ -114,7 +133,8 @@
|
|||
:title="$root.getLz('term.previous')" v-b-tooltip.hover></button>
|
||||
</div>
|
||||
<div class="app-chrome-item">
|
||||
<button class="playback-button stop" @click="mk.stop()" v-if="mk.isPlaying && mk.nowPlayingItem.attributes.playParams.kind == 'radioStation'"
|
||||
<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>
|
||||
|
@ -126,13 +146,16 @@
|
|||
:title="$root.getLz('term.next')" v-b-tooltip.hover></button>
|
||||
</div>
|
||||
<div class="app-chrome-item">
|
||||
<button class="playback-button--small repeat" v-if="mk.repeatMode == 0" :class="isDisabled() && 'disabled'"
|
||||
<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'"
|
||||
<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'"
|
||||
<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>
|
||||
|
@ -149,27 +172,27 @@
|
|||
v-b-tooltip.hover :title="formatVolumeTooltip()">
|
||||
</div>
|
||||
<div class="app-chrome-item generic">
|
||||
<button class="playback-button--small cast"
|
||||
<button class="playback-button--small cast"
|
||||
:title="$root.getLz('term.cast')"
|
||||
v-b-tooltip.hover
|
||||
@click="modals.castMenu = true"></button>
|
||||
</div>
|
||||
<div class="app-chrome-item generic">
|
||||
<button class="playback-button--small queue" :class="{'active': drawer.panel == 'queue'}"
|
||||
<button class="playback-button--small queue" :class="{'active': drawer.panel == 'queue'}"
|
||||
:title="$root.getLz('term.queue')"
|
||||
v-b-tooltip.hover
|
||||
@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"
|
||||
<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"
|
||||
<button class="playback-button--small lyrics"
|
||||
:style="{'opacity': 0.3, 'pointer-events': 'none'}"></button>
|
||||
</template>
|
||||
|
||||
|
|
|
@ -1,286 +1,313 @@
|
|||
<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="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" 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)"
|
||||
@contextmenu="mainMenuVisibility(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="app-chrome-item">
|
||||
<button class="playback-button navigation" @click="navigateBack()" :title="$root.getLz('term.navigateBack')"
|
||||
v-b-tooltip.hover>
|
||||
<svg-icon url="./views/svg/chevron-left.svg"></svg-icon>
|
||||
</button>
|
||||
</div>
|
||||
<div class="app-chrome-item">
|
||||
<button class="playback-button navigation" @click="navigateForward()"
|
||||
:title="$root.getLz('term.navigateForward')" v-b-tooltip.hover>
|
||||
<svg-icon url="./views/svg/chevron-right.svg"></svg-icon>
|
||||
</button>
|
||||
</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>
|
||||
<div class="app-chrome--left">
|
||||
<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" 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)"
|
||||
@contextmenu="mainMenuVisibility(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="app-chrome-item">
|
||||
<button class="playback-button navigation" @click="navigateBack()"
|
||||
:title="$root.getLz('term.navigateBack')"
|
||||
v-b-tooltip.hover>
|
||||
<svg-icon url="./views/svg/chevron-left.svg"></svg-icon>
|
||||
</button>
|
||||
</div>
|
||||
<div class="app-chrome-item">
|
||||
<button class="playback-button navigation" @click="navigateForward()"
|
||||
:title="$root.getLz('term.navigateForward')" v-b-tooltip.hover>
|
||||
<svg-icon url="./views/svg/chevron-right.svg"></svg-icon>
|
||||
</button>
|
||||
</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 playback-control-buttons">
|
||||
<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>
|
||||
</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>
|
||||
</div>
|
||||
<div class="app-chrome-item display--large">
|
||||
<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>
|
||||
</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>
|
||||
</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>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
<div class="app-chrome--center">
|
||||
<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="artwork" id="artworkLCD">
|
||||
<mediaitem-artwork :url="currentArtUrl"></mediaitem-artwork>
|
||||
</div>
|
||||
<b-popover custom-class="mediainfo-popover" target="artworkLCD" triggers="hover" placement="bottom">
|
||||
<div class="content">
|
||||
<div class="shadow-artwork">
|
||||
<mediaitem-artwork :url="currentArtUrl"></mediaitem-artwork>
|
||||
</div>
|
||||
<div class="popover-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`)">
|
||||
{{ mk.nowPlayingItem["attributes"]["artistName"] }}
|
||||
</div>
|
||||
<div class="song-album" @click="getNowPlayingItemDetailed(`album`)">
|
||||
{{
|
||||
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)">
|
||||
{{ $root.getLz("term.miniplayer") }}
|
||||
</button>
|
||||
<button class="md-btn md-btn-small" style="width: 100%" @click="drawer.open = false; fullscreen(true)">
|
||||
{{ $root.getLz("term.fullscreenView") }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</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 spatial-icon" v-if="cfg.audio.maikiwiAudio.spatial === true"
|
||||
:title="$root.getLz('settings.option.audio.enableAdvancedFunctionality.tunedAudioSpatialization') + ' (' + getProfileLz('CTS', cfg.audio.maikiwiAudio.spatialProfile) + ')'" v-b-tooltip.hover
|
||||
></div>
|
||||
<div class="audio-type lossless-icon" v-if="(mk.nowPlayingItem?.localFilesMetadata?.lossless ?? false) === true"
|
||||
:title="mk.nowPlayingItem?.localFilesMetadata?.bitDepth +'-bit / '+ mk.nowPlayingItem?.localFilesMetadata?.sampleRate/1000 + ' kHz ' + mk.nowPlayingItem.localFilesMetadata.container" v-b-tooltip.hover
|
||||
></div>
|
||||
<div class="audio-type ppe-icon" v-if="mk.nowPlayingItem.localFilesMetadata == null && cfg.audio.maikiwiAudio.ciderPPE === true"
|
||||
:title="$root.getLz('settings.option.audio.enableAdvancedFunctionality.ciderPPE')" v-b-tooltip.hover
|
||||
></div>
|
||||
<div class="vdiv display--large" v-if="getThemeDirective('windowLayout') != 'twopanel'"></div>
|
||||
</template>
|
||||
<template v-if="getThemeDirective('windowLayout') != 'twopanel'">
|
||||
<div class="app-chrome-item playback-control-buttons">
|
||||
<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>
|
||||
</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>
|
||||
</div>
|
||||
<div class="app-chrome-item display--large">
|
||||
<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>
|
||||
</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>
|
||||
</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>
|
||||
</div>
|
||||
</div>
|
||||
<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="
|
||||
</template>
|
||||
</div>
|
||||
<div class="app-chrome--center">
|
||||
<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="artwork" id="artworkLCD">
|
||||
<mediaitem-artwork :url="currentArtUrl"></mediaitem-artwork>
|
||||
</div>
|
||||
<b-popover custom-class="mediainfo-popover" target="artworkLCD" triggers="hover" placement="bottom">
|
||||
<div class="content">
|
||||
<div class="shadow-artwork">
|
||||
<mediaitem-artwork :url="currentArtUrl"></mediaitem-artwork>
|
||||
</div>
|
||||
<div class="popover-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`)">
|
||||
{{ mk.nowPlayingItem["attributes"]["artistName"] }}
|
||||
</div>
|
||||
<div class="song-album" @click="getNowPlayingItemDetailed(`album`)">
|
||||
{{
|
||||
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)">
|
||||
{{ $root.getLz("term.miniplayer") }}
|
||||
</button>
|
||||
<button class="md-btn md-btn-small" style="width: 100%"
|
||||
@click="drawer.open = false; fullscreen(true)">
|
||||
{{ $root.getLz("term.fullscreenView") }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</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 spatial-icon" v-if="cfg.audio.maikiwiAudio.spatial === true"
|
||||
:title="$root.getLz('settings.option.audio.enableAdvancedFunctionality.tunedAudioSpatialization') + ' (' + getProfileLz('CTS', cfg.audio.maikiwiAudio.spatialProfile) + ')'"
|
||||
v-b-tooltip.hover
|
||||
></div>
|
||||
<div class="audio-type lossless-icon"
|
||||
v-if="(mk.nowPlayingItem?.localFilesMetadata?.lossless ?? false) === true"
|
||||
:title="mk.nowPlayingItem?.localFilesMetadata?.bitDepth +'-bit / '+ mk.nowPlayingItem?.localFilesMetadata?.sampleRate/1000 + ' kHz ' + mk.nowPlayingItem.localFilesMetadata.container"
|
||||
v-b-tooltip.hover
|
||||
></div>
|
||||
<div class="audio-type ppe-icon"
|
||||
v-if="mk.nowPlayingItem.localFilesMetadata == null && cfg.audio.maikiwiAudio.ciderPPE === true"
|
||||
:title="$root.getLz('settings.option.audio.enableAdvancedFunctionality.ciderPPE')"
|
||||
v-b-tooltip.hover
|
||||
></div>
|
||||
</div>
|
||||
<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"]
|
||||
: ""
|
||||
}}
|
||||
</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'} ]">
|
||||
<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="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()" />
|
||||
</div>
|
||||
</div>
|
||||
{{
|
||||
mk.nowPlayingItem["attributes"]["albumName"]
|
||||
? mk.nowPlayingItem["attributes"]["albumName"]
|
||||
: ""
|
||||
}}
|
||||
</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>
|
||||
<div class="svg-icon"></div>
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
</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'} ]">
|
||||
<p style="width: auto">{{ convertTime(getSongProgress()) }}</p>
|
||||
<p style="width: auto">
|
||||
{{ convertTime(mk.currentPlaybackDuration) }}
|
||||
</p>
|
||||
</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">
|
||||
|
||||
<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()" />
|
||||
</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>
|
||||
<div class="svg-icon"></div>
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</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 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"
|
||||
svg-icon-name="home" page="home">
|
||||
</sidebar-library-item>
|
||||
<sidebar-library-item :name="$root.getLz('term.listenNow')" svg-icon="./assets/feather/play-circle.svg"
|
||||
svg-icon-name="listenNow"
|
||||
page="listen_now"></sidebar-library-item>
|
||||
<sidebar-library-item :name="$root.getLz('term.browse')" svg-icon="./assets/feather/globe.svg"
|
||||
svg-icon-name="browse" page="browse">
|
||||
</sidebar-library-item>
|
||||
<sidebar-library-item :name="$root.getLz('term.radio')" svg-icon="./assets/feather/radio.svg"
|
||||
svg-icon-name="radio" page="radio">
|
||||
</sidebar-library-item>
|
||||
</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" svg-icon-name="home" page="home">
|
||||
</sidebar-library-item>
|
||||
<sidebar-library-item :name="$root.getLz('term.listenNow')" svg-icon="./assets/feather/play-circle.svg" svg-icon-name="listenNow"
|
||||
page="listen_now"></sidebar-library-item>
|
||||
<sidebar-library-item :name="$root.getLz('term.browse')" svg-icon="./assets/feather/globe.svg" svg-icon-name="browse" page="browse">
|
||||
</sidebar-library-item>
|
||||
<sidebar-library-item :name="$root.getLz('term.radio')" svg-icon="./assets/feather/radio.svg" svg-icon-name="radio" 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()"
|
||||
: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()" />
|
||||
</div>
|
||||
<div class="app-chrome-item generic">
|
||||
<button class="playback-button--small cast" :title="$root.getLz('term.cast')"
|
||||
@click="modals.castMenu = true"
|
||||
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>
|
||||
</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>
|
||||
<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()"
|
||||
: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()" />
|
||||
</div>
|
||||
<div class="app-chrome-item generic">
|
||||
<button class="playback-button--small cast" :title="$root.getLz('term.cast')"
|
||||
@click="modals.castMenu = true"
|
||||
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>
|
||||
</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>
|
||||
</template>
|
||||
<template v-else>
|
||||
<button class="playback-button--small lyrics"
|
||||
:style="{'opacity': 0.3, 'pointer-events': 'none'}"></button>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<button class="playback-button--small lyrics" :style="{'opacity': 0.3, 'pointer-events': 'none'}" ></button>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div class="app-chrome-item search">
|
||||
<div class="search-input-container">
|
||||
<div class="search-input--icon"></div>
|
||||
<input type="search" spellcheck="false" @click="$root.appRoute('search');" @focus="search.showHints = true"
|
||||
@blur="setTimeout(()=>{search.showHints = false}, 300)"
|
||||
v-on:keyup.enter="searchQuery();search.showHints = false" @change="$root.appRoute('search');" @input="getSearchHints()"
|
||||
:placeholder="$root.getLz('term.search') + '...'" v-model="search.term" ref="searchInput"
|
||||
class="search-input" />
|
||||
<div class="app-chrome-item search">
|
||||
<div class="search-input-container">
|
||||
<div class="search-input--icon"></div>
|
||||
<input type="search" spellcheck="false" @click="$root.appRoute('search');"
|
||||
@focus="search.showHints = true"
|
||||
@blur="setTimeout(()=>{search.showHints = false}, 300)"
|
||||
v-on:keyup.enter="searchQuery();search.showHints = false" @change="$root.appRoute('search');"
|
||||
@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">
|
||||
<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 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)">
|
||||
{{ hint }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<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" v-else @click="ipcRenderer.send('maximize')"></div>
|
||||
<div class="close" @click="ipcRenderer.send('close')"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<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" v-else @click="ipcRenderer.send('maximize')"></div>
|
||||
<div class="close" @click="ipcRenderer.send('close')"></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)"
|
||||
@contextmenu="mainMenuVisibility(true)" :class="{active: chrome.menuOpened}"></button>
|
||||
</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)"
|
||||
@contextmenu="mainMenuVisibility(true)" :class="{active: chrome.menuOpened}"></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -50,10 +50,10 @@
|
|||
<div id="apple-music-video-player-controls">
|
||||
<div id="player-exit" title="Close" @click="exitMV();fullscreen(false);">
|
||||
<svg fill="white" xmlns="http://www.w3.org/2000/svg" width="21" height="21" viewBox="0 0 21 21"
|
||||
aria-role="presentation" focusable="false" @click="exitMV();fullscreen(false);">
|
||||
aria-role="presentation" focusable="false" @click="exitMV();fullscreen(false);">
|
||||
<path
|
||||
d="M10.5 21C4.724 21 0 16.275 0 10.5S4.724 0 10.5 0 21 4.725 21 10.5 16.276 21 10.5 21zm-3.543-5.967a.96.96 0 00.693-.295l2.837-2.842 2.85 2.842c.167.167.41.295.693.295.552 0 1.001-.461 1.001-1.012 0-.281-.115-.512-.295-.704L11.899 10.5l2.85-2.855a.875.875 0 00.295-.68c0-.55-.45-.998-1.001-.998a.871.871 0 00-.668.295l-2.888 2.855-2.862-2.843a.891.891 0 00-.668-.281.99.99 0 00-1.001.986c0 .269.116.512.295.678L9.088 10.5l-2.837 2.843a.926.926 0 00-.295.678c0 .551.45 1.012 1.001 1.012z"
|
||||
fill-rule="nonzero"/>
|
||||
fill-rule="nonzero" />
|
||||
</svg>
|
||||
</div>
|
||||
<div id="captions" v-if="lyricon">{{((lyricon) ? ((lyrics.length > 0 && lyrics[currentLyricsLine] &&
|
||||
|
@ -67,7 +67,7 @@
|
|||
</div>
|
||||
<div class="playback-info music-player-info">
|
||||
<div class="song-artist-album-content"
|
||||
style="display: inline-block; -webkit-box-orient: horizontal; white-space: nowrap;">
|
||||
style="display: inline-block; -webkit-box-orient: horizontal; white-space: nowrap;">
|
||||
<div class="song-artist" style="display: inline-block">
|
||||
{{ mk.nowPlayingItem?.attributes?.artistName ?? '' }}
|
||||
</div>
|
||||
|
@ -85,7 +85,7 @@
|
|||
@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()">
|
||||
<p style="width: auto">{{ convertTime(mk.currentPlaybackDuration) }}
|
||||
<p style="width: auto">{{ convertTime(mk.currentPlaybackDuration) }}
|
||||
</div>
|
||||
<div class="app-chrome-item display--large">
|
||||
<div class="app-chrome-item volume display--large">
|
||||
|
@ -93,7 +93,8 @@
|
|||
: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"
|
||||
<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>
|
||||
|
@ -102,30 +103,30 @@
|
|||
<button class="playback-button play" @click="mk.play()" v-else
|
||||
:title="$root.getLz('term.play')" v-b-tooltip.hover></button>
|
||||
<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>
|
||||
</template>
|
||||
<template v-else>
|
||||
<button class="playback-button--small lyrics"
|
||||
:style="{'opacity': 0.3, 'pointer-events': 'none'}"></button>
|
||||
</template>
|
||||
</div>
|
||||
<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>
|
||||
</template>
|
||||
<template v-else>
|
||||
<button class="playback-button--small lyrics"
|
||||
:style="{'opacity': 0.3, 'pointer-events': 'none'}"></button>
|
||||
</template>
|
||||
</div>
|
||||
<div id="player-pip"
|
||||
@click="pip()"
|
||||
title="Picture-in-Picture"
|
||||
v-b-tooltip.hover>
|
||||
@click="pip()"
|
||||
title="Picture-in-Picture"
|
||||
v-b-tooltip.hover>
|
||||
<%- include("../svg/pip.svg") %>
|
||||
</div>
|
||||
<div id="player-fullscreen"
|
||||
@click="fullscreen(!fullscreenState)"
|
||||
title="Fullscreen"
|
||||
v-b-tooltip.hover>
|
||||
@click="fullscreen(!fullscreenState)"
|
||||
title="Fullscreen"
|
||||
v-b-tooltip.hover>
|
||||
<%- include("../svg/fullscreen.svg") %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,88 +1,90 @@
|
|||
<script type="text/x-template" id="add-to-playlist">
|
||||
<div class="modal-fullscreen addtoplaylist-panel" @click.self="app.resetState()" @contextmenu.self="app.resetState()">
|
||||
<div class="modal-window">
|
||||
<div class="modal-header">
|
||||
<div class="modal-title">{{app.getLz('action.addToPlaylist')}}</div>
|
||||
<button class="close-btn" @click="app.resetState()" :aria-label="app.getLz('action.close')"></button>
|
||||
</div>
|
||||
<div class="modal-content">
|
||||
<button class="playlist-item"
|
||||
@click="app.addSelectedToNewPlaylist()" style="width:100%;">
|
||||
<div class="icon"><%- include("../svg/plus.svg") %></div>
|
||||
<div class="name">{{app.getLz('action.createPlaylist')}}</div>
|
||||
</button>
|
||||
<sidebar-playlist :playlist-select="playlistSelect" :relate-media-items="relateItems" v-for="item in $root.getPlaylistFolderChildren('p.playlistsroot')" :item="item">
|
||||
</sidebar-playlist>
|
||||
</div>
|
||||
<div class="modal-search">
|
||||
<div class="search-input-container" style="width:100%;margin: 16px 0;">
|
||||
<div class="search-input--icon"></div>
|
||||
<input type="search"
|
||||
ref="searchInput"
|
||||
style="width:100%;"
|
||||
spellcheck="false"
|
||||
:placeholder="app.getLz('term.search') + '...'"
|
||||
v-model="searchQuery"
|
||||
@input="search()"
|
||||
class="search-input">
|
||||
</div>
|
||||
<div class="modal-fullscreen addtoplaylist-panel" @click.self="app.resetState()"
|
||||
@contextmenu.self="app.resetState()">
|
||||
<div class="modal-window">
|
||||
<div class="modal-header">
|
||||
<div class="modal-title">{{app.getLz('action.addToPlaylist')}}</div>
|
||||
<button class="close-btn" @click="app.resetState()" :aria-label="app.getLz('action.close')"></button>
|
||||
</div>
|
||||
<div class="modal-content">
|
||||
<button class="playlist-item"
|
||||
@click="app.addSelectedToNewPlaylist()" style="width:100%;">
|
||||
<div class="icon"><%- include("../svg/plus.svg") %></div>
|
||||
<div class="name">{{app.getLz('action.createPlaylist')}}</div>
|
||||
</button>
|
||||
<sidebar-playlist :playlist-select="playlistSelect" :relate-media-items="relateItems"
|
||||
v-for="item in $root.getPlaylistFolderChildren('p.playlistsroot')" :item="item">
|
||||
</sidebar-playlist>
|
||||
</div>
|
||||
<div class="modal-search">
|
||||
<div class="search-input-container" style="width:100%;margin: 16px 0;">
|
||||
<div class="search-input--icon"></div>
|
||||
<input type="search"
|
||||
ref="searchInput"
|
||||
style="width:100%;"
|
||||
spellcheck="false"
|
||||
:placeholder="app.getLz('term.search') + '...'"
|
||||
v-model="searchQuery"
|
||||
@input="search()"
|
||||
class="search-input">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script>
|
||||
Vue.component('add-to-playlist', {
|
||||
template: '#add-to-playlist',
|
||||
data: function () {
|
||||
return {
|
||||
playlistSorted: [],
|
||||
searchQuery: "",
|
||||
focused: "",
|
||||
app: this.$root,
|
||||
relateItems: []
|
||||
}
|
||||
},
|
||||
props: {
|
||||
playlists: {
|
||||
type: Array,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.relateItems = [this.$root.selectedMediaItems[0].id]
|
||||
this.search()
|
||||
this.$refs.searchInput.focus()
|
||||
this.$refs.searchInput.addEventListener('keydown', (e) => {
|
||||
if (e.keyCode == 13) {
|
||||
if (this.focused != "") {
|
||||
this.addToPlaylist(this.focused)
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
playlistSelect(playlist) {
|
||||
if (playlist.type != "library-playlist-folders") {
|
||||
this.addToPlaylist(playlist.id)
|
||||
}
|
||||
},
|
||||
addToPlaylist(id) {
|
||||
app.addSelectedToPlaylist(id)
|
||||
},
|
||||
search() {
|
||||
this.focused = ""
|
||||
if (this.searchQuery == "") {
|
||||
this.playlistSorted = this.playlists
|
||||
} else {
|
||||
this.playlistSorted = this.playlists.filter(playlist => {
|
||||
return playlist.attributes.name.toLowerCase().indexOf(this.searchQuery.toLowerCase()) > -1
|
||||
})
|
||||
if (this.playlistSorted.length == 1) {
|
||||
this.focused = this.playlistSorted[0].id
|
||||
}
|
||||
}
|
||||
},
|
||||
Vue.component('add-to-playlist', {
|
||||
template: '#add-to-playlist',
|
||||
data: function() {
|
||||
return {
|
||||
playlistSorted: [],
|
||||
searchQuery: "",
|
||||
focused: "",
|
||||
app: this.$root,
|
||||
relateItems: []
|
||||
}
|
||||
},
|
||||
props: {
|
||||
playlists: {
|
||||
type: Array,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.relateItems = [this.$root.selectedMediaItems[0].id]
|
||||
this.search()
|
||||
this.$refs.searchInput.focus()
|
||||
this.$refs.searchInput.addEventListener('keydown', (e) => {
|
||||
if (e.keyCode == 13) {
|
||||
if (this.focused != "") {
|
||||
this.addToPlaylist(this.focused)
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
playlistSelect(playlist) {
|
||||
if (playlist.type != "library-playlist-folders") {
|
||||
this.addToPlaylist(playlist.id)
|
||||
}
|
||||
},
|
||||
addToPlaylist(id) {
|
||||
app.addSelectedToPlaylist(id)
|
||||
},
|
||||
search() {
|
||||
this.focused = ""
|
||||
if (this.searchQuery == "") {
|
||||
this.playlistSorted = this.playlists
|
||||
} else {
|
||||
this.playlistSorted = this.playlists.filter(playlist => {
|
||||
return playlist.attributes.name.toLowerCase().indexOf(this.searchQuery.toLowerCase()) > -1
|
||||
})
|
||||
if (this.playlistSorted.length == 1) {
|
||||
this.focused = this.playlistSorted[0].id
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -1,42 +1,45 @@
|
|||
<script type="text/x-template" id="airplay-modal">
|
||||
<div class="spatialproperties-panel castmenu modal-fullscreen airplay-modal" @click.self="close()" @contextmenu.self="close()">
|
||||
<div class="modal-window airplay-modal">
|
||||
<div class="modal-header">
|
||||
<div class="modal-title">{{'Enter password'}}</div>
|
||||
<button class="close-btn" @click="close()" :aria-label="this.$root.getLz('action.close')"></button>
|
||||
</div>
|
||||
<div class="modal-content" style="overflow-y: overlay; padding: 3%">
|
||||
<input type="text" v-model="passcode"/>
|
||||
</div>
|
||||
<div class="md-footer">
|
||||
<div class="row">
|
||||
<div class="col" >
|
||||
<button style="width:100%" @click="enterPassword()" class="md-btn md-btn-block md-btn-primary">{{'OK'}}</button>
|
||||
<div class="spatialproperties-panel castmenu modal-fullscreen airplay-modal" @click.self="close()"
|
||||
@contextmenu.self="close()">
|
||||
<div class="modal-window airplay-modal">
|
||||
<div class="modal-header">
|
||||
<div class="modal-title">{{'Enter password'}}</div>
|
||||
<button class="close-btn" @click="close()" :aria-label="this.$root.getLz('action.close')"></button>
|
||||
</div>
|
||||
<div class="modal-content" style="overflow-y: overlay; padding: 3%">
|
||||
<input type="text" v-model="passcode" />
|
||||
</div>
|
||||
<div class="md-footer">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<button style="width:100%" @click="enterPassword()" class="md-btn md-btn-block md-btn-primary">
|
||||
{{'OK'}}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
<script>
|
||||
Vue.component('airplay-modal', {
|
||||
template: '#airplay-modal',
|
||||
data: function () {
|
||||
return {
|
||||
passcode: '',
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
},
|
||||
methods: {
|
||||
close() {
|
||||
this.$root.modals.airplayPW = false
|
||||
},
|
||||
enterPassword() {
|
||||
console.log('Entered passCode: ', this.passcode)
|
||||
ipcRenderer.send("setAirPlayPasscode",this.passcode)
|
||||
this.close()
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
Vue.component('airplay-modal', {
|
||||
template: '#airplay-modal',
|
||||
data: function() {
|
||||
return {
|
||||
passcode: '',
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
},
|
||||
methods: {
|
||||
close() {
|
||||
this.$root.modals.airplayPW = false
|
||||
},
|
||||
enterPassword() {
|
||||
console.log('Entered passCode: ', this.passcode)
|
||||
ipcRenderer.send("setAirPlayPasscode", this.passcode)
|
||||
this.close()
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -5,93 +5,98 @@
|
|||
</script>
|
||||
|
||||
<script>
|
||||
Vue.component('animatedartwork-view', {
|
||||
template: '#animatedartwork-view',
|
||||
data: function () {
|
||||
return {
|
||||
app: this.$root,
|
||||
hls: null,
|
||||
}
|
||||
},
|
||||
props: {
|
||||
video: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
priority: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
async mounted() {
|
||||
if (!this.priority && app.cfg.visual.animated_artwork == "limited") {
|
||||
return
|
||||
} else if (app.cfg.visual.animated_artwork == "disabled") {
|
||||
return
|
||||
}
|
||||
if (this.video) {
|
||||
this.$nextTick(function () {
|
||||
var config = {
|
||||
backBufferLength: 0,
|
||||
enableWebVTT: false,
|
||||
enableCEA708Captions: false,
|
||||
emeEnabled: false,
|
||||
abrEwmaDefaultEstimate: 10000,
|
||||
testBandwidth: false,
|
||||
};
|
||||
if (this.hls) {
|
||||
this.hls.detachMedia();
|
||||
} else {
|
||||
Vue.component('animatedartwork-view', {
|
||||
template: '#animatedartwork-view',
|
||||
data: function() {
|
||||
return {
|
||||
app: this.$root,
|
||||
hls: null,
|
||||
}
|
||||
},
|
||||
props: {
|
||||
video: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
priority: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
async mounted() {
|
||||
if (!this.priority && app.cfg.visual.animated_artwork == "limited") {
|
||||
return
|
||||
} else if (app.cfg.visual.animated_artwork == "disabled") {
|
||||
return
|
||||
}
|
||||
if (this.video) {
|
||||
this.$nextTick(function() {
|
||||
var config = {
|
||||
backBufferLength: 0,
|
||||
enableWebVTT: false,
|
||||
enableCEA708Captions: false,
|
||||
emeEnabled: false,
|
||||
abrEwmaDefaultEstimate: 10000,
|
||||
testBandwidth: false,
|
||||
};
|
||||
if (this.hls) {
|
||||
this.hls.detachMedia();
|
||||
} else {
|
||||
|
||||
this.hls = new CiderHls(config);
|
||||
}
|
||||
// bind them together
|
||||
if (this.$refs.video) {
|
||||
let d = "WIDEVINE_SOFTWARE"
|
||||
let h = {
|
||||
initDataTypes: ["cenc", "keyids"],
|
||||
distinctiveIdentifier: "optional",
|
||||
persistentState: "required"
|
||||
}
|
||||
let p = {
|
||||
platformInfo: {requiresCDMAttachOnStart: !0, maxSecurityLevel: d, keySystemConfig: h},
|
||||
appData: {serviceName: "Apple Music"}
|
||||
}
|
||||
|
||||
this.hls.attachMedia(this.$refs.video);
|
||||
this.hls.loadSource(this.video, p);
|
||||
let u = this.hls;
|
||||
var quality = app.cfg.visual.animated_artwork_qualityLevel;
|
||||
setTimeout(() => {
|
||||
let levelsnum = u.levels.map((level)=>{return level.width})
|
||||
if (levelsnum.length > 0) {
|
||||
let qualities = []
|
||||
let qualities2 = []
|
||||
for (let i = 0; i < levelsnum.length; i++) {
|
||||
if (qualities2.indexOf(levelsnum[i]) == -1) {
|
||||
qualities.push({level: i, quality: levelsnum[i]})
|
||||
qualities2.push(levelsnum[i])
|
||||
}
|
||||
}
|
||||
let actualnum = Math.floor(qualities[qualities.length -1 ].level * (quality / 4))
|
||||
if (quality != 0 ){
|
||||
quality = qualities[Math.min(actualnum,qualities.length -1 )].level
|
||||
}
|
||||
if (quality == 4 ){
|
||||
quality = qualities[qualities.length - 1].level
|
||||
}
|
||||
}
|
||||
try{
|
||||
this.hls.loadLevel = parseInt( quality || 1);} catch(e){}},200)
|
||||
}
|
||||
})
|
||||
this.hls = new CiderHls(config);
|
||||
}
|
||||
// bind them together
|
||||
if (this.$refs.video) {
|
||||
let d = "WIDEVINE_SOFTWARE"
|
||||
let h = {
|
||||
initDataTypes: ["cenc", "keyids"],
|
||||
distinctiveIdentifier: "optional",
|
||||
persistentState: "required"
|
||||
}
|
||||
},
|
||||
async beforeDestroy() {
|
||||
if (this.hls) {
|
||||
await this.hls.destroy();
|
||||
this.hls = null
|
||||
let p = {
|
||||
platformInfo: { requiresCDMAttachOnStart: !0, maxSecurityLevel: d, keySystemConfig: h },
|
||||
appData: { serviceName: "Apple Music" }
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
this.hls.attachMedia(this.$refs.video);
|
||||
this.hls.loadSource(this.video, p);
|
||||
let u = this.hls;
|
||||
var quality = app.cfg.visual.animated_artwork_qualityLevel;
|
||||
setTimeout(() => {
|
||||
let levelsnum = u.levels.map((level) => {
|
||||
return level.width
|
||||
})
|
||||
if (levelsnum.length > 0) {
|
||||
let qualities = []
|
||||
let qualities2 = []
|
||||
for (let i = 0; i < levelsnum.length; i++) {
|
||||
if (qualities2.indexOf(levelsnum[i]) == -1) {
|
||||
qualities.push({ level: i, quality: levelsnum[i] })
|
||||
qualities2.push(levelsnum[i])
|
||||
}
|
||||
}
|
||||
let actualnum = Math.floor(qualities[qualities.length - 1].level * (quality / 4))
|
||||
if (quality != 0) {
|
||||
quality = qualities[Math.min(actualnum, qualities.length - 1)].level
|
||||
}
|
||||
if (quality == 4) {
|
||||
quality = qualities[qualities.length - 1].level
|
||||
}
|
||||
}
|
||||
try {
|
||||
this.hls.loadLevel = parseInt(quality || 1);
|
||||
} catch (e) {
|
||||
}
|
||||
}, 200)
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
async beforeDestroy() {
|
||||
if (this.hls) {
|
||||
await this.hls.destroy();
|
||||
this.hls = null
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -15,14 +15,14 @@
|
|||
<transition
|
||||
<% if(env.appRoutes[i].onEnter) {
|
||||
%>
|
||||
v-on:enter="<%- env.appRoutes[i].onEnter %>"
|
||||
v-on:enter="<%- env.appRoutes[i].onEnter; %>"
|
||||
<%
|
||||
}
|
||||
%>
|
||||
:name="$root.chrome.desiredPageTransition">
|
||||
<template
|
||||
v-if="<%- env.appRoutes[i].condition %>">
|
||||
<%- env.appRoutes[i].component %>
|
||||
v-if="<%- env.appRoutes[i].condition; %>">
|
||||
<%- env.appRoutes[i].component; %>
|
||||
</template>
|
||||
</transition>
|
||||
<% } %>
|
||||
|
@ -38,14 +38,13 @@
|
|||
</script>
|
||||
|
||||
<script>
|
||||
Vue.component('app-content-area', {
|
||||
template: '#app-content-area',
|
||||
data: function () {
|
||||
return {
|
||||
scrollPos: 0
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
}
|
||||
});
|
||||
</script>
|
||||
Vue.component('app-content-area', {
|
||||
template: '#app-content-area',
|
||||
data: function() {
|
||||
return {
|
||||
scrollPos: 0
|
||||
}
|
||||
},
|
||||
methods: {}
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -1,49 +1,53 @@
|
|||
<script type="text/x-template" id="artist-chip">
|
||||
<div class="artist-chip" @click.self="route" tabindex="0">
|
||||
<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 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.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>
|
||||
<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>
|
||||
|
||||
<script>
|
||||
Vue.component('artist-chip', {
|
||||
props: {
|
||||
item: {
|
||||
type: Object,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data: function() {
|
||||
return {
|
||||
image: false,
|
||||
artist: {
|
||||
id: null
|
||||
}
|
||||
}
|
||||
},
|
||||
template: '#artist-chip',
|
||||
async mounted() {
|
||||
let artistId = this.item.id
|
||||
if (typeof this.item.relationships == "object") {
|
||||
artistId = this.item.relationships.catalog.data[0].id
|
||||
}
|
||||
app.mk.api.v3.music(`/v1/catalog/${app.mk.storefrontId}/artists/${artistId}`).then(response => {
|
||||
this.artist = response.data.data[0];
|
||||
this.image = true;
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
route() {
|
||||
app.appRoute(`artist/${this.artist.id}`);
|
||||
}
|
||||
Vue.component('artist-chip', {
|
||||
props: {
|
||||
item: {
|
||||
type: Object,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data: function() {
|
||||
return {
|
||||
image: false,
|
||||
artist: {
|
||||
id: null
|
||||
}
|
||||
});
|
||||
</script>
|
||||
}
|
||||
},
|
||||
template: '#artist-chip',
|
||||
async mounted() {
|
||||
let artistId = this.item.id
|
||||
if (typeof this.item.relationships == "object") {
|
||||
artistId = this.item.relationships.catalog.data[0].id
|
||||
}
|
||||
app.mk.api.v3.music(`/v1/catalog/${app.mk.storefrontId}/artists/${artistId}`).then(response => {
|
||||
this.artist = response.data.data[0];
|
||||
this.image = true;
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
route() {
|
||||
app.appRoute(`artist/${this.artist.id}`);
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -1,37 +1,36 @@
|
|||
<script type="text/x-template" id="artwork-material">
|
||||
<div class="artworkMaterial">
|
||||
<mediaitem-artwork :url="src" :size="500" v-for="image in images"/>
|
||||
<mediaitem-artwork :url="src" :size="500" v-for="image in images" />
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script>
|
||||
Vue.component('artwork-material', {
|
||||
template: '#artwork-material',
|
||||
data: function () {
|
||||
return {
|
||||
src: ""
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.src = app.getMediaItemArtwork(this.url, this.size)
|
||||
},
|
||||
props: {
|
||||
url: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
size: {
|
||||
type: [String, Number],
|
||||
required: false,
|
||||
default: '32'
|
||||
},
|
||||
images: {
|
||||
type: [String, Number],
|
||||
required: false,
|
||||
default: '2'
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
}
|
||||
});
|
||||
</script>
|
||||
Vue.component('artwork-material', {
|
||||
template: '#artwork-material',
|
||||
data: function() {
|
||||
return {
|
||||
src: ""
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.src = app.getMediaItemArtwork(this.url, this.size)
|
||||
},
|
||||
props: {
|
||||
url: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
size: {
|
||||
type: [String, Number],
|
||||
required: false,
|
||||
default: '32'
|
||||
},
|
||||
images: {
|
||||
type: [String, Number],
|
||||
required: false,
|
||||
default: '2'
|
||||
}
|
||||
},
|
||||
methods: {}
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -4,7 +4,8 @@
|
|||
<div class="modal-window">
|
||||
<div class="modal-header">
|
||||
<div class="modal-title">{{app.getLz('term.audioControls')}}</div>
|
||||
<button class="close-btn" @click="app.modals.audioControls = false" :aria-label="app.getLz('action.close')"></button>
|
||||
<button class="close-btn" @click="app.modals.audioControls = false"
|
||||
:aria-label="app.getLz('action.close')"></button>
|
||||
</div>
|
||||
<div class="modal-content">
|
||||
<div class="md-option-line">
|
||||
|
@ -14,7 +15,7 @@
|
|||
<div class="md-option-segment md-option-segment_auto percent">
|
||||
<input type="number"
|
||||
style="width: 100%; text-align: center; margin-right: 5px;" min="0"
|
||||
step="2" v-model="volume"/>
|
||||
step="2" v-model="volume" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="md-option-line">
|
||||
|
@ -23,7 +24,7 @@
|
|||
</div>
|
||||
<div class="md-option-segment md-option-segment_auto percent">
|
||||
<input type="number" style="width: 100%; text-align: center; margin-right: 5px;" min="0"
|
||||
v-model="volumeStep"/>
|
||||
v-model="volumeStep" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="md-option-line">
|
||||
|
@ -32,66 +33,66 @@
|
|||
</div>
|
||||
<div class="md-option-segment md-option-segment_auto percent">
|
||||
<input type="number" style="width: 100%; text-align: center; margin-right: 5px;" min="0"
|
||||
v-model="maxVolume"/>
|
||||
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 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>
|
||||
</script>
|
||||
|
||||
<script>
|
||||
Vue.component('audio-controls', {
|
||||
template: '#audio-controls',
|
||||
data: function () {
|
||||
return {
|
||||
app: this.$root,
|
||||
maxVolume: this.$root.cfg.audio.maxVolume * 100,
|
||||
volumeStep: this.$root.cfg.audio.volumeStep * 100,
|
||||
volume: this.$root.cfg.audio.volume * 100
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
maxVolume: function (newValue, _oldValue) {
|
||||
if (newValue > 100) {
|
||||
newValue = 100
|
||||
} else {
|
||||
newValue = Math.round(newValue)
|
||||
}
|
||||
this.$root.cfg.audio.maxVolume = newValue / 100
|
||||
this.maxVolume = newValue
|
||||
console.log(newValue, _oldValue)
|
||||
},
|
||||
volume: function (newValue, _oldValue) {
|
||||
if (newValue > this.maxVolume) {
|
||||
newValue = 100
|
||||
} else {
|
||||
newValue = Math.round(newValue)
|
||||
}
|
||||
this.$root.mk.volume = newValue / 100
|
||||
this.volume = newValue
|
||||
console.log(newValue, _oldValue)
|
||||
},
|
||||
volumeStep: function (newValue, _oldValue) {
|
||||
if (newValue > this.maxVolume) {
|
||||
newValue = 100
|
||||
} else {
|
||||
newValue = Math.round(newValue)
|
||||
}
|
||||
this.$root.cfg.audio.volumeStep = newValue / 100
|
||||
this.volumeStep = newValue
|
||||
console.log(newValue, _oldValue)
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
Vue.component('audio-controls', {
|
||||
template: '#audio-controls',
|
||||
data: function() {
|
||||
return {
|
||||
app: this.$root,
|
||||
maxVolume: this.$root.cfg.audio.maxVolume * 100,
|
||||
volumeStep: this.$root.cfg.audio.volumeStep * 100,
|
||||
volume: this.$root.cfg.audio.volume * 100
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
maxVolume: function(newValue, _oldValue) {
|
||||
if (newValue > 100) {
|
||||
newValue = 100
|
||||
} else {
|
||||
newValue = Math.round(newValue)
|
||||
}
|
||||
this.$root.cfg.audio.maxVolume = newValue / 100
|
||||
this.maxVolume = newValue
|
||||
console.log(newValue, _oldValue)
|
||||
},
|
||||
volume: function(newValue, _oldValue) {
|
||||
if (newValue > this.maxVolume) {
|
||||
newValue = 100
|
||||
} else {
|
||||
newValue = Math.round(newValue)
|
||||
}
|
||||
this.$root.mk.volume = newValue / 100
|
||||
this.volume = newValue
|
||||
console.log(newValue, _oldValue)
|
||||
},
|
||||
volumeStep: function(newValue, _oldValue) {
|
||||
if (newValue > this.maxVolume) {
|
||||
newValue = 100
|
||||
} else {
|
||||
newValue = Math.round(newValue)
|
||||
}
|
||||
this.$root.cfg.audio.volumeStep = newValue / 100
|
||||
this.volumeStep = newValue
|
||||
console.log(newValue, _oldValue)
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -4,7 +4,8 @@
|
|||
<div class="modal-window">
|
||||
<div class="modal-header">
|
||||
<div class="modal-title">{{app.getLz('settings.option.audio.changePlaybackRate')}}</div>
|
||||
<button class="close-btn" @click="app.modals.audioPlaybackRate = false" :aria-label="app.getLz('action.close')"></button>
|
||||
<button class="close-btn" @click="app.modals.audioPlaybackRate = false"
|
||||
:aria-label="app.getLz('action.close')"></button>
|
||||
</div>
|
||||
<div class="modal-content">
|
||||
<div class="md-option-line">
|
||||
|
@ -15,7 +16,8 @@
|
|||
{{playbackRate}} ×
|
||||
</div>
|
||||
<div class="md-option-segment md-option-segment_auto">
|
||||
<input type="range" :step="0.05" min="0.25" :max="2" @wheel="playbackRateWheel" v-model="playbackRate">
|
||||
<input type="range" :step="0.05" min="0.25" :max="2" @wheel="playbackRateWheel"
|
||||
v-model="playbackRate">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -24,36 +26,36 @@
|
|||
</script>
|
||||
|
||||
<script>
|
||||
Vue.component('audio-playbackrate', {
|
||||
template: '#audio-playbackrate',
|
||||
data: function () {
|
||||
return {
|
||||
app: this.$root,
|
||||
playbackRate: this.$root.cfg.audio.playbackRate
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
playbackRate: function (newValue, _oldValue) {
|
||||
this.saveValue(newValue);
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
playbackRateWheel(event) {
|
||||
if (app.checkScrollDirectionIsUp(event)) {
|
||||
this.saveValue(this.$root.cfg.audio.playbackRate + 0.05);
|
||||
} else {
|
||||
this.saveValue(this.$root.cfg.audio.playbackRate - 0.05);
|
||||
}
|
||||
},
|
||||
saveValue(newValue) {
|
||||
newValue = Number(newValue);
|
||||
if (newValue >= 0.25 && newValue <= 2) {
|
||||
newValue = String(newValue).length > 4 ? newValue.toFixed(2) : newValue;
|
||||
this.$root.mk.playbackRate = newValue;
|
||||
this.$root.cfg.audio.playbackRate = newValue;
|
||||
this.playbackRate = newValue;
|
||||
}
|
||||
}
|
||||
Vue.component('audio-playbackrate', {
|
||||
template: '#audio-playbackrate',
|
||||
data: function() {
|
||||
return {
|
||||
app: this.$root,
|
||||
playbackRate: this.$root.cfg.audio.playbackRate
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
playbackRate: function(newValue, _oldValue) {
|
||||
this.saveValue(newValue);
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
playbackRateWheel(event) {
|
||||
if (app.checkScrollDirectionIsUp(event)) {
|
||||
this.saveValue(this.$root.cfg.audio.playbackRate + 0.05);
|
||||
} else {
|
||||
this.saveValue(this.$root.cfg.audio.playbackRate - 0.05);
|
||||
}
|
||||
});
|
||||
},
|
||||
saveValue(newValue) {
|
||||
newValue = Number(newValue);
|
||||
if (newValue >= 0.25 && newValue <= 2) {
|
||||
newValue = String(newValue).length > 4 ? newValue.toFixed(2) : newValue;
|
||||
this.$root.mk.playbackRate = newValue;
|
||||
this.$root.cfg.audio.playbackRate = newValue;
|
||||
this.playbackRate = newValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
<script type="text/x-template" id="audio-settings">
|
||||
<template>
|
||||
<div class="modal-fullscreen addtoplaylist-panel" @click.self="app.modals.audioSettings = false" @contextmenu.self="app.modals.audioSettings = false">
|
||||
<div class="modal-fullscreen addtoplaylist-panel" @click.self="app.modals.audioSettings = false"
|
||||
@contextmenu.self="app.modals.audioSettings = false">
|
||||
<div class="modal-window">
|
||||
<div class="modal-header">
|
||||
<div class="modal-title">{{app.getLz('term.audioSettings')}}</div>
|
||||
<button class="close-btn" @click="app.modals.audioSettings = false" :aria-label="app.getLz('action.close')"></button>
|
||||
<button class="close-btn" @click="app.modals.audioSettings = false"
|
||||
:aria-label="app.getLz('action.close')"></button>
|
||||
</div>
|
||||
<div class="modal-content">
|
||||
<button class="playlist-item"
|
||||
|
@ -34,29 +36,30 @@
|
|||
</script>
|
||||
|
||||
<script>
|
||||
Vue.component('audio-settings', {
|
||||
template: '#audio-settings',
|
||||
data: function () {
|
||||
return {
|
||||
app: this.$root,
|
||||
}
|
||||
},
|
||||
props: {},
|
||||
mounted() {},
|
||||
methods: {
|
||||
openEqualizer() {
|
||||
app.modals.equalizer = true
|
||||
app.modals.audioSettings = false
|
||||
},
|
||||
openAudioControls() {
|
||||
app.modals.audioControls = true
|
||||
app.modals.audioSettings = false
|
||||
},
|
||||
openAudioPlaybackRate() {
|
||||
app.modals.audioPlaybackRate = true
|
||||
app.modals.audioSettings = false
|
||||
},
|
||||
},
|
||||
Vue.component('audio-settings', {
|
||||
template: '#audio-settings',
|
||||
data: function() {
|
||||
return {
|
||||
app: this.$root,
|
||||
}
|
||||
);
|
||||
</script>
|
||||
},
|
||||
props: {},
|
||||
mounted() {
|
||||
},
|
||||
methods: {
|
||||
openEqualizer() {
|
||||
app.modals.equalizer = true
|
||||
app.modals.audioSettings = false
|
||||
},
|
||||
openAudioControls() {
|
||||
app.modals.audioControls = true
|
||||
app.modals.audioSettings = false
|
||||
},
|
||||
openAudioPlaybackRate() {
|
||||
app.modals.audioPlaybackRate = true
|
||||
app.modals.audioSettings = false
|
||||
},
|
||||
},
|
||||
}
|
||||
);
|
||||
</script>
|
||||
|
|
|
@ -1,130 +1,151 @@
|
|||
<script type="text/x-template" id="castmenu">
|
||||
<div class="spatialproperties-panel castmenu modal-fullscreen" @click.self="close()" @contextmenu.self="close()">
|
||||
<div class="modal-window">
|
||||
<div class="modal-header">
|
||||
<div class="modal-title">{{$root.getLz('action.cast.todevices')}}</div>
|
||||
<button class="close-btn" @click="close()" :aria-label="$root.getLz('action.close')"></button>
|
||||
</div>
|
||||
<div class="modal-content" style="overflow-y: overlay; padding: 3%">
|
||||
<div class="md-labeltext">{{$root.getLz('action.cast.chromecast')}}</div>
|
||||
<div class="md-option-container" style="margin-top: 12px;margin-bottom: 12px;overflow-y: scroll;">
|
||||
<template v-if="!scanning">
|
||||
<template v-for="(device) in devices.cast">
|
||||
<div class="md-option-line" style="cursor: pointer" @click="setCast(device)">
|
||||
<div class="md-option-segment">
|
||||
{{ device.name }}
|
||||
<br>
|
||||
<small>{{ device.host }}</small>
|
||||
</div>
|
||||
<div class="md-option-segment_auto" style="display: flex;justify-content: center;align-items: center" v-if="activeCasts.includes(device)">
|
||||
Connected
|
||||
</div>
|
||||
<div class="md-option-segment_auto" v-else style="display: flex;justify-content: center;align-items: center">
|
||||
<svg width="20" height="20" viewBox="0 0 34 34" fill="#fff" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" class="castPlayIndicator"><path d="M28.228,18.327l-16.023,8.983c-0.99,0.555 -2.205,-0.17 -2.205,-1.318l0,-17.984c0,-1.146 1.215,-1.873 2.205,-1.317l16.023,8.982c1.029,0.577 1.029,2.077 0,2.654Z" style="fill-rule:nonzero"></path></svg>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div class="md-option-line" style="cursor: pointer">
|
||||
<div class="md-option-segment">
|
||||
{{$root.getLz('action.cast.scanning')}}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
<div class="md-labeltext" >{{$root.getLz('action.cast.airplay')}}</div>
|
||||
<div class="md-option-container" style="margin-top: 12px;margin-bottom: 12px;overflow-y: scroll;">
|
||||
<div class="md-option-line">
|
||||
<div class="md-option-segment">
|
||||
{{'EXPERIMENTAL!!! Supports Homepods / Apple TVs / Shairport for now, AirPlay on Samsung/LG/Sony devices will be added later'}}
|
||||
<!-- {{$root.getLz('action.cast.airplay.underdevelopment')}} -->
|
||||
<template v-if="true" v-for="(device) in devices.airplay">
|
||||
<div class="md-option-line" style="cursor: pointer" @click="setAirPlayCast(device)">
|
||||
<div class="spatialproperties-panel castmenu modal-fullscreen" @click.self="close()" @contextmenu.self="close()">
|
||||
<div class="modal-window">
|
||||
<div class="modal-header">
|
||||
<div class="modal-title">{{$root.getLz('action.cast.todevices')}}</div>
|
||||
<button class="close-btn" @click="close()" :aria-label="$root.getLz('action.close')"></button>
|
||||
</div>
|
||||
<div class="modal-content" style="overflow-y: overlay; padding: 3%">
|
||||
<div class="md-labeltext">{{$root.getLz('action.cast.chromecast')}}</div>
|
||||
<div class="md-option-container" style="margin-top: 12px;margin-bottom: 12px;overflow-y: scroll;">
|
||||
<template v-if="!scanning">
|
||||
<template v-for="(device) in devices.cast">
|
||||
<div class="md-option-line" style="cursor: pointer" @click="setCast(device)">
|
||||
<div class="md-option-segment">
|
||||
{{ device.name }}
|
||||
<br>
|
||||
<small>{{ device.host }}</small>
|
||||
</div>
|
||||
<div class="md-option-segment_auto"
|
||||
style="display: flex;justify-content: center;align-items: center"
|
||||
v-if="activeCasts.includes(device)">
|
||||
Connected
|
||||
</div>
|
||||
<div class="md-option-segment_auto" v-else
|
||||
style="display: flex;justify-content: center;align-items: center">
|
||||
<svg width="20" height="20" viewBox="0 0 34 34" fill="#fff" version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xml:space="preserve" class="castPlayIndicator"><path
|
||||
d="M28.228,18.327l-16.023,8.983c-0.99,0.555 -2.205,-0.17 -2.205,-1.318l0,-17.984c0,-1.146 1.215,-1.873 2.205,-1.317l16.023,8.982c1.029,0.577 1.029,2.077 0,2.654Z"
|
||||
style="fill-rule:nonzero"></path></svg>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div class="md-option-line" style="cursor: pointer">
|
||||
<div class="md-option-segment">
|
||||
{{ device.name }}
|
||||
<br>
|
||||
<small>{{ device.host }}</small>
|
||||
</div>
|
||||
<div class="md-option-segment_auto" style="display: flex;justify-content: center;align-items: center" v-if="activeCasts.includes(device)">
|
||||
Connected
|
||||
</div>
|
||||
<div class="md-option-segment_auto" v-else style="display: flex;justify-content: center;align-items: center">
|
||||
<svg width="20" height="20" viewBox="0 0 34 34" fill="#fff" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" class="castPlayIndicator"><path d="M28.228,18.327l-16.023,8.983c-0.99,0.555 -2.205,-0.17 -2.205,-1.318l0,-17.984c0,-1.146 1.215,-1.873 2.205,-1.317l16.023,8.982c1.029,0.577 1.029,2.077 0,2.654Z" style="fill-rule:nonzero"></path></svg>
|
||||
{{$root.getLz('action.cast.scanning')}}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
<div class="md-labeltext">{{$root.getLz('action.cast.airplay')}}</div>
|
||||
<div class="md-option-container" style="margin-top: 12px;margin-bottom: 12px;overflow-y: scroll;">
|
||||
<div class="md-option-line">
|
||||
<div class="md-option-segment">
|
||||
{{'EXPERIMENTAL!!! Supports Homepods / Apple TVs / Shairport for now, AirPlay on
|
||||
Samsung/LG/Sony devices will be added later'}}
|
||||
<!-- {{$root.getLz('action.cast.airplay.underdevelopment')}} -->
|
||||
<template v-if="true" v-for="(device) in devices.airplay">
|
||||
<div class="md-option-line" style="cursor: pointer" @click="setAirPlayCast(device)">
|
||||
<div class="md-option-segment">
|
||||
{{ device.name }}
|
||||
<br>
|
||||
<small>{{ device.host }}</small>
|
||||
</div>
|
||||
<div class="md-option-segment_auto"
|
||||
style="display: flex;justify-content: center;align-items: center"
|
||||
v-if="activeCasts.includes(device)">
|
||||
Connected
|
||||
</div>
|
||||
<div class="md-option-segment_auto" v-else
|
||||
style="display: flex;justify-content: center;align-items: center">
|
||||
<svg width="20" height="20" viewBox="0 0 34 34" fill="#fff" version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xml:space="preserve"
|
||||
class="castPlayIndicator"><path
|
||||
d="M28.228,18.327l-16.023,8.983c-0.99,0.555 -2.205,-0.17 -2.205,-1.318l0,-17.984c0,-1.146 1.215,-1.873 2.205,-1.317l16.023,8.982c1.029,0.577 1.029,2.077 0,2.654Z"
|
||||
style="fill-rule:nonzero"></path></svg>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="md-footer">
|
||||
<div class="row">
|
||||
<div class="col" v-if="activeCasts.length != 0">
|
||||
<button style="width:100%" @click="stopCasting()" class="md-btn md-btn-block md-btn-primary">
|
||||
{{$root.getLz('action.cast.stop')}}
|
||||
</button>
|
||||
</div>
|
||||
<div class="col">
|
||||
<button style="width:100%" class="md-btn md-btn-block" @click="scan()">
|
||||
{{$root.getLz('action.cast.scan')}}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="md-footer">
|
||||
<div class="row">
|
||||
<div class="col" v-if="activeCasts.length != 0">
|
||||
<button style="width:100%" @click="stopCasting()" class="md-btn md-btn-block md-btn-primary">{{$root.getLz('action.cast.stop')}}</button>
|
||||
</div>
|
||||
<div class="col">
|
||||
<button style="width:100%" class="md-btn md-btn-block" @click="scan()">{{$root.getLz('action.cast.scan')}}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
<script>
|
||||
Vue.component('castmenu', {
|
||||
template: '#castmenu',
|
||||
data: function () {
|
||||
return {
|
||||
devices: {
|
||||
cast: [],
|
||||
airplay: []
|
||||
},
|
||||
scanning: false,
|
||||
activeCasts: this.$root.activeCasts,
|
||||
Vue.component('castmenu', {
|
||||
template: '#castmenu',
|
||||
data: function() {
|
||||
return {
|
||||
devices: {
|
||||
cast: [],
|
||||
airplay: []
|
||||
},
|
||||
scanning: false,
|
||||
activeCasts: this.$root.activeCasts,
|
||||
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.scan();
|
||||
},
|
||||
watch:{
|
||||
activeCasts: function (newVal, oldVal) {
|
||||
this.$root.activeCasts = this.activeCasts;
|
||||
}},
|
||||
methods: {
|
||||
close() {
|
||||
this.$root.modals.castMenu = false
|
||||
},
|
||||
scan() {
|
||||
let self = this;
|
||||
this.scanning = true;
|
||||
ipcRenderer.send('getChromeCastDevices', '');
|
||||
ipcRenderer.send("getAirplayDevice","")
|
||||
setTimeout(() => {
|
||||
self.devices.cast = ipcRenderer.sendSync("getKnownCastDevices");
|
||||
self.devices.airplay = ipcRenderer.sendSync("getKnownAirplayDevices");
|
||||
self.scanning = false;
|
||||
}, 2000);
|
||||
console.log(this.devices);
|
||||
// vm.$forceUpdate();
|
||||
},
|
||||
setCast(device) {
|
||||
CiderAudio.sendAudio();
|
||||
this.activeCasts.push(device);
|
||||
ipcRenderer.send('performGCCast', device, "Cider", "Playing ...", "Test build", '');
|
||||
},
|
||||
setAirPlayCast(device) {
|
||||
this.activeCasts.push(device);
|
||||
ipcRenderer.send("performAirplayPCM",device.host,device.port,null,"","","","",device.txt,device.airplay2)
|
||||
},
|
||||
stopCasting() {
|
||||
CiderAudio.stopAudio();
|
||||
ipcRenderer.send('disconnectAirplay', '');
|
||||
ipcRenderer.send('stopGCast', '');
|
||||
this.activeCasts = [];
|
||||
// vm.$forceUpdate();
|
||||
},
|
||||
}
|
||||
});
|
||||
</script>
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.scan();
|
||||
},
|
||||
watch: {
|
||||
activeCasts: function(newVal, oldVal) {
|
||||
this.$root.activeCasts = this.activeCasts;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
close() {
|
||||
this.$root.modals.castMenu = false
|
||||
},
|
||||
scan() {
|
||||
let self = this;
|
||||
this.scanning = true;
|
||||
ipcRenderer.send('getChromeCastDevices', '');
|
||||
ipcRenderer.send("getAirplayDevice", "")
|
||||
setTimeout(() => {
|
||||
self.devices.cast = ipcRenderer.sendSync("getKnownCastDevices");
|
||||
self.devices.airplay = ipcRenderer.sendSync("getKnownAirplayDevices");
|
||||
self.scanning = false;
|
||||
}, 2000);
|
||||
console.log(this.devices);
|
||||
// vm.$forceUpdate();
|
||||
},
|
||||
setCast(device) {
|
||||
CiderAudio.sendAudio();
|
||||
this.activeCasts.push(device);
|
||||
ipcRenderer.send('performGCCast', device, "Cider", "Playing ...", "Test build", '');
|
||||
},
|
||||
setAirPlayCast(device) {
|
||||
this.activeCasts.push(device);
|
||||
ipcRenderer.send("performAirplayPCM", device.host, device.port, null, "", "", "", "", device.txt, device.airplay2)
|
||||
},
|
||||
stopCasting() {
|
||||
CiderAudio.stopAudio();
|
||||
ipcRenderer.send('disconnectAirplay', '');
|
||||
ipcRenderer.send('stopGCast', '');
|
||||
this.activeCasts = [];
|
||||
// vm.$forceUpdate();
|
||||
},
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -4,15 +4,17 @@
|
|||
<div class="modal-window">
|
||||
<div class="modal-header">
|
||||
<div class="modal-title">{{app.getLz('action.addToLibrary')}}</div>
|
||||
<button class="close-btn" @click="app.resetState()" :aria-label="app.getLz('action.close')"></button>
|
||||
<button class="close-btn" @click="app.resetState()"
|
||||
:aria-label="app.getLz('action.close')"></button>
|
||||
</div>
|
||||
<div class="modal-content">
|
||||
<button class="playlist-item"
|
||||
:class="{ focused: playlist.id == focused }"
|
||||
@click="addToPlaylist(playlist.id)" style="width:100%;" v-for="playlist in playlistSorted" v-if="playlist.attributes.canEdit && playlist.type != 'library-playlist-folders'">
|
||||
<div class="icon"><%- include("../svg/playlist.svg") %></div>
|
||||
<div class="name">{{ playlist.attributes.name }}</div>
|
||||
</button>
|
||||
:class="{ focused: playlist.id == focused }"
|
||||
@click="addToPlaylist(playlist.id)" style="width:100%;" v-for="playlist in playlistSorted"
|
||||
v-if="playlist.attributes.canEdit && playlist.type != 'library-playlist-folders'">
|
||||
<div class="icon"><%- include("../svg/playlist.svg") %></div>
|
||||
<div class="name">{{ playlist.attributes.name }}</div>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-search">
|
||||
<div class="search-input-container" style="width:100%;margin: 16px 0;">
|
||||
|
@ -33,50 +35,50 @@
|
|||
</script>
|
||||
|
||||
<script>
|
||||
Vue.component('add-to-playlist', {
|
||||
template: '#add-to-playlist',
|
||||
data: function () {
|
||||
return {
|
||||
playlistSorted: [],
|
||||
searchQuery: "",
|
||||
focused: "",
|
||||
app: this.$root,
|
||||
}
|
||||
},
|
||||
props: {
|
||||
playlists: {
|
||||
type: Array,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.search()
|
||||
this.$refs.searchInput.focus()
|
||||
this.$refs.searchInput.addEventListener('keydown', (e) => {
|
||||
if (e.keyCode == 13) {
|
||||
if (this.focused != "") {
|
||||
this.addToPlaylist(this.focused)
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
addToPlaylist(id) {
|
||||
app.addSelectedToPlaylist(id)
|
||||
},
|
||||
search() {
|
||||
this.focused = ""
|
||||
if (this.searchQuery == "") {
|
||||
this.playlistSorted = this.playlists
|
||||
} else {
|
||||
this.playlistSorted = this.playlists.filter(playlist => {
|
||||
return playlist.attributes.name.toLowerCase().indexOf(this.searchQuery.toLowerCase()) > -1
|
||||
})
|
||||
if (this.playlistSorted.length == 1) {
|
||||
this.focused = this.playlistSorted[0].id
|
||||
}
|
||||
}
|
||||
},
|
||||
Vue.component('add-to-playlist', {
|
||||
template: '#add-to-playlist',
|
||||
data: function() {
|
||||
return {
|
||||
playlistSorted: [],
|
||||
searchQuery: "",
|
||||
focused: "",
|
||||
app: this.$root,
|
||||
}
|
||||
},
|
||||
props: {
|
||||
playlists: {
|
||||
type: Array,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.search()
|
||||
this.$refs.searchInput.focus()
|
||||
this.$refs.searchInput.addEventListener('keydown', (e) => {
|
||||
if (e.keyCode == 13) {
|
||||
if (this.focused != "") {
|
||||
this.addToPlaylist(this.focused)
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
addToPlaylist(id) {
|
||||
app.addSelectedToPlaylist(id)
|
||||
},
|
||||
search() {
|
||||
this.focused = ""
|
||||
if (this.searchQuery == "") {
|
||||
this.playlistSorted = this.playlists
|
||||
} else {
|
||||
this.playlistSorted = this.playlists.filter(playlist => {
|
||||
return playlist.attributes.name.toLowerCase().indexOf(this.searchQuery.toLowerCase()) > -1
|
||||
})
|
||||
if (this.playlistSorted.length == 1) {
|
||||
this.focused = this.playlistSorted[0].id
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -1,434 +1,483 @@
|
|||
<script type="text/x-template" id="eq-view">
|
||||
<div class="modal-fullscreen equalizer-panel" @click.self="close()" @contextmenu.self="close()">
|
||||
<div class="modal-window" >
|
||||
<div class="modal-header">
|
||||
<div class="modal-title">{{$root.getLz('term.equalizer')}}</div>
|
||||
<button class="close-btn" @click="close()" :aria-label="$root.getLz('action.close')"></button>
|
||||
<div class="md-option-segment md-option-segment_auto">
|
||||
<select class="md-select" style="width:220px;text-align:center;margin-right:245px" v-model="$root.cfg.audio.equalizer.preset" v-on:change="changePreset($root.cfg.audio.equalizer.preset)">
|
||||
<optgroup :label="$root.getLz('term.userPresets')">
|
||||
<option v-for="preset in $root.cfg.audio.equalizer.presets" :value="preset.preset">{{preset.name}}</option>
|
||||
</optgroup>
|
||||
<optgroup :label="$root.getLz('term.defaultPresets')">
|
||||
<option v-for="preset in defaultPresets" :value="preset.preset">{{preset.name}}</option>
|
||||
</optgroup>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-content">
|
||||
<!-- BANDS = [60, 170, 310, 600, 1000, 3000, 6000, 12000, 14000, 16000]; -->
|
||||
<div class="inputs-container">
|
||||
<div class="input-container mini">
|
||||
{{$root.cfg.audio.equalizer.vibrantBass}}
|
||||
<input tabindex="0" type="range" class="eq-slider mini" orient="vertical" min="-15" max="15" step="1" v-model="$root.cfg.audio.equalizer.vibrantBass" @change="changeVibrantBass()">
|
||||
Vibrant Bass
|
||||
</div>
|
||||
<div class="input-container mini">
|
||||
{{$root.cfg.audio.equalizer.mix}}
|
||||
<input tabindex="0" type="range" class="eq-slider mini" orient="vertical" min="0" max="2" step="0.1" v-model="$root.cfg.audio.equalizer.mix" @change="changeMix()">
|
||||
Mix
|
||||
</div>
|
||||
<div class="input-container header mini">
|
||||
Gain
|
||||
<input type="range" class="eq-slider" orient="vertical" min="-12" max="12" step="0.1" >
|
||||
<div class="freq-header">Freq</div>
|
||||
<div>Q</div>
|
||||
</div>
|
||||
<div class="input-container">
|
||||
<input tabindex="0" type="number" class="eq-freq" orient="vertical" min="-12" max="12" step="0.1" v-model="$root.cfg.audio.equalizer.gain[0]" @change="changeGain(0)">
|
||||
<input tabindex="0" type="range" class="eq-slider" orient="vertical" min="-12" max="12" step="0.1" v-model="$root.cfg.audio.equalizer.gain[0]" @change="changeGain(0)">
|
||||
<input type="number" class="eq-freq" orient="vertical" min="22" max="44" step="2" v-model="$root.cfg.audio.equalizer.frequencies[0]" @change="changeFreq(0)">
|
||||
<input type="number" class="eq-q" orient="vertical" min="0" max="5" step="0.1" v-model="$root.cfg.audio.equalizer.Q[0]" @change="changeQ(0)">
|
||||
</div>
|
||||
<div class="input-container">
|
||||
<input tabindex="0" type="number" class="eq-freq" orient="vertical" min="-12" max="12" step="0.1" v-model="$root.cfg.audio.equalizer.gain[1]" @change="changeGain(1)">
|
||||
<input tabindex="0" type="range" class="eq-slider" orient="vertical" min="-12" max="12" step="0.1" v-model="$root.cfg.audio.equalizer.gain[1]" @change="changeGain(1)">
|
||||
<input type="number" class="eq-freq" orient="vertical" min="44" max="88" step="4" v-model="$root.cfg.audio.equalizer.frequencies[1]" @change="changeFreq(1)">
|
||||
<input type="number" class="eq-q" orient="vertical" min="0" max="5" step="0.1" v-model="$root.cfg.audio.equalizer.Q[1]" @change="changeQ(1)">
|
||||
</div>
|
||||
<div class="input-container">
|
||||
<input tabindex="0" type="number" class="eq-freq" orient="vertical" min="-12" max="12" step="0.1" v-model="$root.cfg.audio.equalizer.gain[2]" @change="changeGain(2)">
|
||||
<input tabindex="0" type="range" class="eq-slider" orient="vertical" min="-12" max="12" step="0.1" v-model="$root.cfg.audio.equalizer.gain[2]" @change="changeGain(2)">
|
||||
<input type="number" class="eq-freq" orient="vertical" min="88" max="177" step="8" v-model="$root.cfg.audio.equalizer.frequencies[2]" @change="changeFreq(2)">
|
||||
<input type="number" class="eq-q" orient="vertical" min="0" max="5" step="0.1" v-model="$root.cfg.audio.equalizer.Q[2]" @change="changeQ(2)">
|
||||
</div>
|
||||
<div class="input-container">
|
||||
<input tabindex="0" type="number" class="eq-freq" orient="vertical" min="-12" max="12" step="0.1" v-model="$root.cfg.audio.equalizer.gain[3]" @change="changeGain(3)">
|
||||
<input tabindex="0" type="range" class="eq-slider" orient="vertical" min="-12" max="12" step="0.1" v-model="$root.cfg.audio.equalizer.gain[3]" @change="changeGain(3)">
|
||||
<input type="number" class="eq-freq" orient="vertical" min="177" max="355" step="16" v-model="$root.cfg.audio.equalizer.frequencies[3]" @change="changeFreq(3)">
|
||||
<input type="number" class="eq-q" orient="vertical" min="0" max="5" step="0.1" v-model="$root.cfg.audio.equalizer.Q[3]" @change="changeQ(3)">
|
||||
</div>
|
||||
<div class="input-container">
|
||||
<input tabindex="0" type="number" class="eq-freq" orient="vertical" min="-12" max="12" step="0.1" v-model="$root.cfg.audio.equalizer.gain[4]" @change="changeGain(4)">
|
||||
<input tabindex="0" type="range" class="eq-slider" orient="vertical" min="-12" max="12" step="0.1" v-model="$root.cfg.audio.equalizer.gain[4]" @change="changeGain(4)">
|
||||
<input type="number" class="eq-freq" orient="vertical" min="355" max="710" step="32" v-model="$root.cfg.audio.equalizer.frequencies[4]" @change="changeFreq(4)">
|
||||
<input type="number" class="eq-q" orient="vertical" min="0" max="5" step="0.1" v-model="$root.cfg.audio.equalizer.Q[4]" @change="changeQ(4)">
|
||||
</div>
|
||||
<div class="input-container">
|
||||
<input tabindex="0" type="number" class="eq-freq" orient="vertical" min="-12" max="12" step="0.1" v-model="$root.cfg.audio.equalizer.gain[5]" @change="changeGain(5)">
|
||||
<input tabindex="0" type="range" class="eq-slider" orient="vertical" min="-12" max="12" step="0.1" v-model="$root.cfg.audio.equalizer.gain[5]" @change="changeGain(5)">
|
||||
<input type="number" class="eq-freq" orient="vertical" min="710" max="1420" step="64" v-model="$root.cfg.audio.equalizer.frequencies[5]" @change="changeFreq(5)">
|
||||
<input type="number" class="eq-q" orient="vertical" min="0" max="5" step="0.1" v-model="$root.cfg.audio.equalizer.Q[5]" @change="changeQ(5)">
|
||||
</div>
|
||||
<div class="input-container">
|
||||
<input tabindex="0" type="number" class="eq-freq" orient="vertical" min="-12" max="12" step="0.1" v-model="$root.cfg.audio.equalizer.gain[6]" @change="changeGain(6)">
|
||||
<input tabindex="0" type="range" class="eq-slider" orient="vertical" min="-12" max="12" step="0.1" v-model="$root.cfg.audio.equalizer.gain[6]" @change="changeGain(6)">
|
||||
<input type="number" class="eq-freq" orient="vertical" min="1420" max="2840" step="128" v-model="$root.cfg.audio.equalizer.frequencies[6]" @change="changeFreq(6)">
|
||||
<input type="number" class="eq-q" orient="vertical" min="0" max="5" step="0.1" v-model="$root.cfg.audio.equalizer.Q[6]" @change="changeQ(6)">
|
||||
</div>
|
||||
<div class="input-container">
|
||||
<input tabindex="0" type="number" class="eq-freq" orient="vertical" min="-12" max="12" step="0.1" v-model="$root.cfg.audio.equalizer.gain[7]" @change="changeGain(7)">
|
||||
<input tabindex="0" type="range" class="eq-slider" orient="vertical" min="-12" max="12" step="0.1" v-model="$root.cfg.audio.equalizer.gain[7]" @change="changeGain(7)">
|
||||
<input type="number" class="eq-freq" orient="vertical" min="2840" max="5680" step="256" v-model="$root.cfg.audio.equalizer.frequencies[7]" @change="changeFreq(7)">
|
||||
<input type="number" class="eq-q" orient="vertical" min="0" max="5" step="0.1" v-model="$root.cfg.audio.equalizer.Q[7]" @change="changeQ(7)">
|
||||
</div>
|
||||
<div class="input-container">
|
||||
<input tabindex="0" type="number" class="eq-freq" orient="vertical" min="-12" max="12" step="0.1" v-model="$root.cfg.audio.equalizer.gain[8]" @change="changeGain(8)">
|
||||
<input tabindex="0" type="range" class="eq-slider" orient="vertical" min="-12" max="12" step="0.1" v-model="$root.cfg.audio.equalizer.gain[8]" @change="changeGain(8)">
|
||||
<input type="number" class="eq-freq" orient="vertical" min="5680" max="11360" step="512" v-model="$root.cfg.audio.equalizer.frequencies[8]" @change="changeFreq(8)">
|
||||
<input type="number" class="eq-q" orient="vertical" min="0" max="5" step="0.1" v-model="$root.cfg.audio.equalizer.Q[8]" @change="changeQ(8)">
|
||||
</div>
|
||||
<div class="input-container">
|
||||
<input tabindex="0" type="number" class="eq-freq" orient="vertical" min="-12" max="12" step="0.1" v-model="$root.cfg.audio.equalizer.gain[9]" @change="changeGain(9)">
|
||||
<input tabindex="0" type="range" class="eq-slider" orient="vertical" min="-12" max="12" step="0.1" v-model="$root.cfg.audio.equalizer.gain[9]" @change="changeGain(9)">
|
||||
<input type="number" class="eq-freq" orient="vertical" min="11360" max="22720" step="1024" v-model="$root.cfg.audio.equalizer.frequencies[9]" @change="changeFreq(9)">
|
||||
<input type="number" class="eq-q" orient="vertical" min="0" max="5" step="0.1" v-model="$root.cfg.audio.equalizer.Q[9]" @change="changeQ(9)">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="modal-lowercontent">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<button class="md-btn" style="width:100%" @click="resetGain()">{{$root.getLz('term.reset')}}</button>
|
||||
</div>
|
||||
<div class="col">
|
||||
<button class="md-btn" style="width:100%" @click="presetOptions($event)">{{$root.getLz('term.menu')}}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script>
|
||||
Vue.component('eq-view', {
|
||||
template: '#eq-view',
|
||||
data: function () {
|
||||
return {
|
||||
// app: this.$root,
|
||||
eqPreset: function () {
|
||||
this.preset = uuidv4()
|
||||
this.name = ""
|
||||
this.frequencies = []
|
||||
this.gain = []
|
||||
this.Q = []
|
||||
this.mix = 1
|
||||
this.vibrantBass = 0
|
||||
this.userGenerated = true
|
||||
},
|
||||
defaultPresets: [
|
||||
{
|
||||
'preset': 'default',
|
||||
'name': 'Default',
|
||||
'frequencies': [32, 63, 125, 250, 500, 1000, 2000, 4000, 8000, 16000],
|
||||
'gain': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
'Q': [1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
|
||||
'mix': 1,
|
||||
'vibrantBass': 0,
|
||||
'userGenerated': false
|
||||
}, {
|
||||
'preset': 'boostAiriness',
|
||||
'name': 'Boost Airiness',
|
||||
'frequencies': [1169, 1733, 5962, 8688, 14125, 18628, 18628, 19000, 19500, 20000],
|
||||
'gain': [-1.41, 0.25, 3.33, 0.22, -0.53, 0.2, 3.64, 0, 0, 0],
|
||||
'Q': [0.405, 2.102, 0.025, 2.5, 7.071, 1.768, 1.146, 1, 1, 1],
|
||||
'mix': 1,
|
||||
'vibrantBass': 0,
|
||||
'userGenerated': false
|
||||
}, {
|
||||
'preset': 'acoustic',
|
||||
'name': 'Acoustic',
|
||||
'frequencies': [32, 75, 125, 220, 700, 1000, 2000, 4000, 10000, 16000],
|
||||
'gain': [0, -8, 0, -0.1, -3, 0, 0, 0, 4, 0],
|
||||
'Q': [1, 0.2, 1, 2.0, 1.4, 1, 1, 1, 0.1, 1],
|
||||
'mix': 1,
|
||||
'vibrantBass': 0,
|
||||
'userGenerated': false
|
||||
}, {
|
||||
'preset': 'clearVocal',
|
||||
'name': 'Clear Vocal',
|
||||
'frequencies': [20, 63, 125, 250, 400, 1000, 2000, 4000, 8000, 20000],
|
||||
'gain': [-22, 0, 0, 0, -3, 0, 1.8, 0, 0, 3.5],
|
||||
'Q': [0.3, 1, 1, 1, 2.0, 1, 0.7, 1, 1, 0.8],
|
||||
'mix': 1,
|
||||
'vibrantBass': 0,
|
||||
'userGenerated': false
|
||||
}, {
|
||||
'preset': 'instrumentClarity',
|
||||
'name': 'Instrument Clarity',
|
||||
'frequencies': [20, 63, 155, 250, 500, 1000, 2000, 5000, 11000, 16000],
|
||||
'gain': [-15, 0, -3, 0, 0, 0, 0, 3.1, 0, 0],
|
||||
'Q': [0.5, 1, 2, 1, 1, 1, 1, 1.5, 0.1, 1],
|
||||
'mix': 1,
|
||||
'vibrantBass': 0,
|
||||
'userGenerated': false
|
||||
}, {
|
||||
'preset': 'reduceHarshness',
|
||||
'name': 'Reduce Harshness',
|
||||
'frequencies': [32, 63, 125, 250, 500, 1128, 2000, 4057, 8000, 16000],
|
||||
'gain': [0, 0, 0, 0, 0, 2, 0, -6.4, 0, 0],
|
||||
'Q': [1, 1, 1, 1, 1, 2, 1, 1, 1, 1],
|
||||
'mix': 1,
|
||||
'vibrantBass': 0,
|
||||
'userGenerated': false
|
||||
}, {
|
||||
'preset': 'smileyFace',
|
||||
'name': 'Smiley Face',
|
||||
'frequencies': [35, 63, 125, 250, 500, 800, 2000, 4000, 8000, 20000],
|
||||
'gain': [5, 0, 0, 0, 0, -5, 0, 0, 0, 5],
|
||||
'Q': [0.1, 1, 1, 1, 1, 0.6, 1, 1, 1, 0.2],
|
||||
'mix': 1,
|
||||
'vibrantBass': 0,
|
||||
'userGenerated': false
|
||||
},
|
||||
{
|
||||
'preset': 'bassBoostSurgical',
|
||||
'name': 'Surgical Bass Boost',
|
||||
'frequencies': [32, 63, 125, 250, 500, 1000, 2000, 4000, 8000, 16000],
|
||||
'gain': [2.7, 2.2, 1.6, 1.4, 0.6, 0, 0, 0, 0, 0],
|
||||
'Q': [1.4, 1.4, 1.4, 1.4, 1.4, 1, 1, 1, 1, 1],
|
||||
'mix': 1,
|
||||
'vibrantBass': 0,
|
||||
'userGenerated': false
|
||||
}, {
|
||||
'preset': 'bassBoostClassic',
|
||||
'name': 'Classic Bass Boost',
|
||||
'frequencies': [32, 63, 160, 250, 500, 1000, 2000, 3500, 8000, 20000],
|
||||
'gain': [2.7, 2.2, 1.6, 1.4, 0.6, 0, 0, 0, 0, 0],
|
||||
'Q': [0.7, 0.7, 0.7, 0.7, 0.7, 1, 1, 1, 1, 1],
|
||||
'mix': 1,
|
||||
'vibrantBass': 0,
|
||||
'userGenerated': false
|
||||
}]
|
||||
}
|
||||
},
|
||||
props: ["src", "url"],
|
||||
mounted() {
|
||||
},
|
||||
methods: {
|
||||
presetOptions(event) {
|
||||
let menu = {
|
||||
items: {
|
||||
"new": {
|
||||
"icon": "./assets/feather/plus.svg",
|
||||
"name": app.getLz('action.newpreset'),
|
||||
action: () => {
|
||||
this.addPreset()
|
||||
}
|
||||
},
|
||||
"delete": {
|
||||
"icon": "./assets/feather/x-circle.svg",
|
||||
"name": app.getLz('action.deletepreset'),
|
||||
action: () => {
|
||||
this.deletePreset()
|
||||
}
|
||||
},
|
||||
"import": {
|
||||
"icon": "./assets/feather/share.svg",
|
||||
"name": app.getLz('action.import'),
|
||||
action: () => {
|
||||
this.importPreset()
|
||||
}
|
||||
},
|
||||
"export": {
|
||||
"icon": "./assets/feather/share.svg",
|
||||
"name": app.getLz('action.export'),
|
||||
action: () => {
|
||||
this.exportPreset()
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
if (!this.$root.cfg.audio.equalizer.userGenerated) {
|
||||
delete menu.items.delete
|
||||
}
|
||||
|
||||
app.showMenuPanel(menu, event)
|
||||
},
|
||||
sharePreset(event) {
|
||||
let menu = {
|
||||
items: [
|
||||
{
|
||||
"icon": "./assets/feather/share.svg",
|
||||
"name": app.getLz('action.import'),
|
||||
"action": function () {
|
||||
notyf.error("Not implemented yet")
|
||||
}
|
||||
},
|
||||
{
|
||||
"icon": "./assets/feather/share.svg",
|
||||
"name": app.getLz('action.export'),
|
||||
"action": function () {
|
||||
notyf.error("Not implemented yet")
|
||||
}
|
||||
},
|
||||
]
|
||||
}
|
||||
app.showMenuPanel(menu, event)
|
||||
},
|
||||
deletePreset() {
|
||||
let presets = this.$root.cfg.audio.equalizer.presets
|
||||
app.confirm(app.getLz('term.deletepreset.warn'), (result) => {
|
||||
if (result) {
|
||||
this.changePreset("default")
|
||||
// find the preset by id (preset) and remove it
|
||||
let index = presets.findIndex(p => p.preset == this.preset)
|
||||
presets.splice(index, 1)
|
||||
notyf.success(app.getLz('term.deletedpreset'))
|
||||
}
|
||||
})
|
||||
},
|
||||
close() {
|
||||
app.modals.equalizer = false
|
||||
},
|
||||
changeVibrantBass() {
|
||||
if (app.cfg.audio.equalizer.vibrantBass !== '0') {
|
||||
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_n0_0();
|
||||
}
|
||||
catch (e) {
|
||||
CiderAudio.hierarchical_loading();
|
||||
}
|
||||
}
|
||||
|
||||
else {
|
||||
CiderAudio.hierarchical_loading();
|
||||
}
|
||||
},
|
||||
changeMix() {
|
||||
if (Math.max(...app.cfg.audio.equalizer.gain) != 0) {
|
||||
try {
|
||||
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_n0_0();
|
||||
} catch (e) { CiderAudio.hierarchical_loading(); }
|
||||
}
|
||||
},
|
||||
changeGain(i) {
|
||||
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_n0_0();
|
||||
}
|
||||
catch (e) { CiderAudio.hierarchical_loading(); }
|
||||
}
|
||||
else {
|
||||
CiderAudio.hierarchical_loading();
|
||||
}
|
||||
},
|
||||
changeFreq(i) {
|
||||
CiderAudio.audioNodes.audioBands[i].frequency.value = app.cfg.audio.equalizer.frequencies[i]
|
||||
},
|
||||
changeQ(i) {
|
||||
CiderAudio.audioNodes.audioBands[i].Q.value = app.cfg.audio.equalizer.Q[i]
|
||||
},
|
||||
resetGain() {
|
||||
this.applyPreset({
|
||||
'frequencies': [32, 63, 125, 250, 500, 1000, 2000, 4000, 8000, 16000],
|
||||
'gain': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
'Q': [1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
|
||||
'mix': 1,
|
||||
'vibrantBass': 0,
|
||||
})
|
||||
if (app.cfg.audio.equalizer.userGenerated) {
|
||||
this.saveSelectedPreset()
|
||||
}
|
||||
},
|
||||
addPreset() {
|
||||
let self = this
|
||||
app.prompt(app.getLz('term.newpreset.name'), (res) => {
|
||||
if (res) {
|
||||
let eqSettings = Clone(app.cfg.audio.equalizer)
|
||||
let newPreset = new self.eqPreset()
|
||||
newPreset.name = res
|
||||
newPreset.frequencies = eqSettings.frequencies
|
||||
newPreset.gain = eqSettings.gain
|
||||
newPreset.Q = eqSettings.Q
|
||||
newPreset.mix = eqSettings.mix
|
||||
newPreset.vibrantBass = eqSettings.vibrantBass
|
||||
app.cfg.audio.equalizer.presets.push(newPreset)
|
||||
notyf.success(app.getLz('term.addedpreset'))
|
||||
self.changePreset(newPreset.preset)
|
||||
}
|
||||
})
|
||||
},
|
||||
saveSelectedPreset() {
|
||||
// Save the current settings to the selected preset
|
||||
let self = this
|
||||
//let preset = app.cfg.audio.equalizer.presets[app.cfg.audio.equalizer.preset]
|
||||
// find the preset by its id (preset)
|
||||
let preset = app.cfg.audio.equalizer.presets.find(p => p.preset == app.cfg.audio.equalizer.preset)
|
||||
preset.frequencies = app.cfg.audio.equalizer.frequencies
|
||||
preset.gain = app.cfg.audio.equalizer.gain
|
||||
preset.Q = app.cfg.audio.equalizer.Q
|
||||
preset.mix = app.cfg.audio.equalizer.mix
|
||||
preset.vibrantBass = app.cfg.audio.equalizer.vibrantBass
|
||||
notyf.success("Saved Preset")
|
||||
},
|
||||
exportPreset() {
|
||||
let preset = app.cfg.audio.equalizer.presets.find(p => p.preset == app.cfg.audio.equalizer.preset)
|
||||
this.$root.copyToClipboard(btoa(JSON.stringify(preset)))
|
||||
},
|
||||
importPreset() {
|
||||
let self = this
|
||||
app.prompt("Enter preset share code", (res) => {
|
||||
if (res) {
|
||||
let preset = JSON.parse(atob(res))
|
||||
if (preset.frequencies && preset.gain && preset.Q && preset.mix && preset.vibrantBass) {
|
||||
// self.applyPreset(preset)
|
||||
app.cfg.audio.equalizer.presets.push(preset)
|
||||
notyf.success(`${preset.name} has been imported.`)
|
||||
}
|
||||
else {
|
||||
notyf.error("Invalid Preset")
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
applyPreset(preset) {
|
||||
Object.assign(this.$root.cfg.audio.equalizer, preset)
|
||||
this.changeVibrantBass()
|
||||
for (var i = 0; i < 10; i++) {
|
||||
try { CiderAudio.audioNodes.audioBands[i].gain.value = app.cfg.audio.equalizer.gain[i] * app.cfg.audio.equalizer.mix }
|
||||
catch (e) {
|
||||
CiderAudio.hierarchical_loading();
|
||||
CiderAudio.audioNodes.audioBands[i].gain.value = app.cfg.audio.equalizer.gain[i] * app.cfg.audio.equalizer.mix
|
||||
}
|
||||
|
||||
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_n0_0();
|
||||
},
|
||||
changePreset(id) {
|
||||
let userPresets = app.cfg.audio.equalizer.presets
|
||||
let defaultPresets = Clone(this.defaultPresets)
|
||||
|
||||
let presets = defaultPresets.concat(userPresets)
|
||||
console.log(presets)
|
||||
let preset = presets.find(p => p.preset == id)
|
||||
|
||||
console.log(preset)
|
||||
|
||||
if (preset) {
|
||||
this.applyPreset(preset)
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<script type="text/x-template" id="eq-view">
|
||||
<div class="modal-fullscreen equalizer-panel" @click.self="close()" @contextmenu.self="close()">
|
||||
<div class="modal-window">
|
||||
<div class="modal-header">
|
||||
<div class="modal-title">{{$root.getLz('term.equalizer')}}</div>
|
||||
<button class="close-btn" @click="close()" :aria-label="$root.getLz('action.close')"></button>
|
||||
<div class="md-option-segment md-option-segment_auto">
|
||||
<select class="md-select" style="width:220px;text-align:center;margin-right:245px"
|
||||
v-model="$root.cfg.audio.equalizer.preset"
|
||||
v-on:change="changePreset($root.cfg.audio.equalizer.preset)">
|
||||
<optgroup :label="$root.getLz('term.userPresets')">
|
||||
<option v-for="preset in $root.cfg.audio.equalizer.presets" :value="preset.preset">
|
||||
{{preset.name}}
|
||||
</option>
|
||||
</optgroup>
|
||||
<optgroup :label="$root.getLz('term.defaultPresets')">
|
||||
<option v-for="preset in defaultPresets" :value="preset.preset">{{preset.name}}</option>
|
||||
</optgroup>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-content">
|
||||
<!-- BANDS = [60, 170, 310, 600, 1000, 3000, 6000, 12000, 14000, 16000]; -->
|
||||
<div class="inputs-container">
|
||||
<div class="input-container mini">
|
||||
{{$root.cfg.audio.equalizer.vibrantBass}}
|
||||
<input tabindex="0" type="range" class="eq-slider mini" orient="vertical" min="-15" max="15"
|
||||
step="1" v-model="$root.cfg.audio.equalizer.vibrantBass" @change="changeVibrantBass()">
|
||||
Vibrant Bass
|
||||
</div>
|
||||
<div class="input-container mini">
|
||||
{{$root.cfg.audio.equalizer.mix}}
|
||||
<input tabindex="0" type="range" class="eq-slider mini" orient="vertical" min="0" max="2"
|
||||
step="0.1" v-model="$root.cfg.audio.equalizer.mix" @change="changeMix()">
|
||||
Mix
|
||||
</div>
|
||||
<div class="input-container header mini">
|
||||
Gain
|
||||
<input type="range" class="eq-slider" orient="vertical" min="-12" max="12" step="0.1">
|
||||
<div class="freq-header">Freq</div>
|
||||
<div>Q</div>
|
||||
</div>
|
||||
<div class="input-container">
|
||||
<input tabindex="0" type="number" class="eq-freq" orient="vertical" min="-12" max="12"
|
||||
step="0.1" v-model="$root.cfg.audio.equalizer.gain[0]" @change="changeGain(0)">
|
||||
<input tabindex="0" type="range" class="eq-slider" orient="vertical" min="-12" max="12"
|
||||
step="0.1" v-model="$root.cfg.audio.equalizer.gain[0]" @change="changeGain(0)">
|
||||
<input type="number" class="eq-freq" orient="vertical" min="22" max="44" step="2"
|
||||
v-model="$root.cfg.audio.equalizer.frequencies[0]" @change="changeFreq(0)">
|
||||
<input type="number" class="eq-q" orient="vertical" min="0" max="5" step="0.1"
|
||||
v-model="$root.cfg.audio.equalizer.Q[0]" @change="changeQ(0)">
|
||||
</div>
|
||||
<div class="input-container">
|
||||
<input tabindex="0" type="number" class="eq-freq" orient="vertical" min="-12" max="12"
|
||||
step="0.1" v-model="$root.cfg.audio.equalizer.gain[1]" @change="changeGain(1)">
|
||||
<input tabindex="0" type="range" class="eq-slider" orient="vertical" min="-12" max="12"
|
||||
step="0.1" v-model="$root.cfg.audio.equalizer.gain[1]" @change="changeGain(1)">
|
||||
<input type="number" class="eq-freq" orient="vertical" min="44" max="88" step="4"
|
||||
v-model="$root.cfg.audio.equalizer.frequencies[1]" @change="changeFreq(1)">
|
||||
<input type="number" class="eq-q" orient="vertical" min="0" max="5" step="0.1"
|
||||
v-model="$root.cfg.audio.equalizer.Q[1]" @change="changeQ(1)">
|
||||
</div>
|
||||
<div class="input-container">
|
||||
<input tabindex="0" type="number" class="eq-freq" orient="vertical" min="-12" max="12"
|
||||
step="0.1" v-model="$root.cfg.audio.equalizer.gain[2]" @change="changeGain(2)">
|
||||
<input tabindex="0" type="range" class="eq-slider" orient="vertical" min="-12" max="12"
|
||||
step="0.1" v-model="$root.cfg.audio.equalizer.gain[2]" @change="changeGain(2)">
|
||||
<input type="number" class="eq-freq" orient="vertical" min="88" max="177" step="8"
|
||||
v-model="$root.cfg.audio.equalizer.frequencies[2]" @change="changeFreq(2)">
|
||||
<input type="number" class="eq-q" orient="vertical" min="0" max="5" step="0.1"
|
||||
v-model="$root.cfg.audio.equalizer.Q[2]" @change="changeQ(2)">
|
||||
</div>
|
||||
<div class="input-container">
|
||||
<input tabindex="0" type="number" class="eq-freq" orient="vertical" min="-12" max="12"
|
||||
step="0.1" v-model="$root.cfg.audio.equalizer.gain[3]" @change="changeGain(3)">
|
||||
<input tabindex="0" type="range" class="eq-slider" orient="vertical" min="-12" max="12"
|
||||
step="0.1" v-model="$root.cfg.audio.equalizer.gain[3]" @change="changeGain(3)">
|
||||
<input type="number" class="eq-freq" orient="vertical" min="177" max="355" step="16"
|
||||
v-model="$root.cfg.audio.equalizer.frequencies[3]" @change="changeFreq(3)">
|
||||
<input type="number" class="eq-q" orient="vertical" min="0" max="5" step="0.1"
|
||||
v-model="$root.cfg.audio.equalizer.Q[3]" @change="changeQ(3)">
|
||||
</div>
|
||||
<div class="input-container">
|
||||
<input tabindex="0" type="number" class="eq-freq" orient="vertical" min="-12" max="12"
|
||||
step="0.1" v-model="$root.cfg.audio.equalizer.gain[4]" @change="changeGain(4)">
|
||||
<input tabindex="0" type="range" class="eq-slider" orient="vertical" min="-12" max="12"
|
||||
step="0.1" v-model="$root.cfg.audio.equalizer.gain[4]" @change="changeGain(4)">
|
||||
<input type="number" class="eq-freq" orient="vertical" min="355" max="710" step="32"
|
||||
v-model="$root.cfg.audio.equalizer.frequencies[4]" @change="changeFreq(4)">
|
||||
<input type="number" class="eq-q" orient="vertical" min="0" max="5" step="0.1"
|
||||
v-model="$root.cfg.audio.equalizer.Q[4]" @change="changeQ(4)">
|
||||
</div>
|
||||
<div class="input-container">
|
||||
<input tabindex="0" type="number" class="eq-freq" orient="vertical" min="-12" max="12"
|
||||
step="0.1" v-model="$root.cfg.audio.equalizer.gain[5]" @change="changeGain(5)">
|
||||
<input tabindex="0" type="range" class="eq-slider" orient="vertical" min="-12" max="12"
|
||||
step="0.1" v-model="$root.cfg.audio.equalizer.gain[5]" @change="changeGain(5)">
|
||||
<input type="number" class="eq-freq" orient="vertical" min="710" max="1420" step="64"
|
||||
v-model="$root.cfg.audio.equalizer.frequencies[5]" @change="changeFreq(5)">
|
||||
<input type="number" class="eq-q" orient="vertical" min="0" max="5" step="0.1"
|
||||
v-model="$root.cfg.audio.equalizer.Q[5]" @change="changeQ(5)">
|
||||
</div>
|
||||
<div class="input-container">
|
||||
<input tabindex="0" type="number" class="eq-freq" orient="vertical" min="-12" max="12"
|
||||
step="0.1" v-model="$root.cfg.audio.equalizer.gain[6]" @change="changeGain(6)">
|
||||
<input tabindex="0" type="range" class="eq-slider" orient="vertical" min="-12" max="12"
|
||||
step="0.1" v-model="$root.cfg.audio.equalizer.gain[6]" @change="changeGain(6)">
|
||||
<input type="number" class="eq-freq" orient="vertical" min="1420" max="2840" step="128"
|
||||
v-model="$root.cfg.audio.equalizer.frequencies[6]" @change="changeFreq(6)">
|
||||
<input type="number" class="eq-q" orient="vertical" min="0" max="5" step="0.1"
|
||||
v-model="$root.cfg.audio.equalizer.Q[6]" @change="changeQ(6)">
|
||||
</div>
|
||||
<div class="input-container">
|
||||
<input tabindex="0" type="number" class="eq-freq" orient="vertical" min="-12" max="12"
|
||||
step="0.1" v-model="$root.cfg.audio.equalizer.gain[7]" @change="changeGain(7)">
|
||||
<input tabindex="0" type="range" class="eq-slider" orient="vertical" min="-12" max="12"
|
||||
step="0.1" v-model="$root.cfg.audio.equalizer.gain[7]" @change="changeGain(7)">
|
||||
<input type="number" class="eq-freq" orient="vertical" min="2840" max="5680" step="256"
|
||||
v-model="$root.cfg.audio.equalizer.frequencies[7]" @change="changeFreq(7)">
|
||||
<input type="number" class="eq-q" orient="vertical" min="0" max="5" step="0.1"
|
||||
v-model="$root.cfg.audio.equalizer.Q[7]" @change="changeQ(7)">
|
||||
</div>
|
||||
<div class="input-container">
|
||||
<input tabindex="0" type="number" class="eq-freq" orient="vertical" min="-12" max="12"
|
||||
step="0.1" v-model="$root.cfg.audio.equalizer.gain[8]" @change="changeGain(8)">
|
||||
<input tabindex="0" type="range" class="eq-slider" orient="vertical" min="-12" max="12"
|
||||
step="0.1" v-model="$root.cfg.audio.equalizer.gain[8]" @change="changeGain(8)">
|
||||
<input type="number" class="eq-freq" orient="vertical" min="5680" max="11360" step="512"
|
||||
v-model="$root.cfg.audio.equalizer.frequencies[8]" @change="changeFreq(8)">
|
||||
<input type="number" class="eq-q" orient="vertical" min="0" max="5" step="0.1"
|
||||
v-model="$root.cfg.audio.equalizer.Q[8]" @change="changeQ(8)">
|
||||
</div>
|
||||
<div class="input-container">
|
||||
<input tabindex="0" type="number" class="eq-freq" orient="vertical" min="-12" max="12"
|
||||
step="0.1" v-model="$root.cfg.audio.equalizer.gain[9]" @change="changeGain(9)">
|
||||
<input tabindex="0" type="range" class="eq-slider" orient="vertical" min="-12" max="12"
|
||||
step="0.1" v-model="$root.cfg.audio.equalizer.gain[9]" @change="changeGain(9)">
|
||||
<input type="number" class="eq-freq" orient="vertical" min="11360" max="22720" step="1024"
|
||||
v-model="$root.cfg.audio.equalizer.frequencies[9]" @change="changeFreq(9)">
|
||||
<input type="number" class="eq-q" orient="vertical" min="0" max="5" step="0.1"
|
||||
v-model="$root.cfg.audio.equalizer.Q[9]" @change="changeQ(9)">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="modal-lowercontent">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<button class="md-btn" style="width:100%" @click="resetGain()">{{$root.getLz('term.reset')}}
|
||||
</button>
|
||||
</div>
|
||||
<div class="col">
|
||||
<button class="md-btn" style="width:100%" @click="presetOptions($event)">
|
||||
{{$root.getLz('term.menu')}}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script>
|
||||
Vue.component('eq-view', {
|
||||
template: '#eq-view',
|
||||
data: function() {
|
||||
return {
|
||||
// app: this.$root,
|
||||
eqPreset: function() {
|
||||
this.preset = uuidv4()
|
||||
this.name = ""
|
||||
this.frequencies = []
|
||||
this.gain = []
|
||||
this.Q = []
|
||||
this.mix = 1
|
||||
this.vibrantBass = 0
|
||||
this.userGenerated = true
|
||||
},
|
||||
defaultPresets: [
|
||||
{
|
||||
'preset': 'default',
|
||||
'name': 'Default',
|
||||
'frequencies': [32, 63, 125, 250, 500, 1000, 2000, 4000, 8000, 16000],
|
||||
'gain': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
'Q': [1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
|
||||
'mix': 1,
|
||||
'vibrantBass': 0,
|
||||
'userGenerated': false
|
||||
}, {
|
||||
'preset': 'boostAiriness',
|
||||
'name': 'Boost Airiness',
|
||||
'frequencies': [1169, 1733, 5962, 8688, 14125, 18628, 18628, 19000, 19500, 20000],
|
||||
'gain': [-1.41, 0.25, 3.33, 0.22, -0.53, 0.2, 3.64, 0, 0, 0],
|
||||
'Q': [0.405, 2.102, 0.025, 2.5, 7.071, 1.768, 1.146, 1, 1, 1],
|
||||
'mix': 1,
|
||||
'vibrantBass': 0,
|
||||
'userGenerated': false
|
||||
}, {
|
||||
'preset': 'acoustic',
|
||||
'name': 'Acoustic',
|
||||
'frequencies': [32, 75, 125, 220, 700, 1000, 2000, 4000, 10000, 16000],
|
||||
'gain': [0, -8, 0, -0.1, -3, 0, 0, 0, 4, 0],
|
||||
'Q': [1, 0.2, 1, 2.0, 1.4, 1, 1, 1, 0.1, 1],
|
||||
'mix': 1,
|
||||
'vibrantBass': 0,
|
||||
'userGenerated': false
|
||||
}, {
|
||||
'preset': 'clearVocal',
|
||||
'name': 'Clear Vocal',
|
||||
'frequencies': [20, 63, 125, 250, 400, 1000, 2000, 4000, 8000, 20000],
|
||||
'gain': [-22, 0, 0, 0, -3, 0, 1.8, 0, 0, 3.5],
|
||||
'Q': [0.3, 1, 1, 1, 2.0, 1, 0.7, 1, 1, 0.8],
|
||||
'mix': 1,
|
||||
'vibrantBass': 0,
|
||||
'userGenerated': false
|
||||
}, {
|
||||
'preset': 'instrumentClarity',
|
||||
'name': 'Instrument Clarity',
|
||||
'frequencies': [20, 63, 155, 250, 500, 1000, 2000, 5000, 11000, 16000],
|
||||
'gain': [-15, 0, -3, 0, 0, 0, 0, 3.1, 0, 0],
|
||||
'Q': [0.5, 1, 2, 1, 1, 1, 1, 1.5, 0.1, 1],
|
||||
'mix': 1,
|
||||
'vibrantBass': 0,
|
||||
'userGenerated': false
|
||||
}, {
|
||||
'preset': 'reduceHarshness',
|
||||
'name': 'Reduce Harshness',
|
||||
'frequencies': [32, 63, 125, 250, 500, 1128, 2000, 4057, 8000, 16000],
|
||||
'gain': [0, 0, 0, 0, 0, 2, 0, -6.4, 0, 0],
|
||||
'Q': [1, 1, 1, 1, 1, 2, 1, 1, 1, 1],
|
||||
'mix': 1,
|
||||
'vibrantBass': 0,
|
||||
'userGenerated': false
|
||||
}, {
|
||||
'preset': 'smileyFace',
|
||||
'name': 'Smiley Face',
|
||||
'frequencies': [35, 63, 125, 250, 500, 800, 2000, 4000, 8000, 20000],
|
||||
'gain': [5, 0, 0, 0, 0, -5, 0, 0, 0, 5],
|
||||
'Q': [0.1, 1, 1, 1, 1, 0.6, 1, 1, 1, 0.2],
|
||||
'mix': 1,
|
||||
'vibrantBass': 0,
|
||||
'userGenerated': false
|
||||
},
|
||||
{
|
||||
'preset': 'bassBoostSurgical',
|
||||
'name': 'Surgical Bass Boost',
|
||||
'frequencies': [32, 63, 125, 250, 500, 1000, 2000, 4000, 8000, 16000],
|
||||
'gain': [2.7, 2.2, 1.6, 1.4, 0.6, 0, 0, 0, 0, 0],
|
||||
'Q': [1.4, 1.4, 1.4, 1.4, 1.4, 1, 1, 1, 1, 1],
|
||||
'mix': 1,
|
||||
'vibrantBass': 0,
|
||||
'userGenerated': false
|
||||
}, {
|
||||
'preset': 'bassBoostClassic',
|
||||
'name': 'Classic Bass Boost',
|
||||
'frequencies': [32, 63, 160, 250, 500, 1000, 2000, 3500, 8000, 20000],
|
||||
'gain': [2.7, 2.2, 1.6, 1.4, 0.6, 0, 0, 0, 0, 0],
|
||||
'Q': [0.7, 0.7, 0.7, 0.7, 0.7, 1, 1, 1, 1, 1],
|
||||
'mix': 1,
|
||||
'vibrantBass': 0,
|
||||
'userGenerated': false
|
||||
}]
|
||||
}
|
||||
},
|
||||
props: ["src", "url"],
|
||||
mounted() {
|
||||
},
|
||||
methods: {
|
||||
presetOptions(event) {
|
||||
let menu = {
|
||||
items: {
|
||||
"new": {
|
||||
"icon": "./assets/feather/plus.svg",
|
||||
"name": app.getLz('action.newpreset'),
|
||||
action: () => {
|
||||
this.addPreset()
|
||||
}
|
||||
},
|
||||
"delete": {
|
||||
"icon": "./assets/feather/x-circle.svg",
|
||||
"name": app.getLz('action.deletepreset'),
|
||||
action: () => {
|
||||
this.deletePreset()
|
||||
}
|
||||
},
|
||||
"import": {
|
||||
"icon": "./assets/feather/share.svg",
|
||||
"name": app.getLz('action.import'),
|
||||
action: () => {
|
||||
this.importPreset()
|
||||
}
|
||||
},
|
||||
"export": {
|
||||
"icon": "./assets/feather/share.svg",
|
||||
"name": app.getLz('action.export'),
|
||||
action: () => {
|
||||
this.exportPreset()
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
if (!this.$root.cfg.audio.equalizer.userGenerated) {
|
||||
delete menu.items.delete
|
||||
}
|
||||
|
||||
app.showMenuPanel(menu, event)
|
||||
},
|
||||
sharePreset(event) {
|
||||
let menu = {
|
||||
items: [
|
||||
{
|
||||
"icon": "./assets/feather/share.svg",
|
||||
"name": app.getLz('action.import'),
|
||||
"action": function() {
|
||||
notyf.error("Not implemented yet")
|
||||
}
|
||||
},
|
||||
{
|
||||
"icon": "./assets/feather/share.svg",
|
||||
"name": app.getLz('action.export'),
|
||||
"action": function() {
|
||||
notyf.error("Not implemented yet")
|
||||
}
|
||||
},
|
||||
]
|
||||
}
|
||||
app.showMenuPanel(menu, event)
|
||||
},
|
||||
deletePreset() {
|
||||
let presets = this.$root.cfg.audio.equalizer.presets
|
||||
app.confirm(app.getLz('term.deletepreset.warn'), (result) => {
|
||||
if (result) {
|
||||
this.changePreset("default")
|
||||
// find the preset by id (preset) and remove it
|
||||
let index = presets.findIndex(p => p.preset == this.preset)
|
||||
presets.splice(index, 1)
|
||||
notyf.success(app.getLz('term.deletedpreset'))
|
||||
}
|
||||
})
|
||||
},
|
||||
close() {
|
||||
app.modals.equalizer = false
|
||||
},
|
||||
changeVibrantBass() {
|
||||
if (app.cfg.audio.equalizer.vibrantBass !== '0') {
|
||||
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_n0_0();
|
||||
} catch (e) {
|
||||
CiderAudio.hierarchical_loading();
|
||||
}
|
||||
} else {
|
||||
CiderAudio.hierarchical_loading();
|
||||
}
|
||||
},
|
||||
changeMix() {
|
||||
if (Math.max(...app.cfg.audio.equalizer.gain) != 0) {
|
||||
try {
|
||||
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_n0_0();
|
||||
} catch (e) {
|
||||
CiderAudio.hierarchical_loading();
|
||||
}
|
||||
}
|
||||
},
|
||||
changeGain(i) {
|
||||
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_n0_0();
|
||||
} catch (e) {
|
||||
CiderAudio.hierarchical_loading();
|
||||
}
|
||||
} else {
|
||||
CiderAudio.hierarchical_loading();
|
||||
}
|
||||
},
|
||||
changeFreq(i) {
|
||||
CiderAudio.audioNodes.audioBands[i].frequency.value = app.cfg.audio.equalizer.frequencies[i]
|
||||
},
|
||||
changeQ(i) {
|
||||
CiderAudio.audioNodes.audioBands[i].Q.value = app.cfg.audio.equalizer.Q[i]
|
||||
},
|
||||
resetGain() {
|
||||
this.applyPreset({
|
||||
'frequencies': [32, 63, 125, 250, 500, 1000, 2000, 4000, 8000, 16000],
|
||||
'gain': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
'Q': [1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
|
||||
'mix': 1,
|
||||
'vibrantBass': 0,
|
||||
})
|
||||
if (app.cfg.audio.equalizer.userGenerated) {
|
||||
this.saveSelectedPreset()
|
||||
}
|
||||
},
|
||||
addPreset() {
|
||||
let self = this
|
||||
app.prompt(app.getLz('term.newpreset.name'), (res) => {
|
||||
if (res) {
|
||||
let eqSettings = Clone(app.cfg.audio.equalizer)
|
||||
let newPreset = new self.eqPreset()
|
||||
newPreset.name = res
|
||||
newPreset.frequencies = eqSettings.frequencies
|
||||
newPreset.gain = eqSettings.gain
|
||||
newPreset.Q = eqSettings.Q
|
||||
newPreset.mix = eqSettings.mix
|
||||
newPreset.vibrantBass = eqSettings.vibrantBass
|
||||
app.cfg.audio.equalizer.presets.push(newPreset)
|
||||
notyf.success(app.getLz('term.addedpreset'))
|
||||
self.changePreset(newPreset.preset)
|
||||
}
|
||||
})
|
||||
},
|
||||
saveSelectedPreset() {
|
||||
// Save the current settings to the selected preset
|
||||
let self = this
|
||||
//let preset = app.cfg.audio.equalizer.presets[app.cfg.audio.equalizer.preset]
|
||||
// find the preset by its id (preset)
|
||||
let preset = app.cfg.audio.equalizer.presets.find(p => p.preset == app.cfg.audio.equalizer.preset)
|
||||
preset.frequencies = app.cfg.audio.equalizer.frequencies
|
||||
preset.gain = app.cfg.audio.equalizer.gain
|
||||
preset.Q = app.cfg.audio.equalizer.Q
|
||||
preset.mix = app.cfg.audio.equalizer.mix
|
||||
preset.vibrantBass = app.cfg.audio.equalizer.vibrantBass
|
||||
notyf.success("Saved Preset")
|
||||
},
|
||||
exportPreset() {
|
||||
let preset = app.cfg.audio.equalizer.presets.find(p => p.preset == app.cfg.audio.equalizer.preset)
|
||||
this.$root.copyToClipboard(btoa(JSON.stringify(preset)))
|
||||
},
|
||||
importPreset() {
|
||||
let self = this
|
||||
app.prompt("Enter preset share code", (res) => {
|
||||
if (res) {
|
||||
let preset = JSON.parse(atob(res))
|
||||
if (preset.frequencies && preset.gain && preset.Q && preset.mix && preset.vibrantBass) {
|
||||
// self.applyPreset(preset)
|
||||
app.cfg.audio.equalizer.presets.push(preset)
|
||||
notyf.success(`${preset.name} has been imported.`)
|
||||
} else {
|
||||
notyf.error("Invalid Preset")
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
applyPreset(preset) {
|
||||
Object.assign(this.$root.cfg.audio.equalizer, preset)
|
||||
this.changeVibrantBass()
|
||||
for (var i = 0; i < 10; i++) {
|
||||
try {
|
||||
CiderAudio.audioNodes.audioBands[i].gain.value = app.cfg.audio.equalizer.gain[i] * app.cfg.audio.equalizer.mix
|
||||
} catch (e) {
|
||||
CiderAudio.hierarchical_loading();
|
||||
CiderAudio.audioNodes.audioBands[i].gain.value = app.cfg.audio.equalizer.gain[i] * app.cfg.audio.equalizer.mix
|
||||
}
|
||||
|
||||
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_n0_0();
|
||||
},
|
||||
changePreset(id) {
|
||||
let userPresets = app.cfg.audio.equalizer.presets
|
||||
let defaultPresets = Clone(this.defaultPresets)
|
||||
|
||||
let presets = defaultPresets.concat(userPresets)
|
||||
console.log(presets)
|
||||
let preset = presets.find(p => p.preset == id)
|
||||
|
||||
console.log(preset)
|
||||
|
||||
if (preset) {
|
||||
this.applyPreset(preset)
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -14,19 +14,26 @@
|
|||
</div>
|
||||
<div class="fs-header" v-if="immersiveEnabled">
|
||||
<div class="top-nav-group">
|
||||
<sidebar-library-item @click.native="tabMode = 'catalog'" :name="$root.getLz('home.title')" svg-icon="./assets/feather/home.svg" svg-icon-name="home" page="home">
|
||||
<sidebar-library-item @click.native="tabMode = 'catalog'" :name="$root.getLz('home.title')"
|
||||
svg-icon="./assets/feather/home.svg" svg-icon-name="home" page="home">
|
||||
</sidebar-library-item>
|
||||
<sidebar-library-item @click.native="tabMode = 'catalog'" :name="$root.getLz('term.listenNow')" svg-icon="./assets/feather/play-circle.svg" svg-icon-name="listenNow"
|
||||
<sidebar-library-item @click.native="tabMode = 'catalog'" :name="$root.getLz('term.listenNow')"
|
||||
svg-icon="./assets/feather/play-circle.svg" svg-icon-name="listenNow"
|
||||
page="listen_now"></sidebar-library-item>
|
||||
<sidebar-library-item @click.native="tabMode = 'catalog'" :name="$root.getLz('term.browse')" svg-icon="./assets/feather/globe.svg" svg-icon-name="browse" page="browse">
|
||||
<sidebar-library-item @click.native="tabMode = 'catalog'" :name="$root.getLz('term.browse')"
|
||||
svg-icon="./assets/feather/globe.svg" svg-icon-name="browse" page="browse">
|
||||
</sidebar-library-item>
|
||||
<sidebar-library-item @click.native="tabMode = 'catalog'" :name="$root.getLz('term.radio')" svg-icon="./assets/feather/radio.svg" svg-icon-name="radio" page="radio">
|
||||
<sidebar-library-item @click.native="tabMode = 'catalog'" :name="$root.getLz('term.radio')"
|
||||
svg-icon="./assets/feather/radio.svg" svg-icon-name="radio" page="radio">
|
||||
</sidebar-library-item>
|
||||
<sidebar-library-item @click.native="tabMode = 'catalog'" :name="$root.getLz('term.library')" svg-icon="./assets/feather/radio.svg" svg-icon-name="library" page="library">
|
||||
<sidebar-library-item @click.native="tabMode = 'catalog'" :name="$root.getLz('term.library')"
|
||||
svg-icon="./assets/feather/radio.svg" svg-icon-name="library" page="library">
|
||||
</sidebar-library-item>
|
||||
<sidebar-library-item @click.native="tabMode = ''" :name="$root.getLz('term.nowPlaying')" svg-icon="./assets/play.svg" svg-icon-name="nowPlaying" page="nowPlaying">
|
||||
<sidebar-library-item @click.native="tabMode = ''" :name="$root.getLz('term.nowPlaying')"
|
||||
svg-icon="./assets/play.svg" svg-icon-name="nowPlaying" page="nowPlaying">
|
||||
</sidebar-library-item>
|
||||
<sidebar-library-item @click.native="tabMode = 'catalog'" name="" svg-icon="./assets/search.svg" svg-icon-name="search" page="search">
|
||||
<sidebar-library-item @click.native="tabMode = 'catalog'" name="" svg-icon="./assets/search.svg"
|
||||
svg-icon-name="search" page="search">
|
||||
</sidebar-library-item>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -59,7 +66,8 @@
|
|||
</div>
|
||||
<div class="song-artist item-navigate" style="display: inline-block;"
|
||||
@click="app.getNowPlayingItemDetailed('album') && app.fullscreen(false)">
|
||||
{{ (app.mk.nowPlayingItem["attributes"]["albumName"]) ? (app.mk.nowPlayingItem["attributes"]["albumName"]) : "" }}
|
||||
{{ (app.mk.nowPlayingItem["attributes"]["albumName"]) ?
|
||||
(app.mk.nowPlayingItem["attributes"]["albumName"]) : "" }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -139,7 +147,7 @@
|
|||
v-b-tooltip.hover :title="$root.formatVolumeTooltip()">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
<div class="col right-col" v-if="tabMode != ''">
|
||||
|
@ -175,77 +183,77 @@
|
|||
</script>
|
||||
|
||||
<script>
|
||||
Vue.component('fullscreen-view', {
|
||||
template: '#fullscreen-view',
|
||||
props: {
|
||||
time: {
|
||||
type: Number,
|
||||
required: false
|
||||
},
|
||||
lyrics: {
|
||||
type: Array,
|
||||
required: false
|
||||
},
|
||||
richlyrics: {
|
||||
type: Array,
|
||||
required: false
|
||||
},
|
||||
image: {
|
||||
type: String,
|
||||
required: false
|
||||
},
|
||||
},
|
||||
data: function () {
|
||||
return {
|
||||
app: this.$root,
|
||||
tabMode: "lyrics",
|
||||
video: null,
|
||||
immersiveEnabled: app.cfg.advanced.experiments.includes("immersive-preview")
|
||||
}
|
||||
},
|
||||
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() {
|
||||
window.addEventListener('keyup', this.onEscapeKeyUp);
|
||||
},
|
||||
beforeDestroy() {
|
||||
window.removeEventListener('keyup', this.onEscapeKeyUp)
|
||||
},
|
||||
methods: {
|
||||
onEscapeKeyUp(event) {
|
||||
if (event.which === 27) {
|
||||
app.fullscreen(false);
|
||||
console.log('js')
|
||||
}
|
||||
},
|
||||
Vue.component('fullscreen-view', {
|
||||
template: '#fullscreen-view',
|
||||
props: {
|
||||
time: {
|
||||
type: Number,
|
||||
required: false
|
||||
},
|
||||
lyrics: {
|
||||
type: Array,
|
||||
required: false
|
||||
},
|
||||
richlyrics: {
|
||||
type: Array,
|
||||
required: false
|
||||
},
|
||||
image: {
|
||||
type: String,
|
||||
required: false
|
||||
},
|
||||
},
|
||||
data: function() {
|
||||
return {
|
||||
app: this.$root,
|
||||
tabMode: "lyrics",
|
||||
video: null,
|
||||
immersiveEnabled: app.cfg.advanced.experiments.includes("immersive-preview")
|
||||
}
|
||||
},
|
||||
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
|
||||
}
|
||||
});
|
||||
</script>
|
||||
} 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() {
|
||||
window.addEventListener('keyup', this.onEscapeKeyUp);
|
||||
},
|
||||
beforeDestroy() {
|
||||
window.removeEventListener('keyup', this.onEscapeKeyUp)
|
||||
},
|
||||
methods: {
|
||||
onEscapeKeyUp(event) {
|
||||
if (event.which === 27) {
|
||||
app.fullscreen(false);
|
||||
console.log('js')
|
||||
}
|
||||
},
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -3,12 +3,12 @@
|
|||
</script>
|
||||
|
||||
<script>
|
||||
var hw = Vue.component('hello-world', {
|
||||
template: '#hello-world',
|
||||
methods: {
|
||||
sayHello: function () {
|
||||
alert('Hello world!');
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
var hw = Vue.component('hello-world', {
|
||||
template: '#hello-world',
|
||||
methods: {
|
||||
sayHello: function() {
|
||||
alert('Hello world!');
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<template v-if="item.type == 'artists'">
|
||||
<mediaitem-square :item="item"></mediaitem-square>
|
||||
</template>
|
||||
<template v-else>
|
||||
<template v-else>
|
||||
<mediaitem-list-item
|
||||
v-if="getKind(item) == 'song'"
|
||||
:index="key"
|
||||
|
@ -14,11 +14,13 @@
|
|||
<mediaitem-square v-else :item="item" :type="getKind(item)"></mediaitem-square>
|
||||
</template>
|
||||
</template>
|
||||
<button v-if="triggerEnabled" style="opacity:0;height: 32px;" v-observe-visibility="{callback: visibilityChanged}">{{this.app.getLz('term.showMore')}}
|
||||
<button v-if="triggerEnabled" style="opacity:0;height: 32px;"
|
||||
v-observe-visibility="{callback: visibilityChanged}">{{this.app.getLz('term.showMore')}}
|
||||
</button>
|
||||
</div>
|
||||
<transition name="fabfade">
|
||||
<button class="top-fab" v-show="showFab" @click="scrollToTop()" :aria-label="app.getLz('action.scrollToTop')">
|
||||
<button class="top-fab" v-show="showFab" @click="scrollToTop()"
|
||||
:aria-label="app.getLz('action.scrollToTop')">
|
||||
<%- include("../svg/arrow-up.svg") %>
|
||||
</button>
|
||||
</transition>
|
||||
|
@ -28,104 +30,104 @@
|
|||
</div>
|
||||
</script>
|
||||
<script>
|
||||
Vue.component('inline-collection-list', {
|
||||
template: "#inline-collection-list",
|
||||
props: {
|
||||
data: {
|
||||
required: true
|
||||
},
|
||||
title: {
|
||||
type: String,
|
||||
required: false
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: "artists"
|
||||
},
|
||||
parentSelector: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: null
|
||||
},
|
||||
},
|
||||
data: function() {
|
||||
return {
|
||||
triggerEnabled: true,
|
||||
canSeeTrigger: false,
|
||||
showFab: false,
|
||||
commonKind: "song",
|
||||
api: this.$root.mk.api,
|
||||
loading: false,
|
||||
app: this.$root,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getKind(item) {
|
||||
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
|
||||
}
|
||||
return this.commonKind
|
||||
},
|
||||
scrollToTop() {
|
||||
let target = document.querySelector(".header-text")
|
||||
document.querySelector(this.parentSelector ?? ".collection-page").scrollTo({
|
||||
top: 0,
|
||||
left: 0,
|
||||
behavior: 'smooth'
|
||||
})
|
||||
},
|
||||
getNext() {
|
||||
let self = this
|
||||
this.triggerEnabled = false;
|
||||
if (typeof this.data.next == "undefined") {
|
||||
return
|
||||
}
|
||||
this.loading = true
|
||||
|
||||
this.api.v3.music(this.data.next, app.collectionList.requestBody).then((response) => {
|
||||
console.log(response)
|
||||
if (!app.collectionList.response.groups) {
|
||||
this.data.data = this.data.data.concat(response.data.data);
|
||||
if (response.data.next) {
|
||||
this.data.next = response.data.next;
|
||||
this.triggerEnabled = true;
|
||||
}
|
||||
this.loading = false
|
||||
} else {
|
||||
if (!response.data.results[app.collectionList.response.groups]) {
|
||||
this.loading = false
|
||||
return
|
||||
}
|
||||
this.data.data = this.data.data.concat(response.data.results[app.collectionList.response.groups].data);
|
||||
if (response.data.results[app.collectionList.response.groups].next) {
|
||||
this.data.next = response.data.results[app.collectionList.response.groups].next;
|
||||
this.triggerEnabled = true;
|
||||
this.loading = false
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
headerVisibility: function(isVisible, entry) {
|
||||
if (isVisible) {
|
||||
this.showFab = false;
|
||||
} else {
|
||||
this.showFab = true;
|
||||
}
|
||||
},
|
||||
visibilityChanged: function(isVisible, entry) {
|
||||
if (isVisible) {
|
||||
this.canSeeTrigger = true;
|
||||
this.getNext();
|
||||
} else {
|
||||
this.canSeeTrigger = false;
|
||||
}
|
||||
}
|
||||
Vue.component('inline-collection-list', {
|
||||
template: "#inline-collection-list",
|
||||
props: {
|
||||
data: {
|
||||
required: true
|
||||
},
|
||||
title: {
|
||||
type: String,
|
||||
required: false
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: "artists"
|
||||
},
|
||||
parentSelector: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: null
|
||||
},
|
||||
},
|
||||
data: function() {
|
||||
return {
|
||||
triggerEnabled: true,
|
||||
canSeeTrigger: false,
|
||||
showFab: false,
|
||||
commonKind: "song",
|
||||
api: this.$root.mk.api,
|
||||
loading: false,
|
||||
app: this.$root,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getKind(item) {
|
||||
if (typeof item.kind != "undefined") {
|
||||
this.commonKind = item.kind;
|
||||
return item.kind
|
||||
}
|
||||
})
|
||||
</script>
|
||||
if (typeof item.attributes.playParams != "undefined") {
|
||||
this.commonKind = item.attributes.playParams.kind
|
||||
return item.attributes.playParams.kind
|
||||
}
|
||||
return this.commonKind
|
||||
},
|
||||
scrollToTop() {
|
||||
let target = document.querySelector(".header-text")
|
||||
document.querySelector(this.parentSelector ?? ".collection-page").scrollTo({
|
||||
top: 0,
|
||||
left: 0,
|
||||
behavior: 'smooth'
|
||||
})
|
||||
},
|
||||
getNext() {
|
||||
let self = this
|
||||
this.triggerEnabled = false;
|
||||
if (typeof this.data.next == "undefined") {
|
||||
return
|
||||
}
|
||||
this.loading = true
|
||||
|
||||
this.api.v3.music(this.data.next, app.collectionList.requestBody).then((response) => {
|
||||
console.log(response)
|
||||
if (!app.collectionList.response.groups) {
|
||||
this.data.data = this.data.data.concat(response.data.data);
|
||||
if (response.data.next) {
|
||||
this.data.next = response.data.next;
|
||||
this.triggerEnabled = true;
|
||||
}
|
||||
this.loading = false
|
||||
} else {
|
||||
if (!response.data.results[app.collectionList.response.groups]) {
|
||||
this.loading = false
|
||||
return
|
||||
}
|
||||
this.data.data = this.data.data.concat(response.data.results[app.collectionList.response.groups].data);
|
||||
if (response.data.results[app.collectionList.response.groups].next) {
|
||||
this.data.next = response.data.results[app.collectionList.response.groups].next;
|
||||
this.triggerEnabled = true;
|
||||
this.loading = false
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
headerVisibility: function(isVisible, entry) {
|
||||
if (isVisible) {
|
||||
this.showFab = false;
|
||||
} else {
|
||||
this.showFab = true;
|
||||
}
|
||||
},
|
||||
visibilityChanged: function(isVisible, entry) {
|
||||
if (isVisible) {
|
||||
this.canSeeTrigger = true;
|
||||
this.getNext();
|
||||
} else {
|
||||
this.canSeeTrigger = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<template v-for="segment in lyrics" v-if="segmentInRange(segment.ts, segment.te, segment.x)">
|
||||
<div class="verse-group active">
|
||||
<template v-for="(verse, verseIndex) in segment.l"
|
||||
v-if="verseInRange(segment.ts, segment.te, verse.o)">
|
||||
v-if="verseInRange(segment.ts, segment.te, verse.o)">
|
||||
<span class="verse verse-active">{{ verse.c }}</span>
|
||||
</template>
|
||||
<template v-else>
|
||||
|
@ -17,4 +17,4 @@
|
|||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
</script>
|
||||
|
|
|
@ -1,192 +1,197 @@
|
|||
<script type="text/x-template" id="libraryartist-item">
|
||||
<div v-observe-visibility="{callback: visibilityChanged}"
|
||||
<div v-observe-visibility="{callback: visibilityChanged}"
|
||||
@click="select"
|
||||
class="cd-mediaitem-list-item"
|
||||
:class="{'mediaitem-selected': app.select_hasMediaItem(guid)}"
|
||||
@contextmenu="contextMenu">
|
||||
<div class="artwork" v-show="isVisible" v-if="showArtwork == true">
|
||||
<mediaitem-artwork
|
||||
:url="getArtwork()"
|
||||
size="50"
|
||||
:type="item.type"></mediaitem-artwork>
|
||||
</div>
|
||||
<div class="info-rect" :style="{'padding-left': (showArtwork ? '' : '16px')}"
|
||||
@dblclick="app.routeView(item)">
|
||||
<div class="title text-overflow-elipsis">
|
||||
{{ item.attributes.name }}
|
||||
</div>
|
||||
<div class="artwork" v-show="isVisible" v-if="showArtwork == true">
|
||||
<mediaitem-artwork
|
||||
:url="getArtwork()"
|
||||
size="50"
|
||||
:type="item.type"></mediaitem-artwork>
|
||||
</div>
|
||||
<div class="info-rect" :style="{'padding-left': (showArtwork ? '' : '16px')}"
|
||||
@dblclick="app.routeView(item)">
|
||||
<div class="title text-overflow-elipsis">
|
||||
{{ item.attributes.name }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script>
|
||||
Vue.component('libraryartist-item', {
|
||||
template: '#libraryartist-item',
|
||||
data: function () {
|
||||
return {
|
||||
isVisible: false,
|
||||
addedToLibrary: false,
|
||||
guid: this.uuidv4(),
|
||||
app: this.$root
|
||||
}
|
||||
},
|
||||
props: {
|
||||
'item': {type: Object, required: true},
|
||||
'parent': {type: String, required: false},
|
||||
'index': {type: Number, required: false, default: -1},
|
||||
'show-artwork': {type: Boolean, default: true},
|
||||
'show-library-status': {type: Boolean, default: true},
|
||||
'show-meta-data': {type: Boolean, default: false},
|
||||
'show-duration': {type: Boolean, default: true},
|
||||
'contextExt': {type: Object, required: false},
|
||||
},
|
||||
methods: {
|
||||
uuidv4() {
|
||||
return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, c =>
|
||||
(c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16)
|
||||
);
|
||||
},
|
||||
msToMinSec(ms) {
|
||||
var minutes = Math.floor(ms / 60000);
|
||||
var seconds = ((ms % 60000) / 1000).toFixed(0);
|
||||
return minutes + ":" + (seconds < 10 ? '0' : '') + seconds;
|
||||
},
|
||||
getDataType() {
|
||||
return this.item.type
|
||||
},
|
||||
async select(e) {
|
||||
let u = this.item
|
||||
let u1 = await app.mk.api.v3.music(`/v1/me/library/artists/${u.id}/albums`, {
|
||||
"platform": "web",
|
||||
"include[library-albums]": "artists,tracks",
|
||||
"include[library-artists]": "catalog",
|
||||
"fields[artists]": "url",
|
||||
"includeOnly": "catalog,artists"
|
||||
})
|
||||
app.showCollection({data : Object.assign({},u1.data.data)}, u.attributes.name?? '', '');
|
||||
app.select_selectMediaItem(u.id, this.getDataType(), this.index, this.guid, true)
|
||||
},
|
||||
getArtwork(){
|
||||
let u = ""
|
||||
try{
|
||||
u = this.item.relationships.catalog.data[0].attributes.artwork.url}
|
||||
catch (e){};
|
||||
return u;
|
||||
},
|
||||
contextMenu(event) {
|
||||
|
||||
let self = this
|
||||
let data_type = this.getDataType()
|
||||
|
||||
let item = self.item
|
||||
item.attributes.artistName = item.attributes.name;
|
||||
|
||||
let useMenu = "normal"
|
||||
if (app.selectedMediaItems.length <= 1) {
|
||||
app.selectedMediaItems = []
|
||||
app.select_selectMediaItem(this.item.id, data_type, this.index, this.guid, true)
|
||||
} else {
|
||||
useMenu = "multiple"
|
||||
}
|
||||
|
||||
let menus = {
|
||||
multiple: {
|
||||
items: [] //
|
||||
},
|
||||
normal: {
|
||||
items: [
|
||||
{
|
||||
"name": app.getLz('action.goToArtist'),
|
||||
"icon": "./assets/feather/user.svg",
|
||||
"action": function () {
|
||||
app.searchAndNavigate(self.item, 'artist')
|
||||
console.log(self.item)
|
||||
}
|
||||
},
|
||||
{
|
||||
"icon": "./assets/feather/radio.svg",
|
||||
"name": app.getLz('action.startRadio'),
|
||||
"action": function () {
|
||||
app.mk.setStationQueue({song: self.item.attributes.playParams.id ?? self.item.id}).then(() => {
|
||||
app.mk.play()
|
||||
app.selectedMediaItems = []
|
||||
})
|
||||
}
|
||||
},
|
||||
{
|
||||
"icon": "./assets/feather/share.svg",
|
||||
"name": app.getLz('action.share'),
|
||||
"action": function () {
|
||||
if (!self.item.attributes.url && self.item.relationships){
|
||||
if (self.item.relationships.catalog){
|
||||
app.mkapi(self.item.attributes.playParams.kind, false, self.item.relationships.catalog.data[0].id).then(u => {self.app.copyToClipboard((u.data.data.length && u.data.data.length > 0)? u.data.data[0].attributes.url : u.data.data.attributes.url)})
|
||||
}
|
||||
} else {
|
||||
self.app.copyToClipboard(self.item.attributes.url)}
|
||||
}
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
if (this.contextExt) {
|
||||
// if this.context-ext.normal is true append all options to the 'normal' menu which is a kvp of arrays
|
||||
if (this.contextExt.normal) {
|
||||
menus.normal.items = menus.normal.items.concat(this.contextExt.normal)
|
||||
}
|
||||
if (this.contextExt.multiple) {
|
||||
menus.multiple.items = menus.multiple.items.concat(this.contextExt.multiple)
|
||||
}
|
||||
}
|
||||
//CiderContextMenu.Create(event, menus[useMenu]); // Depreciated Context Menu
|
||||
app.showMenuPanel(menus[useMenu], event);
|
||||
|
||||
},
|
||||
visibilityChanged: function (isVisible, entry) {
|
||||
this.isVisible = isVisible
|
||||
},
|
||||
addToLibrary() {
|
||||
let item = this.item
|
||||
if (item.attributes.playParams.id) {
|
||||
console.log('adding to library', item.attributes.playParams.id)
|
||||
app.addToLibrary(item.attributes.playParams.id.toString())
|
||||
this.addedToLibrary = true
|
||||
} else if (item.id) {
|
||||
console.log('adding to library', item.id)
|
||||
app.addToLibrary(item.id.toString())
|
||||
this.addedToLibrary = true
|
||||
}
|
||||
},
|
||||
async removeFromLibrary() {
|
||||
let item = this.item
|
||||
let params = {"fields[songs]": "inLibrary", "fields[albums]": "inLibrary", "relate": "library"}
|
||||
let id = item.id ?? item.attributes.playParams.id
|
||||
let res = await app.mkapi(item.attributes.playParams.kind ?? item.type, item.attributes.playParams.isLibrary ?? false, item.attributes.playParams.id ?? item.id, params);
|
||||
if (res && res.relationships && res.relationships.library && res.relationships.library.data && res.relationships.library.data.length > 0) {
|
||||
id = res.relationships.library.data[0].id
|
||||
}
|
||||
let kind = this.item.attributes.playParams.kind ?? this.data.item ?? '';
|
||||
let truekind = (!kind.endsWith("s")) ? (kind + "s") : kind;
|
||||
if (item.attributes.playParams.id) {
|
||||
console.log('remove from library', id)
|
||||
app.removeFromLibrary(truekind, id)
|
||||
this.addedToLibrary = false
|
||||
} else if (item.id) {
|
||||
console.log('remove from library', id)
|
||||
app.removeFromLibrary(truekind, id)
|
||||
this.addedToLibrary = false
|
||||
}
|
||||
},
|
||||
playTrack() {
|
||||
let item = this.item
|
||||
let parent = this.parent
|
||||
let childIndex = this.index
|
||||
console.log(item, parent, childIndex)
|
||||
if (parent != null && childIndex != null) {
|
||||
app.queueParentandplayChild(parent, childIndex, item);
|
||||
} else {
|
||||
app.playMediaItemById(item.attributes.playParams.id ?? item.id, item.attributes.playParams.kind ?? item.type, item.attributes.playParams.isLibrary ?? false, item.attributes.url)
|
||||
}
|
||||
}
|
||||
Vue.component('libraryartist-item', {
|
||||
template: '#libraryartist-item',
|
||||
data: function() {
|
||||
return {
|
||||
isVisible: false,
|
||||
addedToLibrary: false,
|
||||
guid: this.uuidv4(),
|
||||
app: this.$root
|
||||
}
|
||||
},
|
||||
props: {
|
||||
'item': { type: Object, required: true },
|
||||
'parent': { type: String, required: false },
|
||||
'index': { type: Number, required: false, default: -1 },
|
||||
'show-artwork': { type: Boolean, default: true },
|
||||
'show-library-status': { type: Boolean, default: true },
|
||||
'show-meta-data': { type: Boolean, default: false },
|
||||
'show-duration': { type: Boolean, default: true },
|
||||
'contextExt': { type: Object, required: false },
|
||||
},
|
||||
methods: {
|
||||
uuidv4() {
|
||||
return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, c =>
|
||||
(c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16)
|
||||
);
|
||||
},
|
||||
msToMinSec(ms) {
|
||||
var minutes = Math.floor(ms / 60000);
|
||||
var seconds = ((ms % 60000) / 1000).toFixed(0);
|
||||
return minutes + ":" + (seconds < 10 ? '0' : '') + seconds;
|
||||
},
|
||||
getDataType() {
|
||||
return this.item.type
|
||||
},
|
||||
async select(e) {
|
||||
let u = this.item
|
||||
let u1 = await app.mk.api.v3.music(`/v1/me/library/artists/${u.id}/albums`, {
|
||||
"platform": "web",
|
||||
"include[library-albums]": "artists,tracks",
|
||||
"include[library-artists]": "catalog",
|
||||
"fields[artists]": "url",
|
||||
"includeOnly": "catalog,artists"
|
||||
})
|
||||
app.showCollection({ data: Object.assign({}, u1.data.data) }, u.attributes.name ?? '', '');
|
||||
app.select_selectMediaItem(u.id, this.getDataType(), this.index, this.guid, true)
|
||||
},
|
||||
getArtwork() {
|
||||
let u = ""
|
||||
try {
|
||||
u = this.item.relationships.catalog.data[0].attributes.artwork.url
|
||||
} catch (e) {
|
||||
}
|
||||
});
|
||||
</script>
|
||||
;
|
||||
return u;
|
||||
},
|
||||
contextMenu(event) {
|
||||
|
||||
let self = this
|
||||
let data_type = this.getDataType()
|
||||
|
||||
let item = self.item
|
||||
item.attributes.artistName = item.attributes.name;
|
||||
|
||||
let useMenu = "normal"
|
||||
if (app.selectedMediaItems.length <= 1) {
|
||||
app.selectedMediaItems = []
|
||||
app.select_selectMediaItem(this.item.id, data_type, this.index, this.guid, true)
|
||||
} else {
|
||||
useMenu = "multiple"
|
||||
}
|
||||
|
||||
let menus = {
|
||||
multiple: {
|
||||
items: [] //
|
||||
},
|
||||
normal: {
|
||||
items: [
|
||||
{
|
||||
"name": app.getLz('action.goToArtist'),
|
||||
"icon": "./assets/feather/user.svg",
|
||||
"action": function() {
|
||||
app.searchAndNavigate(self.item, 'artist')
|
||||
console.log(self.item)
|
||||
}
|
||||
},
|
||||
{
|
||||
"icon": "./assets/feather/radio.svg",
|
||||
"name": app.getLz('action.startRadio'),
|
||||
"action": function() {
|
||||
app.mk.setStationQueue({ song: self.item.attributes.playParams.id ?? self.item.id }).then(() => {
|
||||
app.mk.play()
|
||||
app.selectedMediaItems = []
|
||||
})
|
||||
}
|
||||
},
|
||||
{
|
||||
"icon": "./assets/feather/share.svg",
|
||||
"name": app.getLz('action.share'),
|
||||
"action": function() {
|
||||
if (!self.item.attributes.url && self.item.relationships) {
|
||||
if (self.item.relationships.catalog) {
|
||||
app.mkapi(self.item.attributes.playParams.kind, false, self.item.relationships.catalog.data[0].id).then(u => {
|
||||
self.app.copyToClipboard((u.data.data.length && u.data.data.length > 0) ? u.data.data[0].attributes.url : u.data.data.attributes.url)
|
||||
})
|
||||
}
|
||||
} else {
|
||||
self.app.copyToClipboard(self.item.attributes.url)
|
||||
}
|
||||
}
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
if (this.contextExt) {
|
||||
// if this.context-ext.normal is true append all options to the 'normal' menu which is a kvp of arrays
|
||||
if (this.contextExt.normal) {
|
||||
menus.normal.items = menus.normal.items.concat(this.contextExt.normal)
|
||||
}
|
||||
if (this.contextExt.multiple) {
|
||||
menus.multiple.items = menus.multiple.items.concat(this.contextExt.multiple)
|
||||
}
|
||||
}
|
||||
//CiderContextMenu.Create(event, menus[useMenu]); // Depreciated Context Menu
|
||||
app.showMenuPanel(menus[useMenu], event);
|
||||
|
||||
},
|
||||
visibilityChanged: function(isVisible, entry) {
|
||||
this.isVisible = isVisible
|
||||
},
|
||||
addToLibrary() {
|
||||
let item = this.item
|
||||
if (item.attributes.playParams.id) {
|
||||
console.log('adding to library', item.attributes.playParams.id)
|
||||
app.addToLibrary(item.attributes.playParams.id.toString())
|
||||
this.addedToLibrary = true
|
||||
} else if (item.id) {
|
||||
console.log('adding to library', item.id)
|
||||
app.addToLibrary(item.id.toString())
|
||||
this.addedToLibrary = true
|
||||
}
|
||||
},
|
||||
async removeFromLibrary() {
|
||||
let item = this.item
|
||||
let params = { "fields[songs]": "inLibrary", "fields[albums]": "inLibrary", "relate": "library" }
|
||||
let id = item.id ?? item.attributes.playParams.id
|
||||
let res = await app.mkapi(item.attributes.playParams.kind ?? item.type, item.attributes.playParams.isLibrary ?? false, item.attributes.playParams.id ?? item.id, params);
|
||||
if (res && res.relationships && res.relationships.library && res.relationships.library.data && res.relationships.library.data.length > 0) {
|
||||
id = res.relationships.library.data[0].id
|
||||
}
|
||||
let kind = this.item.attributes.playParams.kind ?? this.data.item ?? '';
|
||||
let truekind = (!kind.endsWith("s")) ? (kind + "s") : kind;
|
||||
if (item.attributes.playParams.id) {
|
||||
console.log('remove from library', id)
|
||||
app.removeFromLibrary(truekind, id)
|
||||
this.addedToLibrary = false
|
||||
} else if (item.id) {
|
||||
console.log('remove from library', id)
|
||||
app.removeFromLibrary(truekind, id)
|
||||
this.addedToLibrary = false
|
||||
}
|
||||
},
|
||||
playTrack() {
|
||||
let item = this.item
|
||||
let parent = this.parent
|
||||
let childIndex = this.index
|
||||
console.log(item, parent, childIndex)
|
||||
if (parent != null && childIndex != null) {
|
||||
app.queueParentandplayChild(parent, childIndex, item);
|
||||
} else {
|
||||
app.playMediaItemById(item.attributes.playParams.id ?? item.id, item.attributes.playParams.kind ?? item.type, item.attributes.playParams.isLibrary ?? false, item.attributes.url)
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -1,92 +1,106 @@
|
|||
<script type="text/x-template" id="listennow-child">
|
||||
<div v-observe-visibility="{callback: visibilityChanged}">
|
||||
<template v-if="isVisible && recom.attributes.display.kind != 'MusicSuperHeroShelf'">
|
||||
<div class="row">
|
||||
<div class="col" v-if="recom?.relationships['primary-content']?.data?.length > 0" style="display: flex; margin-block:1rem;">
|
||||
<div @click="navigateContent(recom?.relationships['primary-content']?.data[0] ?? recom?.attributes?.title?.contentIds[0] ?? '')" class="listennow-chip" style="height: 40px;width: 40px;align-self: center;margin-right: 10px;" :class="{ 'circle': recom?.relationships['primary-content']?.data[0]?.type == 'artists' }">
|
||||
<mediaitem-artwork v-if="recom?.relationships['primary-content']?.data[0]?.attributes?.artwork != null" :url="recom?.relationships['primary-content']?.data[0]?.attributes?.artwork?.url" :size="100"></mediaitem-artwork>
|
||||
</div>
|
||||
<div @click="navigateContent(recom?.relationships['primary-content']?.data[0] ?? recom?.attributes?.title?.contentIds[0] ?? '')" style="width: fit-content;" :class="{'item-navigate' : (recom?.attributes?.title?.contentIds?.length ?? 0) > 0 | recom?.relationships['primary-content']?.data?.length > 0}">
|
||||
<span style="opacity: 0.5; font-weight: bold;"> {{ recom.attributes.titleWithoutName.stringForDisplay }} </span>
|
||||
<h3 style="margin-block: 0"> {{ recom?.relationships['primary-content']?.data[0].attributes?.name ?? recom.attributes.title.stringForDisplay.replace(recom.attributes.titleWithoutName.stringForDisplay, '') }}</h3>
|
||||
<template v-if="isVisible && recom.attributes.display.kind != 'MusicSuperHeroShelf'">
|
||||
<div class="row">
|
||||
<div class="col" v-if="recom?.relationships['primary-content']?.data?.length > 0"
|
||||
style="display: flex; margin-block:1rem;">
|
||||
<div @click="navigateContent(recom?.relationships['primary-content']?.data[0] ?? recom?.attributes?.title?.contentIds[0] ?? '')"
|
||||
class="listennow-chip" style="height: 40px;width: 40px;align-self: center;margin-right: 10px;"
|
||||
:class="{ 'circle': recom?.relationships['primary-content']?.data[0]?.type == 'artists' }">
|
||||
<mediaitem-artwork
|
||||
v-if="recom?.relationships['primary-content']?.data[0]?.attributes?.artwork != null"
|
||||
:url="recom?.relationships['primary-content']?.data[0]?.attributes?.artwork?.url"
|
||||
:size="100"></mediaitem-artwork>
|
||||
</div>
|
||||
<div @click="navigateContent(recom?.relationships['primary-content']?.data[0] ?? recom?.attributes?.title?.contentIds[0] ?? '')"
|
||||
style="width: fit-content;"
|
||||
:class="{'item-navigate' : (recom?.attributes?.title?.contentIds?.length ?? 0) > 0 | recom?.relationships['primary-content']?.data?.length > 0}">
|
||||
<span style="opacity: 0.5; font-weight: bold;"> {{ recom.attributes.titleWithoutName.stringForDisplay }} </span>
|
||||
<h3 style="margin-block: 0"> {{
|
||||
recom?.relationships['primary-content']?.data[0].attributes?.name ??
|
||||
recom.attributes.title.stringForDisplay.replace(recom.attributes.titleWithoutName.stringForDisplay,
|
||||
'') }}</h3>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="col" v-else style="display: flex; margin-block:1rem;">
|
||||
<h3 @click="navigateContent(recom?.relationships['primary-content']?.data[0] ?? recom?.attributes?.title?.contentIds[0] ?? '')"
|
||||
style="width: fit-content; margin-block:0;"
|
||||
:class="{'item-navigate' : (recom?.attributes?.title?.contentIds?.length ?? 0) > 0 | recom?.relationships['primary-content']?.data?.length > 0}">
|
||||
{{ recom.attributes.title ? recom.attributes.title.stringForDisplay : " "}}</h3>
|
||||
</div>
|
||||
<div class="col-auto cider-flex-center" v-if="recom.relationships.contents.data.length >= 10">
|
||||
<button class="cd-btn-seeall" @click="showCollection(recom)">{{app.getLz('term.seeAll')}}</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col" v-else style="display: flex; margin-block:1rem;">
|
||||
<h3 @click="navigateContent(recom?.relationships['primary-content']?.data[0] ?? recom?.attributes?.title?.contentIds[0] ?? '')" style="width: fit-content; margin-block:0;" :class="{'item-navigate' : (recom?.attributes?.title?.contentIds?.length ?? 0) > 0 | recom?.relationships['primary-content']?.data?.length > 0}">
|
||||
{{ recom.attributes.title ? recom.attributes.title.stringForDisplay : " "}}</h3>
|
||||
</div>
|
||||
<div class="col-auto cider-flex-center" v-if="recom.relationships.contents.data.length >= 10">
|
||||
<button class="cd-btn-seeall" @click="showCollection(recom)" >{{app.getLz('term.seeAll')}}</button>
|
||||
</div>
|
||||
</div>
|
||||
<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
|
||||
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>
|
||||
<template v-else>
|
||||
<mediaitem-scroller-horizontal-sp
|
||||
:withReason="index==0"
|
||||
:items="recom.relationships.contents.data.limit(10)"></mediaitem-scroller-horizontal-sp>
|
||||
</template>
|
||||
</template>
|
||||
<template v-else>
|
||||
<mediaitem-scroller-horizontal-sp
|
||||
:withReason="index==0"
|
||||
:items="recom.relationships.contents.data.limit(10)"></mediaitem-scroller-horizontal-sp>
|
||||
<template v-else-if="recom.attributes.display.kind != 'MusicSuperHeroShelf'">
|
||||
<div style="height:330px"></div>
|
||||
</template>
|
||||
</template>
|
||||
<template v-else-if="recom.attributes.display.kind != 'MusicSuperHeroShelf'">
|
||||
<div style="height:330px"> </div>
|
||||
</template>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
<script>
|
||||
Vue.component('listennow-child', {
|
||||
template: "#listennow-child",
|
||||
props: ["recom","index"],
|
||||
data: function () {
|
||||
return {
|
||||
isVisible: true,
|
||||
app: this.$root
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
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')
|
||||
},
|
||||
navigateContent: async function (id) {
|
||||
Vue.component('listennow-child', {
|
||||
template: "#listennow-child",
|
||||
props: ["recom", "index"],
|
||||
data: function() {
|
||||
return {
|
||||
isVisible: true,
|
||||
app: this.$root
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
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')
|
||||
},
|
||||
navigateContent: async function(id) {
|
||||
|
||||
if (typeof id != "string") {
|
||||
app.routeView(id)
|
||||
} else {
|
||||
try{
|
||||
let a = await app.mk.api.v3.music(`/v1/catalog/${app.mk.storefrontId}?ids[albums]=${id}`)
|
||||
let q1 = a.data?.data[0]
|
||||
if (q1) {
|
||||
app.routeView(q1)
|
||||
} else {
|
||||
let b = await app.mk.api.v3.music(`/v1/catalog/${app.mk.storefrontId}?ids[artists]=${id}`)
|
||||
let q2 = b.data?.data[0]
|
||||
if (q2) {
|
||||
app.routeView(q2)
|
||||
} else {
|
||||
let c = await app.mk.api.v3.music(`/v1/catalog/${app.mk.storefrontId}?ids[playlists]=${id}`)
|
||||
let q3 = c.data?.data[0]
|
||||
if (q3) {
|
||||
app.routeView(q3)
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
let b = await app.mk.api.v3.music(`/v1/catalog/${app.mk.storefrontId}?ids[artists]=${id}`)
|
||||
let q2 = b.data?.data[0]
|
||||
if (q2) {
|
||||
app.routeView(q2)
|
||||
}
|
||||
}
|
||||
if (typeof id != "string") {
|
||||
app.routeView(id)
|
||||
} else {
|
||||
try {
|
||||
let a = await app.mk.api.v3.music(`/v1/catalog/${app.mk.storefrontId}?ids[albums]=${id}`)
|
||||
let q1 = a.data?.data[0]
|
||||
if (q1) {
|
||||
app.routeView(q1)
|
||||
} else {
|
||||
let b = await app.mk.api.v3.music(`/v1/catalog/${app.mk.storefrontId}?ids[artists]=${id}`)
|
||||
let q2 = b.data?.data[0]
|
||||
if (q2) {
|
||||
app.routeView(q2)
|
||||
} else {
|
||||
let c = await app.mk.api.v3.music(`/v1/catalog/${app.mk.storefrontId}?ids[playlists]=${id}`)
|
||||
let q3 = c.data?.data[0]
|
||||
if (q3) {
|
||||
app.routeView(q3)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
let b = await app.mk.api.v3.music(`/v1/catalog/${app.mk.storefrontId}?ids[artists]=${id}`)
|
||||
let q2 = b.data?.data[0]
|
||||
if (q2) {
|
||||
app.routeView(q2)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
|
|
@ -1,69 +1,74 @@
|
|||
<script type="text/x-template" id="listitem-horizontal">
|
||||
<div class="listitem-horizontal">
|
||||
<vue-horizontal>
|
||||
<div v-for="items in itemPages">
|
||||
<mediaitem-list-item
|
||||
v-for="(song, index) in items" :show-library-status="showLibraryStatus" :parent="'listitem-hr' + simplifiedParent"
|
||||
:index="song.index"
|
||||
:item="song"></mediaitem-list-item>
|
||||
</div>
|
||||
</vue-horizontal>
|
||||
</div>
|
||||
<div class="listitem-horizontal">
|
||||
<vue-horizontal>
|
||||
<div v-for="items in itemPages">
|
||||
<mediaitem-list-item
|
||||
v-for="(song, index) in items" :show-library-status="showLibraryStatus"
|
||||
:parent="'listitem-hr' + simplifiedParent"
|
||||
:index="song.index"
|
||||
:item="song"></mediaitem-list-item>
|
||||
</div>
|
||||
</vue-horizontal>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script>
|
||||
Vue.component('listitem-horizontal', {
|
||||
template: '#listitem-horizontal',
|
||||
name: "listitem-horizontal",
|
||||
props: {
|
||||
items: {
|
||||
type: Array,
|
||||
required: true
|
||||
},
|
||||
showLibraryStatus: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
},
|
||||
data: function () {
|
||||
return {
|
||||
itemPages: [],
|
||||
simplifiedParent : []
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
// give every item an id
|
||||
this.items.forEach(function (item, index) {
|
||||
item.id = index;
|
||||
});
|
||||
// split items into pages
|
||||
this.itemPages = app.arrayToChunk(this.items, 4);
|
||||
try{
|
||||
this.simplifiedParent = JSON.stringify(this.items.map ( function(x){return x.attributes.playParams}));
|
||||
console.debug("simplifiedParent: " + this.simplifiedParent);
|
||||
}
|
||||
catch (e){}
|
||||
|
||||
},
|
||||
watch: {
|
||||
items: function (items) {
|
||||
// give every item an id
|
||||
this.items.forEach(function (item, index) {
|
||||
item.id = index;
|
||||
});
|
||||
// split items into pages
|
||||
this.itemPages = app.arrayToChunk(this.items, 4);
|
||||
try{
|
||||
this.simplifiedParent = JSON.stringify(this.items.map ( function(x){return x.attributes.playParams}));
|
||||
console.log("simplifiedParent: " + this.simplifiedParent);
|
||||
}
|
||||
catch (e){}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
sayHello: function () {
|
||||
alert('Hello world!');
|
||||
}
|
||||
Vue.component('listitem-horizontal', {
|
||||
template: '#listitem-horizontal',
|
||||
name: "listitem-horizontal",
|
||||
props: {
|
||||
items: {
|
||||
type: Array,
|
||||
required: true
|
||||
},
|
||||
showLibraryStatus: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
},
|
||||
data: function() {
|
||||
return {
|
||||
itemPages: [],
|
||||
simplifiedParent: []
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
// give every item an id
|
||||
this.items.forEach(function(item, index) {
|
||||
item.id = index;
|
||||
});
|
||||
// split items into pages
|
||||
this.itemPages = app.arrayToChunk(this.items, 4);
|
||||
try {
|
||||
this.simplifiedParent = JSON.stringify(this.items.map(function(x) {
|
||||
return x.attributes.playParams
|
||||
}));
|
||||
console.debug("simplifiedParent: " + this.simplifiedParent);
|
||||
} catch (e) {
|
||||
}
|
||||
|
||||
},
|
||||
watch: {
|
||||
items: function(items) {
|
||||
// give every item an id
|
||||
this.items.forEach(function(item, index) {
|
||||
item.id = index;
|
||||
});
|
||||
// split items into pages
|
||||
this.itemPages = app.arrayToChunk(this.items, 4);
|
||||
try {
|
||||
this.simplifiedParent = JSON.stringify(this.items.map(function(x) {
|
||||
return x.attributes.playParams
|
||||
}));
|
||||
console.log("simplifiedParent: " + this.simplifiedParent);
|
||||
} catch (e) {
|
||||
}
|
||||
});
|
||||
</script>
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
sayHello: function() {
|
||||
alert('Hello world!');
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -5,16 +5,17 @@
|
|||
<h3 class="lyric-line" @click="seekTo(lyric.startTime)" :class="{unsynced : lyric.startTime == 9999999}"
|
||||
v-bind:line-index="index.toString()">
|
||||
<template v-if="richlyrics && richlyrics != [] && richlyrics.length > 0">
|
||||
<div class="richl" >
|
||||
<template v-for="verse in getVerseLine(index-1)" >
|
||||
<span class="verse" :lyricstart="lyric.startTime" :versestart="verse.o" >{{ verse.c }}</span>
|
||||
<div class="richl">
|
||||
<template v-for="verse in getVerseLine(index-1)">
|
||||
<span class="verse" :lyricstart="lyric.startTime"
|
||||
:versestart="verse.o">{{ verse.c }}</span>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div class="norm" >
|
||||
{{ lyric.line }}
|
||||
</div>
|
||||
<div class="norm">
|
||||
{{ lyric.line }}
|
||||
</div>
|
||||
</template>
|
||||
<div class="lyrics-translation" v-if="lyric.translation && lyric.translation != ''">
|
||||
{{ lyric.translation }}
|
||||
|
@ -35,173 +36,182 @@
|
|||
</template>
|
||||
<template v-else>
|
||||
<div class="no-lyrics">
|
||||
{{app.getLz('term.noLyrics')}}</div>
|
||||
{{app.getLz('term.noLyrics')}}
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</script>
|
||||
<script>
|
||||
Vue.component('lyrics-view', {
|
||||
template: '#lyrics-view',
|
||||
props: ["time", "lyrics", "richlyrics", "translation", "onindex", "yoffset"],
|
||||
data: function () {
|
||||
return {
|
||||
app: this.$root,
|
||||
Vue.component('lyrics-view', {
|
||||
template: '#lyrics-view',
|
||||
props: ["time", "lyrics", "richlyrics", "translation", "onindex", "yoffset"],
|
||||
data: function() {
|
||||
return {
|
||||
app: this.$root,
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
time: function() {
|
||||
if (((app.lyricon && app.drawer.open) || app.appMode == 'fullscreen') && this.$refs.lyricsview) {
|
||||
let currentLine = this.$refs.lyricsview.querySelector(`.lyric-line.active`)
|
||||
if (currentLine && currentLine.getElementsByClassName('lyricWaiting').length > 0) {
|
||||
let duration = currentLine.getAttribute("end") - currentLine.getAttribute("start");
|
||||
let u = (this.time - currentLine.getAttribute("start")) / duration;
|
||||
if (u < 0.25 && !currentLine.classList.contains('mode1')) {
|
||||
try {
|
||||
currentLine.classList.add('mode1');
|
||||
currentLine.classList.remove('mode3');
|
||||
currentLine.classList.remove('mode2');
|
||||
} catch (e) {
|
||||
}
|
||||
currentLine.getElementsByClassName('WaitingDot1')[0].style.animation = `dotOpacity ${0.25 * duration}s cubic-bezier(0.42, 0, 0.58, 1) forwards`;
|
||||
currentLine.getElementsByClassName('WaitingDot2')[0].style.animation = ``;
|
||||
currentLine.getElementsByClassName('WaitingDot3')[0].style.animation = ``;
|
||||
currentLine.getElementsByClassName('WaitingDot2')[0].style.opacity = 0.25;
|
||||
currentLine.getElementsByClassName('WaitingDot3')[0].style.opacity = 0.25;
|
||||
|
||||
} else if (u >= 0.25 && u < 0.5 && !currentLine.classList.contains('mode2')) {
|
||||
try {
|
||||
currentLine.classList.add('mode2');
|
||||
currentLine.classList.remove('mode1');
|
||||
currentLine.classList.remove('mode3');
|
||||
} catch (e) {
|
||||
}
|
||||
currentLine.getElementsByClassName('WaitingDot2')[0].style.animation = `dotOpacity ${0.25 * duration}s cubic-bezier(0.42, 0, 0.58, 1) forwards`;
|
||||
currentLine.getElementsByClassName('WaitingDot1')[0].style.animation = ``;
|
||||
currentLine.getElementsByClassName('WaitingDot3')[0].style.animation = ``;
|
||||
currentLine.getElementsByClassName('WaitingDot1')[0].style.opacity = 1;
|
||||
currentLine.getElementsByClassName('WaitingDot3')[0].style.opacity = 0.25;
|
||||
} else if (u >= 0.5 && u < 0.75 && !currentLine.classList.contains('mode3')) {
|
||||
try {
|
||||
currentLine.classList.add('mode3');
|
||||
currentLine.classList.remove('mode1');
|
||||
currentLine.classList.remove('mode2');
|
||||
} catch (e) {
|
||||
}
|
||||
currentLine.getElementsByClassName('WaitingDot3')[0].style.animation = `dotOpacity ${0.25 * duration}s cubic-bezier(0.42, 0, 0.58, 1) forwards`;
|
||||
currentLine.getElementsByClassName('WaitingDot1')[0].style.animation = ``;
|
||||
currentLine.getElementsByClassName('WaitingDot2')[0].style.animation = ``;
|
||||
currentLine.getElementsByClassName('WaitingDot1')[0].style.opacity = 1;
|
||||
currentLine.getElementsByClassName('WaitingDot2')[0].style.opacity = 1;
|
||||
} else if (u >= 0.75 && currentLine.classList.contains('mode3')) {
|
||||
try {
|
||||
currentLine.classList.remove('mode1');
|
||||
currentLine.classList.remove('mode2');
|
||||
currentLine.classList.remove('mode3');
|
||||
} catch (e) {
|
||||
}
|
||||
currentLine.getElementsByClassName('WaitingDot1')[0].style.animation = ``;
|
||||
currentLine.getElementsByClassName('WaitingDot2')[0].style.animation = ``;
|
||||
currentLine.getElementsByClassName('WaitingDot1')[0].style.opacity = 1;
|
||||
currentLine.getElementsByClassName('WaitingDot2')[0].style.opacity = 1;
|
||||
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
time: function () {
|
||||
if (((app.lyricon && app.drawer.open) || app.appMode == 'fullscreen') && this.$refs.lyricsview) {
|
||||
let currentLine = this.$refs.lyricsview.querySelector(`.lyric-line.active`)
|
||||
if (currentLine && currentLine.getElementsByClassName('lyricWaiting').length > 0) {
|
||||
let duration = currentLine.getAttribute("end") - currentLine.getAttribute("start");
|
||||
let u = (this.time - currentLine.getAttribute("start")) / duration;
|
||||
if (u < 0.25 && !currentLine.classList.contains('mode1')) {
|
||||
try {
|
||||
currentLine.classList.add('mode1');
|
||||
currentLine.classList.remove('mode3');
|
||||
currentLine.classList.remove('mode2');
|
||||
} catch (e) {
|
||||
}
|
||||
currentLine.getElementsByClassName('WaitingDot1')[0].style.animation = `dotOpacity ${0.25 * duration}s cubic-bezier(0.42, 0, 0.58, 1) forwards`;
|
||||
currentLine.getElementsByClassName('WaitingDot2')[0].style.animation = ``;
|
||||
currentLine.getElementsByClassName('WaitingDot3')[0].style.animation = ``;
|
||||
currentLine.getElementsByClassName('WaitingDot2')[0].style.opacity = 0.25;
|
||||
currentLine.getElementsByClassName('WaitingDot3')[0].style.opacity = 0.25;
|
||||
|
||||
} else if (u >= 0.25 && u < 0.5 && !currentLine.classList.contains('mode2')) {
|
||||
try {
|
||||
currentLine.classList.add('mode2');
|
||||
currentLine.classList.remove('mode1');
|
||||
currentLine.classList.remove('mode3');
|
||||
} catch (e) {
|
||||
}
|
||||
currentLine.getElementsByClassName('WaitingDot2')[0].style.animation = `dotOpacity ${0.25 * duration}s cubic-bezier(0.42, 0, 0.58, 1) forwards`;
|
||||
currentLine.getElementsByClassName('WaitingDot1')[0].style.animation = ``;
|
||||
currentLine.getElementsByClassName('WaitingDot3')[0].style.animation = ``;
|
||||
currentLine.getElementsByClassName('WaitingDot1')[0].style.opacity = 1;
|
||||
currentLine.getElementsByClassName('WaitingDot3')[0].style.opacity = 0.25;
|
||||
} else if (u >= 0.5 && u < 0.75 && !currentLine.classList.contains('mode3')) {
|
||||
try {
|
||||
currentLine.classList.add('mode3');
|
||||
currentLine.classList.remove('mode1');
|
||||
currentLine.classList.remove('mode2');
|
||||
} catch (e) {
|
||||
}
|
||||
currentLine.getElementsByClassName('WaitingDot3')[0].style.animation = `dotOpacity ${0.25 * duration}s cubic-bezier(0.42, 0, 0.58, 1) forwards`;
|
||||
currentLine.getElementsByClassName('WaitingDot1')[0].style.animation = ``;
|
||||
currentLine.getElementsByClassName('WaitingDot2')[0].style.animation = ``;
|
||||
currentLine.getElementsByClassName('WaitingDot1')[0].style.opacity = 1;
|
||||
currentLine.getElementsByClassName('WaitingDot2')[0].style.opacity = 1;
|
||||
} else if (u >= 0.75 && currentLine.classList.contains('mode3')) {
|
||||
try {
|
||||
currentLine.classList.remove('mode1');
|
||||
currentLine.classList.remove('mode2');
|
||||
currentLine.classList.remove('mode3');
|
||||
} catch (e) {
|
||||
}
|
||||
currentLine.getElementsByClassName('WaitingDot1')[0].style.animation = ``;
|
||||
currentLine.getElementsByClassName('WaitingDot2')[0].style.animation = ``;
|
||||
currentLine.getElementsByClassName('WaitingDot1')[0].style.opacity = 1;
|
||||
currentLine.getElementsByClassName('WaitingDot2')[0].style.opacity = 1;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
this.getActiveLyric();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
},
|
||||
methods: {
|
||||
seekTo(startTime) {
|
||||
if (startTime != 9999999) this.app.seekTo(startTime, false);
|
||||
},
|
||||
getActiveLyric() {
|
||||
const delayfix = 0.1
|
||||
const prevLine = app.currentLyricsLine;
|
||||
for (var i = 0; i < this.lyrics.length; i++) {
|
||||
if (this.time + delayfix >= this.lyrics[i].startTime && this.time + delayfix <= app.lyrics[i].endTime) {
|
||||
if (app.currentLyricsLine != i) {
|
||||
app.currentLyricsLine = i;
|
||||
if (((app.lyricon && app.drawer.open) || app.appMode == 'fullscreen') && this.$refs.lyricsview.querySelector(`.lyric-line[line-index="${i}"]`)) {
|
||||
if (this.$refs.lyricsview.querySelector(`.lyric-line[line-index="${prevLine}"]`)) {
|
||||
this.$refs.lyricsview.querySelector(`.lyric-line[line-index="${prevLine}"]`).classList.remove("active");
|
||||
}
|
||||
this.getActiveLyric();
|
||||
this.$refs.lyricsview.querySelector(`.lyric-line[line-index="${i}"]`).classList.add("active")
|
||||
if (this.checkIfScrollIsStatic) {
|
||||
let lyricElement = this.$refs.lyricsview.querySelector(`.lyric-line[line-index="${i}"]`)
|
||||
// this.$refs.lyricsview.querySelector(`.lyric-line[line-index="${i}"]`).scrollIntoView({
|
||||
// behavior: "smooth",
|
||||
// block: "nearest", inline: 'start'
|
||||
// })
|
||||
let parent = lyricElement.parentElement
|
||||
let parentRect = parent.getBoundingClientRect()
|
||||
let lyricElementRect = lyricElement.getBoundingClientRect()
|
||||
let parentScrollTop = parent.scrollTop
|
||||
let parentScrollLeft = parent.scrollLeft
|
||||
let parentScrollTopDiff = parentScrollTop - parentRect.top
|
||||
let parentScrollLeftDiff = parentScrollLeft - parentRect.left
|
||||
let lyricElementScrollTop = lyricElementRect.top + parentScrollTopDiff
|
||||
let lyricElementScrollLeft = lyricElementRect.left + parentScrollLeftDiff
|
||||
let scrollTopDiff = lyricElementScrollTop - parentScrollTop
|
||||
let scrollLeftDiff = lyricElementScrollLeft - parentScrollLeft
|
||||
let scrollTop = parent.scrollTop + scrollTopDiff
|
||||
let scrollLeft = parent.scrollLeft + scrollLeftDiff
|
||||
parent.scrollTo({
|
||||
top: scrollTop - (this.yoffset ?? 128),
|
||||
left: scrollLeft,
|
||||
behavior: 'smooth'
|
||||
})
|
||||
|
||||
}
|
||||
}
|
||||
} else if (app.currentLyricsLine == 0 && app.drawer.open) {
|
||||
if (this.$refs.lyricsview.querySelector(`.lyric-line[line-index="0"]`) && !this.$refs.lyricsview.querySelector(`.lyric-line[line-index="0"]`).classList.contains("active"))
|
||||
this.$refs.lyricsview.querySelector(`.lyric-line[line-index="0"]`).classList.add("active");
|
||||
}
|
||||
|
||||
},
|
||||
methods: {
|
||||
seekTo(startTime) {
|
||||
if (startTime != 9999999) this.app.seekTo(startTime, false);
|
||||
},
|
||||
getActiveLyric() {
|
||||
const delayfix = 0.1
|
||||
const prevLine = app.currentLyricsLine;
|
||||
for (var i = 0; i < this.lyrics.length; i++) {
|
||||
if (this.time + delayfix >= this.lyrics[i].startTime && this.time + delayfix <= app.lyrics[i].endTime) {
|
||||
if (app.currentLyricsLine != i) {
|
||||
app.currentLyricsLine = i;
|
||||
if (((app.lyricon && app.drawer.open) || app.appMode == 'fullscreen') && this.$refs.lyricsview.querySelector(`.lyric-line[line-index="${i}"]`)) {
|
||||
if (this.$refs.lyricsview.querySelector(`.lyric-line[line-index="${prevLine}"]`)) {this.$refs.lyricsview.querySelector(`.lyric-line[line-index="${prevLine}"]`).classList.remove("active");}
|
||||
this.$refs.lyricsview.querySelector(`.lyric-line[line-index="${i}"]`).classList.add("active")
|
||||
if (this.checkIfScrollIsStatic) {
|
||||
let lyricElement = this.$refs.lyricsview.querySelector(`.lyric-line[line-index="${i}"]`)
|
||||
// this.$refs.lyricsview.querySelector(`.lyric-line[line-index="${i}"]`).scrollIntoView({
|
||||
// behavior: "smooth",
|
||||
// block: "nearest", inline: 'start'
|
||||
// })
|
||||
let parent = lyricElement.parentElement
|
||||
let parentRect = parent.getBoundingClientRect()
|
||||
let lyricElementRect = lyricElement.getBoundingClientRect()
|
||||
let parentScrollTop = parent.scrollTop
|
||||
let parentScrollLeft = parent.scrollLeft
|
||||
let parentScrollTopDiff = parentScrollTop - parentRect.top
|
||||
let parentScrollLeftDiff = parentScrollLeft - parentRect.left
|
||||
let lyricElementScrollTop = lyricElementRect.top + parentScrollTopDiff
|
||||
let lyricElementScrollLeft = lyricElementRect.left + parentScrollLeftDiff
|
||||
let scrollTopDiff = lyricElementScrollTop - parentScrollTop
|
||||
let scrollLeftDiff = lyricElementScrollLeft - parentScrollLeft
|
||||
let scrollTop = parent.scrollTop + scrollTopDiff
|
||||
let scrollLeft = parent.scrollLeft + scrollLeftDiff
|
||||
parent.scrollTo({
|
||||
top: scrollTop - (this.yoffset ?? 128),
|
||||
left: scrollLeft,
|
||||
behavior: 'smooth'
|
||||
})
|
||||
|
||||
}
|
||||
}
|
||||
} else if (app.currentLyricsLine == 0 && app.drawer.open) {
|
||||
if (this.$refs.lyricsview.querySelector(`.lyric-line[line-index="0"]`) && !this.$refs.lyricsview.querySelector(`.lyric-line[line-index="0"]`).classList.contains("active"))
|
||||
this.$refs.lyricsview.querySelector(`.lyric-line[line-index="0"]`).classList.add("active");
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
try{
|
||||
if ((app.drawer.open) || app.appMode == 'fullscreen'){
|
||||
try{this.$refs.lyricsview.querySelector(`.lyric-line[line-index="${prevLine}"]`).childNodes.classList.remove("verse-active");} catch(e){}
|
||||
for (child of this.$refs.lyricsview.querySelector(`.lyric-line[line-index="${app.currentLyricsLine}"]`).querySelectorAll(".verse")){
|
||||
if (this.time + 0.1 >= child.getAttribute("lyricstart") * 1 + child.getAttribute("versestart") * 1){
|
||||
child.classList.add("verse-active");
|
||||
} else {child.classList.remove("verse-active");}}
|
||||
}
|
||||
} catch(e){}
|
||||
|
||||
},
|
||||
getActiveVerse(timeStart, timeEnd, verseTime) {
|
||||
let relativeTime = this.time - timeStart
|
||||
console.log(this.time,timeEnd,timeStart,relativeTime >= verseTime && relativeTime <= timeEnd - timeStart)
|
||||
return relativeTime >= verseTime && relativeTime <= timeEnd - timeStart
|
||||
},
|
||||
getVerseLine(index) {
|
||||
if (this.richlyrics[index] != null && this.richlyrics[index].l != null) {
|
||||
return this.richlyrics[index].l
|
||||
}
|
||||
else return []
|
||||
},
|
||||
qqInstrumental(lyrics) {
|
||||
for(lyric of lyrics){
|
||||
if (lyric.line.includes("纯音乐") && lyric.line.includes("欣赏")){
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
},
|
||||
checkIfScrollIsStatic : setInterval(() => {
|
||||
break;
|
||||
}
|
||||
}
|
||||
try {
|
||||
if ((app.drawer.open) || app.appMode == 'fullscreen') {
|
||||
try {
|
||||
if (position === this.$refs.lyricsview.scrollTop) {
|
||||
clearInterval(checkIfScrollIsStatic)
|
||||
// do something
|
||||
}
|
||||
position = this.$refs.lyricsview.scrollTop
|
||||
this.$refs.lyricsview.querySelector(`.lyric-line[line-index="${prevLine}"]`).childNodes.classList.remove("verse-active");
|
||||
} catch (e) {
|
||||
}
|
||||
}, 50)
|
||||
,
|
||||
for (child of this.$refs.lyricsview.querySelector(`.lyric-line[line-index="${app.currentLyricsLine}"]`).querySelectorAll(".verse")) {
|
||||
if (this.time + 0.1 >= child.getAttribute("lyricstart") * 1 + child.getAttribute("versestart") * 1) {
|
||||
child.classList.add("verse-active");
|
||||
} else {
|
||||
child.classList.remove("verse-active");
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
},
|
||||
getActiveVerse(timeStart, timeEnd, verseTime) {
|
||||
let relativeTime = this.time - timeStart
|
||||
console.log(this.time, timeEnd, timeStart, relativeTime >= verseTime && relativeTime <= timeEnd - timeStart)
|
||||
return relativeTime >= verseTime && relativeTime <= timeEnd - timeStart
|
||||
},
|
||||
getVerseLine(index) {
|
||||
if (this.richlyrics[index] != null && this.richlyrics[index].l != null) {
|
||||
return this.richlyrics[index].l
|
||||
} else return []
|
||||
},
|
||||
qqInstrumental(lyrics) {
|
||||
for (lyric of lyrics) {
|
||||
if (lyric.line.includes("纯音乐") && lyric.line.includes("欣赏")) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
},
|
||||
checkIfScrollIsStatic: setInterval(() => {
|
||||
try {
|
||||
if (position === this.$refs.lyricsview.scrollTop) {
|
||||
clearInterval(checkIfScrollIsStatic)
|
||||
// do something
|
||||
}
|
||||
position = this.$refs.lyricsview.scrollTop
|
||||
} catch (e) {
|
||||
}
|
||||
}, 50)
|
||||
,
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
<script type="text/x-template" id="mediaitem-artwork">
|
||||
<div class="mediaitem-artwork" :style="awStyle" @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="imgSrc"
|
||||
ref="image"
|
||||
decoding="async"
|
||||
|
@ -14,138 +15,138 @@
|
|||
</script>
|
||||
|
||||
<script>
|
||||
Vue.component('mediaitem-artwork', {
|
||||
template: '#mediaitem-artwork',
|
||||
props: {
|
||||
size: {
|
||||
type: [String, Number],
|
||||
default: '120'
|
||||
},
|
||||
width: {
|
||||
type: [String, Number],
|
||||
required: false
|
||||
},
|
||||
bgcolor: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
url: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
video: {
|
||||
type: String,
|
||||
required: false
|
||||
},
|
||||
videoPriority: {
|
||||
type: Boolean,
|
||||
required: false
|
||||
},
|
||||
shadow: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
upscaling: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
Vue.component('mediaitem-artwork', {
|
||||
template: '#mediaitem-artwork',
|
||||
props: {
|
||||
size: {
|
||||
type: [String, Number],
|
||||
default: '120'
|
||||
},
|
||||
width: {
|
||||
type: [String, Number],
|
||||
required: false
|
||||
},
|
||||
bgcolor: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
url: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
video: {
|
||||
type: String,
|
||||
required: false
|
||||
},
|
||||
videoPriority: {
|
||||
type: Boolean,
|
||||
required: false
|
||||
},
|
||||
shadow: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
upscaling: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data: function() {
|
||||
return {
|
||||
app: this.$root,
|
||||
isVisible: false,
|
||||
style: {
|
||||
"box-shadow": ""
|
||||
},
|
||||
data: function () {
|
||||
return {
|
||||
app: this.$root,
|
||||
isVisible: false,
|
||||
style: {
|
||||
"box-shadow": ""
|
||||
},
|
||||
awStyle: {
|
||||
background: this.bgcolor
|
||||
},
|
||||
imgStyle: {
|
||||
opacity: 0,
|
||||
transition: "opacity .25s linear"
|
||||
},
|
||||
classes: [],
|
||||
imgSrc: ""
|
||||
}
|
||||
awStyle: {
|
||||
background: this.bgcolor
|
||||
},
|
||||
computed: {
|
||||
windowRelativeScale: function () {
|
||||
return app.$store.state.windowRelativeScale;
|
||||
}
|
||||
imgStyle: {
|
||||
opacity: 0,
|
||||
transition: "opacity .25s linear"
|
||||
},
|
||||
watch: {
|
||||
windowRelativeScale: function (newValue, oldValue) {
|
||||
this.swapImage(newValue)
|
||||
},
|
||||
url: function (newValue, oldValue) {
|
||||
this.imgSrc = app.getMediaItemArtwork(this.url, this.size, this.width)
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.getClasses()
|
||||
this.imgSrc = app.getMediaItemArtwork(this.url, this.size, this.width)
|
||||
},
|
||||
methods: {
|
||||
swapImage(newValue) {
|
||||
if(!this.upscaling || window.devicePixelRatio !== 1) return
|
||||
if (newValue > 1.5) {
|
||||
this.imgSrc = app.getMediaItemArtwork(this.url, parseInt(this.size * 2.0), parseInt(this.size * 2.0));
|
||||
}
|
||||
},
|
||||
imgLoaded() {
|
||||
this.imgStyle.opacity = 1
|
||||
this.swapImage(app.$store.state.windowRelativeScale)
|
||||
// this.awStyle.background = ""
|
||||
},
|
||||
contextMenu(event) {
|
||||
let self = this
|
||||
app.showMenuPanel({
|
||||
items: {
|
||||
"save": {
|
||||
name: app.getLz('action.openArtworkInBrowser'),
|
||||
action: () => {
|
||||
window.open(app.getMediaItemArtwork(self.url, 1024, 1024))
|
||||
}
|
||||
}
|
||||
}
|
||||
}, event)
|
||||
},
|
||||
getVideoPriority() {
|
||||
if (app.cfg.visual.animated_artwork == "always") {
|
||||
return true;
|
||||
} else if (this.videoPriority && app.cfg.visual.animated_artwork == "limited") {
|
||||
return true
|
||||
} else if (app.cfg.visual.animated_artwork == "disabled") {
|
||||
return false
|
||||
}
|
||||
return this.videoPriority
|
||||
},
|
||||
getClasses() {
|
||||
switch (this.shadow) {
|
||||
case "none":
|
||||
this.classes.push("no-shadow")
|
||||
break;
|
||||
case "large":
|
||||
this.classes.push("shadow")
|
||||
break;
|
||||
case "subtle":
|
||||
this.classes.push("subtle-shadow")
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return this.classes;
|
||||
},
|
||||
getArtworkStyle() {
|
||||
return {
|
||||
width: this.size + 'px',
|
||||
height: this.size + 'px'
|
||||
};
|
||||
}
|
||||
classes: [],
|
||||
imgSrc: ""
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
windowRelativeScale: function() {
|
||||
return app.$store.state.windowRelativeScale;
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
windowRelativeScale: function(newValue, oldValue) {
|
||||
this.swapImage(newValue)
|
||||
},
|
||||
url: function(newValue, oldValue) {
|
||||
this.imgSrc = app.getMediaItemArtwork(this.url, this.size, this.width)
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.getClasses()
|
||||
this.imgSrc = app.getMediaItemArtwork(this.url, this.size, this.width)
|
||||
},
|
||||
methods: {
|
||||
swapImage(newValue) {
|
||||
if (!this.upscaling || window.devicePixelRatio !== 1) return
|
||||
if (newValue > 1.5) {
|
||||
this.imgSrc = app.getMediaItemArtwork(this.url, parseInt(this.size * 2.0), parseInt(this.size * 2.0));
|
||||
}
|
||||
});
|
||||
</script>
|
||||
},
|
||||
imgLoaded() {
|
||||
this.imgStyle.opacity = 1
|
||||
this.swapImage(app.$store.state.windowRelativeScale)
|
||||
// this.awStyle.background = ""
|
||||
},
|
||||
contextMenu(event) {
|
||||
let self = this
|
||||
app.showMenuPanel({
|
||||
items: {
|
||||
"save": {
|
||||
name: app.getLz('action.openArtworkInBrowser'),
|
||||
action: () => {
|
||||
window.open(app.getMediaItemArtwork(self.url, 1024, 1024))
|
||||
}
|
||||
}
|
||||
}
|
||||
}, event)
|
||||
},
|
||||
getVideoPriority() {
|
||||
if (app.cfg.visual.animated_artwork == "always") {
|
||||
return true;
|
||||
} else if (this.videoPriority && app.cfg.visual.animated_artwork == "limited") {
|
||||
return true
|
||||
} else if (app.cfg.visual.animated_artwork == "disabled") {
|
||||
return false
|
||||
}
|
||||
return this.videoPriority
|
||||
},
|
||||
getClasses() {
|
||||
switch (this.shadow) {
|
||||
case "none":
|
||||
this.classes.push("no-shadow")
|
||||
break;
|
||||
case "large":
|
||||
this.classes.push("shadow")
|
||||
break;
|
||||
case "subtle":
|
||||
this.classes.push("subtle-shadow")
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return this.classes;
|
||||
},
|
||||
getArtworkStyle() {
|
||||
return {
|
||||
width: this.size + 'px',
|
||||
height: this.size + 'px'
|
||||
};
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -24,14 +24,14 @@
|
|||
</script>
|
||||
|
||||
<script>
|
||||
Vue.component('mediaitem-hrect', {
|
||||
template: '#mediaitem-hrect',
|
||||
props: ['item'],
|
||||
data: function () {
|
||||
return {
|
||||
app: this.$root,
|
||||
}
|
||||
},
|
||||
methods: {}
|
||||
});
|
||||
</script>
|
||||
Vue.component('mediaitem-hrect', {
|
||||
template: '#mediaitem-hrect',
|
||||
props: ['item'],
|
||||
data: function() {
|
||||
return {
|
||||
app: this.$root,
|
||||
}
|
||||
},
|
||||
methods: {}
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
<div class="button" style="
|
||||
border-radius: 50%;
|
||||
background: rgba(50,50,50,0.7);"
|
||||
:style="[(!(item.attributes?.playParams ? (item.attributes?.playParams?.kind ?? (item.type ?? '')): (item.type ?? '')).includes('radioStation') && !(item.attributes?.playParams ? (item.attributes?.playParams?.kind ?? (item.type ?? '')): (item.type ?? '')).includes('song')) ?
|
||||
:style="[(!(item.attributes?.playParams ? (item.attributes?.playParams?.kind ?? (item.type ?? '')): (item.type ?? '')).includes('radioStation') && !(item.attributes?.playParams ? (item.attributes?.playParams?.kind ?? (item.type ?? '')): (item.type ?? '')).includes('song')) ?
|
||||
{'margin': '205px',
|
||||
'margin-left': '260px', 'margin-bottom': '140px',
|
||||
width: '30px',
|
||||
|
@ -57,18 +57,18 @@
|
|||
</script>
|
||||
|
||||
<script>
|
||||
Vue.component('mediaitem-mvview-sp', {
|
||||
template: '#mediaitem-mvview-sp',
|
||||
props: ['item', "imagesize", "badge"],
|
||||
data: function () {
|
||||
return {
|
||||
app: this.$root,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
log(item) {
|
||||
console.log(item);
|
||||
},
|
||||
}
|
||||
});
|
||||
</script>
|
||||
Vue.component('mediaitem-mvview-sp', {
|
||||
template: '#mediaitem-mvview-sp',
|
||||
props: ['item', "imagesize", "badge"],
|
||||
data: function() {
|
||||
return {
|
||||
app: this.$root,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
log(item) {
|
||||
console.log(item);
|
||||
},
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -27,7 +27,9 @@
|
|||
<div class="title text-overflow-elipsis" @click='app.routeView(item)'>
|
||||
{{ item.attributes.name ?? '' }}
|
||||
</div>
|
||||
<div class="subtitle text-overflow-elipsis item-navigate" v-if="item.attributes.artistName" :style = "{'z-index': ((item.attributes.editorialNotes == null) && item.attributes.artistName) ? '4' : ''}" @click="if (item.attributes.artistName)app.searchAndNavigate(item,'artist')">
|
||||
<div class="subtitle text-overflow-elipsis item-navigate" v-if="item.attributes.artistName"
|
||||
:style="{'z-index': ((item.attributes.editorialNotes == null) && item.attributes.artistName) ? '4' : ''}"
|
||||
@click="if (item.attributes.artistName)app.searchAndNavigate(item,'artist')">
|
||||
{{ item.attributes.artistName ?? '' }}
|
||||
</div>
|
||||
|
||||
|
@ -51,14 +53,14 @@
|
|||
</script>
|
||||
|
||||
<script>
|
||||
Vue.component('mediaitem-mvview', {
|
||||
template: '#mediaitem-mvview',
|
||||
props: ['item', "imagesize"],
|
||||
data: function () {
|
||||
return {
|
||||
app: this.$root,
|
||||
}
|
||||
},
|
||||
methods: {}
|
||||
});
|
||||
</script>
|
||||
Vue.component('mediaitem-mvview', {
|
||||
template: '#mediaitem-mvview',
|
||||
props: ['item', "imagesize"],
|
||||
data: function() {
|
||||
return {
|
||||
app: this.$root,
|
||||
}
|
||||
},
|
||||
methods: {}
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
<script type="text/x-template" id="mediaitem-scroller-horizontal-large">
|
||||
<vue-horizontal>
|
||||
<mediaitem-square :item="item" :key="item?.id ?? ''"
|
||||
v-for="item in items"></mediaitem-square>
|
||||
v-for="item in items"></mediaitem-square>
|
||||
</vue-horizontal>
|
||||
</script>
|
||||
|
||||
|
||||
<script>
|
||||
Vue.component('mediaitem-scroller-horizontal-large', {
|
||||
template: '#mediaitem-scroller-horizontal-large',
|
||||
props: ['items']
|
||||
});
|
||||
</script>
|
||||
Vue.component('mediaitem-scroller-horizontal-large', {
|
||||
template: '#mediaitem-scroller-horizontal-large',
|
||||
props: ['items']
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -2,15 +2,15 @@
|
|||
<vue-horizontal>
|
||||
<template v-if="browsesp">
|
||||
<mediaitem-mvview-sp
|
||||
:item="
|
||||
:item="
|
||||
((item?.attributes?.kind != null || item?.attributes?.type == 'editorial-elements')
|
||||
? item :
|
||||
? item :
|
||||
((item.relationships && item.relationships.contents ) ? item.relationships.contents.data[0] : item)) ?? (item)"
|
||||
:imagesize="imagesize"
|
||||
:badge="item.attributes ?? [] " v-for="item in items"></mediaitem-mvview-sp>
|
||||
</template>
|
||||
<template v-else>
|
||||
<mediaitem-square :kind="kind" size="600" :key="item?.id ?? ''"
|
||||
<mediaitem-square :kind="kind" size="600" :key="item?.id ?? ''"
|
||||
:item="item ? ((item.attributes?.kind != null || item.type == 'editorial-elements') ? item : ((item.relationships && item.relationships.contents ) ? item.relationships.contents.data[0] : item)) : []"
|
||||
:imagesize="imagesize"
|
||||
v-for="item in items"></mediaitem-square>
|
||||
|
@ -20,34 +20,34 @@
|
|||
|
||||
|
||||
<script>
|
||||
Vue.component('mediaitem-scroller-horizontal-mvview', {
|
||||
template: '#mediaitem-scroller-horizontal-mvview',
|
||||
props: {
|
||||
items: {
|
||||
type: Array,
|
||||
required: true
|
||||
},
|
||||
imagesize: {
|
||||
type: Number,
|
||||
required: false
|
||||
},
|
||||
browsesp: {
|
||||
type: Boolean,
|
||||
required: false
|
||||
},
|
||||
kind: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: ""
|
||||
}
|
||||
},
|
||||
data: function () {
|
||||
return {
|
||||
app: this.$root,
|
||||
}
|
||||
},
|
||||
// mounted(){
|
||||
// console.log('hes',this.items)
|
||||
// }
|
||||
});
|
||||
</script>
|
||||
Vue.component('mediaitem-scroller-horizontal-mvview', {
|
||||
template: '#mediaitem-scroller-horizontal-mvview',
|
||||
props: {
|
||||
items: {
|
||||
type: Array,
|
||||
required: true
|
||||
},
|
||||
imagesize: {
|
||||
type: Number,
|
||||
required: false
|
||||
},
|
||||
browsesp: {
|
||||
type: Boolean,
|
||||
required: false
|
||||
},
|
||||
kind: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: ""
|
||||
}
|
||||
},
|
||||
data: function() {
|
||||
return {
|
||||
app: this.$root,
|
||||
}
|
||||
},
|
||||
// mounted(){
|
||||
// console.log('hes',this.items)
|
||||
// }
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -1,26 +1,26 @@
|
|||
<script type="text/x-template" id="mediaitem-scroller-horizontal-sp">
|
||||
<div class="cd-hmedia-scroller hmedia-scroller-card">
|
||||
<vue-horizontal>
|
||||
<template>
|
||||
<mediaitem-square kind="card" :item="item" size="300" :reasonShown="withReason"
|
||||
v-for="item in items"></mediaitem-square>
|
||||
</template>
|
||||
</vue-horizontal>
|
||||
</div>
|
||||
<div class="cd-hmedia-scroller hmedia-scroller-card">
|
||||
<vue-horizontal>
|
||||
<template>
|
||||
<mediaitem-square kind="card" :item="item" size="300" :reasonShown="withReason"
|
||||
v-for="item in items"></mediaitem-square>
|
||||
</template>
|
||||
</vue-horizontal>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script>
|
||||
Vue.component('mediaitem-scroller-horizontal-sp', {
|
||||
template: '#mediaitem-scroller-horizontal-sp',
|
||||
props: {
|
||||
'items': { type: Array , required: false },
|
||||
'withReason': { type: Boolean, required: false, default: false },
|
||||
},
|
||||
data: function () {
|
||||
return {
|
||||
app: this.$root,
|
||||
}
|
||||
},
|
||||
methods: {}
|
||||
});
|
||||
Vue.component('mediaitem-scroller-horizontal-sp', {
|
||||
template: '#mediaitem-scroller-horizontal-sp',
|
||||
props: {
|
||||
'items': { type: Array, required: false },
|
||||
'withReason': { type: Boolean, required: false, default: false },
|
||||
},
|
||||
data: function() {
|
||||
return {
|
||||
app: this.$root,
|
||||
}
|
||||
},
|
||||
methods: {}
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -6,27 +6,27 @@
|
|||
</script>
|
||||
|
||||
<script>
|
||||
Vue.component('mediaitem-scroller-horizontal', {
|
||||
template: '#mediaitem-scroller-horizontal',
|
||||
props: {
|
||||
'items': {
|
||||
type: Array,
|
||||
required: false
|
||||
},
|
||||
'kind': {
|
||||
type: String,
|
||||
required: false,
|
||||
defualt: ""
|
||||
}
|
||||
},
|
||||
data: function() {
|
||||
return {
|
||||
app: this.$root,
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
// this.$refs.horizontal.refresh()
|
||||
},
|
||||
methods: {}
|
||||
});
|
||||
</script>
|
||||
Vue.component('mediaitem-scroller-horizontal', {
|
||||
template: '#mediaitem-scroller-horizontal',
|
||||
props: {
|
||||
'items': {
|
||||
type: Array,
|
||||
required: false
|
||||
},
|
||||
'kind': {
|
||||
type: String,
|
||||
required: false,
|
||||
defualt: ""
|
||||
}
|
||||
},
|
||||
data: function() {
|
||||
return {
|
||||
app: this.$root,
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
// this.$refs.horizontal.refresh()
|
||||
},
|
||||
methods: {}
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -36,105 +36,105 @@
|
|||
|
||||
|
||||
<script>
|
||||
Vue.component('cider-menu-panel', {
|
||||
template: '#cider-menu-panel',
|
||||
data: function () {
|
||||
return {
|
||||
app: this.$root,
|
||||
menuPanel: this.$root.menuPanel,
|
||||
content: this.$root.menuPanel.content,
|
||||
getSvgIcon: this.$root.getSvgIcon,
|
||||
position: [0, 0],
|
||||
size: [0, 0],
|
||||
event: this.$root.menuPanel.event,
|
||||
direction: "down",
|
||||
elStyle: {
|
||||
opacity: 0
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
if (this.event) {
|
||||
this.position = [this.event.clientX, this.event.clientY];
|
||||
}
|
||||
this.$nextTick(() => {
|
||||
// this.size = [document.querySelector(".menu-panel-body").offsetWidth, document.querySelector(".menu-panel-body").offsetHeight];
|
||||
// ugly hack
|
||||
setTimeout(this.getStyle, 1)
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
getBodyClasses() {
|
||||
if (this.direction == "down") {
|
||||
return ["menu-panel-body-down"]
|
||||
} else if (this.direction == "up") {
|
||||
return ["menu-panel-body-up"]
|
||||
} else {
|
||||
return ["foo"]
|
||||
}
|
||||
},
|
||||
getClasses(item) {
|
||||
if (item["active"]) {
|
||||
return "active";
|
||||
}
|
||||
},
|
||||
getStyle() {
|
||||
let style = {}
|
||||
this.size = [this.$refs.menubody.offsetWidth, this.$refs.menubody.offsetHeight];
|
||||
if (this.event) {
|
||||
style["position"] = "absolute";
|
||||
style["left"] = this.event.clientX + "px";
|
||||
style["top"] = this.event.clientY + "px";
|
||||
// make sure the menu panel isnt off the screen
|
||||
if (this.event.clientX + this.size[0] > window.innerWidth) {
|
||||
style["left"] = (this.event.clientX - this.size[0]) + "px";
|
||||
}
|
||||
if (this.event.clientY + this.size[1] > window.innerHeight) {
|
||||
style["top"] = (this.event.clientY - this.size[1]) + "px";
|
||||
}
|
||||
|
||||
|
||||
// if the panel is above the mouse, set the direction to up
|
||||
if (this.event.clientY < this.size[1]) {
|
||||
this.direction = "up";
|
||||
} else {
|
||||
this.direction = "down";
|
||||
}
|
||||
// check if the panel is too long and goes off the screen vertically,
|
||||
// if so move it upwards
|
||||
if (this.event.clientY + this.size[1] > window.innerHeight) {
|
||||
style["top"] = (this.event.clientY - this.size[1]) + "px";
|
||||
}
|
||||
}
|
||||
style["opacity"] = 1
|
||||
this.elStyle = style;
|
||||
},
|
||||
getItemStyle(item) {
|
||||
let style = {}
|
||||
if (item["disabled"]) {
|
||||
style = Object.assign(style, {
|
||||
"pointer-events": "none",
|
||||
"opacity": "0.5",
|
||||
});
|
||||
}
|
||||
return style
|
||||
},
|
||||
canDisplay(item) {
|
||||
if (!item["hidden"]) {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
},
|
||||
async getActions() {
|
||||
return this.content.items;
|
||||
},
|
||||
action(item) {
|
||||
item.action()
|
||||
if (!item["keepOpen"]) {
|
||||
this.menuPanel.visible = false
|
||||
}
|
||||
}
|
||||
Vue.component('cider-menu-panel', {
|
||||
template: '#cider-menu-panel',
|
||||
data: function() {
|
||||
return {
|
||||
app: this.$root,
|
||||
menuPanel: this.$root.menuPanel,
|
||||
content: this.$root.menuPanel.content,
|
||||
getSvgIcon: this.$root.getSvgIcon,
|
||||
position: [0, 0],
|
||||
size: [0, 0],
|
||||
event: this.$root.menuPanel.event,
|
||||
direction: "down",
|
||||
elStyle: {
|
||||
opacity: 0
|
||||
}
|
||||
});
|
||||
</script>
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
if (this.event) {
|
||||
this.position = [this.event.clientX, this.event.clientY];
|
||||
}
|
||||
this.$nextTick(() => {
|
||||
// this.size = [document.querySelector(".menu-panel-body").offsetWidth, document.querySelector(".menu-panel-body").offsetHeight];
|
||||
// ugly hack
|
||||
setTimeout(this.getStyle, 1)
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
getBodyClasses() {
|
||||
if (this.direction == "down") {
|
||||
return ["menu-panel-body-down"]
|
||||
} else if (this.direction == "up") {
|
||||
return ["menu-panel-body-up"]
|
||||
} else {
|
||||
return ["foo"]
|
||||
}
|
||||
},
|
||||
getClasses(item) {
|
||||
if (item["active"]) {
|
||||
return "active";
|
||||
}
|
||||
},
|
||||
getStyle() {
|
||||
let style = {}
|
||||
this.size = [this.$refs.menubody.offsetWidth, this.$refs.menubody.offsetHeight];
|
||||
if (this.event) {
|
||||
style["position"] = "absolute";
|
||||
style["left"] = this.event.clientX + "px";
|
||||
style["top"] = this.event.clientY + "px";
|
||||
// make sure the menu panel isnt off the screen
|
||||
if (this.event.clientX + this.size[0] > window.innerWidth) {
|
||||
style["left"] = (this.event.clientX - this.size[0]) + "px";
|
||||
}
|
||||
if (this.event.clientY + this.size[1] > window.innerHeight) {
|
||||
style["top"] = (this.event.clientY - this.size[1]) + "px";
|
||||
}
|
||||
|
||||
|
||||
// if the panel is above the mouse, set the direction to up
|
||||
if (this.event.clientY < this.size[1]) {
|
||||
this.direction = "up";
|
||||
} else {
|
||||
this.direction = "down";
|
||||
}
|
||||
// check if the panel is too long and goes off the screen vertically,
|
||||
// if so move it upwards
|
||||
if (this.event.clientY + this.size[1] > window.innerHeight) {
|
||||
style["top"] = (this.event.clientY - this.size[1]) + "px";
|
||||
}
|
||||
}
|
||||
style["opacity"] = 1
|
||||
this.elStyle = style;
|
||||
},
|
||||
getItemStyle(item) {
|
||||
let style = {}
|
||||
if (item["disabled"]) {
|
||||
style = Object.assign(style, {
|
||||
"pointer-events": "none",
|
||||
"opacity": "0.5",
|
||||
});
|
||||
}
|
||||
return style
|
||||
},
|
||||
canDisplay(item) {
|
||||
if (!item["hidden"]) {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
},
|
||||
async getActions() {
|
||||
return this.content.items;
|
||||
},
|
||||
action(item) {
|
||||
item.action()
|
||||
if (!item["keepOpen"]) {
|
||||
this.menuPanel.visible = false
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -2,186 +2,206 @@
|
|||
<div class="mini-view" tabindex="0">
|
||||
<div class="background">
|
||||
</div>
|
||||
<div class="player-pin" title="Pin to Top" v-if="app.cfg.visual.miniplayer_top_toggle === false" @click="app.pinMiniPlayer()">
|
||||
<div class="player-pin" title="Pin to Top" v-if="app.cfg.visual.miniplayer_top_toggle === false"
|
||||
@click="app.pinMiniPlayer()">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 28 28" fill="none" class="feather feather-pin">
|
||||
<path d="M7.05664 16.3613C7.05664 17.1523 7.59277 17.6797 8.42773 17.6797H13.1299V21.8369C13.1299 23.0762 13.7539 24.3242 14 24.3242C14.2373 24.3242 14.8613 23.0762 14.8613 21.8369V17.6797H19.5635C20.3984 17.6797 20.9346 17.1523 20.9346 16.3613C20.9346 14.4717 19.4316 12.5293 16.9531 11.6152L16.6631 7.52832C17.9727 6.78125 19.0098 5.96387 19.4668 5.38379C19.7041 5.06738 19.8271 4.75098 19.8271 4.46973C19.8271 3.88965 19.3789 3.45898 18.7197 3.45898H9.27148C8.6123 3.45898 8.16406 3.88965 8.16406 4.46973C8.16406 4.75098 8.28711 5.06738 8.52441 5.38379C8.98145 5.96387 10.0186 6.78125 11.3281 7.52832L11.0469 11.6152C8.55957 12.5293 7.05664 14.4717 7.05664 16.3613Z" fill="#ff2654"/>
|
||||
<path d="M7.05664 16.3613C7.05664 17.1523 7.59277 17.6797 8.42773 17.6797H13.1299V21.8369C13.1299 23.0762 13.7539 24.3242 14 24.3242C14.2373 24.3242 14.8613 23.0762 14.8613 21.8369V17.6797H19.5635C20.3984 17.6797 20.9346 17.1523 20.9346 16.3613C20.9346 14.4717 19.4316 12.5293 16.9531 11.6152L16.6631 7.52832C17.9727 6.78125 19.0098 5.96387 19.4668 5.38379C19.7041 5.06738 19.8271 4.75098 19.8271 4.46973C19.8271 3.88965 19.3789 3.45898 18.7197 3.45898H9.27148C8.6123 3.45898 8.16406 3.88965 8.16406 4.46973C8.16406 4.75098 8.28711 5.06738 8.52441 5.38379C8.98145 5.96387 10.0186 6.78125 11.3281 7.52832L11.0469 11.6152C8.55957 12.5293 7.05664 14.4717 7.05664 16.3613Z"
|
||||
fill="#ff2654" />
|
||||
</svg>
|
||||
</div>
|
||||
<div class="player-pin" title="Unpin to Top" v-if="app.cfg.visual.miniplayer_top_toggle === true" @click="app.pinMiniPlayer(false)">
|
||||
<div class="player-pin" title="Unpin to Top" v-if="app.cfg.visual.miniplayer_top_toggle === true"
|
||||
@click="app.pinMiniPlayer(false)">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 28 28" fill="none" class="feather feather-pin-slashed">
|
||||
<path d="M9.271 3.459c-.659 0-1.107.43-1.107 1.01 0 .282.114.59.352.897.448.59 1.494 1.415 2.777 2.162l-.07 1.02 8.99 8.991c.458-.202.722-.615.722-1.178 0-1.89-1.503-3.832-3.947-4.746l-.29-4.087c1.275-.747 2.312-1.555 2.76-2.144.246-.308.37-.633.37-.914 0-.58-.45-1.011-1.108-1.011H9.27ZM5.15 6.061l16.076 16.057c.272.281.73.273.993 0a.703.703 0 0 0 0-.984L6.15 5.076a.716.716 0 0 0-1.002 0 .711.711 0 0 0 0 .985Zm1.908 10.3c0 .791.536 1.319 1.37 1.319h4.703v4.157c0 1.24.624 2.487.861 2.487.246 0 .87-1.248.87-2.487V17.81h.413l-5.537-5.545c-1.678 1.002-2.68 2.557-2.68 4.095Z" fill="#ff2654"/>
|
||||
<path d="M9.271 3.459c-.659 0-1.107.43-1.107 1.01 0 .282.114.59.352.897.448.59 1.494 1.415 2.777 2.162l-.07 1.02 8.99 8.991c.458-.202.722-.615.722-1.178 0-1.89-1.503-3.832-3.947-4.746l-.29-4.087c1.275-.747 2.312-1.555 2.76-2.144.246-.308.37-.633.37-.914 0-.58-.45-1.011-1.108-1.011H9.27ZM5.15 6.061l16.076 16.057c.272.281.73.273.993 0a.703.703 0 0 0 0-.984L6.15 5.076a.716.716 0 0 0-1.002 0 .711.711 0 0 0 0 .985Zm1.908 10.3c0 .791.536 1.319 1.37 1.319h4.703v4.157c0 1.24.624 2.487.861 2.487.246 0 .87-1.248.87-2.487V17.81h.413l-5.537-5.545c-1.678 1.002-2.68 2.557-2.68 4.095Z"
|
||||
fill="#ff2654" />
|
||||
</svg>
|
||||
</div>
|
||||
<div class="player-exit" title="Close" @click="app.miniPlayer(false)">
|
||||
<svg fill="#323232e3" width="21" height="21" viewBox="0 0 21 21" aria-role="presentation" focusable="false" xmlns="http://www.w3.org/2000/svg">
|
||||
<svg fill="#323232e3" width="21" height="21" viewBox="0 0 21 21" aria-role="presentation" focusable="false"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<defs>
|
||||
<radialGradient gradientUnits="userSpaceOnUse" cx="10.5" cy="10.5" r="10.5" id="gradient-0">
|
||||
<stop offset="0" style="stop-color: rgba(168, 163, 163, 1)"/>
|
||||
<stop offset="1" style="stop-color: rgba(118, 111, 111, 1)"/>
|
||||
<stop offset="0" style="stop-color: rgba(168, 163, 163, 1)" />
|
||||
<stop offset="1" style="stop-color: rgba(118, 111, 111, 1)" />
|
||||
</radialGradient>
|
||||
</defs>
|
||||
<path d="M10.5 21C4.724 21 0 16.275 0 10.5S4.724 0 10.5 0 21 4.725 21 10.5 16.276 21 10.5 21zm-3.543-5.967a.96.96 0 00.693-.295l2.837-2.842 2.85 2.842c.167.167.41.295.693.295.552 0 1.001-.461 1.001-1.012 0-.281-.115-.512-.295-.704L11.899 10.5l2.85-2.855a.875.875 0 00.295-.68c0-.55-.45-.998-1.001-.998a.871.871 0 00-.668.295l-2.888 2.855-2.862-2.843a.891.891 0 00-.668-.281.99.99 0 00-1.001.986c0 .269.116.512.295.678L9.088 10.5l-2.837 2.843a.926.926 0 00-.295.678c0 .551.45 1.012 1.001 1.012z"
|
||||
fill-rule="nonzero" style="stroke-miterlimit: 11; vector-effect: non-scaling-stroke; stroke-width: 31px; fill: url(#gradient-0);"/>
|
||||
fill-rule="nonzero"
|
||||
style="stroke-miterlimit: 11; vector-effect: non-scaling-stroke; stroke-width: 31px; fill: url(#gradient-0);" />
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col artwork-col">
|
||||
<div class="artwork" @click="app.miniPlayer(false)">
|
||||
<div class="artwork" @click="app.miniPlayer(false)">
|
||||
<mediaitem-artwork
|
||||
:size="600"
|
||||
:url="image ?? ''"
|
||||
></mediaitem-artwork>
|
||||
</div>
|
||||
<div class="controls-parents">
|
||||
<template v-if="app.mkReady()">
|
||||
<div class="app-playback-controls" @mouseover="app.chrome.progresshover = true"
|
||||
@mouseleave="app.chrome.progresshover = false" @contextmenu="app.nowPlayingContextMenu">
|
||||
<div class="playback-info">
|
||||
<div class="song-name">
|
||||
{{ app.mk.nowPlayingItem["attributes"]["name"] }}
|
||||
</div>
|
||||
<div
|
||||
style="display: inline-block; -webkit-box-orient: horizontal; white-space: nowrap; margin-top: 0.25vh; overflow: hidden; margin-bottom: 5px;">
|
||||
<div class="item-navigate song-artist" style="display: inline-block;"
|
||||
@click="app.getNowPlayingItemDetailed(`artist`)">
|
||||
{{ app.mk.nowPlayingItem["attributes"]["artistName"] }}
|
||||
<template v-if="app.mkReady()">
|
||||
<div class="app-playback-controls" @mouseover="app.chrome.progresshover = true"
|
||||
@mouseleave="app.chrome.progresshover = false" @contextmenu="app.nowPlayingContextMenu">
|
||||
<div class="playback-info">
|
||||
<div class="song-name">
|
||||
{{ app.mk.nowPlayingItem["attributes"]["name"] }}
|
||||
</div>
|
||||
<div class="song-artist item-navigate" style="display: inline-block;"
|
||||
@click="app.getNowPlayingItemDetailed('album')">
|
||||
{{ (app.mk.nowPlayingItem["attributes"]["albumName"]) ? (" — " +
|
||||
app.mk.nowPlayingItem["attributes"]["albumName"]) : "" }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="song-progress">
|
||||
<div class="song-duration" style="justify-content: space-between; height: 1px; margin-bottom: 1px;"
|
||||
:style="[app.chrome.progresshover ? {'display': 'flex'} : {'display' : 'none'} ]">
|
||||
<p style="width: auto">{{ app.convertTime(app.getSongProgress()) }}</p>
|
||||
<p style="width: auto">{{ app.convertTime(app.mk.currentPlaybackDuration) }}</p>
|
||||
<div
|
||||
style="display: inline-block; -webkit-box-orient: horizontal; white-space: nowrap; margin-top: 0.25vh; overflow: hidden; margin-bottom: 5px;">
|
||||
<div class="item-navigate song-artist" style="display: inline-block;"
|
||||
@click="app.getNowPlayingItemDetailed(`artist`)">
|
||||
{{ app.mk.nowPlayingItem["attributes"]["artistName"] }}
|
||||
</div>
|
||||
<div class="song-artist item-navigate" style="display: inline-block;"
|
||||
@click="app.getNowPlayingItemDetailed('album')">
|
||||
{{ (app.mk.nowPlayingItem["attributes"]["albumName"]) ? (" — " +
|
||||
app.mk.nowPlayingItem["attributes"]["albumName"]) : "" }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<input type="range" step="0.01" min="0" :style="app.progressBarStyle()"
|
||||
@input="app.playerLCD.desiredDuration = $event.target.value;app.playerLCD.userInteraction = true"
|
||||
@mouseup="app.mk.seekToTime($event.target.value);app.playerLCD.desiredDuration = 0;app.playerLCD.userInteraction = false"
|
||||
:max="app.mk.currentPlaybackDuration" :value="app.getSongProgress()">
|
||||
<div class="song-progress">
|
||||
<div class="song-duration"
|
||||
style="justify-content: space-between; height: 1px; margin-bottom: 1px;"
|
||||
:style="[app.chrome.progresshover ? {'display': 'flex'} : {'display' : 'none'} ]">
|
||||
<p style="width: auto">{{ app.convertTime(app.getSongProgress()) }}</p>
|
||||
<p style="width: auto">{{ app.convertTime(app.mk.currentPlaybackDuration) }}</p>
|
||||
</div>
|
||||
|
||||
<input type="range" step="0.01" min="0" :style="app.progressBarStyle()"
|
||||
@input="app.playerLCD.desiredDuration = $event.target.value;app.playerLCD.userInteraction = true"
|
||||
@mouseup="app.mk.seekToTime($event.target.value);app.playerLCD.desiredDuration = 0;app.playerLCD.userInteraction = false"
|
||||
:max="app.mk.currentPlaybackDuration" :value="app.getSongProgress()">
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-buttons">
|
||||
<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 class="app-chrome-item volume display--large">
|
||||
<div class="input-container">
|
||||
<button class="volume-button--small volume" @click="app.muteButtonPressed()"
|
||||
:class="{'active': app.cfg.audio.volume == 0}"></button>
|
||||
<input type="range" class="slider" @wheel="app.volumeWheel"
|
||||
:step="app.cfg.audio.volumeStep" min="0" :max="app.cfg.audio.maxVolume"
|
||||
v-model="app.mk.volume"
|
||||
v-if="typeof app.mk.volume != 'undefined'" @change="app.checkMuteChange()">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-buttons">
|
||||
<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 class="app-chrome-item volume display--large">
|
||||
<div class="input-container">
|
||||
<button class="volume-button--small volume" @click="app.muteButtonPressed()" :class="{'active': app.cfg.audio.volume == 0}"></button>
|
||||
<input type="range" class="slider" @wheel="app.volumeWheel" :step="app.cfg.audio.volumeStep" min="0" :max="app.cfg.audio.maxVolume" v-model="app.mk.volume"
|
||||
v-if="typeof app.mk.volume != 'undefined'" @change="app.checkMuteChange()">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
<!-- <div class="row fs-row">
|
||||
|
||||
<div class="col right-col" v-if="tabMode != ''">
|
||||
<div class="fs-info">
|
||||
<div>Name</div>
|
||||
<div>Name</div>
|
||||
<div>Name</div>
|
||||
</div>
|
||||
<div class="lyrics-col" v-if="tabMode == 'lyrics'">
|
||||
<lyrics-view :yoffset="120" :time="time" :lyrics="lyrics"
|
||||
:richlyrics="richlyrics"></lyrics-view>
|
||||
</div>
|
||||
<div class="queue-col" v-if="tabMode == 'queue'">
|
||||
<cider-queue v-if="tabMode == 'queue'" ref="queue" ></cider-queue>
|
||||
</div>
|
||||
</div>
|
||||
<!-- <div class="row fs-row">
|
||||
|
||||
<div class="col right-col" v-if="tabMode != ''">
|
||||
<div class="fs-info">
|
||||
<div>Name</div>
|
||||
<div>Name</div>
|
||||
<div>Name</div>
|
||||
</div>
|
||||
<div class="lyrics-col" v-if="tabMode == 'lyrics'">
|
||||
<lyrics-view :yoffset="120" :time="time" :lyrics="lyrics"
|
||||
:richlyrics="richlyrics"></lyrics-view>
|
||||
</div>
|
||||
<div class="queue-col" v-if="tabMode == 'queue'">
|
||||
<cider-queue v-if="tabMode == 'queue'" ref="queue" ></cider-queue>
|
||||
</div>
|
||||
</div>
|
||||
</div> -->
|
||||
<!-- <div class="tab-toggles">
|
||||
<div class="lyrics" :class="{active: tabMode == 'lyrics'}" @click="tabMode = (tabMode == 'lyrics') ? '' : 'lyrics'"></div>
|
||||
<div class="queue" :class="{active: tabMode == 'queue'}" @click="tabMode = (tabMode == 'queue') ? '' :'queue'"></div>
|
||||
</div> -->
|
||||
</div> -->
|
||||
<!-- <div class="tab-toggles">
|
||||
<div class="lyrics" :class="{active: tabMode == 'lyrics'}" @click="tabMode = (tabMode == 'lyrics') ? '' : 'lyrics'"></div>
|
||||
<div class="queue" :class="{active: tabMode == 'queue'}" @click="tabMode = (tabMode == 'queue') ? '' :'queue'"></div>
|
||||
</div> -->
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<script>
|
||||
Vue.component('mini-view', {
|
||||
template: '#mini-view',
|
||||
props: {
|
||||
time: {
|
||||
type: Number,
|
||||
required: false
|
||||
},
|
||||
lyrics: {
|
||||
type: Array,
|
||||
required: false
|
||||
},
|
||||
richlyrics: {
|
||||
type: Array,
|
||||
required: false
|
||||
},
|
||||
image: {
|
||||
type: String,
|
||||
required: false
|
||||
},
|
||||
},
|
||||
data: function () {
|
||||
return {
|
||||
app: this.$root,
|
||||
tabMode: "",
|
||||
}
|
||||
},
|
||||
beforeMount() {
|
||||
window.addEventListener('keyup', this.onEscapeKeyUp);
|
||||
},
|
||||
beforeDestroy() {
|
||||
window.removeEventListener('keyup', this.onEscapeKeyUp)
|
||||
},
|
||||
mounted() {
|
||||
app.pinMiniPlayer(true)
|
||||
},
|
||||
methods: {
|
||||
onEscapeKeyUp(event) {
|
||||
if (event.which === 27) {
|
||||
app.miniPlayer(false);
|
||||
console.log('js')
|
||||
}
|
||||
},
|
||||
Vue.component('mini-view', {
|
||||
template: '#mini-view',
|
||||
props: {
|
||||
time: {
|
||||
type: Number,
|
||||
required: false
|
||||
},
|
||||
lyrics: {
|
||||
type: Array,
|
||||
required: false
|
||||
},
|
||||
richlyrics: {
|
||||
type: Array,
|
||||
required: false
|
||||
},
|
||||
image: {
|
||||
type: String,
|
||||
required: false
|
||||
},
|
||||
},
|
||||
data: function() {
|
||||
return {
|
||||
app: this.$root,
|
||||
tabMode: "",
|
||||
}
|
||||
},
|
||||
beforeMount() {
|
||||
window.addEventListener('keyup', this.onEscapeKeyUp);
|
||||
},
|
||||
beforeDestroy() {
|
||||
window.removeEventListener('keyup', this.onEscapeKeyUp)
|
||||
},
|
||||
mounted() {
|
||||
app.pinMiniPlayer(true)
|
||||
},
|
||||
methods: {
|
||||
onEscapeKeyUp(event) {
|
||||
if (event.which === 27) {
|
||||
app.miniPlayer(false);
|
||||
console.log('js')
|
||||
}
|
||||
});
|
||||
</script>
|
||||
},
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<script type="text/x-template" id="moreinfo-modal">
|
||||
<div class="modal-fullscreen spatialproperties-panel moreinfo-modal" @click.self="if(timedelay) close()">
|
||||
<div class="modal-window" >
|
||||
<div class="modal-window">
|
||||
<div class="modal-header">
|
||||
<div class="modal-title">{{data.title}}</div>
|
||||
<div class="modal-subtitle modal-title">{{data.subtitle ?? ""}}</div>
|
||||
|
@ -15,28 +15,28 @@
|
|||
</script>
|
||||
|
||||
<script>
|
||||
Vue.component('moreinfo-modal', {
|
||||
template: '#moreinfo-modal',
|
||||
data: function () {
|
||||
return {
|
||||
app: this.$root,
|
||||
timedelay: false,
|
||||
}
|
||||
},
|
||||
props: ["data"],
|
||||
mounted() {
|
||||
let self = this;
|
||||
this.$nextTick(()=>{
|
||||
setTimeout(function(){
|
||||
self.timedelay = true
|
||||
}, 1000);
|
||||
})
|
||||
Vue.component('moreinfo-modal', {
|
||||
template: '#moreinfo-modal',
|
||||
data: function() {
|
||||
return {
|
||||
app: this.$root,
|
||||
timedelay: false,
|
||||
}
|
||||
},
|
||||
props: ["data"],
|
||||
mounted() {
|
||||
let self = this;
|
||||
this.$nextTick(() => {
|
||||
setTimeout(function() {
|
||||
self.timedelay = true
|
||||
}, 1000);
|
||||
})
|
||||
|
||||
},
|
||||
methods: {
|
||||
close() {
|
||||
app.modals.moreInfo = false;
|
||||
},
|
||||
}
|
||||
});
|
||||
</script>
|
||||
},
|
||||
methods: {
|
||||
close() {
|
||||
app.modals.moreInfo = false;
|
||||
},
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -1,37 +1,38 @@
|
|||
<script type="text/x-template" id="pagination">
|
||||
<div class="pagination-container" v-if="!isInfinite">
|
||||
<button
|
||||
class="md-btn page-btn"
|
||||
:disabled="effectivePage === 1"
|
||||
@click="goToPage(1)"
|
||||
class="md-btn page-btn"
|
||||
:disabled="effectivePage === 1"
|
||||
@click="goToPage(1)"
|
||||
>
|
||||
<img class="md-ico-first"/>
|
||||
<img class="md-ico-first" />
|
||||
</button>
|
||||
<button
|
||||
class="md-btn page-btn prev"
|
||||
:disabled="effectivePage === 1"
|
||||
@click="goToPrevious()"
|
||||
class="md-btn page-btn prev"
|
||||
:disabled="effectivePage === 1"
|
||||
@click="goToPrevious()"
|
||||
>
|
||||
<img class="md-ico-prev"/>
|
||||
<img class="md-ico-prev" />
|
||||
</button>
|
||||
<button
|
||||
:class="`md-btn page-btn${ isCurrentPage(page) ? ' md-btn-primary': ''}`"
|
||||
@click="goToPage(page)"
|
||||
v-for="page in pagesToShow"
|
||||
>{{ page }}</button>
|
||||
<button
|
||||
class="md-btn page-btn next"
|
||||
:disabled="effectivePage === numPages"
|
||||
@click="goToNext()"
|
||||
>
|
||||
<img class="md-ico-next"/>
|
||||
:class="`md-btn page-btn${ isCurrentPage(page) ? ' md-btn-primary': ''}`"
|
||||
@click="goToPage(page)"
|
||||
v-for="page in pagesToShow"
|
||||
>{{ page }}
|
||||
</button>
|
||||
<button
|
||||
class="md-btn page-btn last"
|
||||
:disabled="effectivePage === numPages"
|
||||
@click="goToEnd()"
|
||||
class="md-btn page-btn next"
|
||||
:disabled="effectivePage === numPages"
|
||||
@click="goToNext()"
|
||||
>
|
||||
<img class="md-ico-last"/>
|
||||
<img class="md-ico-next" />
|
||||
</button>
|
||||
<button
|
||||
class="md-btn page-btn last"
|
||||
:disabled="effectivePage === numPages"
|
||||
@click="goToEnd()"
|
||||
>
|
||||
<img class="md-ico-last" />
|
||||
</button>
|
||||
<div class="page-btn md-input-number">
|
||||
<input type="number" min="1" :max="numPages" :value="effectivePage" @change="changePage" />
|
||||
|
@ -41,135 +42,135 @@
|
|||
</script>
|
||||
|
||||
<script>
|
||||
Vue.component('pagination', {
|
||||
template: "#pagination",
|
||||
props: {
|
||||
'length': { type: Number, required: true },
|
||||
'pageSize': { type: Number, required: true },
|
||||
'scroll': { type: String, required: true },
|
||||
'scrollSelector': { type: String, required: true }
|
||||
},
|
||||
data: function () {
|
||||
return { currentPage: 1 }
|
||||
},
|
||||
mounted() {
|
||||
document.querySelector(this.scrollSelector)
|
||||
.addEventListener("scroll", this.handleScroll)
|
||||
},
|
||||
destroyed() {
|
||||
document.querySelector(this.scrollSelector)
|
||||
.removeEventListener("scroll", this.handleScroll)
|
||||
},
|
||||
watch: {
|
||||
'length': function () {
|
||||
if (this.isInfinite) {
|
||||
// If a search reduces the number of things to show, we want to limit
|
||||
// the number of songs shown as well. This is to prevent you scrolling
|
||||
// to load your entire library, searching for one song, and then having
|
||||
// th re-render the entire library
|
||||
if (this.currentPage > this.numPages) {
|
||||
this.currentPage = this.numPages;
|
||||
this.$emit("onRangeChange", this.currentRange);
|
||||
}
|
||||
} else {
|
||||
this.$emit("onRangeChange", this.currentRange);
|
||||
}
|
||||
},
|
||||
'scroll': function () {
|
||||
// When changing modes, set the page to 1. This is primarily to
|
||||
// prevent going to a high page (e.g., 50) and then switching to infinite
|
||||
// and showing 12.5k songs
|
||||
this.currentPage = 1;
|
||||
this.$emit("onRangeChange", this.currentRange);
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
isInfinite: function () {
|
||||
return this.scroll === "infinite"
|
||||
},
|
||||
currentRange: function () {
|
||||
if (this.isInfinite) {
|
||||
return [0, this.currentPage * this.pageSize];
|
||||
} else {
|
||||
const startingPage = Math.min(this.numPages, this.currentPage);
|
||||
|
||||
return [
|
||||
(startingPage - 1) * this.pageSize,
|
||||
startingPage * this.pageSize
|
||||
];
|
||||
}
|
||||
},
|
||||
effectivePage: function () {
|
||||
return Math.min(this.currentPage, this.numPages)
|
||||
},
|
||||
numPages: function () {
|
||||
return Math.ceil(this.length / this.pageSize) || 1;
|
||||
},
|
||||
pagesToShow: function () {
|
||||
let start = this.currentPage - 2;
|
||||
let end = this.currentPage + 2;
|
||||
|
||||
if (start < 1) {
|
||||
end += (1 - start);
|
||||
start = 1;
|
||||
}
|
||||
|
||||
const endDifference = end - this.numPages;
|
||||
if (endDifference > 0) {
|
||||
end = this.numPages;
|
||||
start = Math.max(1, start - endDifference);
|
||||
}
|
||||
|
||||
const array = [];
|
||||
for (let idx = start; idx <= end; idx++) {
|
||||
array.push(idx);
|
||||
}
|
||||
return array;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// Infinite Scrolling
|
||||
handleScroll: function (event) {
|
||||
if (this.isInfinite &&
|
||||
this.currentPage < this.numPages &&
|
||||
event.target.scrollTop >= event.target.scrollHeight - event.target.clientHeight) {
|
||||
this.currentPage += 1;
|
||||
this.$emit("onRangeChange", this.currentRange);
|
||||
}
|
||||
},
|
||||
// Pagination
|
||||
isCurrentPage: function (idx) {
|
||||
return idx === this.currentPage ||
|
||||
(idx === this.numPages && this.currentPage > this.numPages);
|
||||
},
|
||||
changePage: function (event) {
|
||||
const value = event.target.valueAsNumber;
|
||||
|
||||
if (!isNaN(value) && value >= 1 && value <= this.numPages) {
|
||||
this.currentPage = value;
|
||||
this.$emit("onRangeChange", this.currentRange);
|
||||
}
|
||||
},
|
||||
goToPage: function (page) {
|
||||
this.currentPage = page;
|
||||
this.$emit("onRangeChange", this.currentRange);
|
||||
},
|
||||
goToPrevious: function () {
|
||||
if (this.currentPage > 1) {
|
||||
this.currentPage -= 1;
|
||||
this.$emit("onRangeChange", this.currentRange);
|
||||
}
|
||||
},
|
||||
goToNext: function () {
|
||||
if (this.currentPage < this.numPages) {
|
||||
this.currentPage += 1;
|
||||
this.$emit("onRangeChange", this.currentRange);
|
||||
}
|
||||
},
|
||||
goToEnd: function () {
|
||||
this.currentPage = this.numPages;
|
||||
this.$emit("onRangeChange", this.currentRange);
|
||||
}
|
||||
Vue.component('pagination', {
|
||||
template: "#pagination",
|
||||
props: {
|
||||
'length': { type: Number, required: true },
|
||||
'pageSize': { type: Number, required: true },
|
||||
'scroll': { type: String, required: true },
|
||||
'scrollSelector': { type: String, required: true }
|
||||
},
|
||||
data: function() {
|
||||
return { currentPage: 1 }
|
||||
},
|
||||
mounted() {
|
||||
document.querySelector(this.scrollSelector)
|
||||
.addEventListener("scroll", this.handleScroll)
|
||||
},
|
||||
destroyed() {
|
||||
document.querySelector(this.scrollSelector)
|
||||
.removeEventListener("scroll", this.handleScroll)
|
||||
},
|
||||
watch: {
|
||||
'length': function() {
|
||||
if (this.isInfinite) {
|
||||
// If a search reduces the number of things to show, we want to limit
|
||||
// the number of songs shown as well. This is to prevent you scrolling
|
||||
// to load your entire library, searching for one song, and then having
|
||||
// th re-render the entire library
|
||||
if (this.currentPage > this.numPages) {
|
||||
this.currentPage = this.numPages;
|
||||
this.$emit("onRangeChange", this.currentRange);
|
||||
}
|
||||
} else {
|
||||
this.$emit("onRangeChange", this.currentRange);
|
||||
}
|
||||
})
|
||||
</script>
|
||||
},
|
||||
'scroll': function() {
|
||||
// When changing modes, set the page to 1. This is primarily to
|
||||
// prevent going to a high page (e.g., 50) and then switching to infinite
|
||||
// and showing 12.5k songs
|
||||
this.currentPage = 1;
|
||||
this.$emit("onRangeChange", this.currentRange);
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
isInfinite: function() {
|
||||
return this.scroll === "infinite"
|
||||
},
|
||||
currentRange: function() {
|
||||
if (this.isInfinite) {
|
||||
return [0, this.currentPage * this.pageSize];
|
||||
} else {
|
||||
const startingPage = Math.min(this.numPages, this.currentPage);
|
||||
|
||||
return [
|
||||
(startingPage - 1) * this.pageSize,
|
||||
startingPage * this.pageSize
|
||||
];
|
||||
}
|
||||
},
|
||||
effectivePage: function() {
|
||||
return Math.min(this.currentPage, this.numPages)
|
||||
},
|
||||
numPages: function() {
|
||||
return Math.ceil(this.length / this.pageSize) || 1;
|
||||
},
|
||||
pagesToShow: function() {
|
||||
let start = this.currentPage - 2;
|
||||
let end = this.currentPage + 2;
|
||||
|
||||
if (start < 1) {
|
||||
end += (1 - start);
|
||||
start = 1;
|
||||
}
|
||||
|
||||
const endDifference = end - this.numPages;
|
||||
if (endDifference > 0) {
|
||||
end = this.numPages;
|
||||
start = Math.max(1, start - endDifference);
|
||||
}
|
||||
|
||||
const array = [];
|
||||
for (let idx = start; idx <= end; idx++) {
|
||||
array.push(idx);
|
||||
}
|
||||
return array;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// Infinite Scrolling
|
||||
handleScroll: function(event) {
|
||||
if (this.isInfinite &&
|
||||
this.currentPage < this.numPages &&
|
||||
event.target.scrollTop >= event.target.scrollHeight - event.target.clientHeight) {
|
||||
this.currentPage += 1;
|
||||
this.$emit("onRangeChange", this.currentRange);
|
||||
}
|
||||
},
|
||||
// Pagination
|
||||
isCurrentPage: function(idx) {
|
||||
return idx === this.currentPage ||
|
||||
(idx === this.numPages && this.currentPage > this.numPages);
|
||||
},
|
||||
changePage: function(event) {
|
||||
const value = event.target.valueAsNumber;
|
||||
|
||||
if (!isNaN(value) && value >= 1 && value <= this.numPages) {
|
||||
this.currentPage = value;
|
||||
this.$emit("onRangeChange", this.currentRange);
|
||||
}
|
||||
},
|
||||
goToPage: function(page) {
|
||||
this.currentPage = page;
|
||||
this.$emit("onRangeChange", this.currentRange);
|
||||
},
|
||||
goToPrevious: function() {
|
||||
if (this.currentPage > 1) {
|
||||
this.currentPage -= 1;
|
||||
this.$emit("onRangeChange", this.currentRange);
|
||||
}
|
||||
},
|
||||
goToNext: function() {
|
||||
if (this.currentPage < this.numPages) {
|
||||
this.currentPage += 1;
|
||||
this.$emit("onRangeChange", this.currentRange);
|
||||
}
|
||||
},
|
||||
goToEnd: function() {
|
||||
this.currentPage = this.numPages;
|
||||
this.$emit("onRangeChange", this.currentRange);
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
|
|
@ -1,65 +1,66 @@
|
|||
<script type="text/x-template" id="pathmenu">
|
||||
<div class="spatialproperties-panel castmenu pathmenu modal-fullscreen" @click.self="close()" @contextmenu.self="close()">
|
||||
<div class="modal-window">
|
||||
<div class="modal-header">
|
||||
<div class="modal-title">{{'Edit Paths'}}</div>
|
||||
<button class="close-btn" @click="close()" :aria-label="$root.getLz('action.close')"></button>
|
||||
</div>
|
||||
<div class="modal-content">
|
||||
<template v-for="folder of folders">
|
||||
<div class="md-option-line">
|
||||
<div class="md-option-segment">
|
||||
{{folder}}
|
||||
<div class="spatialproperties-panel castmenu pathmenu modal-fullscreen" @click.self="close()"
|
||||
@contextmenu.self="close()">
|
||||
<div class="modal-window">
|
||||
<div class="modal-header">
|
||||
<div class="modal-title">{{'Edit Paths'}}</div>
|
||||
<button class="close-btn" @click="close()" :aria-label="$root.getLz('action.close')"></button>
|
||||
</div>
|
||||
<div class="modal-content">
|
||||
<template v-for="folder of folders">
|
||||
<div class="md-option-line">
|
||||
<div class="md-option-segment">
|
||||
{{folder}}
|
||||
</div>
|
||||
<div class="md-option-segment md-option-segment_auto">
|
||||
<button class="md-btn" @click="remove(folder)">
|
||||
{{'Remove'}}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<div class="md-option-line">
|
||||
<div class="md-option-segment md-option-segment_auto">
|
||||
<button class="md-btn" @click="remove(folder)">
|
||||
{{'Remove'}}
|
||||
<button class="md-btn" @click="add()">
|
||||
{{'Add Path'}}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<div class="md-option-line">
|
||||
<div class="md-option-segment md-option-segment_auto">
|
||||
<button class="md-btn" @click="add()">
|
||||
{{'Add Path'}}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
<script>
|
||||
Vue.component('pathmenu', {
|
||||
template: '#pathmenu',
|
||||
data: function () {
|
||||
return {
|
||||
folders: [],
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.folders = this.$root.cfg.libraryPrefs.localPaths;
|
||||
},
|
||||
watch:{},
|
||||
methods: {
|
||||
close() {
|
||||
this.$root.modals.pathMenu = false
|
||||
},
|
||||
async add(){
|
||||
const result = await ipcRenderer.invoke('folderSelector')
|
||||
for (i of result){
|
||||
if (this.folders.findIndex(x => x.startsWith(i)) == -1){
|
||||
this.folders.push(i)
|
||||
}
|
||||
}
|
||||
this.$root.cfg.libraryPrefs.localPaths = this.folders;
|
||||
ipcRenderer.invoke("scanLibrary")
|
||||
},
|
||||
remove(dir){
|
||||
this.folders = this.folders.filter(item => item !== dir)
|
||||
this.$root.cfg.libraryPrefs.localPaths = this.folders;
|
||||
ipcRenderer.invoke("scanLibrary")
|
||||
}
|
||||
Vue.component('pathmenu', {
|
||||
template: '#pathmenu',
|
||||
data: function() {
|
||||
return {
|
||||
folders: [],
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.folders = this.$root.cfg.libraryPrefs.localPaths;
|
||||
},
|
||||
watch: {},
|
||||
methods: {
|
||||
close() {
|
||||
this.$root.modals.pathMenu = false
|
||||
},
|
||||
async add() {
|
||||
const result = await ipcRenderer.invoke('folderSelector')
|
||||
for (i of result) {
|
||||
if (this.folders.findIndex(x => x.startsWith(i)) == -1) {
|
||||
this.folders.push(i)
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
this.$root.cfg.libraryPrefs.localPaths = this.folders;
|
||||
ipcRenderer.invoke("scanLibrary")
|
||||
},
|
||||
remove(dir) {
|
||||
this.folders = this.folders.filter(item => item !== dir)
|
||||
this.$root.cfg.libraryPrefs.localPaths = this.folders;
|
||||
ipcRenderer.invoke("scanLibrary")
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
<script type="text/x-template" id="plugin-menu">
|
||||
<div class="modal-fullscreen addtoplaylist-panel" @click.self="app.resetState()" @contextmenu.self="app.resetState()">
|
||||
<div class="modal-fullscreen addtoplaylist-panel" @click.self="app.resetState()"
|
||||
@contextmenu.self="app.resetState()">
|
||||
<div class="modal-window">
|
||||
<div class="modal-header">
|
||||
<div class="modal-title">{{$root.getLz('term.pluginMenu')}}</div>
|
||||
|
@ -10,30 +11,32 @@
|
|||
<span class="icon"><%- include("../svg/x.svg") %></span>
|
||||
<span class="name" style="top: 0.5px;">{{$root.getLz('term.pluginMenu.none')}}</span>
|
||||
</span>
|
||||
<button class="playlist-item" @click="entry.onClick(); closeMenu();" v-for="entry in app.pluginMenuEntries">
|
||||
<span class="icon"><%- include("../svg/grid.svg") %></span>
|
||||
<span class="name" style="top: 0.5px;">{{ entry.name }}</span>
|
||||
</button>
|
||||
<button class="playlist-item" @click="entry.onClick(); closeMenu();"
|
||||
v-for="entry in app.pluginMenuEntries">
|
||||
<span class="icon"><%- include("../svg/grid.svg") %></span>
|
||||
<span class="name" style="top: 0.5px;">{{ entry.name }}</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script>
|
||||
Vue.component('plugin-menu', {
|
||||
template: '#plugin-menu',
|
||||
data: function () {
|
||||
return {
|
||||
app: this.$root,
|
||||
}
|
||||
},
|
||||
props: {},
|
||||
mounted() {},
|
||||
methods: {
|
||||
closeMenu() {
|
||||
app.modals.pluginMenu = false
|
||||
},
|
||||
},
|
||||
Vue.component('plugin-menu', {
|
||||
template: '#plugin-menu',
|
||||
data: function() {
|
||||
return {
|
||||
app: this.$root,
|
||||
}
|
||||
);
|
||||
</script>
|
||||
},
|
||||
props: {},
|
||||
mounted() {
|
||||
},
|
||||
methods: {
|
||||
closeMenu() {
|
||||
app.modals.pluginMenu = false
|
||||
},
|
||||
},
|
||||
}
|
||||
);
|
||||
</script>
|
||||
|
|
|
@ -1,34 +1,34 @@
|
|||
<script type="text/x-template" id="qrcode-modal">
|
||||
<div class="modal-fullscreen spatialproperties-panel">
|
||||
<div class="modal-window" >
|
||||
<div class="modal-window">
|
||||
<div class="modal-header">
|
||||
<div class="modal-title">{{`Web Remote QR : ` + url }}</div>
|
||||
<button class="close-btn" @click="close()" :aria-label="app.getLz('action.close')"></button>
|
||||
</div>
|
||||
<div class="modal-content">
|
||||
<img class="qrimg" :src="src"/>
|
||||
<img class="qrimg" :src="src" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script>
|
||||
Vue.component('qrcode-modal', {
|
||||
template: '#qrcode-modal',
|
||||
data: function () {
|
||||
return {
|
||||
app: this.$root,
|
||||
Vue.component('qrcode-modal', {
|
||||
template: '#qrcode-modal',
|
||||
data: function() {
|
||||
return {
|
||||
app: this.$root,
|
||||
|
||||
}
|
||||
},
|
||||
props: ["src","url"],
|
||||
mounted() {
|
||||
}
|
||||
},
|
||||
props: ["src", "url"],
|
||||
mounted() {
|
||||
|
||||
},
|
||||
methods: {
|
||||
close() {
|
||||
app.resetState()
|
||||
},
|
||||
}
|
||||
});
|
||||
</script>
|
||||
},
|
||||
methods: {
|
||||
close() {
|
||||
app.resetState()
|
||||
},
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -14,7 +14,8 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="queue-body" v-if="page == 'history'">
|
||||
<mediaitem-list-item :show-library-status="false" v-for="item in history" :item="item"></mediaitem-list-item>
|
||||
<mediaitem-list-item :show-library-status="false" v-for="item in history"
|
||||
:item="item"></mediaitem-list-item>
|
||||
</div>
|
||||
<div class="queue-body" v-if="page == 'queue'">
|
||||
<draggable v-model="queueItems" @start="drag=true" @end="drag=false;move()">
|
||||
|
@ -27,18 +28,26 @@
|
|||
<div class="row">
|
||||
<div class="col-auto cider-flex-center">
|
||||
<div class="artwork">
|
||||
<mediaitem-artwork :url="queueItem.item.attributes.artwork ? queueItem.item.attributes.artwork.url : ''" :size="32"></mediaitem-artwork>
|
||||
<mediaitem-artwork
|
||||
:url="queueItem.item.attributes.artwork ? queueItem.item.attributes.artwork.url : ''"
|
||||
:size="32"></mediaitem-artwork>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col queue-info">
|
||||
<div class="queue-title text-overflow-elipsis">{{ queueItem.item.attributes.name }}</div>
|
||||
<div class="queue-subtitle text-overflow-elipsis">{{ queueItem.item.attributes.artistName }} — {{ queueItem.item.attributes.albumName }}</div>
|
||||
<div class="queue-title text-overflow-elipsis">{{ queueItem.item.attributes.name }}
|
||||
</div>
|
||||
<div class="queue-subtitle text-overflow-elipsis">{{
|
||||
queueItem.item.attributes.artistName }} — {{ queueItem.item.attributes.albumName }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="queue-explicit-icon cider-flex-center" v-if="queueItem.item.attributes.contentRating == 'explicit'">
|
||||
<div class="queue-explicit-icon cider-flex-center"
|
||||
v-if="queueItem.item.attributes.contentRating == 'explicit'">
|
||||
<div class="explicit-icon"></div>
|
||||
</div>
|
||||
<div class="col queue-duration-info">
|
||||
<div class="queue-duration cider-flex-center">{{convertTimeToString(queueItem.item.attributes.durationInMillis)}}</div>
|
||||
<div class="queue-duration cider-flex-center">
|
||||
{{convertTimeToString(queueItem.item.attributes.durationInMillis)}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -47,138 +56,144 @@
|
|||
</div>
|
||||
<div class="queue-footer">
|
||||
<div class="btn-group" style="width:100%;">
|
||||
<button class="md-btn md-btn-small" :class="{'md-btn-primary': (page == 'queue')}" @click="page = 'queue'">{{app.getLz('term.queue')}}</button>
|
||||
<button class="md-btn md-btn-small" :class="{'md-btn-primary': (page == 'history')}" @click="getHistory();page = 'history'">{{app.getLz('term.history')}}</button>
|
||||
<button class="md-btn md-btn-small" :class="{'md-btn-primary': (page == 'queue')}"
|
||||
@click="page = 'queue'">{{app.getLz('term.queue')}}
|
||||
</button>
|
||||
<button class="md-btn md-btn-small" :class="{'md-btn-primary': (page == 'history')}"
|
||||
@click="getHistory();page = 'history'">{{app.getLz('term.history')}}
|
||||
</button>
|
||||
</div>
|
||||
<button class="md-btn md-btn-small" style="width:100%;margin-top:6px;" v-if="queueItems.length > 1" @click="app.mk.clearQueue();updateQueue()">{{app.getLz('term.clearAll')}}</button>
|
||||
<button class="md-btn md-btn-small" style="width:100%;margin-top:6px;" v-if="queueItems.length > 1"
|
||||
@click="app.mk.clearQueue();updateQueue()">{{app.getLz('term.clearAll')}}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
|
||||
<script>
|
||||
Vue.component('cider-queue', {
|
||||
template: '#cider-queue',
|
||||
data: function () {
|
||||
return {
|
||||
drag: false,
|
||||
queuePosition: 0,
|
||||
queueItems: [],
|
||||
selected: -1,
|
||||
selectedItems: [],
|
||||
history: [],
|
||||
page: "queue",
|
||||
app: this.$root
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
displayQueueItems() {
|
||||
const displayLimit = 50;
|
||||
const lastDisplayPosition = Math.min(displayLimit + this.queuePosition, this.queueItems.length);
|
||||
return this.queueItems.slice(this.queuePosition, lastDisplayPosition);
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.updateQueue()
|
||||
},
|
||||
methods: {
|
||||
async getHistory() {
|
||||
let history = await app.mk.api.v3.music(`/v1/me/recent/played/tracks`, { l : this.$root.mklang})
|
||||
this.history = history.data.data
|
||||
},
|
||||
select(e, position) {
|
||||
if (e.ctrlKey || e.shiftKey) {
|
||||
if (this.selectedItems.indexOf(position) == -1) {
|
||||
this.selectedItems.push(position)
|
||||
} else {
|
||||
this.selectedItems.splice(this.selectedItems.indexOf(position), 1)
|
||||
}
|
||||
} else {
|
||||
this.selectedItems = [position]
|
||||
}
|
||||
},
|
||||
queueContext(event, item, position) {
|
||||
let self = this
|
||||
let useMenu = "single"
|
||||
if (this.selectedItems.length > 1) {
|
||||
useMenu = "multiple"
|
||||
}
|
||||
let menus = {
|
||||
single: {
|
||||
items: [{
|
||||
"name": app.getLz('action.removeFromQueue'),
|
||||
"action": function () {
|
||||
self.queueItems.splice(position, 1)
|
||||
app.mk.queue._queueItems = self.queueItems;
|
||||
app.mk.queue._reindex()
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": app.getLz('action.startRadio'),
|
||||
"action": function () {
|
||||
app.mk.setStationQueue({
|
||||
song: item.attributes.playParams.id ?? item.id
|
||||
}).then(() => {
|
||||
app.mk.play()
|
||||
})
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": app.getLz('action.goToArtist'),
|
||||
"action": function () {
|
||||
app.searchAndNavigate(item,'artist')
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": app.getLz('action.goToAlbum'),
|
||||
"action": function () {
|
||||
app.searchAndNavigate(item,'album')
|
||||
}
|
||||
},
|
||||
]
|
||||
},
|
||||
multiple: {
|
||||
items: [{
|
||||
"name": app.getLz('action.removeTracks').replace('${self.selectedItems.length}', self.selectedItems.length.toString()),
|
||||
"action": function () {
|
||||
// add property to items to be removed
|
||||
self.selectedItems.forEach(function (item) {
|
||||
self.queueItems[item].remove = true
|
||||
})
|
||||
// remove items
|
||||
self.queueItems = self.queueItems.filter(function (item) {
|
||||
return !item.remove
|
||||
})
|
||||
app.mk.queue._reindex()
|
||||
self.selectedItems = []
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
app.showMenuPanel(menus[useMenu], event);
|
||||
},
|
||||
playQueueItem(id) {
|
||||
app.mk.changeToMediaAtIndex(app.mk.queue._itemIDs.indexOf(id))
|
||||
},
|
||||
updateQueue() {
|
||||
this.selected = -1
|
||||
if (app.mk.queue) {
|
||||
this.queuePosition = app.mk.queue.position;
|
||||
this.queueItems = app.mk.queue._queueItems;
|
||||
} else {
|
||||
this.queuePosition = 0;
|
||||
this.queueItems = [];
|
||||
}
|
||||
},
|
||||
move() {
|
||||
this.selected = -1
|
||||
app.mk.queue._queueItems = this.queueItems;
|
||||
app.mk.queue._reindex()
|
||||
},
|
||||
convertTimeToString(timeInMilliseconds) {
|
||||
var seconds = ((timeInMilliseconds % 60000) / 1000).toFixed(0);
|
||||
return Math.floor(timeInMilliseconds/60000) + ":" + (seconds < 10 ? '0' : '') + seconds;
|
||||
}
|
||||
Vue.component('cider-queue', {
|
||||
template: '#cider-queue',
|
||||
data: function() {
|
||||
return {
|
||||
drag: false,
|
||||
queuePosition: 0,
|
||||
queueItems: [],
|
||||
selected: -1,
|
||||
selectedItems: [],
|
||||
history: [],
|
||||
page: "queue",
|
||||
app: this.$root
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
displayQueueItems() {
|
||||
const displayLimit = 50;
|
||||
const lastDisplayPosition = Math.min(displayLimit + this.queuePosition, this.queueItems.length);
|
||||
return this.queueItems.slice(this.queuePosition, lastDisplayPosition);
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.updateQueue()
|
||||
},
|
||||
methods: {
|
||||
async getHistory() {
|
||||
let history = await app.mk.api.v3.music(`/v1/me/recent/played/tracks`, { l: this.$root.mklang })
|
||||
this.history = history.data.data
|
||||
},
|
||||
select(e, position) {
|
||||
if (e.ctrlKey || e.shiftKey) {
|
||||
if (this.selectedItems.indexOf(position) == -1) {
|
||||
this.selectedItems.push(position)
|
||||
} else {
|
||||
this.selectedItems.splice(this.selectedItems.indexOf(position), 1)
|
||||
}
|
||||
} else {
|
||||
this.selectedItems = [position]
|
||||
}
|
||||
});
|
||||
</script>
|
||||
},
|
||||
queueContext(event, item, position) {
|
||||
let self = this
|
||||
let useMenu = "single"
|
||||
if (this.selectedItems.length > 1) {
|
||||
useMenu = "multiple"
|
||||
}
|
||||
let menus = {
|
||||
single: {
|
||||
items: [{
|
||||
"name": app.getLz('action.removeFromQueue'),
|
||||
"action": function() {
|
||||
self.queueItems.splice(position, 1)
|
||||
app.mk.queue._queueItems = self.queueItems;
|
||||
app.mk.queue._reindex()
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": app.getLz('action.startRadio'),
|
||||
"action": function() {
|
||||
app.mk.setStationQueue({
|
||||
song: item.attributes.playParams.id ?? item.id
|
||||
}).then(() => {
|
||||
app.mk.play()
|
||||
})
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": app.getLz('action.goToArtist'),
|
||||
"action": function() {
|
||||
app.searchAndNavigate(item, 'artist')
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": app.getLz('action.goToAlbum'),
|
||||
"action": function() {
|
||||
app.searchAndNavigate(item, 'album')
|
||||
}
|
||||
},
|
||||
]
|
||||
},
|
||||
multiple: {
|
||||
items: [{
|
||||
"name": app.getLz('action.removeTracks').replace('${self.selectedItems.length}', self.selectedItems.length.toString()),
|
||||
"action": function() {
|
||||
// add property to items to be removed
|
||||
self.selectedItems.forEach(function(item) {
|
||||
self.queueItems[item].remove = true
|
||||
})
|
||||
// remove items
|
||||
self.queueItems = self.queueItems.filter(function(item) {
|
||||
return !item.remove
|
||||
})
|
||||
app.mk.queue._reindex()
|
||||
self.selectedItems = []
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
app.showMenuPanel(menus[useMenu], event);
|
||||
},
|
||||
playQueueItem(id) {
|
||||
app.mk.changeToMediaAtIndex(app.mk.queue._itemIDs.indexOf(id))
|
||||
},
|
||||
updateQueue() {
|
||||
this.selected = -1
|
||||
if (app.mk.queue) {
|
||||
this.queuePosition = app.mk.queue.position;
|
||||
this.queueItems = app.mk.queue._queueItems;
|
||||
} else {
|
||||
this.queuePosition = 0;
|
||||
this.queueItems = [];
|
||||
}
|
||||
},
|
||||
move() {
|
||||
this.selected = -1
|
||||
app.mk.queue._queueItems = this.queueItems;
|
||||
app.mk.queue._reindex()
|
||||
},
|
||||
convertTimeToString(timeInMilliseconds) {
|
||||
var seconds = ((timeInMilliseconds % 60000) / 1000).toFixed(0);
|
||||
return Math.floor(timeInMilliseconds / 60000) + ":" + (seconds < 10 ? '0' : '') + seconds;
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
<script type="text/x-template" id="keybinds-settings">
|
||||
<div class="keybinds-page">
|
||||
<div class="md-option-header">
|
||||
<span>{{$root.getLz('settings.option.general.keybindings')}}</span>
|
||||
</div>
|
||||
<div class="md-option-header">
|
||||
<span>{{$root.getLz('settings.option.general.keybindings')}}</span>
|
||||
</div>
|
||||
<div class="settings-option-body">
|
||||
<div class="md-option-header-sub">
|
||||
<span>{{$root.getLz('settings.option.general.keybindings.library')}}</span>
|
||||
|
@ -207,7 +207,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<button class="md-btn md-btn-large md-btn-block" @click="keyBindReset()">
|
||||
{{$root.getLz('term.reset')}}
|
||||
{{$root.getLz('term.reset')}}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
|
@ -215,109 +215,109 @@
|
|||
</script>
|
||||
|
||||
<script>
|
||||
Vue.component('keybinds-settings', {
|
||||
template: "#keybinds-settings",
|
||||
props: [],
|
||||
data: function () {
|
||||
return {
|
||||
app: this.$root
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
keyBindUpdate: function (action) {
|
||||
const blur = document.createElement('div');
|
||||
blur.className = 'blur';
|
||||
blur.style.backgroundColor = 'rgba(0,0,0,0.25)';
|
||||
blur.style.position = 'fixed';
|
||||
blur.style.top = '0';
|
||||
blur.style.left = '0';
|
||||
blur.style.width = '100%';
|
||||
blur.style.height = '100%';
|
||||
blur.style.zIndex = '9999';
|
||||
blur.style.display = 'flex';
|
||||
blur.style.alignItems = 'center';
|
||||
blur.style.justifyContent = 'center';
|
||||
blur.style.fontSize = '2em';
|
||||
blur.style.color = 'white';
|
||||
blur.innerHTML = `<center>${app.getLz('settings.option.general.keybindings.pressCombination')}<br />${app.getLz('settings.option.general.keybindings.pressEscape')}</center>`
|
||||
document.body.appendChild(blur);
|
||||
Vue.component('keybinds-settings', {
|
||||
template: "#keybinds-settings",
|
||||
props: [],
|
||||
data: function() {
|
||||
return {
|
||||
app: this.$root
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
keyBindUpdate: function(action) {
|
||||
const blur = document.createElement('div');
|
||||
blur.className = 'blur';
|
||||
blur.style.backgroundColor = 'rgba(0,0,0,0.25)';
|
||||
blur.style.position = 'fixed';
|
||||
blur.style.top = '0';
|
||||
blur.style.left = '0';
|
||||
blur.style.width = '100%';
|
||||
blur.style.height = '100%';
|
||||
blur.style.zIndex = '9999';
|
||||
blur.style.display = 'flex';
|
||||
blur.style.alignItems = 'center';
|
||||
blur.style.justifyContent = 'center';
|
||||
blur.style.fontSize = '2em';
|
||||
blur.style.color = 'white';
|
||||
blur.innerHTML = `<center>${app.getLz('settings.option.general.keybindings.pressCombination')}<br />${app.getLz('settings.option.general.keybindings.pressEscape')}</center>`
|
||||
document.body.appendChild(blur);
|
||||
|
||||
let keyBind = [];
|
||||
const keyBindTimeout = setTimeout(function () {
|
||||
keyBind = [];
|
||||
document.body.removeChild(blur);
|
||||
}, 30000);
|
||||
const keyBindUpdate = function (e) {
|
||||
if (document.body.contains(blur)) {
|
||||
if (e.key == 'Escape') {
|
||||
document.body.removeChild(blur);
|
||||
clearTimeout(keyBindTimeout);
|
||||
return;
|
||||
} else {
|
||||
if (e.keyCode >= 65 && e.keyCode <= 90 && e.keyCode <= 97 && e.keyCode <= 122) {
|
||||
keyBind.push(e.key.toUpperCase());
|
||||
} else {
|
||||
keyBind.push(e.key);
|
||||
}
|
||||
if (keyBind.length === 2) {
|
||||
if (keyBind[0] !== keyBind[1]) {
|
||||
app.cfg.general.keybindings[action] = keyBind
|
||||
document.body.removeChild(blur);
|
||||
clearTimeout(keyBindTimeout);
|
||||
notyf.success(app.getLz('settings.notyf.general.keybindings.update.success'));
|
||||
app.confirm(app.getLz("settings.prompt.general.keybindings.update.success"), (ok) => {
|
||||
if (ok) ipcRenderer.invoke("relaunchApp")
|
||||
})
|
||||
} else {
|
||||
keyBind = [];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
document.addEventListener('keydown', keyBindUpdate);
|
||||
},
|
||||
keyBindReset: function () {
|
||||
app.cfg.general.keybindings.search = [app.platform == "darwin" ? "Command" : "Control", "F"];
|
||||
app.cfg.general.keybindings.listnow = [app.platform == "darwin" ? "Command" : "Control", "L"];
|
||||
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", "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",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.zoomn = [app.platform == "darwin" ? "Command" : "Control", "numadd"];
|
||||
app.cfg.general.keybindings.zoomt = [app.platform == "darwin" ? "Command" : "Control", "numsub"];
|
||||
app.cfg.general.keybindings.zoomrst = [app.platform == "darwin" ? "Command" : "Control", "num0"];
|
||||
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'));
|
||||
app.confirm(app.getLz("settings.prompt.general.keybindings.update.success"), (ok) => {
|
||||
let keyBind = [];
|
||||
const keyBindTimeout = setTimeout(function() {
|
||||
keyBind = [];
|
||||
document.body.removeChild(blur);
|
||||
}, 30000);
|
||||
const keyBindUpdate = function(e) {
|
||||
if (document.body.contains(blur)) {
|
||||
if (e.key == 'Escape') {
|
||||
document.body.removeChild(blur);
|
||||
clearTimeout(keyBindTimeout);
|
||||
return;
|
||||
} else {
|
||||
if (e.keyCode >= 65 && e.keyCode <= 90 && e.keyCode <= 97 && e.keyCode <= 122) {
|
||||
keyBind.push(e.key.toUpperCase());
|
||||
} else {
|
||||
keyBind.push(e.key);
|
||||
}
|
||||
if (keyBind.length === 2) {
|
||||
if (keyBind[0] !== keyBind[1]) {
|
||||
app.cfg.general.keybindings[action] = keyBind
|
||||
document.body.removeChild(blur);
|
||||
clearTimeout(keyBindTimeout);
|
||||
notyf.success(app.getLz('settings.notyf.general.keybindings.update.success'));
|
||||
app.confirm(app.getLz("settings.prompt.general.keybindings.update.success"), (ok) => {
|
||||
if (ok) ipcRenderer.invoke("relaunchApp")
|
||||
})
|
||||
},
|
||||
getLanguages: function () {
|
||||
let langs = this.$root.lzListing
|
||||
let categories = {
|
||||
"main": [],
|
||||
"fun": [],
|
||||
"unsorted": []
|
||||
})
|
||||
} else {
|
||||
keyBind = [];
|
||||
}
|
||||
// sort by category if category is undefined or empty put it in "unsorted"
|
||||
for (let i = 0; i < langs.length; i++) {
|
||||
if (langs[i].category === undefined || langs[i].category === "") {
|
||||
categories.unsorted.push(langs[i])
|
||||
} else {
|
||||
categories[langs[i].category].push(langs[i])
|
||||
}
|
||||
}
|
||||
// return
|
||||
return categories
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
document.addEventListener('keydown', keyBindUpdate);
|
||||
},
|
||||
keyBindReset: function() {
|
||||
app.cfg.general.keybindings.search = [app.platform == "darwin" ? "Command" : "Control", "F"];
|
||||
app.cfg.general.keybindings.listnow = [app.platform == "darwin" ? "Command" : "Control", "L"];
|
||||
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", "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", 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.zoomn = [app.platform == "darwin" ? "Command" : "Control", "numadd"];
|
||||
app.cfg.general.keybindings.zoomt = [app.platform == "darwin" ? "Command" : "Control", "numsub"];
|
||||
app.cfg.general.keybindings.zoomrst = [app.platform == "darwin" ? "Command" : "Control", "num0"];
|
||||
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'));
|
||||
app.confirm(app.getLz("settings.prompt.general.keybindings.update.success"), (ok) => {
|
||||
if (ok) ipcRenderer.invoke("relaunchApp")
|
||||
})
|
||||
},
|
||||
getLanguages: function() {
|
||||
let langs = this.$root.lzListing
|
||||
let categories = {
|
||||
"main": [],
|
||||
"fun": [],
|
||||
"unsorted": []
|
||||
}
|
||||
})
|
||||
</script>
|
||||
// sort by category if category is undefined or empty put it in "unsorted"
|
||||
for (let i = 0; i < langs.length; i++) {
|
||||
if (langs[i].category === undefined || langs[i].category === "") {
|
||||
categories.unsorted.push(langs[i])
|
||||
} else {
|
||||
categories[langs[i].category].push(langs[i])
|
||||
}
|
||||
}
|
||||
// return
|
||||
return categories
|
||||
},
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
|
|
@ -21,7 +21,8 @@
|
|||
<div class="row">
|
||||
<div class="col cider-flex-center">
|
||||
<div>
|
||||
<h4 class="repo-name">{{ (repo.description != null) ? repo.description : repo.full_name }}</h4>
|
||||
<h4 class="repo-name">{{ (repo.description != null) ? repo.description :
|
||||
repo.full_name }}</h4>
|
||||
<div>⭐ {{ repo.stargazers_count }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -37,7 +38,8 @@
|
|||
<div>
|
||||
<h3 class="repo-preview-name">{{ openRepo.description }}</h3>
|
||||
<div>
|
||||
<div class="svg-icon inline" :style="{'--url': 'url(\'./assets/github.svg\')'}"></div>
|
||||
<div class="svg-icon inline"
|
||||
:style="{'--url': 'url(\'./assets/github.svg\')'}"></div>
|
||||
<a class="repo-url" target="_blank" :href="openRepo.html_url">{{ openRepo.full_name
|
||||
}}</a></div>
|
||||
<div>⭐ {{ openRepo.stargazers_count }}</div>
|
||||
|
@ -62,127 +64,127 @@
|
|||
</div>
|
||||
</script>
|
||||
<script>
|
||||
Vue.component('plugins-github', {
|
||||
template: "#plugins-github",
|
||||
props: [],
|
||||
data: function () {
|
||||
return {
|
||||
repos: [],
|
||||
openRepo: {
|
||||
id: -1,
|
||||
name: '',
|
||||
description: '',
|
||||
html_url: '',
|
||||
stargazers_count: 0,
|
||||
owner: {
|
||||
avatar_url: ''
|
||||
},
|
||||
readme: ""
|
||||
},
|
||||
themesInstalled: []
|
||||
}
|
||||
Vue.component('plugins-github', {
|
||||
template: "#plugins-github",
|
||||
props: [],
|
||||
data: function() {
|
||||
return {
|
||||
repos: [],
|
||||
openRepo: {
|
||||
id: -1,
|
||||
name: '',
|
||||
description: '',
|
||||
html_url: '',
|
||||
stargazers_count: 0,
|
||||
owner: {
|
||||
avatar_url: ''
|
||||
},
|
||||
readme: ""
|
||||
},
|
||||
mounted() {
|
||||
this.getRepos();
|
||||
// this.getInstalledThemes();
|
||||
},
|
||||
methods: {
|
||||
getInstalledThemes() {
|
||||
let self = this
|
||||
const themes = ipcRenderer.sendSync("get-themes")
|
||||
// for each theme, get the github_repo property and push it to the themesInstalled array, if not blank
|
||||
themes.forEach(theme => {
|
||||
if (theme.github_repo !== "") {
|
||||
self.themesInstalled.push(theme.github_repo)
|
||||
}
|
||||
})
|
||||
},
|
||||
showRepo(repo) {
|
||||
const self = this
|
||||
const readmeUrl = `https://raw.githubusercontent.com/${repo.full_name}/main/README.md`;
|
||||
var requestOptions = {
|
||||
method: 'GET',
|
||||
redirect: 'follow'
|
||||
};
|
||||
themesInstalled: []
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.getRepos();
|
||||
// this.getInstalledThemes();
|
||||
},
|
||||
methods: {
|
||||
getInstalledThemes() {
|
||||
let self = this
|
||||
const themes = ipcRenderer.sendSync("get-themes")
|
||||
// for each theme, get the github_repo property and push it to the themesInstalled array, if not blank
|
||||
themes.forEach(theme => {
|
||||
if (theme.github_repo !== "") {
|
||||
self.themesInstalled.push(theme.github_repo)
|
||||
}
|
||||
})
|
||||
},
|
||||
showRepo(repo) {
|
||||
const self = this
|
||||
const readmeUrl = `https://raw.githubusercontent.com/${repo.full_name}/main/README.md`;
|
||||
var requestOptions = {
|
||||
method: 'GET',
|
||||
redirect: 'follow'
|
||||
};
|
||||
|
||||
fetch(readmeUrl, requestOptions)
|
||||
.then(response => response.text())
|
||||
.then(result => {
|
||||
self.openRepo = repo
|
||||
self.openRepo.readme = self.convertReadMe(result);
|
||||
})
|
||||
.catch(error => {
|
||||
self.openRepo = repo
|
||||
self.openRepo.readme = `This repository doesn't have a README.md file.`;
|
||||
console.log('error', error)
|
||||
});
|
||||
},
|
||||
convertReadMe(text) {
|
||||
return marked.parse(text)
|
||||
},
|
||||
installThemeRepo(repo) {
|
||||
let self = this
|
||||
let msg = app.stringTemplateParser(app.getLz('settings.option.visual.plugin.github.install.confirm'), {
|
||||
repo: repo.full_name
|
||||
});
|
||||
app.confirm(msg, (res) => {
|
||||
if (res) {
|
||||
ipcRenderer.once("plugin-installed", (event, arg) => {
|
||||
if (arg.success) {
|
||||
self.themes = []
|
||||
notyf.success(app.getLz('settings.notyf.visual.plugin.install.success'));
|
||||
app.confirm(app.getLz("settings.prompt.visual.plugin.github.success"), (ok)=>{
|
||||
if (ok) {
|
||||
ipcRenderer.invoke("relaunchApp")
|
||||
} else {
|
||||
return
|
||||
}
|
||||
})
|
||||
} else {
|
||||
notyf.error(app.getLz('settings.notyf.visual.plugin.install.error'));
|
||||
}
|
||||
});
|
||||
ipcRenderer.invoke("get-github-plugin", repo.html_url)
|
||||
}
|
||||
fetch(readmeUrl, requestOptions)
|
||||
.then(response => response.text())
|
||||
.then(result => {
|
||||
self.openRepo = repo
|
||||
self.openRepo.readme = self.convertReadMe(result);
|
||||
})
|
||||
.catch(error => {
|
||||
self.openRepo = repo
|
||||
self.openRepo.readme = `This repository doesn't have a README.md file.`;
|
||||
console.log('error', error)
|
||||
});
|
||||
},
|
||||
convertReadMe(text) {
|
||||
return marked.parse(text)
|
||||
},
|
||||
installThemeRepo(repo) {
|
||||
let self = this
|
||||
let msg = app.stringTemplateParser(app.getLz('settings.option.visual.plugin.github.install.confirm'), {
|
||||
repo: repo.full_name
|
||||
});
|
||||
app.confirm(msg, (res) => {
|
||||
if (res) {
|
||||
ipcRenderer.once("plugin-installed", (event, arg) => {
|
||||
if (arg.success) {
|
||||
self.themes = []
|
||||
notyf.success(app.getLz('settings.notyf.visual.plugin.install.success'));
|
||||
app.confirm(app.getLz("settings.prompt.visual.plugin.github.success"), (ok) => {
|
||||
if (ok) {
|
||||
ipcRenderer.invoke("relaunchApp")
|
||||
} else {
|
||||
return
|
||||
}
|
||||
})
|
||||
},
|
||||
installThemeURL() {
|
||||
let self = this
|
||||
app.prompt(app.getLz('settings.prompt.visual.plugin.github.URL'), (result) => {
|
||||
if (result) {
|
||||
ipcRenderer.once("plugin-installed", (event, arg) => {
|
||||
if (arg.success) {
|
||||
self.themes = ipcRenderer.sendSync("get-themes")
|
||||
app.confirm(app.getLz("settings.prompt.visual.plugin.github.success"), (ok)=>{
|
||||
if (ok) {
|
||||
ipcRenderer.invoke("relaunchApp")
|
||||
} else {
|
||||
return
|
||||
}
|
||||
})
|
||||
notyf.success(app.getLz('settings.notyf.visual.plugin.install.success'));
|
||||
} else {
|
||||
notyf.error(app.getLz('settings.notyf.visual.plugin.install.error'));
|
||||
}
|
||||
});
|
||||
ipcRenderer.invoke("get-github-plugin", result)
|
||||
}
|
||||
});
|
||||
},
|
||||
getRepos() {
|
||||
let self = this
|
||||
var requestOptions = {
|
||||
method: 'GET',
|
||||
redirect: 'follow'
|
||||
};
|
||||
} else {
|
||||
notyf.error(app.getLz('settings.notyf.visual.plugin.install.error'));
|
||||
}
|
||||
});
|
||||
ipcRenderer.invoke("get-github-plugin", repo.html_url)
|
||||
}
|
||||
})
|
||||
},
|
||||
installThemeURL() {
|
||||
let self = this
|
||||
app.prompt(app.getLz('settings.prompt.visual.plugin.github.URL'), (result) => {
|
||||
if (result) {
|
||||
ipcRenderer.once("plugin-installed", (event, arg) => {
|
||||
if (arg.success) {
|
||||
self.themes = ipcRenderer.sendSync("get-themes")
|
||||
app.confirm(app.getLz("settings.prompt.visual.plugin.github.success"), (ok) => {
|
||||
if (ok) {
|
||||
ipcRenderer.invoke("relaunchApp")
|
||||
} else {
|
||||
return
|
||||
}
|
||||
})
|
||||
notyf.success(app.getLz('settings.notyf.visual.plugin.install.success'));
|
||||
} else {
|
||||
notyf.error(app.getLz('settings.notyf.visual.plugin.install.error'));
|
||||
}
|
||||
});
|
||||
ipcRenderer.invoke("get-github-plugin", result)
|
||||
}
|
||||
});
|
||||
},
|
||||
getRepos() {
|
||||
let self = this
|
||||
var requestOptions = {
|
||||
method: 'GET',
|
||||
redirect: 'follow'
|
||||
};
|
||||
|
||||
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
|
||||
})
|
||||
.catch(error => console.log('error', error));
|
||||
}
|
||||
}
|
||||
})
|
||||
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
|
||||
})
|
||||
.catch(error => console.log('error', error));
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
|
|
@ -78,120 +78,120 @@
|
|||
</div>
|
||||
</script>
|
||||
<script>
|
||||
Vue.component('themes-github', {
|
||||
template: "#themes-github",
|
||||
props: [],
|
||||
data: function () {
|
||||
return {
|
||||
repos: [],
|
||||
openRepo: {
|
||||
id: -1,
|
||||
name: '',
|
||||
description: '',
|
||||
html_url: '',
|
||||
stargazers_count: 0,
|
||||
owner: {
|
||||
avatar_url: ''
|
||||
},
|
||||
readme: ""
|
||||
},
|
||||
themesInstalled: [],
|
||||
themes: []
|
||||
}
|
||||
Vue.component('themes-github', {
|
||||
template: "#themes-github",
|
||||
props: [],
|
||||
data: function() {
|
||||
return {
|
||||
repos: [],
|
||||
openRepo: {
|
||||
id: -1,
|
||||
name: '',
|
||||
description: '',
|
||||
html_url: '',
|
||||
stargazers_count: 0,
|
||||
owner: {
|
||||
avatar_url: ''
|
||||
},
|
||||
readme: ""
|
||||
},
|
||||
mounted() {
|
||||
this.themes = ipcRenderer.sendSync("get-themes")
|
||||
this.getRepos();
|
||||
this.getInstalledThemes();
|
||||
},
|
||||
methods: {
|
||||
openThemesFolder() {
|
||||
ipcRenderer.invoke("open-path", "themes")
|
||||
},
|
||||
getInstalledThemes() {
|
||||
let self = this
|
||||
const themes = ipcRenderer.sendSync("get-themes")
|
||||
// for each theme, get the github_repo property and push it to the themesInstalled array, if not blank
|
||||
themes.forEach(theme => {
|
||||
if (theme.github_repo !== "" && typeof theme.commit != "") {
|
||||
self.themesInstalled.push(theme.github_repo.toLowerCase())
|
||||
}
|
||||
})
|
||||
},
|
||||
showRepo(repo) {
|
||||
const self = this
|
||||
const readmeUrl = `https://raw.githubusercontent.com/${repo.full_name}/main/README.md`;
|
||||
var requestOptions = {
|
||||
method: 'GET',
|
||||
redirect: 'follow'
|
||||
};
|
||||
themesInstalled: [],
|
||||
themes: []
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.themes = ipcRenderer.sendSync("get-themes")
|
||||
this.getRepos();
|
||||
this.getInstalledThemes();
|
||||
},
|
||||
methods: {
|
||||
openThemesFolder() {
|
||||
ipcRenderer.invoke("open-path", "themes")
|
||||
},
|
||||
getInstalledThemes() {
|
||||
let self = this
|
||||
const themes = ipcRenderer.sendSync("get-themes")
|
||||
// for each theme, get the github_repo property and push it to the themesInstalled array, if not blank
|
||||
themes.forEach(theme => {
|
||||
if (theme.github_repo !== "" && typeof theme.commit != "") {
|
||||
self.themesInstalled.push(theme.github_repo.toLowerCase())
|
||||
}
|
||||
})
|
||||
},
|
||||
showRepo(repo) {
|
||||
const self = this
|
||||
const readmeUrl = `https://raw.githubusercontent.com/${repo.full_name}/main/README.md`;
|
||||
var requestOptions = {
|
||||
method: 'GET',
|
||||
redirect: 'follow'
|
||||
};
|
||||
|
||||
fetch(readmeUrl, requestOptions)
|
||||
.then(response => response.text())
|
||||
.then(result => {
|
||||
self.openRepo = repo
|
||||
self.openRepo.readme = self.convertReadMe(result);
|
||||
})
|
||||
.catch(error => {
|
||||
self.openRepo = repo
|
||||
self.openRepo.readme = `This repository doesn't have a README.md file.`;
|
||||
console.log('error', error)
|
||||
});
|
||||
},
|
||||
convertReadMe(text) {
|
||||
return marked.parse(text)
|
||||
},
|
||||
installThemeRepo(repo) {
|
||||
let self = this
|
||||
let msg = app.stringTemplateParser(app.getLz('settings.option.visual.theme.github.install.confirm'), {
|
||||
repo: repo.full_name
|
||||
});
|
||||
app.confirm(msg, (res) => {
|
||||
if (res) {
|
||||
ipcRenderer.once("theme-installed", (event, arg) => {
|
||||
if (arg.success) {
|
||||
self.themes = ipcRenderer.sendSync("get-themes")
|
||||
self.getInstalledThemes()
|
||||
notyf.success(app.getLz('settings.notyf.visual.theme.install.success'));
|
||||
} else {
|
||||
notyf.error(app.getLz('settings.notyf.visual.theme.install.error'));
|
||||
}
|
||||
});
|
||||
ipcRenderer.invoke("get-github-theme", repo.html_url)
|
||||
}
|
||||
})
|
||||
},
|
||||
installThemeURL() {
|
||||
let self = this
|
||||
app.prompt(app.getLz('settings.prompt.visual.theme.github.URL'), (result) => {
|
||||
if (result) {
|
||||
ipcRenderer.once("theme-installed", (event, arg) => {
|
||||
if (arg.success) {
|
||||
self.themes = ipcRenderer.sendSync("get-themes")
|
||||
notyf.success(app.getLz('settings.notyf.visual.theme.install.success'));
|
||||
} else {
|
||||
notyf.error(app.getLz('settings.notyf.visual.theme.install.error'));
|
||||
}
|
||||
});
|
||||
ipcRenderer.invoke("get-github-theme", result)
|
||||
}
|
||||
});
|
||||
},
|
||||
getRepos() {
|
||||
let self = this
|
||||
var requestOptions = {
|
||||
method: 'GET',
|
||||
redirect: 'follow'
|
||||
};
|
||||
fetch(readmeUrl, requestOptions)
|
||||
.then(response => response.text())
|
||||
.then(result => {
|
||||
self.openRepo = repo
|
||||
self.openRepo.readme = self.convertReadMe(result);
|
||||
})
|
||||
.catch(error => {
|
||||
self.openRepo = repo
|
||||
self.openRepo.readme = `This repository doesn't have a README.md file.`;
|
||||
console.log('error', error)
|
||||
});
|
||||
},
|
||||
convertReadMe(text) {
|
||||
return marked.parse(text)
|
||||
},
|
||||
installThemeRepo(repo) {
|
||||
let self = this
|
||||
let msg = app.stringTemplateParser(app.getLz('settings.option.visual.theme.github.install.confirm'), {
|
||||
repo: repo.full_name
|
||||
});
|
||||
app.confirm(msg, (res) => {
|
||||
if (res) {
|
||||
ipcRenderer.once("theme-installed", (event, arg) => {
|
||||
if (arg.success) {
|
||||
self.themes = ipcRenderer.sendSync("get-themes")
|
||||
self.getInstalledThemes()
|
||||
notyf.success(app.getLz('settings.notyf.visual.theme.install.success'));
|
||||
} else {
|
||||
notyf.error(app.getLz('settings.notyf.visual.theme.install.error'));
|
||||
}
|
||||
});
|
||||
ipcRenderer.invoke("get-github-theme", repo.html_url)
|
||||
}
|
||||
})
|
||||
},
|
||||
installThemeURL() {
|
||||
let self = this
|
||||
app.prompt(app.getLz('settings.prompt.visual.theme.github.URL'), (result) => {
|
||||
if (result) {
|
||||
ipcRenderer.once("theme-installed", (event, arg) => {
|
||||
if (arg.success) {
|
||||
self.themes = ipcRenderer.sendSync("get-themes")
|
||||
notyf.success(app.getLz('settings.notyf.visual.theme.install.success'));
|
||||
} else {
|
||||
notyf.error(app.getLz('settings.notyf.visual.theme.install.error'));
|
||||
}
|
||||
});
|
||||
ipcRenderer.invoke("get-github-theme", result)
|
||||
}
|
||||
});
|
||||
},
|
||||
getRepos() {
|
||||
let self = this
|
||||
var requestOptions = {
|
||||
method: 'GET',
|
||||
redirect: 'follow'
|
||||
};
|
||||
|
||||
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
|
||||
self.repos = items
|
||||
})
|
||||
.catch(error => console.log('error', error));
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
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
|
||||
self.repos = items
|
||||
})
|
||||
.catch(error => console.log('error', error));
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
|
|
@ -32,9 +32,9 @@
|
|||
<ul class="list-group list-group-flush">
|
||||
<template v-for="theme in themes">
|
||||
<li @click="addStyle(theme.file)"
|
||||
@contextmenu="contextMenu($event, theme)"
|
||||
class="list-group-item list-group-item-dark"
|
||||
:class="{'applied': $root.cfg.visual.styles.includes(theme.file)}">
|
||||
@contextmenu="contextMenu($event, theme)"
|
||||
class="list-group-item list-group-item-dark"
|
||||
:class="{'applied': $root.cfg.visual.styles.includes(theme.file)}">
|
||||
|
||||
<b-row>
|
||||
<b-col class="themeLabel">{{theme.name}}</b-col>
|
||||
|
@ -51,33 +51,34 @@
|
|||
<button class="themeContextMenu codicon codicon-package"></button>
|
||||
</b-col>
|
||||
<b-col sm="auto">
|
||||
<button @click.stop="contextMenu($event, theme)" class="themeContextMenu codicon codicon-list-unordered"></button>
|
||||
<button @click.stop="contextMenu($event, theme)"
|
||||
class="themeContextMenu codicon codicon-list-unordered"></button>
|
||||
</b-col>
|
||||
</template>
|
||||
|
||||
</b-row>
|
||||
</li>
|
||||
<li @click="addStyle(packEntry.file)"
|
||||
@contextmenu="contextMenu($event, theme)"
|
||||
class="list-group-item list-group-item-dark addon"
|
||||
v-for="packEntry in theme.pack"
|
||||
:class="{'applied': $root.cfg.visual.styles.includes(packEntry.file)}"
|
||||
v-if="theme.pack">
|
||||
@contextmenu="contextMenu($event, theme)"
|
||||
class="list-group-item list-group-item-dark addon"
|
||||
v-for="packEntry in theme.pack"
|
||||
:class="{'applied': $root.cfg.visual.styles.includes(packEntry.file)}"
|
||||
v-if="theme.pack">
|
||||
|
||||
<b-row>
|
||||
<b-col class="themeLabel">{{packEntry.name}}</b-col>
|
||||
<template v-if="$root.cfg.visual.styles.includes(packEntry.file)">
|
||||
<b-col sm="auto">
|
||||
<button class="themeContextMenu codicon codicon-check"></button>
|
||||
</b-col>
|
||||
</template>
|
||||
<template v-else>
|
||||
<b-col sm="auto">
|
||||
<button class="themeContextMenu codicon codicon-diff-added"></button>
|
||||
</b-col>
|
||||
</template>
|
||||
</b-row>
|
||||
</li>
|
||||
<b-row>
|
||||
<b-col class="themeLabel">{{packEntry.name}}</b-col>
|
||||
<template v-if="$root.cfg.visual.styles.includes(packEntry.file)">
|
||||
<b-col sm="auto">
|
||||
<button class="themeContextMenu codicon codicon-check"></button>
|
||||
</b-col>
|
||||
</template>
|
||||
<template v-else>
|
||||
<b-col sm="auto">
|
||||
<button class="themeContextMenu codicon codicon-diff-added"></button>
|
||||
</b-col>
|
||||
</template>
|
||||
</b-row>
|
||||
</li>
|
||||
</template>
|
||||
</ul>
|
||||
</div>
|
||||
|
@ -86,17 +87,17 @@
|
|||
<div class="repo-header">
|
||||
<h4>{{ $root.getLz("settings.option.visual.theme.github.applied") }} </h4>
|
||||
</div>
|
||||
<stylestack-editor ref="stackEditor" v-if="themes.length != 0" :themes="themes"/>
|
||||
<stylestack-editor ref="stackEditor" v-if="themes.length != 0" :themes="themes" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script>
|
||||
// do not translate
|
||||
Vue.component('stylestack-editor', {
|
||||
/*html*/
|
||||
template: `
|
||||
// do not translate
|
||||
Vue.component('stylestack-editor', {
|
||||
/*html*/
|
||||
template: `
|
||||
<div class="stylestack-editor" >
|
||||
<draggable class="list-group" v-model="$root.cfg.visual.styles" @end="$root.reloadStyles()">
|
||||
<b-list-group-item variant="dark" v-for="theme in $root.cfg.visual.styles" :key="theme">
|
||||
|
@ -113,255 +114,255 @@
|
|||
</draggable>
|
||||
</div>
|
||||
`,
|
||||
props: {
|
||||
themes: {
|
||||
type: Array,
|
||||
default: [],
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data: function () {
|
||||
return {
|
||||
selected: null,
|
||||
newTheme: null,
|
||||
themeList: []
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
console.log(this.themes)
|
||||
this.themeList = [...this.themes]
|
||||
props: {
|
||||
themes: {
|
||||
type: Array,
|
||||
default: [],
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data: function() {
|
||||
return {
|
||||
selected: null,
|
||||
newTheme: null,
|
||||
themeList: []
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
console.log(this.themes)
|
||||
this.themeList = [...this.themes]
|
||||
|
||||
this.themeList.forEach(theme => {
|
||||
if (theme.pack) {
|
||||
theme.pack.forEach(packEntry => {
|
||||
packEntry.file = theme.file.replace('index.less', '') + packEntry.file
|
||||
this.themeList.push(packEntry)
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
gitHubExplore() {
|
||||
this.$root.openSettingsPage("github-themes")
|
||||
},
|
||||
getThemeName(filename) {
|
||||
try {
|
||||
return this.themeList.find(theme => theme.file === filename).name;
|
||||
} catch (e) {
|
||||
return filename;
|
||||
}
|
||||
},
|
||||
moveUp() {
|
||||
const styles = this.$root.cfg.visual.styles
|
||||
const index = styles.indexOf(this.selected)
|
||||
if (index > 0) {
|
||||
styles.splice(index, 1)
|
||||
styles.splice(index - 1, 0, this.selected)
|
||||
}
|
||||
this.$root.reloadStyles()
|
||||
},
|
||||
moveDown() {
|
||||
const styles = this.$root.cfg.visual.styles
|
||||
const index = styles.indexOf(this.selected)
|
||||
if (index < styles.length - 1) {
|
||||
styles.splice(index, 1)
|
||||
styles.splice(index + 1, 0, this.selected)
|
||||
}
|
||||
this.$root.reloadStyles()
|
||||
},
|
||||
remove(style) {
|
||||
const styles = this.$root.cfg.visual.styles
|
||||
const index = styles.indexOf(style)
|
||||
styles.splice(index, 1)
|
||||
this.$root.reloadStyles()
|
||||
},
|
||||
addStyle(style) {
|
||||
const styles = this.$root.cfg.visual.styles
|
||||
styles.push(style)
|
||||
this.$root.reloadStyles()
|
||||
}
|
||||
this.themeList.forEach(theme => {
|
||||
if (theme.pack) {
|
||||
theme.pack.forEach(packEntry => {
|
||||
packEntry.file = theme.file.replace('index.less', '') + packEntry.file
|
||||
this.themeList.push(packEntry)
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
gitHubExplore() {
|
||||
this.$root.openSettingsPage("github-themes")
|
||||
},
|
||||
getThemeName(filename) {
|
||||
try {
|
||||
return this.themeList.find(theme => theme.file === filename).name;
|
||||
} catch (e) {
|
||||
return filename;
|
||||
}
|
||||
},
|
||||
moveUp() {
|
||||
const styles = this.$root.cfg.visual.styles
|
||||
const index = styles.indexOf(this.selected)
|
||||
if (index > 0) {
|
||||
styles.splice(index, 1)
|
||||
styles.splice(index - 1, 0, this.selected)
|
||||
}
|
||||
this.$root.reloadStyles()
|
||||
},
|
||||
moveDown() {
|
||||
const styles = this.$root.cfg.visual.styles
|
||||
const index = styles.indexOf(this.selected)
|
||||
if (index < styles.length - 1) {
|
||||
styles.splice(index, 1)
|
||||
styles.splice(index + 1, 0, this.selected)
|
||||
}
|
||||
this.$root.reloadStyles()
|
||||
},
|
||||
remove(style) {
|
||||
const styles = this.$root.cfg.visual.styles
|
||||
const index = styles.indexOf(style)
|
||||
styles.splice(index, 1)
|
||||
this.$root.reloadStyles()
|
||||
},
|
||||
addStyle(style) {
|
||||
const styles = this.$root.cfg.visual.styles
|
||||
styles.push(style)
|
||||
this.$root.reloadStyles()
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<script>
|
||||
Vue.component('installed-themes', {
|
||||
template: "#installed-themes",
|
||||
props: [],
|
||||
data: function () {
|
||||
return {
|
||||
repos: [],
|
||||
openRepo: {
|
||||
id: -1,
|
||||
name: '',
|
||||
description: '',
|
||||
html_url: '',
|
||||
stargazers_count: 0,
|
||||
owner: {
|
||||
avatar_url: ''
|
||||
},
|
||||
readme: ""
|
||||
},
|
||||
themesInstalled: [],
|
||||
themes: []
|
||||
}
|
||||
Vue.component('installed-themes', {
|
||||
template: "#installed-themes",
|
||||
props: [],
|
||||
data: function() {
|
||||
return {
|
||||
repos: [],
|
||||
openRepo: {
|
||||
id: -1,
|
||||
name: '',
|
||||
description: '',
|
||||
html_url: '',
|
||||
stargazers_count: 0,
|
||||
owner: {
|
||||
avatar_url: ''
|
||||
},
|
||||
readme: ""
|
||||
},
|
||||
mounted() {
|
||||
this.getThemesList();
|
||||
},
|
||||
methods: {
|
||||
getThemesList() {
|
||||
let self = this
|
||||
let themes = ipcRenderer.sendSync("get-themes")
|
||||
themes.unshift({
|
||||
name: "Acrylic Grain",
|
||||
file: "grain.less"
|
||||
})
|
||||
themes.unshift({
|
||||
name: "Sweetener",
|
||||
file: "sweetener.less"
|
||||
})
|
||||
themes.unshift({
|
||||
name: "Reduce Visuals",
|
||||
file: "reduce_visuals.less"
|
||||
})
|
||||
// themes.unshift({
|
||||
// name: "Inline Drawer",
|
||||
// file: "inline_drawer.less"
|
||||
// })
|
||||
themes.unshift({
|
||||
name: "Dark",
|
||||
file: "dark.less"
|
||||
})
|
||||
this.themes = themes
|
||||
},
|
||||
contextMenu(event, theme) {
|
||||
let self = this
|
||||
let menu = {
|
||||
items: {
|
||||
"uninstall": {
|
||||
name: app.getLz("settings.option.visual.theme.uninstall"),
|
||||
disabled: true,
|
||||
action: () => {
|
||||
app.confirm(app.stringTemplateParser(app.getLz("settings.prompt.visual.theme.uninstallTheme"), {
|
||||
theme: theme.name ?? theme.file
|
||||
}), (res) => {
|
||||
if (res) {
|
||||
console.debug(theme)
|
||||
ipcRenderer.once("theme-uninstalled", (event, args) => {
|
||||
console.debug(event, args)
|
||||
self.getThemesList()
|
||||
})
|
||||
ipcRenderer.invoke("uninstall-theme", theme.path)
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
},
|
||||
"viewInfo": {
|
||||
name: app.getLz("settings.option.visual.theme.viewInfo"),
|
||||
disabled: true,
|
||||
action: () => {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (theme.path) {
|
||||
menu.items.uninstall.disabled = false
|
||||
}
|
||||
this.$root.showMenuPanel(menu, event)
|
||||
},
|
||||
openThemesFolder() {
|
||||
ipcRenderer.invoke("open-path", "themes")
|
||||
},
|
||||
getInstalledThemes() {
|
||||
let self = this
|
||||
const themes = ipcRenderer.sendSync("get-themes")
|
||||
// for each theme, get the github_repo property and push it to the themesInstalled array, if not blank
|
||||
themes.forEach(theme => {
|
||||
if (theme.github_repo !== "" && typeof theme.commit != "") {
|
||||
self.themesInstalled.push(theme.github_repo.toLowerCase())
|
||||
}
|
||||
})
|
||||
},
|
||||
addStyle(filename) {
|
||||
this.$refs.stackEditor.addStyle(filename)
|
||||
},
|
||||
showRepo(repo) {
|
||||
const self = this
|
||||
const readmeUrl = `https://raw.githubusercontent.com/${repo.full_name}/main/README.md`;
|
||||
var requestOptions = {
|
||||
method: 'GET',
|
||||
redirect: 'follow'
|
||||
};
|
||||
|
||||
fetch(readmeUrl, requestOptions)
|
||||
.then(response => response.text())
|
||||
.then(result => {
|
||||
self.openRepo = repo
|
||||
self.openRepo.readme = self.convertReadMe(result);
|
||||
themesInstalled: [],
|
||||
themes: []
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.getThemesList();
|
||||
},
|
||||
methods: {
|
||||
getThemesList() {
|
||||
let self = this
|
||||
let themes = ipcRenderer.sendSync("get-themes")
|
||||
themes.unshift({
|
||||
name: "Acrylic Grain",
|
||||
file: "grain.less"
|
||||
})
|
||||
themes.unshift({
|
||||
name: "Sweetener",
|
||||
file: "sweetener.less"
|
||||
})
|
||||
themes.unshift({
|
||||
name: "Reduce Visuals",
|
||||
file: "reduce_visuals.less"
|
||||
})
|
||||
// themes.unshift({
|
||||
// name: "Inline Drawer",
|
||||
// file: "inline_drawer.less"
|
||||
// })
|
||||
themes.unshift({
|
||||
name: "Dark",
|
||||
file: "dark.less"
|
||||
})
|
||||
this.themes = themes
|
||||
},
|
||||
contextMenu(event, theme) {
|
||||
let self = this
|
||||
let menu = {
|
||||
items: {
|
||||
"uninstall": {
|
||||
name: app.getLz("settings.option.visual.theme.uninstall"),
|
||||
disabled: true,
|
||||
action: () => {
|
||||
app.confirm(app.stringTemplateParser(app.getLz("settings.prompt.visual.theme.uninstallTheme"), {
|
||||
theme: theme.name ?? theme.file
|
||||
}), (res) => {
|
||||
if (res) {
|
||||
console.debug(theme)
|
||||
ipcRenderer.once("theme-uninstalled", (event, args) => {
|
||||
console.debug(event, args)
|
||||
self.getThemesList()
|
||||
})
|
||||
.catch(error => {
|
||||
self.openRepo = repo
|
||||
self.openRepo.readme = `This repository doesn't have a README.md file.`;
|
||||
console.log('error', error)
|
||||
});
|
||||
},
|
||||
convertReadMe(text) {
|
||||
return marked.parse(text)
|
||||
},
|
||||
installThemeRepo(repo) {
|
||||
let self = this
|
||||
let msg = app.stringTemplateParser(app.getLz('settings.option.visual.theme.github.install.confirm'), {
|
||||
repo: repo.full_name
|
||||
});
|
||||
app.confirm(msg, (res) => {
|
||||
if (res) {
|
||||
ipcRenderer.once("theme-installed", (event, arg) => {
|
||||
if (arg.success) {
|
||||
self.themes = ipcRenderer.sendSync("get-themes")
|
||||
self.getInstalledThemes()
|
||||
notyf.success(app.getLz('settings.notyf.visual.theme.install.success'));
|
||||
} else {
|
||||
notyf.error(app.getLz('settings.notyf.visual.theme.install.error'));
|
||||
}
|
||||
});
|
||||
ipcRenderer.invoke("get-github-theme", repo.html_url)
|
||||
}
|
||||
ipcRenderer.invoke("uninstall-theme", theme.path)
|
||||
}
|
||||
})
|
||||
},
|
||||
installThemeURL() {
|
||||
let self = this
|
||||
app.prompt(app.getLz('settings.prompt.visual.theme.github.URL'), (result) => {
|
||||
if (result) {
|
||||
ipcRenderer.once("theme-installed", (event, arg) => {
|
||||
if (arg.success) {
|
||||
self.themes = ipcRenderer.sendSync("get-themes")
|
||||
notyf.success(app.getLz('settings.notyf.visual.theme.install.success'));
|
||||
} else {
|
||||
notyf.error(app.getLz('settings.notyf.visual.theme.install.error'));
|
||||
}
|
||||
});
|
||||
ipcRenderer.invoke("get-github-theme", result)
|
||||
}
|
||||
});
|
||||
},
|
||||
getRepos() {
|
||||
let self = this
|
||||
var requestOptions = {
|
||||
method: 'GET',
|
||||
redirect: 'follow'
|
||||
};
|
||||
|
||||
fetch("https://api.github.com/search/repositories?q=topic:cidermusictheme fork:true", requestOptions)
|
||||
.then(response => response.text())
|
||||
.then(result => {
|
||||
let items = JSON.parse(result).items
|
||||
self.repos = items
|
||||
})
|
||||
.catch(error => console.log('error', error));
|
||||
}
|
||||
},
|
||||
"viewInfo": {
|
||||
name: app.getLz("settings.option.visual.theme.viewInfo"),
|
||||
disabled: true,
|
||||
action: () => {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
if (theme.path) {
|
||||
menu.items.uninstall.disabled = false
|
||||
}
|
||||
this.$root.showMenuPanel(menu, event)
|
||||
},
|
||||
openThemesFolder() {
|
||||
ipcRenderer.invoke("open-path", "themes")
|
||||
},
|
||||
getInstalledThemes() {
|
||||
let self = this
|
||||
const themes = ipcRenderer.sendSync("get-themes")
|
||||
// for each theme, get the github_repo property and push it to the themesInstalled array, if not blank
|
||||
themes.forEach(theme => {
|
||||
if (theme.github_repo !== "" && typeof theme.commit != "") {
|
||||
self.themesInstalled.push(theme.github_repo.toLowerCase())
|
||||
}
|
||||
})
|
||||
},
|
||||
addStyle(filename) {
|
||||
this.$refs.stackEditor.addStyle(filename)
|
||||
},
|
||||
showRepo(repo) {
|
||||
const self = this
|
||||
const readmeUrl = `https://raw.githubusercontent.com/${repo.full_name}/main/README.md`;
|
||||
var requestOptions = {
|
||||
method: 'GET',
|
||||
redirect: 'follow'
|
||||
};
|
||||
|
||||
fetch(readmeUrl, requestOptions)
|
||||
.then(response => response.text())
|
||||
.then(result => {
|
||||
self.openRepo = repo
|
||||
self.openRepo.readme = self.convertReadMe(result);
|
||||
})
|
||||
.catch(error => {
|
||||
self.openRepo = repo
|
||||
self.openRepo.readme = `This repository doesn't have a README.md file.`;
|
||||
console.log('error', error)
|
||||
});
|
||||
},
|
||||
convertReadMe(text) {
|
||||
return marked.parse(text)
|
||||
},
|
||||
installThemeRepo(repo) {
|
||||
let self = this
|
||||
let msg = app.stringTemplateParser(app.getLz('settings.option.visual.theme.github.install.confirm'), {
|
||||
repo: repo.full_name
|
||||
});
|
||||
app.confirm(msg, (res) => {
|
||||
if (res) {
|
||||
ipcRenderer.once("theme-installed", (event, arg) => {
|
||||
if (arg.success) {
|
||||
self.themes = ipcRenderer.sendSync("get-themes")
|
||||
self.getInstalledThemes()
|
||||
notyf.success(app.getLz('settings.notyf.visual.theme.install.success'));
|
||||
} else {
|
||||
notyf.error(app.getLz('settings.notyf.visual.theme.install.error'));
|
||||
}
|
||||
});
|
||||
ipcRenderer.invoke("get-github-theme", repo.html_url)
|
||||
}
|
||||
})
|
||||
},
|
||||
installThemeURL() {
|
||||
let self = this
|
||||
app.prompt(app.getLz('settings.prompt.visual.theme.github.URL'), (result) => {
|
||||
if (result) {
|
||||
ipcRenderer.once("theme-installed", (event, arg) => {
|
||||
if (arg.success) {
|
||||
self.themes = ipcRenderer.sendSync("get-themes")
|
||||
notyf.success(app.getLz('settings.notyf.visual.theme.install.success'));
|
||||
} else {
|
||||
notyf.error(app.getLz('settings.notyf.visual.theme.install.error'));
|
||||
}
|
||||
});
|
||||
ipcRenderer.invoke("get-github-theme", result)
|
||||
}
|
||||
});
|
||||
},
|
||||
getRepos() {
|
||||
let self = this
|
||||
var requestOptions = {
|
||||
method: 'GET',
|
||||
redirect: 'follow'
|
||||
};
|
||||
|
||||
fetch("https://api.github.com/search/repositories?q=topic:cidermusictheme fork:true", requestOptions)
|
||||
.then(response => response.text())
|
||||
.then(result => {
|
||||
let items = JSON.parse(result).items
|
||||
self.repos = items
|
||||
})
|
||||
.catch(error => console.log('error', error));
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
<b-tab>
|
||||
<template #title>
|
||||
<div>
|
||||
<svg-icon url="./assets/settings.svg" classes="svg-md" name="settings-general"/>
|
||||
<svg-icon url="./assets/settings.svg" classes="svg-md" name="settings-general" />
|
||||
</div>
|
||||
<div>
|
||||
{{ $root.getLz('settings.header.general') }}
|
||||
|
@ -61,7 +61,7 @@
|
|||
<label>
|
||||
<input type="checkbox" v-model="$root.cfg.general.privateEnabled"
|
||||
v-on:change="$root.mk.privateEnabled = $root.cfg.general.privateEnabled"
|
||||
switch/>
|
||||
switch />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -71,7 +71,7 @@
|
|||
</div>
|
||||
<div class="md-option-segment md-option-segment_auto">
|
||||
<label>
|
||||
<input type="checkbox" v-model="app.cfg.general.onStartup.enabled" switch/>
|
||||
<input type="checkbox" v-model="app.cfg.general.onStartup.enabled" switch />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -81,7 +81,7 @@
|
|||
</div>
|
||||
<div class="md-option-segment md-option-segment_auto">
|
||||
<label>
|
||||
<input type="checkbox" v-model="app.cfg.general.onStartup.hidden" switch/>
|
||||
<input type="checkbox" v-model="app.cfg.general.onStartup.hidden" switch />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -163,7 +163,7 @@
|
|||
<label>
|
||||
<input type="checkbox"
|
||||
v-model="app.cfg.general.sidebarItems.recentlyAdded"
|
||||
switch/>
|
||||
switch />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -175,7 +175,7 @@
|
|||
<label>
|
||||
<input type="checkbox"
|
||||
v-model="app.cfg.general.sidebarItems.songs"
|
||||
switch/>
|
||||
switch />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -187,7 +187,7 @@
|
|||
<label>
|
||||
<input type="checkbox"
|
||||
v-model="app.cfg.general.sidebarItems.albums"
|
||||
switch/>
|
||||
switch />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -199,7 +199,7 @@
|
|||
<label>
|
||||
<input type="checkbox"
|
||||
v-model="app.cfg.general.sidebarItems.artists"
|
||||
switch/>
|
||||
switch />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -211,7 +211,7 @@
|
|||
<label>
|
||||
<input type="checkbox"
|
||||
v-model="app.cfg.general.sidebarItems.videos"
|
||||
switch/>
|
||||
switch />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -223,7 +223,7 @@
|
|||
<label>
|
||||
<input type="checkbox"
|
||||
v-model="app.cfg.general.sidebarItems.podcasts"
|
||||
switch/>
|
||||
switch />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -247,7 +247,7 @@
|
|||
<div class="md-option-segment md-option-segment_auto">
|
||||
<label>
|
||||
<input type="checkbox" v-model="app.cfg.general.themeUpdateNotification"
|
||||
switch/>
|
||||
switch />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -258,7 +258,7 @@
|
|||
<div class="md-option-segment md-option-segment_auto">
|
||||
<label>
|
||||
<input type="checkbox" v-model="app.cfg.general.showLovedTracksInline"
|
||||
switch/>
|
||||
switch />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -279,7 +279,7 @@
|
|||
<b-tab>
|
||||
<template #title>
|
||||
<div>
|
||||
<svg-icon url="./assets/feather/headphones.svg" classes="svg-md" name="settings-audio"/>
|
||||
<svg-icon url="./assets/feather/headphones.svg" classes="svg-md" name="settings-audio" />
|
||||
</div>
|
||||
<div>
|
||||
{{ $root.getLz('settings.header.audio') }}
|
||||
|
@ -343,7 +343,7 @@
|
|||
<label>
|
||||
<input type="checkbox" v-model="app.cfg.audio.seamless_audio"
|
||||
v-on:change="app.mk._bag.features['seamless-audio-transitions'] = app.cfg.audio.seamless_audio"
|
||||
switch/>
|
||||
switch />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -372,7 +372,7 @@
|
|||
<input type="checkbox" v-model="app.cfg.audio.normalization"
|
||||
v-on:change="toggleNormalization"
|
||||
: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/>
|
||||
switch />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -385,7 +385,7 @@
|
|||
</div>
|
||||
<div class="md-option-segment md-option-segment_auto">
|
||||
<label>
|
||||
<input type="checkbox" v-model="app.cfg.audio.dBSPL" switch/>
|
||||
<input type="checkbox" v-model="app.cfg.audio.dBSPL" switch />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -397,7 +397,7 @@
|
|||
</div>
|
||||
<div class="md-option-segment md-option-segment_auto">
|
||||
<label>
|
||||
<input type="number" v-model="app.cfg.audio.dBSPLcalibration"/>
|
||||
<input type="number" v-model="app.cfg.audio.dBSPLcalibration" />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -408,33 +408,33 @@
|
|||
<b-tab>
|
||||
<template #title>
|
||||
<div>
|
||||
<svg-icon url="./assets/feather/zap.svg" classes="svg-md" name="settings-audiolabs"/>
|
||||
<svg-icon url="./assets/feather/zap.svg" classes="svg-md" name="settings-audiolabs" />
|
||||
</div>
|
||||
<div>
|
||||
{{ $root.getLz('settings.option.audio.audioLab') }}
|
||||
</div>
|
||||
</template>
|
||||
<div class="settings-tab-content">
|
||||
<audiolabs-page/>
|
||||
<audiolabs-page />
|
||||
</div>
|
||||
</b-tab>
|
||||
<b-tab>
|
||||
<template #title>
|
||||
<div>
|
||||
<svg-icon url="./assets/feather/style.svg" classes="svg-md" name="settings-styles"/>
|
||||
<svg-icon url="./assets/feather/style.svg" classes="svg-md" name="settings-styles" />
|
||||
</div>
|
||||
<div>
|
||||
{{ $root.getLz('settings.header.visual.styles') }}
|
||||
</div>
|
||||
</template>
|
||||
<div class="settings-tab-content">
|
||||
<installed-themes/>
|
||||
<installed-themes />
|
||||
</div>
|
||||
</b-tab>
|
||||
<b-tab>
|
||||
<template #title>
|
||||
<div>
|
||||
<svg-icon url="./assets/feather/pen-tool.svg" classes="svg-md" name="settings-visual"/>
|
||||
<svg-icon url="./assets/feather/pen-tool.svg" classes="svg-md" name="settings-visual" />
|
||||
</div>
|
||||
<div>
|
||||
{{ $root.getLz('settings.header.visual') }}
|
||||
|
@ -504,7 +504,7 @@
|
|||
{{$root.getLz('settings.option.visual.windowColor')}}
|
||||
</div>
|
||||
<div class="md-option-segment_auto">
|
||||
<input type="color" v-model="app.cfg.visual.windowColor"/>
|
||||
<input type="color" v-model="app.cfg.visual.windowColor" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="md-option-line">
|
||||
|
@ -513,7 +513,7 @@
|
|||
</div>
|
||||
<div class="md-option-segment_auto">
|
||||
<input type="checkbox" v-model="app.cfg.visual.customAccentColor"
|
||||
:disabled="app.cfg.visual.purplePodcastPlaybackBar" switch/>
|
||||
:disabled="app.cfg.visual.purplePodcastPlaybackBar" switch />
|
||||
</div>
|
||||
</div>
|
||||
<div class="md-option-line child" v-if="app.cfg.visual.customAccentColor">
|
||||
|
@ -521,7 +521,7 @@
|
|||
{{$root.getLz('settings.option.visual.accentColor')}}
|
||||
</div>
|
||||
<div class="md-option-segment_auto">
|
||||
<input type="color" v-model="app.cfg.visual.accentColor"/>
|
||||
<input type="color" v-model="app.cfg.visual.accentColor" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="md-option-line">
|
||||
|
@ -530,7 +530,7 @@
|
|||
</div>
|
||||
<div class="md-option-segment_auto">
|
||||
<input type="checkbox" v-model="app.cfg.visual.purplePodcastPlaybackBar"
|
||||
:disabled="app.cfg.visual.customAccentColor" switch/>
|
||||
:disabled="app.cfg.visual.customAccentColor" switch />
|
||||
</div>
|
||||
</div>
|
||||
<div class="md-option-line">
|
||||
|
@ -538,7 +538,7 @@
|
|||
{{$root.getLz('settings.option.visual.compactArtistHeader')}}
|
||||
</div>
|
||||
<div class="md-option-segment_auto">
|
||||
<input type="checkbox" v-model="app.cfg.visual.compactArtistHeader" switch/>
|
||||
<input type="checkbox" v-model="app.cfg.visual.compactArtistHeader" switch />
|
||||
</div>
|
||||
</div>
|
||||
<div class="md-option-line">
|
||||
|
@ -569,7 +569,7 @@
|
|||
<div class="md-option-segment md-option-segment_auto">
|
||||
<label>
|
||||
<input type="checkbox" v-model="app.cfg.visual.showuserinfo"
|
||||
v-on:change="toggleUserInfo" switch/>
|
||||
v-on:change="toggleUserInfo" switch />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -604,7 +604,7 @@
|
|||
</div>
|
||||
<div class="md-option-segment md-option-segment_auto">
|
||||
<label>
|
||||
<input type="checkbox" v-model="app.cfg.general.close_button_hide" switch/>
|
||||
<input type="checkbox" v-model="app.cfg.general.close_button_hide" switch />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -616,7 +616,7 @@
|
|||
<div class="md-option-segment md-option-segment_auto">
|
||||
<label>
|
||||
<input type="checkbox" v-model="app.cfg.visual.nativeTitleBar" switch
|
||||
@change="promptForRelaunch()"/>
|
||||
@change="promptForRelaunch()" />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -697,7 +697,8 @@
|
|||
</div>
|
||||
<div class="md-option-segment md-option-segment_auto">
|
||||
<label>
|
||||
<input type="checkbox" switch v-model="app.cfg.visual.bg_artwork_rotation"/>
|
||||
<input type="checkbox" switch
|
||||
v-model="app.cfg.visual.bg_artwork_rotation" />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -708,20 +709,20 @@
|
|||
<b-tab>
|
||||
<template #title>
|
||||
<div>
|
||||
<svg-icon url="./assets/feather/plugins.svg" classes="svg-md" name="settings-plugins"/>
|
||||
<svg-icon url="./assets/feather/plugins.svg" classes="svg-md" name="settings-plugins" />
|
||||
</div>
|
||||
<div>
|
||||
{{ $root.getLz('term.plugins') }}
|
||||
</div>
|
||||
</template>
|
||||
<div class="settings-tab-content">
|
||||
<plugins-github/>
|
||||
<plugins-github />
|
||||
</div>
|
||||
</b-tab>
|
||||
<b-tab>
|
||||
<template #title>
|
||||
<div>
|
||||
<svg-icon url="./assets/feather/mic.svg" classes="svg-md" name="settings-lyrics"/>
|
||||
<svg-icon url="./assets/feather/mic.svg" classes="svg-md" name="settings-lyrics" />
|
||||
</div>
|
||||
<div>
|
||||
{{ $root.getLz('settings.header.lyrics') }}
|
||||
|
@ -740,7 +741,7 @@
|
|||
</div>
|
||||
<div class="md-option-segment md-option-segment_auto">
|
||||
<label>
|
||||
<input type="checkbox" v-model="app.cfg.lyrics.enable_mxm" switch/>
|
||||
<input type="checkbox" v-model="app.cfg.lyrics.enable_mxm" switch />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -750,7 +751,7 @@
|
|||
</div>
|
||||
<div class="md-option-segment md-option-segment_auto">
|
||||
<label>
|
||||
<input type="checkbox" v-model="app.cfg.lyrics.mxm_karaoke" switch/>
|
||||
<input type="checkbox" v-model="app.cfg.lyrics.mxm_karaoke" switch />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -844,7 +845,7 @@
|
|||
</div>
|
||||
<div class="md-option-segment md-option-segment_auto">
|
||||
<label>
|
||||
<input type="checkbox" v-model="app.cfg.lyrics.enable_yt" switch/>
|
||||
<input type="checkbox" v-model="app.cfg.lyrics.enable_yt" switch />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -854,7 +855,7 @@
|
|||
</div>
|
||||
<div class="md-option-segment md-option-segment_auto">
|
||||
<label>
|
||||
<input type="checkbox" v-model="app.cfg.lyrics.enable_qq" switch/>
|
||||
<input type="checkbox" v-model="app.cfg.lyrics.enable_qq" switch />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -865,7 +866,7 @@
|
|||
<b-tab>
|
||||
<template #title>
|
||||
<div>
|
||||
<svg-icon url="./assets/feather/radio.svg" classes="svg-md" name="settings-connectivity"/>
|
||||
<svg-icon url="./assets/feather/radio.svg" classes="svg-md" name="settings-connectivity" />
|
||||
</div>
|
||||
<div>
|
||||
{{ $root.getLz('settings.header.connectivity') }}
|
||||
|
@ -886,7 +887,7 @@
|
|||
<div class="md-option-segment md-option-segment_auto">
|
||||
<label>
|
||||
<input type="checkbox" v-model="app.cfg.general.playbackNotifications"
|
||||
switch/>
|
||||
switch />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -899,7 +900,7 @@
|
|||
<div class="md-option-segment md-option-segment_auto">
|
||||
<label>
|
||||
<input type="checkbox" v-model="app.cfg.connectivity.discord_rpc.enabled"
|
||||
switch/>
|
||||
switch />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -926,7 +927,7 @@
|
|||
<div class="md-option-segment md-option-segment_auto">
|
||||
<label>
|
||||
<input type="checkbox"
|
||||
v-model="app.cfg.connectivity.discord_rpc.clear_on_pause" switch/>
|
||||
v-model="app.cfg.connectivity.discord_rpc.clear_on_pause" switch />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -938,7 +939,7 @@
|
|||
<div class="md-option-segment md-option-segment_auto">
|
||||
<label>
|
||||
<input type="checkbox"
|
||||
v-model="app.cfg.connectivity.discord_rpc.hide_buttons" switch/>
|
||||
v-model="app.cfg.connectivity.discord_rpc.hide_buttons" switch />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -950,14 +951,14 @@
|
|||
<div class="md-option-segment md-option-segment_auto">
|
||||
<label>
|
||||
<input type="checkbox"
|
||||
v-model="app.cfg.connectivity.discord_rpc.hide_timestamp" switch/>
|
||||
v-model="app.cfg.connectivity.discord_rpc.hide_timestamp" switch />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="md-option-line" v-show="app.cfg.connectivity.discord_rpc.enabled != false">
|
||||
<div class="md-option-segment">
|
||||
{{$root.getLz('settings.option.connectivity.discordRPC.detailsFormat')}}<br/>
|
||||
{{$root.getLz('settings.option.connectivity.discordRPC.detailsFormat')}}<br />
|
||||
<small>{{$root.getLz('term.variables')}}: {artist}, {composer}, {title},
|
||||
{album},
|
||||
{trackNumber}</small>
|
||||
|
@ -965,7 +966,7 @@
|
|||
<div class="md-option-segment md-option-segment_auto">
|
||||
<label>
|
||||
<input type="text"
|
||||
v-model="app.cfg.connectivity.discord_rpc.details_format"/>
|
||||
v-model="app.cfg.connectivity.discord_rpc.details_format" />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -979,7 +980,8 @@
|
|||
</div>
|
||||
<div class="md-option-segment md-option-segment_auto">
|
||||
<label>
|
||||
<input type="text" v-model="app.cfg.connectivity.discord_rpc.state_format"/>
|
||||
<input type="text"
|
||||
v-model="app.cfg.connectivity.discord_rpc.state_format" />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1018,9 +1020,9 @@
|
|||
<div class="md-option-segment md-option-segment_auto">
|
||||
<label>
|
||||
<form @submit.prevent="submitToken">
|
||||
<input type="text" autofocus id="lfmToken"/>
|
||||
<input type="text" autofocus id="lfmToken" />
|
||||
<input type="submit" class="md-btn"
|
||||
@value="$root.getLz('action.submit')"/>
|
||||
@value="$root.getLz('action.submit')" />
|
||||
</form>
|
||||
</label>
|
||||
</div>
|
||||
|
@ -1032,7 +1034,7 @@
|
|||
<div class="md-option-segment md-option-segment_auto">
|
||||
<label>
|
||||
<input type="number" min="50" max="100"
|
||||
v-model="app.cfg.connectivity.lastfm.scrobble_after"/>
|
||||
v-model="app.cfg.connectivity.lastfm.scrobble_after" />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1044,7 +1046,7 @@
|
|||
<div class="md-option-segment md-option-segment_auto">
|
||||
<label>
|
||||
<input type="checkbox" v-model="app.cfg.connectivity.lastfm.filter_loop"
|
||||
switch/>
|
||||
switch />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1055,7 +1057,7 @@
|
|||
<div class="md-option-segment md-option-segment_auto">
|
||||
<label>
|
||||
<input type="checkbox" v-model="app.cfg.connectivity.lastfm.remove_featured"
|
||||
switch/>
|
||||
switch />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1077,7 +1079,7 @@
|
|||
<b-tab>
|
||||
<template #title>
|
||||
<div>
|
||||
<svg-icon url="./assets/feather/hard-drive.svg" classes="svg-md" name="settings-advanced"/>
|
||||
<svg-icon url="./assets/feather/hard-drive.svg" classes="svg-md" name="settings-advanced" />
|
||||
</div>
|
||||
<div>
|
||||
{{$root.getLz('settings.header.advanced')}}
|
||||
|
@ -1118,7 +1120,7 @@
|
|||
</div>
|
||||
<div class="md-option-segment md-option-segment_auto">
|
||||
<label>
|
||||
<input type="checkbox" v-model="app.cfg.advanced.disableLogging" switch/>
|
||||
<input type="checkbox" v-model="app.cfg.advanced.disableLogging" switch />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1161,7 +1163,7 @@
|
|||
<input type="checkbox"
|
||||
v-model="app.cfg.advanced.experiments.includes('immersive-preview')"
|
||||
@click="app.cfg.advanced.experiments.includes('immersive-preview') ? removeExperiment('immersive-preview') : addExperiment('immersive-preview')"
|
||||
switch/>
|
||||
switch />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1177,7 +1179,7 @@
|
|||
<input type="checkbox"
|
||||
v-model="app.cfg.advanced.experiments.includes('unknown-sources')"
|
||||
@click="app.cfg.advanced.experiments.includes('unknown-sources') ? removeExperiment('unknown-sources') : addExperiment('unknown-sources')"
|
||||
switch/>
|
||||
switch />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1192,7 +1194,7 @@
|
|||
<input type="checkbox"
|
||||
v-model="app.cfg.advanced.experiments.includes('ampv3')"
|
||||
@click="app.cfg.advanced.experiments.includes('ampv3') ? removeExperiment('ampv3') : addExperiment('ampv3')"
|
||||
switch/>
|
||||
switch />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1206,7 +1208,7 @@
|
|||
<div class="md-option-segment md-option-segment_auto">
|
||||
<label>
|
||||
<input type="checkbox" v-model="app.cfg.advanced.playlistTrackMapping"
|
||||
switch/>
|
||||
switch />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1221,7 +1223,7 @@
|
|||
<input type="checkbox"
|
||||
v-model="app.cfg.advanced.experiments.includes('compactui')"
|
||||
@click="app.cfg.advanced.experiments.includes('compactui') ? removeExperiment('compactui') : addExperiment('compactui')"
|
||||
switch :disabled="!!app.getThemeDirective('forceUI')"/>
|
||||
switch :disabled="!!app.getThemeDirective('forceUI')" />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1235,7 +1237,7 @@
|
|||
<input type="checkbox" disabled
|
||||
v-model="app.cfg.advanced.experiments.includes('inline-playlists')"
|
||||
@click="app.cfg.advanced.experiments.includes('inline-playlists') ? removeExperiment('inline-playlists') : addExperiment('inline-playlists')"
|
||||
switch/>
|
||||
switch />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1248,7 +1250,7 @@
|
|||
<div class="md-option-segment md-option-segment_auto">
|
||||
<label>
|
||||
<input type="checkbox" v-model="app.cfg.visual.transparent" switch
|
||||
@change="promptForRelaunch()"/>
|
||||
@change="promptForRelaunch()" />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1280,14 +1282,14 @@
|
|||
<!--keybinds Settings -->
|
||||
<b-tab id="hid">
|
||||
<template>
|
||||
<keybinds-settings/>
|
||||
<keybinds-settings />
|
||||
</template>
|
||||
</b-tab>
|
||||
<!--keybinds-settings -->
|
||||
<!--Github-theme-settings -->
|
||||
<b-tab id="hid">
|
||||
<template>
|
||||
<themes-github/>
|
||||
<themes-github />
|
||||
</template>
|
||||
</b-tab>
|
||||
<!--Github-theme-settings -->
|
||||
|
@ -1383,164 +1385,164 @@
|
|||
</div>
|
||||
</script>
|
||||
<script>
|
||||
Vue.component("settings-window", {
|
||||
template: "#settings-window",
|
||||
data: function () {
|
||||
return {
|
||||
app: this.$root,
|
||||
themes: ipcRenderer.sendSync("get-themes"),
|
||||
tabIndex: 0,
|
||||
canChangeHash: false,
|
||||
lastfmConnecting: false
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
tabIndex: function (val) {
|
||||
if (this.canChangeHash) {
|
||||
// window.location.hash = `#settings/${val}`
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
sidebarVis() {
|
||||
const tabIndex = app.$store.state.pageState['settings'].currentTabIndex
|
||||
if (tabIndex == 3 || tabIndex == 5 || tabIndex == 10) {
|
||||
return true;
|
||||
}
|
||||
return false
|
||||
},
|
||||
close() {
|
||||
this.$root.modals.settings = false
|
||||
},
|
||||
windowBgStyleChange() {
|
||||
this.$root.getNowPlayingArtworkBG(undefined, true)
|
||||
if (this.$root.cfg.visual.window_background_style === "mica") {
|
||||
this.$root.spawnMica()
|
||||
}
|
||||
},
|
||||
reinstallWidevineCDM() {
|
||||
app.confirm(app.getLz("settings.option.experimental.reinstallwidevine.confirm"), (ok) => {
|
||||
if (ok) {
|
||||
ipcRenderer.invoke("reinstall-widevine-cdm");
|
||||
}
|
||||
})
|
||||
},
|
||||
gitHubExplore() {
|
||||
app.openSettingsPage("github-themes")
|
||||
},
|
||||
copyLogs() {
|
||||
ipcRenderer.send('fetch-log')
|
||||
notyf.success(app.getLz('term.share.success'));
|
||||
},
|
||||
openAppData() {
|
||||
ipcRenderer.send('open-appdata')
|
||||
},
|
||||
getLanguages: function () {
|
||||
let langs = this.$root.lzListing
|
||||
let categories = {
|
||||
"main": [],
|
||||
"fun": [],
|
||||
"unsorted": []
|
||||
}
|
||||
// sort by category if category is undefined or empty put it in "unsorted"
|
||||
for (let i = 0; i < langs.length; i++) {
|
||||
if (langs[i].category === undefined || langs[i].category === "") {
|
||||
categories.unsorted.push(langs[i])
|
||||
} else {
|
||||
categories[langs[i].category].push(langs[i])
|
||||
}
|
||||
}
|
||||
// return
|
||||
return categories
|
||||
},
|
||||
addExperiment(flag) {
|
||||
app.cfg.advanced.experiments.push(flag);
|
||||
},
|
||||
removeExperiment(flag) {
|
||||
app.cfg.advanced.experiments.splice(app.cfg.advanced.experiments.indexOf(flag), 1);
|
||||
},
|
||||
toggleNormalization: function () {
|
||||
if (app.cfg.audio.normalization) {
|
||||
CiderAudio.normalizerOn()
|
||||
} else {
|
||||
CiderAudio.normalizerOff()
|
||||
}
|
||||
},
|
||||
changeAudioQuality: function () {
|
||||
app.mk.bitrate = MusicKit.PlaybackBitrate[app.cfg.audio.quality];
|
||||
},
|
||||
toggleUserInfo: function () {
|
||||
app.chrome.hideUserInfo = !app.cfg.visual.showuserinfo
|
||||
},
|
||||
sendDataToMTT: function () {
|
||||
ipcRenderer.invoke('setStoreValue', 'general.close_behavior', app.cfg.general.close_behavior);
|
||||
// setStoreValue does not change plugin store values somehow
|
||||
ipcRenderer.invoke('update-store-mtt', app.cfg.general.close_behavior);
|
||||
},
|
||||
checkIfUpdateDisabled() {
|
||||
if (app.cfg.main.UPDATABLE) return;
|
||||
|
||||
let updateFields = document.getElementsByClassName('update-check');
|
||||
for (let i = 0; i < updateFields.length; i++) {
|
||||
updateFields[i].style = "opacity: 0.5; pointer-events: none;";
|
||||
updateFields[i].title = "Not available on this type of build";
|
||||
}
|
||||
|
||||
},
|
||||
promptForRelaunch() {
|
||||
app.confirm(app.getLz('action.relaunch.confirm'), function (result) {
|
||||
if (result) {
|
||||
ipcRenderer.send('relaunchApp', '');
|
||||
}
|
||||
});
|
||||
},
|
||||
authCC() {
|
||||
ipcRenderer.send('cc-auth')
|
||||
},
|
||||
logoutCC() {
|
||||
ipcRenderer.send('cc-logout')
|
||||
},
|
||||
reloadDiscordRPC() {
|
||||
ipcRenderer.send('reloadRPC')
|
||||
},
|
||||
lfmDisconnect() {
|
||||
this.$root.cfg.connectivity.lastfm.enabled = false;
|
||||
this.$root.cfg.connectivity.lastfm.secrets.username = "";
|
||||
this.$root.cfg.connectivity.lastfm.secrets.key = "";
|
||||
ipcRenderer.send('lastfm:disconnect');
|
||||
},
|
||||
async lfmAuthorize() {
|
||||
this.lastfmConnecting = true;
|
||||
window.open(await ipcRenderer.invoke('lastfm:url'));
|
||||
app.notyf.success(app.getLz('settings.notyf.connectivity.lastfmScrobble.connecting'));
|
||||
|
||||
/* Just a timeout for the button */
|
||||
setTimeout(() => {
|
||||
if (!this.$root.cfg.connectivity.lastfm.enabled) {
|
||||
app.notyf.error(app.getLz('settings.notyf.connectivity.lastfmScrobble.connectError'));
|
||||
console.warn('[lastfm:authorize] Last.fm authorization timed out.');
|
||||
this.lastfmConnecting = false;
|
||||
}
|
||||
}, 20000);
|
||||
|
||||
ipcRenderer.once('lastfm:authenticated', (_e, session) => {
|
||||
this.$root.cfg.connectivity.lastfm.secrets.username = session.username
|
||||
this.$root.cfg.connectivity.lastfm.secrets.key = session.key
|
||||
this.$root.cfg.connectivity.lastfm.enabled = true
|
||||
this.lastfmConnecting = false;
|
||||
app.notyf.success(app.getLz('settings.notyf.connectivity.lastfmScrobble.connectSuccess'));
|
||||
})
|
||||
},
|
||||
filterChange(e) {
|
||||
this.$root.cfg.connectivity.lastfm.filter_types[e.target.value] = e.target.checked;
|
||||
},
|
||||
submitToken() {
|
||||
const token = document.getElementById('lfmToken').value;
|
||||
ipcRenderer.send('lastfm:auth', token);
|
||||
},
|
||||
openLocalSongsPathMenu() {
|
||||
app.modals.pathMenu = true
|
||||
}
|
||||
Vue.component("settings-window", {
|
||||
template: "#settings-window",
|
||||
data: function() {
|
||||
return {
|
||||
app: this.$root,
|
||||
themes: ipcRenderer.sendSync("get-themes"),
|
||||
tabIndex: 0,
|
||||
canChangeHash: false,
|
||||
lastfmConnecting: false
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
tabIndex: function(val) {
|
||||
if (this.canChangeHash) {
|
||||
// window.location.hash = `#settings/${val}`
|
||||
}
|
||||
})
|
||||
</script>
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
sidebarVis() {
|
||||
const tabIndex = app.$store.state.pageState['settings'].currentTabIndex
|
||||
if (tabIndex == 3 || tabIndex == 5 || tabIndex == 10) {
|
||||
return true;
|
||||
}
|
||||
return false
|
||||
},
|
||||
close() {
|
||||
this.$root.modals.settings = false
|
||||
},
|
||||
windowBgStyleChange() {
|
||||
this.$root.getNowPlayingArtworkBG(undefined, true)
|
||||
if (this.$root.cfg.visual.window_background_style === "mica") {
|
||||
this.$root.spawnMica()
|
||||
}
|
||||
},
|
||||
reinstallWidevineCDM() {
|
||||
app.confirm(app.getLz("settings.option.experimental.reinstallwidevine.confirm"), (ok) => {
|
||||
if (ok) {
|
||||
ipcRenderer.invoke("reinstall-widevine-cdm");
|
||||
}
|
||||
})
|
||||
},
|
||||
gitHubExplore() {
|
||||
app.openSettingsPage("github-themes")
|
||||
},
|
||||
copyLogs() {
|
||||
ipcRenderer.send('fetch-log')
|
||||
notyf.success(app.getLz('term.share.success'));
|
||||
},
|
||||
openAppData() {
|
||||
ipcRenderer.send('open-appdata')
|
||||
},
|
||||
getLanguages: function() {
|
||||
let langs = this.$root.lzListing
|
||||
let categories = {
|
||||
"main": [],
|
||||
"fun": [],
|
||||
"unsorted": []
|
||||
}
|
||||
// sort by category if category is undefined or empty put it in "unsorted"
|
||||
for (let i = 0; i < langs.length; i++) {
|
||||
if (langs[i].category === undefined || langs[i].category === "") {
|
||||
categories.unsorted.push(langs[i])
|
||||
} else {
|
||||
categories[langs[i].category].push(langs[i])
|
||||
}
|
||||
}
|
||||
// return
|
||||
return categories
|
||||
},
|
||||
addExperiment(flag) {
|
||||
app.cfg.advanced.experiments.push(flag);
|
||||
},
|
||||
removeExperiment(flag) {
|
||||
app.cfg.advanced.experiments.splice(app.cfg.advanced.experiments.indexOf(flag), 1);
|
||||
},
|
||||
toggleNormalization: function() {
|
||||
if (app.cfg.audio.normalization) {
|
||||
CiderAudio.normalizerOn()
|
||||
} else {
|
||||
CiderAudio.normalizerOff()
|
||||
}
|
||||
},
|
||||
changeAudioQuality: function() {
|
||||
app.mk.bitrate = MusicKit.PlaybackBitrate[app.cfg.audio.quality];
|
||||
},
|
||||
toggleUserInfo: function() {
|
||||
app.chrome.hideUserInfo = !app.cfg.visual.showuserinfo
|
||||
},
|
||||
sendDataToMTT: function() {
|
||||
ipcRenderer.invoke('setStoreValue', 'general.close_behavior', app.cfg.general.close_behavior);
|
||||
// setStoreValue does not change plugin store values somehow
|
||||
ipcRenderer.invoke('update-store-mtt', app.cfg.general.close_behavior);
|
||||
},
|
||||
checkIfUpdateDisabled() {
|
||||
if (app.cfg.main.UPDATABLE) return;
|
||||
|
||||
let updateFields = document.getElementsByClassName('update-check');
|
||||
for (let i = 0; i < updateFields.length; i++) {
|
||||
updateFields[i].style = "opacity: 0.5; pointer-events: none;";
|
||||
updateFields[i].title = "Not available on this type of build";
|
||||
}
|
||||
|
||||
},
|
||||
promptForRelaunch() {
|
||||
app.confirm(app.getLz('action.relaunch.confirm'), function(result) {
|
||||
if (result) {
|
||||
ipcRenderer.send('relaunchApp', '');
|
||||
}
|
||||
});
|
||||
},
|
||||
authCC() {
|
||||
ipcRenderer.send('cc-auth')
|
||||
},
|
||||
logoutCC() {
|
||||
ipcRenderer.send('cc-logout')
|
||||
},
|
||||
reloadDiscordRPC() {
|
||||
ipcRenderer.send('reloadRPC')
|
||||
},
|
||||
lfmDisconnect() {
|
||||
this.$root.cfg.connectivity.lastfm.enabled = false;
|
||||
this.$root.cfg.connectivity.lastfm.secrets.username = "";
|
||||
this.$root.cfg.connectivity.lastfm.secrets.key = "";
|
||||
ipcRenderer.send('lastfm:disconnect');
|
||||
},
|
||||
async lfmAuthorize() {
|
||||
this.lastfmConnecting = true;
|
||||
window.open(await ipcRenderer.invoke('lastfm:url'));
|
||||
app.notyf.success(app.getLz('settings.notyf.connectivity.lastfmScrobble.connecting'));
|
||||
|
||||
/* Just a timeout for the button */
|
||||
setTimeout(() => {
|
||||
if (!this.$root.cfg.connectivity.lastfm.enabled) {
|
||||
app.notyf.error(app.getLz('settings.notyf.connectivity.lastfmScrobble.connectError'));
|
||||
console.warn('[lastfm:authorize] Last.fm authorization timed out.');
|
||||
this.lastfmConnecting = false;
|
||||
}
|
||||
}, 20000);
|
||||
|
||||
ipcRenderer.once('lastfm:authenticated', (_e, session) => {
|
||||
this.$root.cfg.connectivity.lastfm.secrets.username = session.username
|
||||
this.$root.cfg.connectivity.lastfm.secrets.key = session.key
|
||||
this.$root.cfg.connectivity.lastfm.enabled = true
|
||||
this.lastfmConnecting = false;
|
||||
app.notyf.success(app.getLz('settings.notyf.connectivity.lastfmScrobble.connectSuccess'));
|
||||
})
|
||||
},
|
||||
filterChange(e) {
|
||||
this.$root.cfg.connectivity.lastfm.filter_types[e.target.value] = e.target.checked;
|
||||
},
|
||||
submitToken() {
|
||||
const token = document.getElementById('lfmToken').value;
|
||||
ipcRenderer.send('lastfm:auth', token);
|
||||
},
|
||||
openLocalSongsPathMenu() {
|
||||
app.modals.pathMenu = true
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
<script type="text/x-template" id="add-to-playlist">
|
||||
<template>
|
||||
<div class="modal-fullscreen addtoplaylist-panel" @click.self="app.resetState()" @contextmenu.self="app.resetState()">
|
||||
<div class="modal-fullscreen addtoplaylist-panel" @click.self="app.resetState()"
|
||||
@contextmenu.self="app.resetState()">
|
||||
<div class="modal-window">
|
||||
<div class="modal-header">
|
||||
<div class="modal-title">{{app.getLz('action.addToPlaylist')}}</div>
|
||||
<button class="close-btn" @click="app.resetState()" :aria-label="app.getLz('action.close')"></button>
|
||||
<button class="close-btn" @click="app.resetState()"
|
||||
:aria-label="app.getLz('action.close')"></button>
|
||||
</div>
|
||||
<div class="modal-content">
|
||||
<button class="playlist-item"
|
||||
|
@ -12,7 +14,8 @@
|
|||
<div class="icon"><%- include("../svg/plus.svg") %></div>
|
||||
<div class="name">{{app.getLz('action.createPlaylist')}}</div>
|
||||
</button>
|
||||
<sidebar-playlist :playlist-select="playlistSelect" v-for="item in $root.getPlaylistFolderChildren('p.playlistsroot')" :item="item">
|
||||
<sidebar-playlist :playlist-select="playlistSelect"
|
||||
v-for="item in $root.getPlaylistFolderChildren('p.playlistsroot')" :item="item">
|
||||
</sidebar-playlist>
|
||||
</div>
|
||||
<div class="modal-search">
|
||||
|
@ -34,55 +37,55 @@
|
|||
</script>
|
||||
|
||||
<script>
|
||||
Vue.component('add-to-playlist', {
|
||||
template: '#add-to-playlist',
|
||||
data: function () {
|
||||
return {
|
||||
playlistSorted: [],
|
||||
searchQuery: "",
|
||||
focused: "",
|
||||
app: this.$root,
|
||||
}
|
||||
},
|
||||
props: {
|
||||
playlists: {
|
||||
type: Array,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.search()
|
||||
this.$refs.searchInput.focus()
|
||||
this.$refs.searchInput.addEventListener('keydown', (e) => {
|
||||
if (e.keyCode == 13) {
|
||||
if (this.focused != "") {
|
||||
this.addToPlaylist(this.focused)
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
playlistSelect(playlist) {
|
||||
if (playlist.type != "library-playlist-folders") {
|
||||
this.addToPlaylist(playlist.id)
|
||||
}
|
||||
},
|
||||
addToPlaylist(id) {
|
||||
app.addSelectedToPlaylist(id)
|
||||
},
|
||||
search() {
|
||||
this.focused = ""
|
||||
if (this.searchQuery == "") {
|
||||
this.playlistSorted = this.playlists
|
||||
} else {
|
||||
this.playlistSorted = this.playlists.filter(playlist => {
|
||||
return playlist.attributes.name.toLowerCase().indexOf(this.searchQuery.toLowerCase()) > -1
|
||||
})
|
||||
if (this.playlistSorted.length == 1) {
|
||||
this.focused = this.playlistSorted[0].id
|
||||
}
|
||||
}
|
||||
},
|
||||
Vue.component('add-to-playlist', {
|
||||
template: '#add-to-playlist',
|
||||
data: function() {
|
||||
return {
|
||||
playlistSorted: [],
|
||||
searchQuery: "",
|
||||
focused: "",
|
||||
app: this.$root,
|
||||
}
|
||||
},
|
||||
props: {
|
||||
playlists: {
|
||||
type: Array,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.search()
|
||||
this.$refs.searchInput.focus()
|
||||
this.$refs.searchInput.addEventListener('keydown', (e) => {
|
||||
if (e.keyCode == 13) {
|
||||
if (this.focused != "") {
|
||||
this.addToPlaylist(this.focused)
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
playlistSelect(playlist) {
|
||||
if (playlist.type != "library-playlist-folders") {
|
||||
this.addToPlaylist(playlist.id)
|
||||
}
|
||||
},
|
||||
addToPlaylist(id) {
|
||||
app.addSelectedToPlaylist(id)
|
||||
},
|
||||
search() {
|
||||
this.focused = ""
|
||||
if (this.searchQuery == "") {
|
||||
this.playlistSorted = this.playlists
|
||||
} else {
|
||||
this.playlistSorted = this.playlists.filter(playlist => {
|
||||
return playlist.attributes.name.toLowerCase().indexOf(this.searchQuery.toLowerCase()) > -1
|
||||
})
|
||||
if (this.playlistSorted.length == 1) {
|
||||
this.focused = this.playlistSorted[0].id
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<script type="text/x-template" id="sidebar-playlist">
|
||||
<div class="sidebar-playlist" :key="item.id">
|
||||
<button class="app-sidebar-item app-sidebar-item-playlist" :key="item.id"
|
||||
<button class="app-sidebar-item app-sidebar-item-playlist" :key="item.id"
|
||||
:class="item.type != 'library-playlist-folders' ? {'active': $root.page.includes(item.id)} : ['playlist-folder', {'folder-button-active': folderOpened}, isPlaylistSelected]"
|
||||
@contextmenu="playlistContextMenu($event, item.id)"
|
||||
@dragstart="startDrag($event, item)"
|
||||
|
@ -9,14 +9,17 @@
|
|||
:href="item.href"
|
||||
@click='clickEvent()'>
|
||||
<template v-if="!renaming">
|
||||
<svg-icon :url="icon" name="sidebar-playlist"/> {{ item.attributes.name }}
|
||||
<svg-icon :url="icon" name="sidebar-playlist" />
|
||||
{{ item.attributes.name }}
|
||||
<small class="presentNotice" v-if="hasRelatedMediaItems">(Track present)</small>
|
||||
</template>
|
||||
<input type="text" v-model="item.attributes.name" class="pl-rename-field" @blur="rename()" @keydown.enter="rename()" v-else>
|
||||
<input type="text" v-model="item.attributes.name" class="pl-rename-field" @blur="rename()"
|
||||
@keydown.enter="rename()" v-else>
|
||||
</button>
|
||||
<div class="folder-body" v-if="item.type === 'library-playlist-folders' && folderOpened">
|
||||
<template v-if="children.length != 0">
|
||||
<sidebar-playlist v-for="item in children" :relate-media-items="relateMediaItems" :playlist-select="playlistSelect" :item="item" :key="item.id"></sidebar-playlist>
|
||||
<sidebar-playlist v-for="item in children" :relate-media-items="relateMediaItems"
|
||||
:playlist-select="playlistSelect" :item="item" :key="item.id"></sidebar-playlist>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div class="spinner"></div>
|
||||
|
@ -26,263 +29,265 @@
|
|||
</script>
|
||||
|
||||
<script>
|
||||
Vue.component('sidebar-playlist', {
|
||||
template: '#sidebar-playlist',
|
||||
props: {
|
||||
item: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
playlistSelect: {
|
||||
type: Function,
|
||||
required: false
|
||||
},
|
||||
relateMediaItems: {
|
||||
type: Array,
|
||||
required: false,
|
||||
default() {
|
||||
return []
|
||||
}
|
||||
}
|
||||
},
|
||||
data: function () {
|
||||
return {
|
||||
folderOpened: false,
|
||||
children: [],
|
||||
playlistRoot: "p.playlistsroot",
|
||||
renaming: false,
|
||||
icon: "",
|
||||
hasRelatedMediaItems: false
|
||||
}
|
||||
},
|
||||
async mounted() {
|
||||
if (this.item.type !== "library-playlist-folders") {
|
||||
this.icon = ("./assets/feather/list.svg")
|
||||
} else {
|
||||
this.icon = ("./assets/feather/folder.svg")
|
||||
}
|
||||
let playlistMap = this.$root.playlists.trackMapping
|
||||
if (this.relateMediaItems.length != 0) {
|
||||
if (playlistMap[this.relateMediaItems[0]]) {
|
||||
if (playlistMap[this.relateMediaItems[0]].includes(this.item.id)) {
|
||||
this.hasRelatedMediaItems = true
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
clickEvent() {
|
||||
if (this.item.type != "library-playlist-folders") {
|
||||
if (this.playlistSelect) {
|
||||
this.playlistSelect(this.item)
|
||||
} else {
|
||||
this.openPlaylist(this.item)
|
||||
}
|
||||
} else {
|
||||
this.getPlaylistChildren(this.item)
|
||||
}
|
||||
},
|
||||
rename() {
|
||||
this.renaming = false
|
||||
|
||||
if (this.item.type === "library-playlist-folders") {
|
||||
this.$root.editPlaylistFolder(this.item.id, this.item.attributes.name)
|
||||
} else {
|
||||
this.$root.editPlaylist(this.item.id, this.item.attributes.name)
|
||||
}
|
||||
},
|
||||
async getChildren() {
|
||||
let self = this
|
||||
this.children = []
|
||||
this.children = this.$root.playlists.listing.filter(child => {
|
||||
if (child.parent == self.item.id) {
|
||||
return child
|
||||
}
|
||||
})
|
||||
},
|
||||
async move(item, sendTo) {
|
||||
let self = this
|
||||
console.log(sendTo)
|
||||
let type = item.type.replace("library-", "")
|
||||
let typeTo = sendTo.type
|
||||
this.$root.mk.api.v3.music(`/v1/me/library/${type}/${item.id}/parent`, {}, {
|
||||
fetchOptions: {
|
||||
method: "PUT",
|
||||
body: JSON.stringify({
|
||||
data: [{
|
||||
id: sendTo.id,
|
||||
type: typeTo
|
||||
}]
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
// find the item in this.$root.playlists.listing and store it in a variable
|
||||
this.$root.playlists.listing.filter(playlist => {
|
||||
if (playlist.id == item.id) {
|
||||
console.log(playlist)
|
||||
playlist.parent = sendTo.id
|
||||
|
||||
}
|
||||
})
|
||||
if (typeof this.$root.getChildren == "function") {
|
||||
this.$root.getChildren()
|
||||
console.log(this.$root.children)
|
||||
}
|
||||
await this.getChildren()
|
||||
this.$root.sortPlaylists()
|
||||
// await this.$root.refreshPlaylists()
|
||||
},
|
||||
playlistContextMenu(event, playlist_id) {
|
||||
let menu = {
|
||||
items: {
|
||||
"moveToParent": {
|
||||
name: this.$root.getLz('action.moveToTop'),
|
||||
action: () => {
|
||||
let self = this
|
||||
this.move(this.item, {
|
||||
id: this.playlistRoot,
|
||||
type: "library-playlist-folders"
|
||||
})
|
||||
setTimeout(() => { self.getChildren() }, 2000)
|
||||
}
|
||||
},
|
||||
"rename": {
|
||||
name: this.$root.getLz('action.rename'),
|
||||
action: () => {
|
||||
this.renaming = true
|
||||
setTimeout(() => {
|
||||
document.querySelector(".pl-rename-field").focus()
|
||||
document.querySelector(".pl-rename-field").select()
|
||||
}, 100)
|
||||
}
|
||||
},
|
||||
"deleteFromPlaylist": {
|
||||
name: this.$root.getLz('action.removeFromLibrary'),
|
||||
action: () => {
|
||||
this.$root.deletePlaylist(playlist_id)
|
||||
}
|
||||
},
|
||||
"addToFavorites": {
|
||||
name: this.$root.getLz('action.addToFavorites'),
|
||||
disabled: true,
|
||||
hidden: true,
|
||||
action: () => {
|
||||
this.addFavorite(playlist_id, "library-playlists")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (this.item.type === "library-playlist-folders") {
|
||||
menu.items.addToFavorites.disabled = true
|
||||
}
|
||||
app.showMenuPanel(menu, event)
|
||||
},
|
||||
dragOver(evt) {
|
||||
evt.preventDefault();
|
||||
evt.dataTransfer.dropEffect = "move";
|
||||
},
|
||||
onDrop(evt) {
|
||||
let data = JSON.parse(evt.dataTransfer.getData("text/plain"))
|
||||
evt.preventDefault();
|
||||
if (data.id == this.item.id) {
|
||||
return;
|
||||
}
|
||||
console.log(data)
|
||||
if (data) {
|
||||
if (this.item.type == "library-playlists" || this.item.type == "library-playlist-folders") {
|
||||
if (data.type == "library-playlists" && this.item.type == "library-playlists") {
|
||||
return
|
||||
}
|
||||
this.move(data, this.item)
|
||||
}
|
||||
}
|
||||
},
|
||||
startDrag(evt) {
|
||||
evt.dataTransfer.dropEffect = 'move'
|
||||
evt.dataTransfer.effectAllowed = 'move'
|
||||
evt.dataTransfer.setData('text/plain', JSON.stringify(this.item))
|
||||
},
|
||||
openPlaylist(item) {
|
||||
this.$root.appRoute(`playlist_` + item.id);
|
||||
this.$root.showingPlaylist = [];
|
||||
if (item.id == 'ciderlocal') {
|
||||
this.$root.showingPlaylist = {
|
||||
"id": "ciderlocal",
|
||||
"type": "library-playlists",
|
||||
"href": "",
|
||||
"attributes": {
|
||||
"artwork": {
|
||||
"width": null,
|
||||
"height": null,
|
||||
"url": "",
|
||||
"hasP3": false
|
||||
},
|
||||
"dateAdded": "2021-02-16T03:39:47Z",
|
||||
"name": "Local Songs",
|
||||
"canDelete": true,
|
||||
"hasCatalog": true,
|
||||
"canEdit": true,
|
||||
"playParams": {
|
||||
"id": "ciderlocal",
|
||||
"kind": "playlist",
|
||||
"isLibrary": true,
|
||||
},
|
||||
"isPublic": true,
|
||||
"description": {
|
||||
"standard": ""
|
||||
}
|
||||
},
|
||||
"relationships": {
|
||||
"tracks": {
|
||||
"href": "",
|
||||
"data": this.$root.library.localsongs
|
||||
}
|
||||
}
|
||||
}
|
||||
this.$root.playlists.loadingState = 1;
|
||||
} else {
|
||||
this.$root.getPlaylistFromID(this.$root.page.substring(9), true)
|
||||
}
|
||||
},
|
||||
getPlaylistChildren(item) {
|
||||
let self = this
|
||||
this.children = []
|
||||
this.getChildren()
|
||||
this.toggleFolder()
|
||||
|
||||
this.$root.mk.api.v3.music(`v1/me/library/playlist-folders/${item.id}/children`).then(data => {
|
||||
let children = data.data.data;
|
||||
children.forEach(child => {
|
||||
if (!self.$root.playlists.listing.find(listing => listing.id == child.id)) {
|
||||
child.parent = self.item.id
|
||||
self.$root.playlists.listing.push(child)
|
||||
}
|
||||
})
|
||||
|
||||
self.$root.playlists.listing.sort((a, b) => {
|
||||
if (a.type === 'library-playlist-folders' && b.type !== 'library-playlist-folders') {
|
||||
return -1
|
||||
} else if (a.type !== 'library-playlist-folders' && b.type === 'library-playlist-folders') {
|
||||
return 1
|
||||
} else {
|
||||
return 0
|
||||
}
|
||||
})
|
||||
self.getChildren()
|
||||
})
|
||||
},
|
||||
isPlaylistSelected(item) {
|
||||
if (this.$root.showingPlaylist.id == item.id) {
|
||||
return ["active"]
|
||||
} else {
|
||||
return []
|
||||
}
|
||||
},
|
||||
toggleFolder() {
|
||||
this.folderOpened = !this.folderOpened;
|
||||
}
|
||||
Vue.component('sidebar-playlist', {
|
||||
template: '#sidebar-playlist',
|
||||
props: {
|
||||
item: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
playlistSelect: {
|
||||
type: Function,
|
||||
required: false
|
||||
},
|
||||
relateMediaItems: {
|
||||
type: Array,
|
||||
required: false,
|
||||
default() {
|
||||
return []
|
||||
}
|
||||
});
|
||||
</script>
|
||||
}
|
||||
},
|
||||
data: function() {
|
||||
return {
|
||||
folderOpened: false,
|
||||
children: [],
|
||||
playlistRoot: "p.playlistsroot",
|
||||
renaming: false,
|
||||
icon: "",
|
||||
hasRelatedMediaItems: false
|
||||
}
|
||||
},
|
||||
async mounted() {
|
||||
if (this.item.type !== "library-playlist-folders") {
|
||||
this.icon = ("./assets/feather/list.svg")
|
||||
} else {
|
||||
this.icon = ("./assets/feather/folder.svg")
|
||||
}
|
||||
let playlistMap = this.$root.playlists.trackMapping
|
||||
if (this.relateMediaItems.length != 0) {
|
||||
if (playlistMap[this.relateMediaItems[0]]) {
|
||||
if (playlistMap[this.relateMediaItems[0]].includes(this.item.id)) {
|
||||
this.hasRelatedMediaItems = true
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
clickEvent() {
|
||||
if (this.item.type != "library-playlist-folders") {
|
||||
if (this.playlistSelect) {
|
||||
this.playlistSelect(this.item)
|
||||
} else {
|
||||
this.openPlaylist(this.item)
|
||||
}
|
||||
} else {
|
||||
this.getPlaylistChildren(this.item)
|
||||
}
|
||||
},
|
||||
rename() {
|
||||
this.renaming = false
|
||||
|
||||
if (this.item.type === "library-playlist-folders") {
|
||||
this.$root.editPlaylistFolder(this.item.id, this.item.attributes.name)
|
||||
} else {
|
||||
this.$root.editPlaylist(this.item.id, this.item.attributes.name)
|
||||
}
|
||||
},
|
||||
async getChildren() {
|
||||
let self = this
|
||||
this.children = []
|
||||
this.children = this.$root.playlists.listing.filter(child => {
|
||||
if (child.parent == self.item.id) {
|
||||
return child
|
||||
}
|
||||
})
|
||||
},
|
||||
async move(item, sendTo) {
|
||||
let self = this
|
||||
console.log(sendTo)
|
||||
let type = item.type.replace("library-", "")
|
||||
let typeTo = sendTo.type
|
||||
this.$root.mk.api.v3.music(`/v1/me/library/${type}/${item.id}/parent`, {}, {
|
||||
fetchOptions: {
|
||||
method: "PUT",
|
||||
body: JSON.stringify({
|
||||
data: [{
|
||||
id: sendTo.id,
|
||||
type: typeTo
|
||||
}]
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
// find the item in this.$root.playlists.listing and store it in a variable
|
||||
this.$root.playlists.listing.filter(playlist => {
|
||||
if (playlist.id == item.id) {
|
||||
console.log(playlist)
|
||||
playlist.parent = sendTo.id
|
||||
|
||||
}
|
||||
})
|
||||
if (typeof this.$root.getChildren == "function") {
|
||||
this.$root.getChildren()
|
||||
console.log(this.$root.children)
|
||||
}
|
||||
await this.getChildren()
|
||||
this.$root.sortPlaylists()
|
||||
// await this.$root.refreshPlaylists()
|
||||
},
|
||||
playlistContextMenu(event, playlist_id) {
|
||||
let menu = {
|
||||
items: {
|
||||
"moveToParent": {
|
||||
name: this.$root.getLz('action.moveToTop'),
|
||||
action: () => {
|
||||
let self = this
|
||||
this.move(this.item, {
|
||||
id: this.playlistRoot,
|
||||
type: "library-playlist-folders"
|
||||
})
|
||||
setTimeout(() => {
|
||||
self.getChildren()
|
||||
}, 2000)
|
||||
}
|
||||
},
|
||||
"rename": {
|
||||
name: this.$root.getLz('action.rename'),
|
||||
action: () => {
|
||||
this.renaming = true
|
||||
setTimeout(() => {
|
||||
document.querySelector(".pl-rename-field").focus()
|
||||
document.querySelector(".pl-rename-field").select()
|
||||
}, 100)
|
||||
}
|
||||
},
|
||||
"deleteFromPlaylist": {
|
||||
name: this.$root.getLz('action.removeFromLibrary'),
|
||||
action: () => {
|
||||
this.$root.deletePlaylist(playlist_id)
|
||||
}
|
||||
},
|
||||
"addToFavorites": {
|
||||
name: this.$root.getLz('action.addToFavorites'),
|
||||
disabled: true,
|
||||
hidden: true,
|
||||
action: () => {
|
||||
this.addFavorite(playlist_id, "library-playlists")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (this.item.type === "library-playlist-folders") {
|
||||
menu.items.addToFavorites.disabled = true
|
||||
}
|
||||
app.showMenuPanel(menu, event)
|
||||
},
|
||||
dragOver(evt) {
|
||||
evt.preventDefault();
|
||||
evt.dataTransfer.dropEffect = "move";
|
||||
},
|
||||
onDrop(evt) {
|
||||
let data = JSON.parse(evt.dataTransfer.getData("text/plain"))
|
||||
evt.preventDefault();
|
||||
if (data.id == this.item.id) {
|
||||
return;
|
||||
}
|
||||
console.log(data)
|
||||
if (data) {
|
||||
if (this.item.type == "library-playlists" || this.item.type == "library-playlist-folders") {
|
||||
if (data.type == "library-playlists" && this.item.type == "library-playlists") {
|
||||
return
|
||||
}
|
||||
this.move(data, this.item)
|
||||
}
|
||||
}
|
||||
},
|
||||
startDrag(evt) {
|
||||
evt.dataTransfer.dropEffect = 'move'
|
||||
evt.dataTransfer.effectAllowed = 'move'
|
||||
evt.dataTransfer.setData('text/plain', JSON.stringify(this.item))
|
||||
},
|
||||
openPlaylist(item) {
|
||||
this.$root.appRoute(`playlist_` + item.id);
|
||||
this.$root.showingPlaylist = [];
|
||||
if (item.id == 'ciderlocal') {
|
||||
this.$root.showingPlaylist = {
|
||||
"id": "ciderlocal",
|
||||
"type": "library-playlists",
|
||||
"href": "",
|
||||
"attributes": {
|
||||
"artwork": {
|
||||
"width": null,
|
||||
"height": null,
|
||||
"url": "",
|
||||
"hasP3": false
|
||||
},
|
||||
"dateAdded": "2021-02-16T03:39:47Z",
|
||||
"name": "Local Songs",
|
||||
"canDelete": true,
|
||||
"hasCatalog": true,
|
||||
"canEdit": true,
|
||||
"playParams": {
|
||||
"id": "ciderlocal",
|
||||
"kind": "playlist",
|
||||
"isLibrary": true,
|
||||
},
|
||||
"isPublic": true,
|
||||
"description": {
|
||||
"standard": ""
|
||||
}
|
||||
},
|
||||
"relationships": {
|
||||
"tracks": {
|
||||
"href": "",
|
||||
"data": this.$root.library.localsongs
|
||||
}
|
||||
}
|
||||
}
|
||||
this.$root.playlists.loadingState = 1;
|
||||
} else {
|
||||
this.$root.getPlaylistFromID(this.$root.page.substring(9), true)
|
||||
}
|
||||
},
|
||||
getPlaylistChildren(item) {
|
||||
let self = this
|
||||
this.children = []
|
||||
this.getChildren()
|
||||
this.toggleFolder()
|
||||
|
||||
this.$root.mk.api.v3.music(`v1/me/library/playlist-folders/${item.id}/children`).then(data => {
|
||||
let children = data.data.data;
|
||||
children.forEach(child => {
|
||||
if (!self.$root.playlists.listing.find(listing => listing.id == child.id)) {
|
||||
child.parent = self.item.id
|
||||
self.$root.playlists.listing.push(child)
|
||||
}
|
||||
})
|
||||
|
||||
self.$root.playlists.listing.sort((a, b) => {
|
||||
if (a.type === 'library-playlist-folders' && b.type !== 'library-playlist-folders') {
|
||||
return -1
|
||||
} else if (a.type !== 'library-playlist-folders' && b.type === 'library-playlist-folders') {
|
||||
return 1
|
||||
} else {
|
||||
return 0
|
||||
}
|
||||
})
|
||||
self.getChildren()
|
||||
})
|
||||
},
|
||||
isPlaylistSelected(item) {
|
||||
if (this.$root.showingPlaylist.id == item.id) {
|
||||
return ["active"]
|
||||
} else {
|
||||
return []
|
||||
}
|
||||
},
|
||||
toggleFolder() {
|
||||
this.folderOpened = !this.folderOpened;
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -140,12 +140,12 @@
|
|||
</template>
|
||||
<template v-if="$root.cfg.libraryPrefs.localPaths.length != 0">
|
||||
<div class="app-sidebar-header-text"
|
||||
@click="$root.cfg.general.sidebarCollapsed.localLibrary = !$root.cfg.general.sidebarCollapsed.localLibrary"
|
||||
:class="{collapsed: $root.cfg.general.sidebarCollapsed.localLibrary}">
|
||||
Local Library
|
||||
@click="$root.cfg.general.sidebarCollapsed.localLibrary = !$root.cfg.general.sidebarCollapsed.localLibrary"
|
||||
:class="{collapsed: $root.cfg.general.sidebarCollapsed.localLibrary}">
|
||||
Local Library
|
||||
</div>
|
||||
<template v-if="!$root.cfg.general.sidebarCollapsed.localLibrary">
|
||||
<sidebar-playlist :item="{attributes: { name:'Songs'} , id:'ciderlocal'}"></sidebar-playlist>
|
||||
<sidebar-playlist :item="{attributes: { name:'Songs'} , id:'ciderlocal'}"></sidebar-playlist>
|
||||
</template>
|
||||
</template>
|
||||
<template v-if="$root.getPlaylistFolderChildren('p.applemusic').length != 0">
|
||||
|
@ -310,7 +310,7 @@
|
|||
</script>
|
||||
|
||||
<script>
|
||||
Vue.component("cider-app-sidebar", {
|
||||
template: "#cider-app-sidebar"
|
||||
})
|
||||
</script>
|
||||
Vue.component("cider-app-sidebar", {
|
||||
template: "#cider-app-sidebar"
|
||||
})
|
||||
</script>
|
||||
|
|
|
@ -15,123 +15,123 @@
|
|||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no, viewport-fit=cover">
|
||||
<title>Cider</title>
|
||||
<link rel="<%- (env.dev ? " stylesheet" : "stylesheet/less" ) %>" type="text/css" href="style.<%- (env.dev ? "css"
|
||||
: "less" ) %>"/>
|
||||
<!-- <link rel="stylesheet/less" type="text/css" id="userTheme" href="themes/default.less"/>-->
|
||||
<script src="./lib/less.js"></script>
|
||||
<script src="<%- (env.dev ? " ./lib/vue.js" : "./lib/vue.dev.js" ) %>"></script>
|
||||
<script src="./lib/smoothscroll.js"></script>
|
||||
<link rel="manifest" href="./manifest.json?v=2">
|
||||
<script src="https://js-cdn.music.apple.com/hls.js/2.141.0/hls.js/hls.js"></script>
|
||||
<script src="hlscider.js"></script>
|
||||
<script src="./lib/jquery-3.2.1.slim.min.js"></script>
|
||||
<script src="./lib/popper.min.js"></script>
|
||||
<script src="./lib/bootstrap.min.js"></script>
|
||||
<script src="./lib/bootbox.min.js"></script>
|
||||
<script src="./lib/notyf.min.js"></script>
|
||||
<script src="./lib/marked.js"></script>
|
||||
<script src="./lib/velocity.min.js"></script>
|
||||
<script src="./lib/fast-plural-rules.js"></script>
|
||||
<script src="./lib/resonance-audio.min.js"></script>
|
||||
<script src="./lib/stackblur.min.js"></script>
|
||||
<link rel="<%- (env.dev ? " stylesheet" : "stylesheet/less") %>" type="text/css" href="style.<%- (env.dev ? "css"
|
||||
: "less") %>" />
|
||||
<!-- <link rel="stylesheet/less" type="text/css" id="userTheme" href="themes/default.less"/>-->
|
||||
<script src="./lib/less.js"></script>
|
||||
<script src="<%- (env.dev ? " ./lib/vue.js" : "./lib/vue.dev.js"); %>"></script>
|
||||
<script src="./lib/smoothscroll.js"></script>
|
||||
<link rel="manifest" href="./manifest.json?v=2">
|
||||
<script src="https://js-cdn.music.apple.com/hls.js/2.141.0/hls.js/hls.js"></script>
|
||||
<script src="hlscider.js"></script>
|
||||
<script src="./lib/jquery-3.2.1.slim.min.js"></script>
|
||||
<script src="./lib/popper.min.js"></script>
|
||||
<script src="./lib/bootstrap.min.js"></script>
|
||||
<script src="./lib/bootbox.min.js"></script>
|
||||
<script src="./lib/notyf.min.js"></script>
|
||||
<script src="./lib/marked.js"></script>
|
||||
<script src="./lib/velocity.min.js"></script>
|
||||
<script src="./lib/fast-plural-rules.js"></script>
|
||||
<script src="./lib/resonance-audio.min.js"></script>
|
||||
<script src="./lib/stackblur.min.js"></script>
|
||||
|
||||
<style>
|
||||
#LOADER {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: #1E1E1E;
|
||||
z-index: 99999;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
<style>
|
||||
#LOADER {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: #1E1E1E;
|
||||
z-index: 99999;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
#LOADER>svg {
|
||||
width: 128px;
|
||||
}
|
||||
#LOADER > svg {
|
||||
width: 128px;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: light) {
|
||||
#LOADER {
|
||||
background-color: #eee;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@media (prefers-color-scheme: light) {
|
||||
#LOADER {
|
||||
background-color: #eee;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body class="notransparency" oncontextmenu="return false;" loading="1" os-release="<%= parseInt(env.osRelease) %>"
|
||||
platform="<%= env.platform %>">
|
||||
<script src="<%- (env.dev ? " ./lib/vue.js" : "./lib/vue.dev.js" ) %>"></script>
|
||||
<script src="./lib/vue-horizontal.js"></script>
|
||||
<script src="./lib/bootstrap-vue.min.js"></script>
|
||||
<script src="./lib/vuex.min.js"></script>
|
||||
<script src="./lib/sortable.min.js"></script>
|
||||
<script src="./lib/vue-observe-visibility.min.js"></script>
|
||||
<script src="./lib/vuedraggable.umd.min.js"></script>
|
||||
<script>
|
||||
window.quasarConfig = {
|
||||
brand: {
|
||||
primary: '#fc3c44'
|
||||
},
|
||||
config: {
|
||||
dark: true
|
||||
},
|
||||
loadingBar: { skipHijack: true }
|
||||
}
|
||||
</script>
|
||||
<!-- <script src="./lib/quasar/quasar.umd.min.js"></script> -->
|
||||
<script type="module" src="./main/app.js"></script>
|
||||
<body class="notransparency" oncontextmenu="return false;" loading="1" os-release="<%= parseInt(env.osRelease) ;%>"
|
||||
platform="<%= env.platform ;%>">
|
||||
<script src="<%- (env.dev ? " ./lib/vue.js" : "./lib/vue.dev.js"); %>"></script>
|
||||
<script src="./lib/vue-horizontal.js"></script>
|
||||
<script src="./lib/bootstrap-vue.min.js"></script>
|
||||
<script src="./lib/vuex.min.js"></script>
|
||||
<script src="./lib/sortable.min.js"></script>
|
||||
<script src="./lib/vue-observe-visibility.min.js"></script>
|
||||
<script src="./lib/vuedraggable.umd.min.js"></script>
|
||||
<script>
|
||||
window.quasarConfig = {
|
||||
brand: {
|
||||
primary: '#fc3c44'
|
||||
},
|
||||
config: {
|
||||
dark: true
|
||||
},
|
||||
loadingBar: { skipHijack: true }
|
||||
}
|
||||
</script>
|
||||
<!-- <script src="./lib/quasar/quasar.umd.min.js"></script> -->
|
||||
<script type="module" src="./main/app.js"></script>
|
||||
|
||||
<div id="LOADER">
|
||||
<%- include("../assets/cider-round.svg") %>
|
||||
</div>
|
||||
<div id="app" :class="getAppClasses()" v-if="appVisible" :window-state="chrome.windowState" :style="getAppStyle()"
|
||||
:library-visible="(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'); %>
|
||||
<%- include('app/app-navigation'); %>
|
||||
<%- include('app/chrome-bottom'); %>
|
||||
</div>
|
||||
</transition>
|
||||
<transition name="fsModeSwitch">
|
||||
<div class="fullscreen-view-container" v-if="appMode == 'fullscreen'">
|
||||
<fullscreen-view :image="currentArtUrlRaw" :time="mk.currentPlaybackTime - lyricOffset" :lyrics="lyrics"
|
||||
:richlyrics="richlyrics"></fullscreen-view>
|
||||
</div>
|
||||
</transition>
|
||||
<transition name="fsModeSwitch">
|
||||
<div class="fullscreen-view-container" v-if="appMode == 'mini'">
|
||||
<mini-view :image="currentArtUrlRaw" :time="mk.currentPlaybackTime - lyricOffset" :lyrics="lyrics"
|
||||
:richlyrics="richlyrics">
|
||||
</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>
|
||||
<div id="LOADER">
|
||||
<%- include("../assets/cider-round.svg") %>
|
||||
</div>
|
||||
<div id="app" :class="getAppClasses()" v-if="appVisible" :window-state="chrome.windowState" :style="getAppStyle()"
|
||||
:library-visible="(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'); %>
|
||||
<%- include('app/app-navigation'); %>
|
||||
<%- include('app/chrome-bottom'); %>
|
||||
</div>
|
||||
</transition>
|
||||
<transition name="fsModeSwitch">
|
||||
<div class="fullscreen-view-container" v-if="appMode == 'fullscreen'">
|
||||
<fullscreen-view :image="currentArtUrlRaw" :time="mk.currentPlaybackTime - lyricOffset" :lyrics="lyrics"
|
||||
:richlyrics="richlyrics"></fullscreen-view>
|
||||
</div>
|
||||
</transition>
|
||||
<transition name="fsModeSwitch">
|
||||
<div class="fullscreen-view-container" v-if="appMode == 'mini'">
|
||||
<mini-view :image="currentArtUrlRaw" :time="mk.currentPlaybackTime - lyricOffset" :lyrics="lyrics"
|
||||
:richlyrics="richlyrics">
|
||||
</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>
|
||||
|
||||
<% for(var i=0; i < Object.keys(env.components).length ; i++) { %>
|
||||
<%- include(env.components[i]); %>
|
||||
<% } %>
|
||||
<% for(var i = 0; i < Object.keys(env.components).length ; i++) { %>
|
||||
<%- include(env.components[i]); %>
|
||||
<% } %>
|
||||
|
||||
<script async
|
||||
src="<%- (env.useV3 ? 'https://js-cdn.music.apple.com/musickit/v3/amp/musickit.js' : 'https://api.cider.sh/musickit.js') %>"
|
||||
data-web-components>
|
||||
</script>
|
||||
<script src="index.js?v=1"></script>
|
||||
<script async
|
||||
src="<%- (env.useV3 ? "https://js-cdn.music.apple.com/musickit/v3/amp/musickit.js" : "https://api.cider.sh/musickit.js"); %>"
|
||||
data-web-components>
|
||||
</script>
|
||||
<script src="index.js?v=1"></script>
|
||||
|
||||
<script type="text/x-template" id="am-musiccovershelf">
|
||||
<script type="text/x-template" id="am-musiccovershelf">
|
||||
<h1>{{ component.attributes.title.stringForDisplay }}</h1>
|
||||
</script>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
</html>
|
||||
|
|
|
@ -6,19 +6,33 @@
|
|||
<p style="text-align: center" id="version">{{ $root.getLz("term.version") }} {{ $root.version }}</p>
|
||||
<p style="text-align: center"> {{$root.getLz('about.thanks')}} </p>
|
||||
|
||||
<p style="text-align: center">"{{$root.getLz('term.appleMusic')}}" - {{$root.getLz('term.copyright')}} © 2022 <a href="https://www.apple.com/" class="dt-footer__link"
|
||||
target="_blank"
|
||||
rel="noopener" data-dt-link-to-exclude="">{{$root.getLz('term.appleInc')}}</a>
|
||||
{{$root.getLz('term.rightsReserved')}}</p>
|
||||
<p style="text-align: center">"{{$root.getLz('term.appleMusic')}}" - {{$root.getLz('term.copyright')}} ©
|
||||
2022 <a href="https://www.apple.com/" class="dt-footer__link"
|
||||
target="_blank"
|
||||
rel="noopener" data-dt-link-to-exclude="">{{$root.getLz('term.appleInc')}}</a>
|
||||
{{$root.getLz('term.rightsReserved')}}</p>
|
||||
<hr>
|
||||
<h3>{{$root.getLz('term.sponsor')}}</h3>
|
||||
<button onclick="window.open('https://github.com/sponsors/ciderapp')" class="md-btn sponsorBtn githubBtn"><img src="./assets/github.svg"/>GitHub Sponsors</button>
|
||||
<button onclick="window.open('https://ko-fi.com/cryptofyre')" class="md-btn sponsorBtn kofiBtn"><img src="./assets/ko_fi.svg"/>Ko-fi</button>
|
||||
<button onclick="window.open('https://opencollective.com/ciderapp')" class="md-btn sponsorBtn opencollectiveBtn"><img src="./assets/open_collective.svg"/>Open Collective</button>
|
||||
<button onclick="window.open('https://github.com/sponsors/ciderapp')"
|
||||
class="md-btn sponsorBtn githubBtn"><img src="./assets/github.svg" />GitHub Sponsors
|
||||
</button>
|
||||
<button onclick="window.open('https://ko-fi.com/cryptofyre')" class="md-btn sponsorBtn kofiBtn"><img
|
||||
src="./assets/ko_fi.svg" />Ko-fi
|
||||
</button>
|
||||
<button onclick="window.open('https://opencollective.com/ciderapp')"
|
||||
class="md-btn sponsorBtn opencollectiveBtn"><img src="./assets/open_collective.svg" />Open
|
||||
Collective
|
||||
</button>
|
||||
<h3>{{$root.getLz('term.socials')}}</h3>
|
||||
<button onclick="window.open('https://github.com/ciderapp/Cider')" class="md-btn sponsorBtn githubBtn"><img src="./assets/github.svg"/>{{$root.getLz('term.github')}}</button>
|
||||
<button onclick="window.open('https://discord.gg/applemusic')" class="md-btn sponsorBtn discordBtn"><img style="height: 26px;" src="./assets/discord.svg"/>{{$root.getLz('term.discord')}}</button>
|
||||
<button onclick="window.open('https://twitter.com/UseCider')" class="md-btn sponsorBtn twitterBtn"><img src="./assets/twitter.svg"/>Twitter</button>
|
||||
<button onclick="window.open('https://github.com/ciderapp/Cider')" class="md-btn sponsorBtn githubBtn">
|
||||
<img src="./assets/github.svg" />{{$root.getLz('term.github')}}
|
||||
</button>
|
||||
<button onclick="window.open('https://discord.gg/applemusic')" class="md-btn sponsorBtn discordBtn"><img
|
||||
style="height: 26px;" src="./assets/discord.svg" />{{$root.getLz('term.discord')}}
|
||||
</button>
|
||||
<button onclick="window.open('https://twitter.com/UseCider')" class="md-btn sponsorBtn twitterBtn"><img
|
||||
src="./assets/twitter.svg" />Twitter
|
||||
</button>
|
||||
|
||||
</div>
|
||||
<div class="col">
|
||||
|
@ -26,14 +40,18 @@
|
|||
<div class="col">
|
||||
<h3>{{$root.getLz('term.ciderTeam')}}</h3>
|
||||
<div class="md-btn teamBtn" v-for="member in team" @click="window.open(member.link)">
|
||||
<img :src="member.avatar"/>
|
||||
<img :src="member.avatar" />
|
||||
<div class="row" style="width:100%;">
|
||||
<div class="col" style="text-align: left;">
|
||||
{{ member.name }}
|
||||
</div>
|
||||
<div class="col" style="text-align: right">
|
||||
<button @click.stop="window.open(member.twitter)" class="social-btn" v-if="member.twitter">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="white" style=""><path d="M24 4.557c-.883.392-1.832.656-2.828.775 1.017-.609 1.798-1.574 2.165-2.724-.951.564-2.005.974-3.127 1.195-.897-.957-2.178-1.555-3.594-1.555-3.179 0-5.515 2.966-4.797 6.045-4.091-.205-7.719-2.165-10.148-5.144-1.29 2.213-.669 5.108 1.523 6.574-.806-.026-1.566-.247-2.229-.616-.054 2.281 1.581 4.415 3.949 4.89-.693.188-1.452.232-2.224.084.626 1.956 2.444 3.379 4.6 3.419-2.07 1.623-4.678 2.348-7.29 2.04 2.179 1.397 4.768 2.212 7.548 2.212 9.142 0 14.307-7.721 13.995-14.646.962-.695 1.797-1.562 2.457-2.549z"></path></svg>
|
||||
<button @click.stop="window.open(member.twitter)" class="social-btn"
|
||||
v-if="member.twitter">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24"
|
||||
viewBox="0 0 24 24" fill="white" style="">
|
||||
<path d="M24 4.557c-.883.392-1.832.656-2.828.775 1.017-.609 1.798-1.574 2.165-2.724-.951.564-2.005.974-3.127 1.195-.897-.957-2.178-1.555-3.594-1.555-3.179 0-5.515 2.966-4.797 6.045-4.091-.205-7.719-2.165-10.148-5.144-1.29 2.213-.669 5.108 1.523 6.574-.806-.026-1.566-.247-2.229-.616-.054 2.281 1.581 4.415 3.949 4.89-.693.188-1.452.232-2.224.084.626 1.956 2.444 3.379 4.6 3.419-2.07 1.623-4.678 2.348-7.29 2.04 2.179 1.397 4.768 2.212 7.548 2.212 9.142 0 14.307-7.721 13.995-14.646.962-.695 1.797-1.562 2.457-2.549z"></path>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
|
@ -51,105 +69,103 @@
|
|||
<img class="md-contributors"
|
||||
style="cursor:pointer;width:100%;"
|
||||
onclick="window.open('https://github.com/ciderapp/Cider/graphs/contributors')"
|
||||
src="https://contrib.rocks/image?repo=ciderapp/Cider&columns=25"/>
|
||||
src="https://contrib.rocks/image?repo=ciderapp/Cider&columns=25" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
<script>
|
||||
Vue.component('about-page', {
|
||||
template: '#about-page',
|
||||
data: function () {
|
||||
return {
|
||||
window: window,
|
||||
version: app.version,
|
||||
team: [
|
||||
{
|
||||
name: 'cryptofyre',
|
||||
link: 'https://github.com/cryptofyre',
|
||||
role: app.getLz('term.developer'),
|
||||
avatar: 'https://avatars.githubusercontent.com/u/33162551?v=4',
|
||||
twitter: 'https://twitter.com/cryptofyre'
|
||||
},
|
||||
{
|
||||
name: 'Core',
|
||||
link: 'https://github.com/coredev-uk',
|
||||
role: app.getLz('term.developer'),
|
||||
avatar: 'https://avatars.githubusercontent.com/u/64542347?v=4',
|
||||
twitter: 'https://twitter.com/core_hdd'
|
||||
},
|
||||
{
|
||||
name: 'Quacksire',
|
||||
link: 'https://github.com/quacksire',
|
||||
role: app.getLz('term.developer'),
|
||||
avatar: 'https://avatars.githubusercontent.com/u/19170969?v=4',
|
||||
twitter: 'https://twitter.com/duckdoquack'
|
||||
},
|
||||
{
|
||||
name: 'booploops',
|
||||
link: 'https://github.com/booploops',
|
||||
role: app.getLz('term.developer'),
|
||||
avatar: 'https://avatars.githubusercontent.com/u/49113086?v=4',
|
||||
twitter: 'https://twitter.com/boopl00ps'
|
||||
},
|
||||
{
|
||||
name: 'vapormusic',
|
||||
link: 'https://github.com/vapormusic',
|
||||
role: app.getLz('term.developer'),
|
||||
avatar: 'https://avatars.githubusercontent.com/u/27716185?v=4'
|
||||
},
|
||||
{
|
||||
name: 'crypticplank',
|
||||
link: 'https://github.com/crypticplank',
|
||||
role: app.getLz('term.developer'),
|
||||
avatar: 'https://avatars.githubusercontent.com/u/52553007?v=4',
|
||||
twitter: 'https://twitter.com/crypticplank'
|
||||
},
|
||||
{
|
||||
name: 'Maikiwi',
|
||||
link: 'https://github.com/maikirakiwi',
|
||||
role: app.getLz('term.developer'),
|
||||
avatar: 'https://avatars.githubusercontent.com/u/74925636?v=4',
|
||||
twitter: 'https://twitter.com/notmaikiwi'
|
||||
},
|
||||
{
|
||||
name: 'yazninja',
|
||||
link: 'https://github.com/yazninja',
|
||||
role: app.getLz('term.developer'),
|
||||
avatar: 'https://avatars.githubusercontent.com/u/71800112?v=4',
|
||||
twitter: 'https://twitter.com/YazNinjaa'
|
||||
},
|
||||
{
|
||||
name: 'GamingLiamStudios',
|
||||
link: 'https://github.com/GamingLiamStudios',
|
||||
role: app.getLz('term.developer'),
|
||||
avatar: 'https://avatars.githubusercontent.com/u/58615717?v=4',
|
||||
twitter: 'https://twitter.com/GLStudios_'
|
||||
},
|
||||
{
|
||||
name: 'Amaru',
|
||||
link: 'https://github.com/Amaru8',
|
||||
role: app.getLz('term.developer'),
|
||||
avatar: 'https://avatars.githubusercontent.com/u/52407090?v=4'
|
||||
},
|
||||
{
|
||||
name: 'Void',
|
||||
link: 'https://twitter.com/MoonyVoid',
|
||||
role: app.getLz('term.socialTeam'),
|
||||
avatar: 'https://pbs.twimg.com/profile_images/1226463559472816129/8LScNYED_400x400.jpg'
|
||||
},
|
||||
{
|
||||
name: 'NoseySG',
|
||||
link: 'https://twitter.com/noah_grose',
|
||||
role: app.getLz('term.socialTeam'),
|
||||
avatar: 'https://pbs.twimg.com/profile_images/1496944907260420099/D5gl6H4J_400x400.jpg'
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
||||
}
|
||||
});
|
||||
</script>
|
||||
Vue.component('about-page', {
|
||||
template: '#about-page',
|
||||
data: function() {
|
||||
return {
|
||||
window: window,
|
||||
version: app.version,
|
||||
team: [
|
||||
{
|
||||
name: 'cryptofyre',
|
||||
link: 'https://github.com/cryptofyre',
|
||||
role: app.getLz('term.developer'),
|
||||
avatar: 'https://avatars.githubusercontent.com/u/33162551?v=4',
|
||||
twitter: 'https://twitter.com/cryptofyre'
|
||||
},
|
||||
{
|
||||
name: 'Core',
|
||||
link: 'https://github.com/coredev-uk',
|
||||
role: app.getLz('term.developer'),
|
||||
avatar: 'https://avatars.githubusercontent.com/u/64542347?v=4',
|
||||
twitter: 'https://twitter.com/core_hdd'
|
||||
},
|
||||
{
|
||||
name: 'Quacksire',
|
||||
link: 'https://github.com/quacksire',
|
||||
role: app.getLz('term.developer'),
|
||||
avatar: 'https://avatars.githubusercontent.com/u/19170969?v=4',
|
||||
twitter: 'https://twitter.com/duckdoquack'
|
||||
},
|
||||
{
|
||||
name: 'booploops',
|
||||
link: 'https://github.com/booploops',
|
||||
role: app.getLz('term.developer'),
|
||||
avatar: 'https://avatars.githubusercontent.com/u/49113086?v=4',
|
||||
twitter: 'https://twitter.com/boopl00ps'
|
||||
},
|
||||
{
|
||||
name: 'vapormusic',
|
||||
link: 'https://github.com/vapormusic',
|
||||
role: app.getLz('term.developer'),
|
||||
avatar: 'https://avatars.githubusercontent.com/u/27716185?v=4'
|
||||
},
|
||||
{
|
||||
name: 'crypticplank',
|
||||
link: 'https://github.com/crypticplank',
|
||||
role: app.getLz('term.developer'),
|
||||
avatar: 'https://avatars.githubusercontent.com/u/52553007?v=4',
|
||||
twitter: 'https://twitter.com/crypticplank'
|
||||
},
|
||||
{
|
||||
name: 'Maikiwi',
|
||||
link: 'https://github.com/maikirakiwi',
|
||||
role: app.getLz('term.developer'),
|
||||
avatar: 'https://avatars.githubusercontent.com/u/74925636?v=4',
|
||||
twitter: 'https://twitter.com/notmaikiwi'
|
||||
},
|
||||
{
|
||||
name: 'yazninja',
|
||||
link: 'https://github.com/yazninja',
|
||||
role: app.getLz('term.developer'),
|
||||
avatar: 'https://avatars.githubusercontent.com/u/71800112?v=4',
|
||||
twitter: 'https://twitter.com/YazNinjaa'
|
||||
},
|
||||
{
|
||||
name: 'GamingLiamStudios',
|
||||
link: 'https://github.com/GamingLiamStudios',
|
||||
role: app.getLz('term.developer'),
|
||||
avatar: 'https://avatars.githubusercontent.com/u/58615717?v=4',
|
||||
twitter: 'https://twitter.com/GLStudios_'
|
||||
},
|
||||
{
|
||||
name: 'Amaru',
|
||||
link: 'https://github.com/Amaru8',
|
||||
role: app.getLz('term.developer'),
|
||||
avatar: 'https://avatars.githubusercontent.com/u/52407090?v=4'
|
||||
},
|
||||
{
|
||||
name: 'Void',
|
||||
link: 'https://twitter.com/MoonyVoid',
|
||||
role: app.getLz('term.socialTeam'),
|
||||
avatar: 'https://pbs.twimg.com/profile_images/1226463559472816129/8LScNYED_400x400.jpg'
|
||||
},
|
||||
{
|
||||
name: 'NoseySG',
|
||||
link: 'https://twitter.com/noah_grose',
|
||||
role: app.getLz('term.socialTeam'),
|
||||
avatar: 'https://pbs.twimg.com/profile_images/1496944907260420099/D5gl6H4J_400x400.jpg'
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
methods: {}
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -1,18 +1,18 @@
|
|||
<script type="text/x-template" id="apple-account-settings">
|
||||
<div style="display:flex;width:100%;height:100%;padding-top: var(--navigationBarHeight);position:absolute;top:0;left:0;">
|
||||
<webview id="foo" src="https://music.apple.com/includes/commerce/account/settings?product=music&isFullscreen=true&isModal=false" style="display:inline-flex; width:100%;"></webview>
|
||||
<webview id="foo"
|
||||
src="https://music.apple.com/includes/commerce/account/settings?product=music&isFullscreen=true&isModal=false"
|
||||
style="display:inline-flex; width:100%;"></webview>
|
||||
</div>
|
||||
</script>
|
||||
<script>
|
||||
Vue.component('apple-account-settings', {
|
||||
template: '#apple-account-settings',
|
||||
mounted() {
|
||||
document.querySelector("#foo").addEventListener("dom-ready", ()=>{
|
||||
// document.querySelector("#foo").executeJavaScript(`document.body.innerHTML += ("<style>.header {display: none!important;} </style>")`)
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
|
||||
}
|
||||
});
|
||||
</script>
|
||||
Vue.component('apple-account-settings', {
|
||||
template: '#apple-account-settings',
|
||||
mounted() {
|
||||
document.querySelector("#foo").addEventListener("dom-ready", () => {
|
||||
// document.querySelector("#foo").executeJavaScript(`document.body.innerHTML += ("<style>.header {display: none!important;} </style>")`)
|
||||
})
|
||||
},
|
||||
methods: {}
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -2,41 +2,47 @@
|
|||
<div class="content-inner">
|
||||
<h1 class="header-text">{{ data.attributes.shortName ?? data.attributes.name}}</h1>
|
||||
<template v-if="data.relationships && data.relationships.grouping">
|
||||
<template v-for="(recom,index) in data.relationships.grouping.data[0].relationships.tabs.data[0].relationships.children.data">
|
||||
<div class="row">
|
||||
<div class="col" v-if="recom.attributes.name != 'Chart Set'">
|
||||
<h3>{{ recom.attributes.name ?? ""}}</h3>
|
||||
</div>
|
||||
<div class="col-auto cider-flex-center" v-if="index != 0 && recom.relationships && ((recom.relationships.children && recom.relationships.children.data.length > 10) || (recom.relationships.contents && recom.relationships.contents.data.length > 10))">
|
||||
<button class="cd-btn-seeall" @click="app.showCollection(recom.relationships.children ? recom.relationships.children : recom.relationships.contents, recom.attributes.name ?? '', 'listen_now')" >{{app.getLz('term.seeAll')}}</button>
|
||||
</div>
|
||||
<template
|
||||
v-for="(recom,index) in data.relationships.grouping.data[0].relationships.tabs.data[0].relationships.children.data">
|
||||
<div class="row">
|
||||
<div class="col" v-if="recom.attributes.name != 'Chart Set'">
|
||||
<h3>{{ recom.attributes.name ?? ""}}</h3>
|
||||
</div>
|
||||
<template v-if="recom.relationships && ((recom.relationships.children && recom.relationships.children.data) || (recom.relationships.contents && recom.relationships.contents.data))">
|
||||
<template v-if="(recom.attributes.name && recom.attributes.name.includes('ideo')) || index === 0">
|
||||
<mediaitem-scroller-horizontal-mvview :imagesize="800" :browsesp="index == 0"
|
||||
:items="recom.relationships.children ? recom.relationships.children.data.limit(10) : recom.relationships.contents.data.limit(10)"></mediaitem-scroller-horizontal-mvview>
|
||||
</template>
|
||||
<template v-else-if="recom.attributes.name == 'Chart Set'">
|
||||
|
||||
</template>
|
||||
<template v-else>
|
||||
<mediaitem-scroller-horizontal-large
|
||||
:items="recom.relationships.children ? recom.relationships.children.data.limit(10) : recom.relationships.contents.data.limit(10)"></mediaitem-scroller-horizontal-large>
|
||||
</template>
|
||||
<div class="col-auto cider-flex-center"
|
||||
v-if="index != 0 && recom.relationships && ((recom.relationships.children && recom.relationships.children.data.length > 10) || (recom.relationships.contents && recom.relationships.contents.data.length > 10))">
|
||||
<button class="cd-btn-seeall"
|
||||
@click="app.showCollection(recom.relationships.children ? recom.relationships.children : recom.relationships.contents, recom.attributes.name ?? '', 'listen_now')">
|
||||
{{app.getLz('term.seeAll')}}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<template
|
||||
v-if="recom.relationships && ((recom.relationships.children && recom.relationships.children.data) || (recom.relationships.contents && recom.relationships.contents.data))">
|
||||
<template v-if="(recom.attributes.name && recom.attributes.name.includes('ideo')) || index === 0">
|
||||
<mediaitem-scroller-horizontal-mvview :imagesize="800" :browsesp="index == 0"
|
||||
:items="recom.relationships.children ? recom.relationships.children.data.limit(10) : recom.relationships.contents.data.limit(10)"></mediaitem-scroller-horizontal-mvview>
|
||||
</template>
|
||||
<template v-else-if="recom.attributes.name == 'Chart Set'">
|
||||
|
||||
</template>
|
||||
<template v-else>
|
||||
<mediaitem-scroller-horizontal-large
|
||||
:items="recom.relationships.children ? recom.relationships.children.data.limit(10) : recom.relationships.contents.data.limit(10)"></mediaitem-scroller-horizontal-large>
|
||||
</template>
|
||||
</template>
|
||||
</template>
|
||||
</template>
|
||||
</template>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script>
|
||||
Vue.component('cider-applecurator', {
|
||||
template: "#cider-applecurator",
|
||||
props: ["data"],
|
||||
data: function() {
|
||||
return {
|
||||
app: this.$root
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
Vue.component('cider-applecurator', {
|
||||
template: "#cider-applecurator",
|
||||
props: ["data"],
|
||||
data: function() {
|
||||
return {
|
||||
app: this.$root
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
|
|
@ -8,7 +8,9 @@
|
|||
<h3>{{app.getLz('home.followedArtists')}}</h3>
|
||||
</div>
|
||||
<div class="col-auto nopadding cider-flex-center">
|
||||
<button class="cd-btn-seeall" @click="syncFavorites()" v-if="!syncingFavs">{{app.getLz('home.syncFavorites')}}</button>
|
||||
<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>
|
||||
|
@ -17,8 +19,10 @@
|
|||
<mediaitem-square :item="artist" kind="small"></mediaitem-square>
|
||||
<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.removeFavorite')}}
|
||||
<div class="svg-icon"
|
||||
:style="{'--url': 'url(./assets/feather/x-circle.svg)'}"></div>
|
||||
</div>
|
||||
{{app.getLz('action.removeFavorite')}}
|
||||
</button>
|
||||
</div>
|
||||
</vue-horizontal>
|
||||
|
@ -50,80 +54,81 @@
|
|||
</script>
|
||||
|
||||
<script>
|
||||
Vue.component('cider-artist-feed', {
|
||||
template: '#cider-artist-feed',
|
||||
data: function () {
|
||||
return {
|
||||
app: this.$root,
|
||||
followedArtists: this.$root.cfg.home.followedArtists,
|
||||
artistFeed: [],
|
||||
artists: [],
|
||||
syncingFavs: false
|
||||
}
|
||||
},
|
||||
async mounted() {
|
||||
let self = this
|
||||
await this.getArtistFeed()
|
||||
},
|
||||
methods: {
|
||||
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)
|
||||
}
|
||||
let artist = this.artists.find(a => a.id == id)
|
||||
let index2 = this.artists.indexOf(artist)
|
||||
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() {
|
||||
let artists = this.followedArtists
|
||||
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 = []
|
||||
for (let artistIdx = 0; artistIdx < artists.length; artistIdx += 50) {
|
||||
chunks.push(artists.slice(artistIdx, artistIdx + 50))
|
||||
}
|
||||
try {
|
||||
const chunkArtistData = await Promise.all(chunks.map(chunk =>
|
||||
this.app.mk.api.v3.music(`/v1/catalog/${app.mk.storefrontId}/artists?ids=${chunk.toString()}&views=latest-release&include[songs]=albums&fields[albums]=artistName,artistUrl,artwork,contentRating,editorialArtwork,editorialVideo,name,playParams,releaseDate,url,trackCount&limit[artists:top-songs]=2&art[url]=f`)))
|
||||
chunkArtistData.forEach(chunkResult =>
|
||||
chunkResult.data.data.forEach(item => {
|
||||
self.artists.push(item)
|
||||
if (item.views["latest-release"].data.length != 0) {
|
||||
self.artistFeed.push(item.views["latest-release"].data[0])
|
||||
}
|
||||
}))
|
||||
// sort artistFeed by attributes.releaseDate descending, date is formatted as "YYYY-MM-DD"
|
||||
this.artistFeed.sort((a, b) => {
|
||||
let dateA = new Date(a.attributes.releaseDate)
|
||||
let dateB = new Date(b.attributes.releaseDate)
|
||||
return dateB - dateA
|
||||
})
|
||||
} catch (err) { }
|
||||
}
|
||||
Vue.component('cider-artist-feed', {
|
||||
template: '#cider-artist-feed',
|
||||
data: function() {
|
||||
return {
|
||||
app: this.$root,
|
||||
followedArtists: this.$root.cfg.home.followedArtists,
|
||||
artistFeed: [],
|
||||
artists: [],
|
||||
syncingFavs: false
|
||||
}
|
||||
},
|
||||
async mounted() {
|
||||
let self = this
|
||||
await this.getArtistFeed()
|
||||
},
|
||||
methods: {
|
||||
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)
|
||||
}
|
||||
});
|
||||
</script>
|
||||
let artist = this.artists.find(a => a.id == id)
|
||||
let index2 = this.artists.indexOf(artist)
|
||||
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() {
|
||||
let artists = this.followedArtists
|
||||
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 = []
|
||||
for (let artistIdx = 0; artistIdx < artists.length; artistIdx += 50) {
|
||||
chunks.push(artists.slice(artistIdx, artistIdx + 50))
|
||||
}
|
||||
try {
|
||||
const chunkArtistData = await Promise.all(chunks.map(chunk =>
|
||||
this.app.mk.api.v3.music(`/v1/catalog/${app.mk.storefrontId}/artists?ids=${chunk.toString()}&views=latest-release&include[songs]=albums&fields[albums]=artistName,artistUrl,artwork,contentRating,editorialArtwork,editorialVideo,name,playParams,releaseDate,url,trackCount&limit[artists:top-songs]=2&art[url]=f`)))
|
||||
chunkArtistData.forEach(chunkResult =>
|
||||
chunkResult.data.data.forEach(item => {
|
||||
self.artists.push(item)
|
||||
if (item.views["latest-release"].data.length != 0) {
|
||||
self.artistFeed.push(item.views["latest-release"].data[0])
|
||||
}
|
||||
}))
|
||||
// sort artistFeed by attributes.releaseDate descending, date is formatted as "YYYY-MM-DD"
|
||||
this.artistFeed.sort((a, b) => {
|
||||
let dateA = new Date(a.attributes.releaseDate)
|
||||
let dateB = new Date(b.attributes.releaseDate)
|
||||
return dateB - dateA
|
||||
})
|
||||
} catch (err) {
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
<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) || hasHero()) ? 'animated' : '']">
|
||||
<div :class="['artist-header', { 'artist-header-compact': app.cfg.visual.compactArtistHeader }]" :key="data.id" v-observe-visibility="{callback: isHeaderVisible}">
|
||||
<div :class="['artist-header', { 'artist-header-compact': app.cfg.visual.compactArtistHeader }]" :key="data.id"
|
||||
v-observe-visibility="{callback: isHeaderVisible}">
|
||||
<animatedartwork-view
|
||||
:priority="true"
|
||||
v-if="hasAnimated()"
|
||||
|
@ -26,7 +27,7 @@
|
|||
<div class="col cider-flex-center artist-title"
|
||||
:class="{'artist-animation-on': (data.attributes.editorialVideo && (data.attributes.editorialVideo.motionArtistWide16x9 || data.attributes.editorialVideo.motionArtistFullscreen16x9)) || hasHero() }"
|
||||
:style="{ 'color': '#' +hasHeroObject()?.textColor1 ?? ''}"
|
||||
>
|
||||
>
|
||||
<button class="artist-play" @click="app.mk.setStationQueue({artist:'a-'+data.id}).then(()=>{
|
||||
app.mk.play()
|
||||
})" :aria-label="app.getLz('term.play')"><%- include("../svg/play.svg") %></button>
|
||||
|
@ -42,10 +43,10 @@
|
|||
<div class="svg-icon"></div>
|
||||
</button>
|
||||
</div>
|
||||
<div class="artworkContainer"
|
||||
<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>
|
||||
<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>
|
||||
|
@ -157,133 +158,133 @@
|
|||
</div>
|
||||
</script>
|
||||
<script>
|
||||
Vue.component('cider-artist', {
|
||||
template: "#cider-artist",
|
||||
props: ['data'],
|
||||
data: function () {
|
||||
return {
|
||||
topSongsExpanded: false,
|
||||
app: this.$root,
|
||||
headerVisible: true
|
||||
}
|
||||
},
|
||||
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;
|
||||
},
|
||||
hasHeroObject() {
|
||||
if(this.data.attributes?.editorialArtwork?.centeredFullscreenBackground){
|
||||
return this.data.attributes?.editorialArtwork?.centeredFullscreenBackground
|
||||
} else if(this.data.attributes?.editorialArtwork?.bannerUber) {
|
||||
return this.data.attributes?.editorialArtwork?.bannerUber
|
||||
} else if(this.data.attributes?.editorialArtwork?.subscriptionHero){
|
||||
return this.data.attributes?.editorialArtwork?.subscriptionHero
|
||||
}
|
||||
return [];
|
||||
},
|
||||
isHeaderVisible(visible) {
|
||||
this.headerVisible = visible
|
||||
},
|
||||
async artistMenu(event) {
|
||||
let self = this
|
||||
let followAction = "follow"
|
||||
let followActions = {
|
||||
follow: {
|
||||
icon: "./assets/feather/plus-circle.svg",
|
||||
name: app.getLz('action.follow'),
|
||||
action: () => {
|
||||
self.app.cfg.home.followedArtists.push(self.data.id)
|
||||
}
|
||||
},
|
||||
unfollow: {
|
||||
icon: "./assets/feather/x-circle.svg",
|
||||
name: app.getLz('action.unfollow'),
|
||||
action: () => {
|
||||
let index = self.app.cfg.home.followedArtists.indexOf(self.data.id)
|
||||
if (index > -1) {
|
||||
self.app.cfg.home.followedArtists.splice(index, 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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(() => {
|
||||
app.mk.play()
|
||||
})
|
||||
}
|
||||
},
|
||||
favoriteActions[inFavorites ? "removeFavorite" : "favorite"],
|
||||
// followActions[followAction],
|
||||
{
|
||||
icon: "./assets/feather/share.svg",
|
||||
name: app.getLz('term.share'),
|
||||
action: () => {
|
||||
self.app.copyToClipboard(self.data.attributes.url)
|
||||
}
|
||||
}
|
||||
]
|
||||
}, event)
|
||||
},
|
||||
getArtistPalette(artist) {
|
||||
if (artist["attributes"]["artwork"]) {
|
||||
return {
|
||||
"background": "#" + artist["attributes"]["artwork"]["bgColor"],
|
||||
"color": "#" + artist["attributes"]["artwork"]["textColor1"],
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
"background": "#000000",
|
||||
"color": "#ffffff",
|
||||
}
|
||||
}
|
||||
},
|
||||
getTopResult() {
|
||||
if (this.search.results["meta"]) {
|
||||
return this.search.results[this.search.results.meta.results.order[0]]["data"][0]
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
Vue.component('cider-artist', {
|
||||
template: "#cider-artist",
|
||||
props: ['data'],
|
||||
data: function() {
|
||||
return {
|
||||
topSongsExpanded: false,
|
||||
app: this.$root,
|
||||
headerVisible: true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
hasAnimated() {
|
||||
if (this.data.attributes?.editorialVideo && (this.data.attributes?.editorialVideo?.motionArtistWide16x9 || this.data.attributes?.editorialVideo?.motionArtistFullscreen16x9)) {
|
||||
return true;
|
||||
}
|
||||
})
|
||||
</script>
|
||||
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;
|
||||
},
|
||||
hasHeroObject() {
|
||||
if (this.data.attributes?.editorialArtwork?.centeredFullscreenBackground) {
|
||||
return this.data.attributes?.editorialArtwork?.centeredFullscreenBackground
|
||||
} else if (this.data.attributes?.editorialArtwork?.bannerUber) {
|
||||
return this.data.attributes?.editorialArtwork?.bannerUber
|
||||
} else if (this.data.attributes?.editorialArtwork?.subscriptionHero) {
|
||||
return this.data.attributes?.editorialArtwork?.subscriptionHero
|
||||
}
|
||||
return [];
|
||||
},
|
||||
isHeaderVisible(visible) {
|
||||
this.headerVisible = visible
|
||||
},
|
||||
async artistMenu(event) {
|
||||
let self = this
|
||||
let followAction = "follow"
|
||||
let followActions = {
|
||||
follow: {
|
||||
icon: "./assets/feather/plus-circle.svg",
|
||||
name: app.getLz('action.follow'),
|
||||
action: () => {
|
||||
self.app.cfg.home.followedArtists.push(self.data.id)
|
||||
}
|
||||
},
|
||||
unfollow: {
|
||||
icon: "./assets/feather/x-circle.svg",
|
||||
name: app.getLz('action.unfollow'),
|
||||
action: () => {
|
||||
let index = self.app.cfg.home.followedArtists.indexOf(self.data.id)
|
||||
if (index > -1) {
|
||||
self.app.cfg.home.followedArtists.splice(index, 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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(() => {
|
||||
app.mk.play()
|
||||
})
|
||||
}
|
||||
},
|
||||
favoriteActions[inFavorites ? "removeFavorite" : "favorite"],
|
||||
// followActions[followAction],
|
||||
{
|
||||
icon: "./assets/feather/share.svg",
|
||||
name: app.getLz('term.share'),
|
||||
action: () => {
|
||||
self.app.copyToClipboard(self.data.attributes.url)
|
||||
}
|
||||
}
|
||||
]
|
||||
}, event)
|
||||
},
|
||||
getArtistPalette(artist) {
|
||||
if (artist["attributes"]["artwork"]) {
|
||||
return {
|
||||
"background": "#" + artist["attributes"]["artwork"]["bgColor"],
|
||||
"color": "#" + artist["attributes"]["artwork"]["textColor1"],
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
"background": "#000000",
|
||||
"color": "#ffffff",
|
||||
}
|
||||
}
|
||||
},
|
||||
getTopResult() {
|
||||
if (this.search.results["meta"]) {
|
||||
return this.search.results[this.search.results.meta.results.order[0]]["data"][0]
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
|
|
@ -1,183 +1,196 @@
|
|||
<script type="text/x-template" id="audiolabs-page">
|
||||
<div class="audiolabs-page">
|
||||
<div class="md-option-container">
|
||||
<div class="settings-option-body">
|
||||
<div class="md-option-line">
|
||||
<b-jumbotron :header="$root.getLz('settings.option.audio.audioLab')"
|
||||
lead="Designed by Cider Acoustic Technologies in California"></b-jumbotron>
|
||||
</div>
|
||||
<div class="md-option-line">
|
||||
<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="app.cfg.audio.maikiwiAudio.ciderPPE"
|
||||
v-on:change="CiderAudio.hierarchical_loading();" switch/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="md-option-line" v-show="app.cfg.audio.maikiwiAudio.ciderPPE === true">
|
||||
<div class="md-option-segment">
|
||||
{{$root.getLz('settings.option.audio.enableAdvancedFunctionality.ciderPPEStrength')}}
|
||||
<br>
|
||||
<small>{{$root.getLz('settings.option.audio.enableAdvancedFunctionality.ciderPPEStrength.description')}}</small>
|
||||
</div>
|
||||
<div class="md-option-segment md-option-segment_auto">
|
||||
<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 ({{$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>
|
||||
<div class="md-option-line">
|
||||
<div class="md-option-segment">
|
||||
Cider Opportunistic Correction System
|
||||
<br>
|
||||
<small>Takes advantage of the sonic characteristics of a specific equipment and adapts it to be more 'Cider' oriented.</small>
|
||||
</div>
|
||||
<div class="md-option-segment md-option-segment_auto">
|
||||
<select class="md-select" style="width:180px;"
|
||||
v-model="app.cfg.audio.maikiwiAudio.opportunisticCorrection_state"
|
||||
v-on:change="CiderAudio.hierarchical_loading()">
|
||||
<option value="OFF">OFF</option>
|
||||
<option value="CHU">Moondrop Chu</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="md-option-line">
|
||||
<div class="md-option-segment">
|
||||
{{$root.getLz('settings.option.audio.enableAdvancedFunctionality.atmosphereRealizer')}} [1]
|
||||
<br>
|
||||
<small>{{$root.getLz('settings.option.audio.enableAdvancedFunctionality.atmosphereRealizer.description')}}</small>
|
||||
</div>
|
||||
<div class="md-option-segment md-option-segment_auto">
|
||||
<input type="checkbox" v-model="app.cfg.audio.maikiwiAudio.atmosphereRealizer1"
|
||||
v-on:change="CiderAudio.hierarchical_loading();" switch/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="md-option-line" v-show="app.cfg.audio.maikiwiAudio.atmosphereRealizer1 === true">
|
||||
<div class="md-option-segment">
|
||||
{{$root.getLz('settings.option.audio.enableAdvancedFunctionality.atmosphereRealizerMode')}} [1]
|
||||
<br>
|
||||
<small>{{$root.getLz('settings.option.audio.enableAdvancedFunctionality.atmosphereRealizerMode.description')}}</small>
|
||||
</div>
|
||||
<div class="md-option-segment md-option-segment_auto">
|
||||
<select class="md-select" style="width:230px;"
|
||||
v-model="$root.cfg.audio.maikiwiAudio.atmosphereRealizer1_value"
|
||||
v-on:change="CiderAudio.hierarchical_loading();">
|
||||
<option v-for="profile in arprofiles" :value="profile.id">{{ $root.getProfileLz("CAR", profile.id) }}</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="md-option-line">
|
||||
<div class="md-option-segment">
|
||||
{{$root.getLz('settings.option.audio.enableAdvancedFunctionality.atmosphereRealizer')}} [2]
|
||||
<br>
|
||||
<small>{{$root.getLz('settings.option.audio.enableAdvancedFunctionality.atmosphereRealizer.description')}}</small>
|
||||
</div>
|
||||
<div class="md-option-segment md-option-segment_auto">
|
||||
<input type="checkbox" v-model="app.cfg.audio.maikiwiAudio.atmosphereRealizer2"
|
||||
v-on:change="CiderAudio.hierarchical_loading();" switch/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="md-option-line" v-show="app.cfg.audio.maikiwiAudio.atmosphereRealizer2 === true">
|
||||
<div class="md-option-segment">
|
||||
{{$root.getLz('settings.option.audio.enableAdvancedFunctionality.atmosphereRealizerMode')}} [2]
|
||||
<br>
|
||||
<small>{{$root.getLz('settings.option.audio.enableAdvancedFunctionality.atmosphereRealizerMode.description')}}</small>
|
||||
</div>
|
||||
<div class="md-option-segment md-option-segment_auto">
|
||||
<select class="md-select" style="width:230px;"
|
||||
v-model="$root.cfg.audio.maikiwiAudio.atmosphereRealizer2_value"
|
||||
v-on:change="CiderAudio.hierarchical_loading();">
|
||||
<option v-for="profile in arprofiles" :value="profile.id">{{ $root.getProfileLz("CAR", profile.id) }}</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="md-option-line">
|
||||
<div class="md-option-segment">
|
||||
{{$root.getLz('settings.option.audio.enableAdvancedFunctionality.tunedAudioSpatialization')}}
|
||||
<br>
|
||||
<small>{{$root.getLz('settings.option.audio.enableAdvancedFunctionality.tunedAudioSpatialization.description')}}</small>
|
||||
</div>
|
||||
<div class="md-option-segment md-option-segment_auto">
|
||||
<input type="checkbox" v-model="app.cfg.audio.maikiwiAudio.spatial"
|
||||
v-on:change="CiderAudio.hierarchical_loading();" switch/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="md-option-line"
|
||||
v-show="app.cfg.audio.maikiwiAudio.spatial === true">
|
||||
<div class="md-option-segment">
|
||||
{{$root.getLz('settings.option.audio.enableAdvancedFunctionality.tunedAudioSpatialization.profile')}}
|
||||
<br>
|
||||
<small>{{$root.getLz('settings.option.audio.enableAdvancedFunctionality.tunedAudioSpatialization.profile.description')}}</small>
|
||||
</div>
|
||||
<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="CiderAudio.hierarchical_loading();">
|
||||
<option v-for="profile in spprofiles" :value="profile.id">{{ $root.getProfileLz("CTS", profile.name) }}</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div style="opacity: 0.5; pointer-events: none" v-if="false">
|
||||
<div class="md-option-header">
|
||||
<span>{{$root.getLz('settings.header.unfinished')}}</span>
|
||||
</div>
|
||||
<div class="md-option-line">
|
||||
<div class="md-option-segment">
|
||||
Cider Origami™️ Vocal Enhancer/Remasterer
|
||||
<br>
|
||||
<small>Re-textures the vocals by carving out the frequencies and adjusts them to the
|
||||
selected profile.<br>
|
||||
<b>Modern:</b>
|
||||
Modernizes vocals that was recorded on old microphones while preserving the artist's individualistic style.<br>
|
||||
<b>Articulate:</b>
|
||||
Wrapping every detail of the vocal to your ear, resulting in a more expressive voice.
|
||||
</small>
|
||||
</div>
|
||||
<div class="md-option-segment md-option-segment_auto">
|
||||
<select class="md-select">
|
||||
<option value="none">
|
||||
{{$root.getLz('settings.header.visual.windowBackgroundStyle.none')}}
|
||||
</option>
|
||||
<option value="modern">
|
||||
Modern
|
||||
</option>
|
||||
<option value="intimate">
|
||||
Intimate
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script>
|
||||
Vue.component('audiolabs-page', {
|
||||
template: "#audiolabs-page",
|
||||
props: [],
|
||||
data: function () {
|
||||
return {
|
||||
app: this.$root,
|
||||
arprofiles: CiderAudio.atmosphereRealizerProfiles,
|
||||
spprofiles: CiderAudio.spatialProfiles
|
||||
}
|
||||
},
|
||||
mounted: function () {
|
||||
|
||||
},
|
||||
methods: {
|
||||
}
|
||||
})
|
||||
</script>
|
||||
<script type="text/x-template" id="audiolabs-page">
|
||||
<div class="audiolabs-page">
|
||||
<div class="md-option-container">
|
||||
<div class="settings-option-body">
|
||||
<div class="md-option-line">
|
||||
<b-jumbotron :header="$root.getLz('settings.option.audio.audioLab')"
|
||||
lead="Designed by Cider Acoustic Technologies in California"></b-jumbotron>
|
||||
</div>
|
||||
<div class="md-option-line">
|
||||
<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="app.cfg.audio.maikiwiAudio.ciderPPE"
|
||||
v-on:change="CiderAudio.hierarchical_loading();" switch />
|
||||
</div>
|
||||
</div>
|
||||
<div class="md-option-line" v-show="app.cfg.audio.maikiwiAudio.ciderPPE === true">
|
||||
<div class="md-option-segment">
|
||||
{{$root.getLz('settings.option.audio.enableAdvancedFunctionality.ciderPPEStrength')}}
|
||||
<br>
|
||||
<small>{{$root.getLz('settings.option.audio.enableAdvancedFunctionality.ciderPPEStrength.description')}}</small>
|
||||
</div>
|
||||
<div class="md-option-segment md-option-segment_auto">
|
||||
<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
|
||||
({{$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>
|
||||
<div class="md-option-line">
|
||||
<div class="md-option-segment">
|
||||
Cider Opportunistic Correction System
|
||||
<br>
|
||||
<small>Takes advantage of the sonic characteristics of a specific equipment and adapts it to be
|
||||
more 'Cider' oriented.</small>
|
||||
</div>
|
||||
<div class="md-option-segment md-option-segment_auto">
|
||||
<select class="md-select" style="width:180px;"
|
||||
v-model="app.cfg.audio.maikiwiAudio.opportunisticCorrection_state"
|
||||
v-on:change="CiderAudio.hierarchical_loading()">
|
||||
<option value="OFF">OFF</option>
|
||||
<option value="CHU">Moondrop Chu</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="md-option-line">
|
||||
<div class="md-option-segment">
|
||||
{{$root.getLz('settings.option.audio.enableAdvancedFunctionality.atmosphereRealizer')}} [1]
|
||||
<br>
|
||||
<small>{{$root.getLz('settings.option.audio.enableAdvancedFunctionality.atmosphereRealizer.description')}}</small>
|
||||
</div>
|
||||
<div class="md-option-segment md-option-segment_auto">
|
||||
<input type="checkbox" v-model="app.cfg.audio.maikiwiAudio.atmosphereRealizer1"
|
||||
v-on:change="CiderAudio.hierarchical_loading();" switch />
|
||||
</div>
|
||||
</div>
|
||||
<div class="md-option-line" v-show="app.cfg.audio.maikiwiAudio.atmosphereRealizer1 === true">
|
||||
<div class="md-option-segment">
|
||||
{{$root.getLz('settings.option.audio.enableAdvancedFunctionality.atmosphereRealizerMode')}} [1]
|
||||
<br>
|
||||
<small>{{$root.getLz('settings.option.audio.enableAdvancedFunctionality.atmosphereRealizerMode.description')}}</small>
|
||||
</div>
|
||||
<div class="md-option-segment md-option-segment_auto">
|
||||
<select class="md-select" style="width:230px;"
|
||||
v-model="$root.cfg.audio.maikiwiAudio.atmosphereRealizer1_value"
|
||||
v-on:change="CiderAudio.hierarchical_loading();">
|
||||
<option v-for="profile in arprofiles" :value="profile.id">{{ $root.getProfileLz("CAR",
|
||||
profile.id) }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="md-option-line">
|
||||
<div class="md-option-segment">
|
||||
{{$root.getLz('settings.option.audio.enableAdvancedFunctionality.atmosphereRealizer')}} [2]
|
||||
<br>
|
||||
<small>{{$root.getLz('settings.option.audio.enableAdvancedFunctionality.atmosphereRealizer.description')}}</small>
|
||||
</div>
|
||||
<div class="md-option-segment md-option-segment_auto">
|
||||
<input type="checkbox" v-model="app.cfg.audio.maikiwiAudio.atmosphereRealizer2"
|
||||
v-on:change="CiderAudio.hierarchical_loading();" switch />
|
||||
</div>
|
||||
</div>
|
||||
<div class="md-option-line" v-show="app.cfg.audio.maikiwiAudio.atmosphereRealizer2 === true">
|
||||
<div class="md-option-segment">
|
||||
{{$root.getLz('settings.option.audio.enableAdvancedFunctionality.atmosphereRealizerMode')}} [2]
|
||||
<br>
|
||||
<small>{{$root.getLz('settings.option.audio.enableAdvancedFunctionality.atmosphereRealizerMode.description')}}</small>
|
||||
</div>
|
||||
<div class="md-option-segment md-option-segment_auto">
|
||||
<select class="md-select" style="width:230px;"
|
||||
v-model="$root.cfg.audio.maikiwiAudio.atmosphereRealizer2_value"
|
||||
v-on:change="CiderAudio.hierarchical_loading();">
|
||||
<option v-for="profile in arprofiles" :value="profile.id">{{ $root.getProfileLz("CAR",
|
||||
profile.id) }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="md-option-line">
|
||||
<div class="md-option-segment">
|
||||
{{$root.getLz('settings.option.audio.enableAdvancedFunctionality.tunedAudioSpatialization')}}
|
||||
<br>
|
||||
<small>{{$root.getLz('settings.option.audio.enableAdvancedFunctionality.tunedAudioSpatialization.description')}}</small>
|
||||
</div>
|
||||
<div class="md-option-segment md-option-segment_auto">
|
||||
<input type="checkbox" v-model="app.cfg.audio.maikiwiAudio.spatial"
|
||||
v-on:change="CiderAudio.hierarchical_loading();" switch />
|
||||
</div>
|
||||
</div>
|
||||
<div class="md-option-line"
|
||||
v-show="app.cfg.audio.maikiwiAudio.spatial === true">
|
||||
<div class="md-option-segment">
|
||||
{{$root.getLz('settings.option.audio.enableAdvancedFunctionality.tunedAudioSpatialization.profile')}}
|
||||
<br>
|
||||
<small>{{$root.getLz('settings.option.audio.enableAdvancedFunctionality.tunedAudioSpatialization.profile.description')}}</small>
|
||||
</div>
|
||||
<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="CiderAudio.hierarchical_loading();">
|
||||
<option v-for="profile in spprofiles" :value="profile.id">{{ $root.getProfileLz("CTS",
|
||||
profile.name) }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div style="opacity: 0.5; pointer-events: none" v-if="false">
|
||||
<div class="md-option-header">
|
||||
<span>{{$root.getLz('settings.header.unfinished')}}</span>
|
||||
</div>
|
||||
<div class="md-option-line">
|
||||
<div class="md-option-segment">
|
||||
Cider Origami™️ Vocal Enhancer/Remasterer
|
||||
<br>
|
||||
<small>Re-textures the vocals by carving out the frequencies and adjusts them to the
|
||||
selected profile.<br>
|
||||
<b>Modern:</b>
|
||||
Modernizes vocals that was recorded on old microphones while preserving the artist's
|
||||
individualistic style.<br>
|
||||
<b>Articulate:</b>
|
||||
Wrapping every detail of the vocal to your ear, resulting in a more expressive voice.
|
||||
</small>
|
||||
</div>
|
||||
<div class="md-option-segment md-option-segment_auto">
|
||||
<select class="md-select">
|
||||
<option value="none">
|
||||
{{$root.getLz('settings.header.visual.windowBackgroundStyle.none')}}
|
||||
</option>
|
||||
<option value="modern">
|
||||
Modern
|
||||
</option>
|
||||
<option value="intimate">
|
||||
Intimate
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script>
|
||||
Vue.component('audiolabs-page', {
|
||||
template: "#audiolabs-page",
|
||||
props: [],
|
||||
data: function() {
|
||||
return {
|
||||
app: this.$root,
|
||||
arprofiles: CiderAudio.atmosphereRealizerProfiles,
|
||||
spprofiles: CiderAudio.spatialProfiles
|
||||
}
|
||||
},
|
||||
mounted: function() {
|
||||
|
||||
},
|
||||
methods: {}
|
||||
})
|
||||
</script>
|
||||
|
|
|
@ -1,57 +1,71 @@
|
|||
<script type="text/x-template" id="cider-browse">
|
||||
<div class="content-inner">
|
||||
<h1 class="header-text">{{$root.getLz("term.browse")}}</h1>
|
||||
<template v-if="data.relationships && data.relationships.tabs">
|
||||
<template v-for="(recom,index) in data.relationships.tabs.data[0].relationships.children.data">
|
||||
<div class="row">
|
||||
<div class="col" v-if="recom.attributes.name != 'Chart Set'">
|
||||
<h3>{{ recom.attributes.name ?? ""}}</h3>
|
||||
</div>
|
||||
<div class="col-auto cider-flex-center" v-if="index != 0 && recom.relationships && ((recom.relationships.children && recom.relationships.children.data.length > 10) || (recom.relationships.contents && recom.relationships.contents.data.length > 10))">
|
||||
<button class="cd-btn-seeall" v-if="recom.relationships.room" @click="app.showRoom(recom.relationships.room?.data[0].href)" >{{app.getLz('term.seeAll')}}</button>
|
||||
<button class="cd-btn-seeall" v-else @click="app.showCollection(recom.relationships.children ? recom.relationships.children : recom.relationships.contents, recom.attributes.name ?? '', 'listen_now')" >{{app.getLz('term.seeAll')}}</button>
|
||||
</div>
|
||||
</div>
|
||||
<template v-if="(recom.relationships != null && ((recom.relationships.children && recom.relationships.children.data) || (recom.relationships.contents && recom.relationships.contents.data)))">
|
||||
<template v-if="index === 0|| (data.relationships.tabs.data[0].relationships.children.data[0].relationships == null && index === 1)">
|
||||
<mediaitem-scroller-horizontal-mvview :imagesize="800" :browsesp="index == 0|| (data.relationships.tabs.data[0].relationships.children.data[0].relationships == null && index === 1)" :kind="recom.attributes.editorialElementKind"
|
||||
:items="recom.relationships.children ? recom.relationships.children.data.limit(10) : recom.relationships.contents.data.limit(10)"></mediaitem-scroller-horizontal-mvview>
|
||||
</template>
|
||||
<template v-else-if="(['327']).includes(recom.attributes.editorialElementKind)">
|
||||
<div class="mediaitem-list-item__grid">
|
||||
<listitem-horizontal :items="recom.relationships.contents.data.limit(20)">
|
||||
</listitem-horizontal>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else-if="(['385']).includes(recom.attributes.editorialElementKind)">
|
||||
<mediaitem-scroller-horizontal-mvview :imagesize="800" :kind="recom.attributes.editorialElementKind"
|
||||
:items="recom.relationships.children ? recom.relationships.children.data.limit(10) : recom.relationships.contents.data.limit(10)"></mediaitem-scroller-horizontal-mvview>
|
||||
</template>
|
||||
<template v-else-if="recom.attributes.name == 'Chart Set'">
|
||||
<!-- ignored -->
|
||||
</template>
|
||||
<template v-else>
|
||||
<mediaitem-scroller-horizontal-large
|
||||
:items="recom.relationships.children ? recom.relationships.children.data.limit(10) : recom.relationships.contents.data.limit(10)"></mediaitem-scroller-horizontal-large>
|
||||
</template>
|
||||
</template>
|
||||
<template v-else>
|
||||
<template v-if="recom.attributes.links && recom.attributes.editorialElementKind.includes('391')">
|
||||
<div class="grouping-container">
|
||||
<button class="grouping-btn" @click="$root.goToGrouping(link.url)" v-for="link in recom.attributes.links">{{ link.label }}</button>
|
||||
<div class="content-inner">
|
||||
<h1 class="header-text">{{$root.getLz("term.browse")}}</h1>
|
||||
<template v-if="data.relationships && data.relationships.tabs">
|
||||
<template v-for="(recom,index) in data.relationships.tabs.data[0].relationships.children.data">
|
||||
<div class="row">
|
||||
<div class="col" v-if="recom.attributes.name != 'Chart Set'">
|
||||
<h3>{{ recom.attributes.name ?? ""}}</h3>
|
||||
</div>
|
||||
<div class="col-auto cider-flex-center"
|
||||
v-if="index != 0 && recom.relationships && ((recom.relationships.children && recom.relationships.children.data.length > 10) || (recom.relationships.contents && recom.relationships.contents.data.length > 10))">
|
||||
<button class="cd-btn-seeall" v-if="recom.relationships.room"
|
||||
@click="app.showRoom(recom.relationships.room?.data[0].href)">
|
||||
{{app.getLz('term.seeAll')}}
|
||||
</button>
|
||||
<button class="cd-btn-seeall" v-else
|
||||
@click="app.showCollection(recom.relationships.children ? recom.relationships.children : recom.relationships.contents, recom.attributes.name ?? '', 'listen_now')">
|
||||
{{app.getLz('term.seeAll')}}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<template
|
||||
v-if="(recom.relationships != null && ((recom.relationships.children && recom.relationships.children.data) || (recom.relationships.contents && recom.relationships.contents.data)))">
|
||||
<template
|
||||
v-if="index === 0|| (data.relationships.tabs.data[0].relationships.children.data[0].relationships == null && index === 1)">
|
||||
<mediaitem-scroller-horizontal-mvview :imagesize="800"
|
||||
:browsesp="index == 0|| (data.relationships.tabs.data[0].relationships.children.data[0].relationships == null && index === 1)"
|
||||
:kind="recom.attributes.editorialElementKind"
|
||||
:items="recom.relationships.children ? recom.relationships.children.data.limit(10) : recom.relationships.contents.data.limit(10)"></mediaitem-scroller-horizontal-mvview>
|
||||
</template>
|
||||
<template v-else-if="(['327']).includes(recom.attributes.editorialElementKind)">
|
||||
<div class="mediaitem-list-item__grid">
|
||||
<listitem-horizontal :items="recom.relationships.contents.data.limit(20)">
|
||||
</listitem-horizontal>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else-if="(['385']).includes(recom.attributes.editorialElementKind)">
|
||||
<mediaitem-scroller-horizontal-mvview :imagesize="800"
|
||||
:kind="recom.attributes.editorialElementKind"
|
||||
:items="recom.relationships.children ? recom.relationships.children.data.limit(10) : recom.relationships.contents.data.limit(10)"></mediaitem-scroller-horizontal-mvview>
|
||||
</template>
|
||||
<template v-else-if="recom.attributes.name == 'Chart Set'">
|
||||
<!-- ignored -->
|
||||
</template>
|
||||
<template v-else>
|
||||
<mediaitem-scroller-horizontal-large
|
||||
:items="recom.relationships.children ? recom.relationships.children.data.limit(10) : recom.relationships.contents.data.limit(10)"></mediaitem-scroller-horizontal-large>
|
||||
</template>
|
||||
</template>
|
||||
<template v-else>
|
||||
<template v-if="recom.attributes.links && recom.attributes.editorialElementKind.includes('391')">
|
||||
<div class="grouping-container">
|
||||
<button class="grouping-btn" @click="$root.goToGrouping(link.url)"
|
||||
v-for="link in recom.attributes.links">{{ link.label }}
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
</template>
|
||||
</template>
|
||||
</template>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script>
|
||||
Vue.component("cider-browse", {
|
||||
template: "#cider-browse",
|
||||
props: ["data"],
|
||||
data: function () {
|
||||
data: function() {
|
||||
return {
|
||||
app: this.$root,
|
||||
};
|
||||
|
@ -59,7 +73,6 @@
|
|||
mounted() {
|
||||
this.$root.getBrowsePage();
|
||||
},
|
||||
methods: {
|
||||
}
|
||||
methods: {}
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -1,133 +1,151 @@
|
|||
<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 cider-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>
|
||||
<template v-if="songs != []">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<h3>{{ songs.name ?? ""}}</h3>
|
||||
</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 cider-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 class="col-auto cider-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>
|
||||
<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 cider-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>
|
||||
<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>
|
||||
<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 cider-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 class="col-auto cider-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>
|
||||
<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 cider-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="(albums?.data ?? []).limit(10)"></mediaitem-scroller-horizontal-large>
|
||||
</template>
|
||||
<template v-if="playlists != []">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<h3>{{ playlists.name ?? ""}}</h3>
|
||||
</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 cider-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 class="col-auto cider-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>
|
||||
<mediaitem-scroller-horizontal-large
|
||||
:items="(citycharts?.data ?? []).limit(10)"></mediaitem-scroller-horizontal-large>
|
||||
</template>
|
||||
|
||||
</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 cider-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 cider-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 cider-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>
|
||||
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>
|
||||
|
|
|
@ -1,50 +1,57 @@
|
|||
<script type="text/x-template" id="cider-multiroom">
|
||||
<div class="content-inner cider-multiroom">
|
||||
<div class="artworkContainer" v-if ="data.attributes?.uber?.masterArt?.url">
|
||||
<artwork-material :url="data.attributes?.uber?.masterArt?.url ?? ''" size="800" images="1"></artwork-material>
|
||||
<div class="artworkContainer" v-if="data.attributes?.uber?.masterArt?.url">
|
||||
<artwork-material :url="data.attributes?.uber?.masterArt?.url ?? ''" size="800"
|
||||
images="1"></artwork-material>
|
||||
</div>
|
||||
<div class="detail">
|
||||
<h1 class="header-text">{{data.attributes?.title ?? ""}}</h1>
|
||||
<h2 class="header-desc" v-html='data.relationships?.children?.data[0]?.attributes?.description ?? ""'></h2>
|
||||
<template v-if="data.relationships">
|
||||
<template v-for="(recom,index) in data.relationships.children.data">
|
||||
<template v-if="(recom.relationships?.contents?.data ?? []).length > 0">
|
||||
<template v-if="(recom.relationships?.contents?.data ?? []).length > 0">
|
||||
<div class="row">
|
||||
<div class="col" v-if="recom.attributes.name != 'Chart Set'">
|
||||
<h3>{{ recom.attributes?.title ?? ""}}</h3>
|
||||
</div>
|
||||
<div class="col-auto cider-flex-center" v-if="index != 0 && recom.relationships && ((recom.relationships.children && recom.relationships.children.data.length > 10) || (recom.relationships.contents && recom.relationships.contents.data.length > 10))">
|
||||
<button class="cd-btn-seeall" @click="app.showCollection(recom.relationships.children ? recom.relationships.children : recom.relationships.contents, recom.attributes.name ?? '', 'listen_now')" >{{app.getLz('term.seeAll')}}</button>
|
||||
<div class="col-auto cider-flex-center"
|
||||
v-if="index != 0 && recom.relationships && ((recom.relationships.children && recom.relationships.children.data.length > 10) || (recom.relationships.contents && recom.relationships.contents.data.length > 10))">
|
||||
<button class="cd-btn-seeall"
|
||||
@click="app.showCollection(recom.relationships.children ? recom.relationships.children : recom.relationships.contents, recom.attributes.name ?? '', 'listen_now')">
|
||||
{{app.getLz('term.seeAll')}}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<template v-if="recom.relationships && ((recom.relationships.children && recom.relationships.children.data) || (recom.relationships.contents && recom.relationships.contents.data))">
|
||||
<template v-if="(recom.attributes.name && recom.attributes.name.includes('ideo')) || index === 0">
|
||||
<template
|
||||
v-if="recom.relationships && ((recom.relationships.children && recom.relationships.children.data) || (recom.relationships.contents && recom.relationships.contents.data))">
|
||||
<template
|
||||
v-if="(recom.attributes.name && recom.attributes.name.includes('ideo')) || index === 0">
|
||||
<mediaitem-scroller-horizontal-mvview :imagesize="800" :browsesp="index == 0"
|
||||
:items="recom.relationships.children ? recom.relationships.children.data.limit(10) : recom.relationships.contents.data.limit(10)"></mediaitem-scroller-horizontal-mvview>
|
||||
:items="recom.relationships.children ? recom.relationships.children.data.limit(10) : recom.relationships.contents.data.limit(10)"></mediaitem-scroller-horizontal-mvview>
|
||||
</template>
|
||||
<template v-else-if="recom.attributes.name == 'Chart Set'">
|
||||
|
||||
|
||||
</template>
|
||||
<template v-else>
|
||||
<mediaitem-scroller-horizontal-large
|
||||
:items="recom.relationships.children ? recom.relationships.children.data.limit(10) : recom.relationships.contents.data.limit(10)"></mediaitem-scroller-horizontal-large>
|
||||
</template>
|
||||
</template>
|
||||
</template>
|
||||
</template>
|
||||
</template>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script>
|
||||
Vue.component('cider-multiroom', {
|
||||
template: "#cider-multiroom",
|
||||
props: ["data"],
|
||||
data: function() {
|
||||
return {
|
||||
app: this.$root
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
Vue.component('cider-multiroom', {
|
||||
template: "#cider-multiroom",
|
||||
props: ["data"],
|
||||
data: function() {
|
||||
return {
|
||||
app: this.$root
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
|
|
@ -16,52 +16,56 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="artist-body">
|
||||
<template v-if="data.relationships && data.relationships['shared-playlists']">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<h3>{{ 'Shared Playlists' ?? ""}}</h3>
|
||||
<template v-if="data.relationships && data.relationships['shared-playlists']">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<h3>{{ 'Shared Playlists' ?? ""}}</h3>
|
||||
</div>
|
||||
<div class="col-auto cider-flex-center"
|
||||
v-if="data.relationships['shared-playlists'].data.length >= 10">
|
||||
<button class="cd-btn-seeall"
|
||||
@click="app.showCollection(data.relationships['shared-playlists'],'Shared Playlists' ?? '', 'default')">
|
||||
{{app.getLz('term.seeAll')}}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-auto cider-flex-center" v-if="data.relationships['shared-playlists'].data.length >= 10">
|
||||
<button class="cd-btn-seeall" @click="app.showCollection(data.relationships['shared-playlists'],'Shared Playlists' ?? '', 'default')">{{app.getLz('term.seeAll')}}</button>
|
||||
</div>
|
||||
</div>
|
||||
<mediaitem-square :item="item" v-for="item in data.relationships['shared-playlists'].data.limit(10)">
|
||||
</mediaitem-square>
|
||||
<mediaitem-square :item="item" v-for="item in data.relationships['shared-playlists'].data.limit(10)">
|
||||
</mediaitem-square>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
<script>
|
||||
Vue.component('cider-socialprofile', {
|
||||
template: "#cider-socialprofile",
|
||||
props: ['data'],
|
||||
data: function () {
|
||||
return {
|
||||
topSongsExpanded: false,
|
||||
app: this.$root
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getArtistPalette(artist) {
|
||||
if (artist?.attributes?.artwork != null) {
|
||||
return {
|
||||
"background": "#" + artist["attributes"]["artwork"]["bgColor"],
|
||||
"color": "#" + artist["attributes"]["artwork"]["textColor1"],
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
"background": "#000000",
|
||||
"color": "#ffffff",
|
||||
}
|
||||
}
|
||||
},
|
||||
getTopResult() {
|
||||
if (this.search.results["meta"]) {
|
||||
return this.search.results[this.search.results.meta.results.order[0]]["data"][0]
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
Vue.component('cider-socialprofile', {
|
||||
template: "#cider-socialprofile",
|
||||
props: ['data'],
|
||||
data: function() {
|
||||
return {
|
||||
topSongsExpanded: false,
|
||||
app: this.$root
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getArtistPalette(artist) {
|
||||
if (artist?.attributes?.artwork != null) {
|
||||
return {
|
||||
"background": "#" + artist["attributes"]["artwork"]["bgColor"],
|
||||
"color": "#" + artist["attributes"]["artwork"]["textColor1"],
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
"background": "#000000",
|
||||
"color": "#ffffff",
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
},
|
||||
getTopResult() {
|
||||
if (this.search.results["meta"]) {
|
||||
return this.search.results[this.search.results.meta.results.order[0]]["data"][0]
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<template v-if="item.type == 'artists'">
|
||||
<mediaitem-square :item="item"></mediaitem-square>
|
||||
</template>
|
||||
<template v-else>
|
||||
<template v-else>
|
||||
<mediaitem-list-item
|
||||
v-if="getKind(item) == 'song'"
|
||||
:index="key"
|
||||
|
@ -14,11 +14,13 @@
|
|||
<mediaitem-square v-else :item="item" :type="getKind(item)"></mediaitem-square>
|
||||
</template>
|
||||
</template>
|
||||
<button v-if="triggerEnabled" style="opacity:0;height: 32px;" v-observe-visibility="{callback: visibilityChanged}">{{this.app.getLz('term.showMore')}}
|
||||
<button v-if="triggerEnabled" style="opacity:0;height: 32px;"
|
||||
v-observe-visibility="{callback: visibilityChanged}">{{this.app.getLz('term.showMore')}}
|
||||
</button>
|
||||
</div>
|
||||
<transition name="fabfade">
|
||||
<button class="top-fab" v-show="showFab" @click="scrollToTop()" :aria-label="app.getLz('action.scrollToTop')">
|
||||
<button class="top-fab" v-show="showFab" @click="scrollToTop()"
|
||||
:aria-label="app.getLz('action.scrollToTop')">
|
||||
<%- include("../svg/arrow-up.svg") %>
|
||||
</button>
|
||||
</transition>
|
||||
|
@ -28,121 +30,121 @@
|
|||
</div>
|
||||
</script>
|
||||
<script>
|
||||
Vue.component('cider-collection-list', {
|
||||
template: "#cider-collection-list",
|
||||
props: {
|
||||
data: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
title: {
|
||||
type: String,
|
||||
required: false
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: "artists"
|
||||
}
|
||||
},
|
||||
data: function() {
|
||||
return {
|
||||
triggerEnabled: true,
|
||||
canSeeTrigger: false,
|
||||
showFab: false,
|
||||
commonKind: "song",
|
||||
api: this.$root.mk.api,
|
||||
loading: false,
|
||||
app: this.$root,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getClasses() {
|
||||
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;
|
||||
return item.kind
|
||||
}
|
||||
if (typeof item.attributes.playParams != "undefined") {
|
||||
// this.commonKind = item.attributes.playParams.kind
|
||||
return item.attributes.playParams.kind
|
||||
}
|
||||
return this.commonKind
|
||||
},
|
||||
scrollToTop() {
|
||||
let target = document.querySelector(".header-text")
|
||||
document.querySelector("#app-content").scrollTo({
|
||||
top: 0,
|
||||
left: 0,
|
||||
behavior: 'smooth'
|
||||
})
|
||||
},
|
||||
getNext() {
|
||||
let self = this
|
||||
this.triggerEnabled = false;
|
||||
if (typeof this.data.next == "undefined") {
|
||||
return
|
||||
}
|
||||
this.loading = true
|
||||
|
||||
this.api.v3.music(this.data.next, app.collectionList.requestBody).then((response) => {
|
||||
console.log(response)
|
||||
if (!app.collectionList.response.groups) {
|
||||
this.data.data = this.data.data.concat(response.data.data);
|
||||
if (response.data.next) {
|
||||
this.data.next = response.data.next;
|
||||
this.triggerEnabled = true;
|
||||
}
|
||||
this.loading = false
|
||||
} else {
|
||||
if (!response.data.results[app.collectionList.response.groups]) {
|
||||
this.loading = false
|
||||
return
|
||||
}
|
||||
this.data.data = this.data.data.concat(response.data.results[app.collectionList.response.groups].data);
|
||||
if (response.data.results[app.collectionList.response.groups].next) {
|
||||
this.data.next = response.data.results[app.collectionList.response.groups].next;
|
||||
this.triggerEnabled = true;
|
||||
this.loading = false
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
headerVisibility: function(isVisible, entry) {
|
||||
if (isVisible) {
|
||||
this.showFab = false;
|
||||
} else {
|
||||
this.showFab = true;
|
||||
}
|
||||
},
|
||||
visibilityChanged: function(isVisible, entry) {
|
||||
if (isVisible) {
|
||||
this.canSeeTrigger = true;
|
||||
this.getNext();
|
||||
} else {
|
||||
this.canSeeTrigger = false;
|
||||
}
|
||||
}
|
||||
Vue.component('cider-collection-list', {
|
||||
template: "#cider-collection-list",
|
||||
props: {
|
||||
data: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
title: {
|
||||
type: String,
|
||||
required: false
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: "artists"
|
||||
}
|
||||
},
|
||||
data: function() {
|
||||
return {
|
||||
triggerEnabled: true,
|
||||
canSeeTrigger: false,
|
||||
showFab: false,
|
||||
commonKind: "song",
|
||||
api: this.$root.mk.api,
|
||||
loading: false,
|
||||
app: this.$root,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getClasses() {
|
||||
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 "";
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
},
|
||||
getKind(item) {
|
||||
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
|
||||
}
|
||||
return this.commonKind
|
||||
},
|
||||
scrollToTop() {
|
||||
let target = document.querySelector(".header-text")
|
||||
document.querySelector("#app-content").scrollTo({
|
||||
top: 0,
|
||||
left: 0,
|
||||
behavior: 'smooth'
|
||||
})
|
||||
},
|
||||
getNext() {
|
||||
let self = this
|
||||
this.triggerEnabled = false;
|
||||
if (typeof this.data.next == "undefined") {
|
||||
return
|
||||
}
|
||||
this.loading = true
|
||||
|
||||
this.api.v3.music(this.data.next, app.collectionList.requestBody).then((response) => {
|
||||
console.log(response)
|
||||
if (!app.collectionList.response.groups) {
|
||||
this.data.data = this.data.data.concat(response.data.data);
|
||||
if (response.data.next) {
|
||||
this.data.next = response.data.next;
|
||||
this.triggerEnabled = true;
|
||||
}
|
||||
this.loading = false
|
||||
} else {
|
||||
if (!response.data.results[app.collectionList.response.groups]) {
|
||||
this.loading = false
|
||||
return
|
||||
}
|
||||
this.data.data = this.data.data.concat(response.data.results[app.collectionList.response.groups].data);
|
||||
if (response.data.results[app.collectionList.response.groups].next) {
|
||||
this.data.next = response.data.results[app.collectionList.response.groups].next;
|
||||
this.triggerEnabled = true;
|
||||
this.loading = false
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
headerVisibility: function(isVisible, entry) {
|
||||
if (isVisible) {
|
||||
this.showFab = false;
|
||||
} else {
|
||||
this.showFab = true;
|
||||
}
|
||||
},
|
||||
visibilityChanged: function(isVisible, entry) {
|
||||
if (isVisible) {
|
||||
this.canSeeTrigger = true;
|
||||
this.getNext();
|
||||
} else {
|
||||
this.canSeeTrigger = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
|
|
@ -4,18 +4,16 @@
|
|||
</div>
|
||||
</script>
|
||||
<script>
|
||||
Vue.component('connected', {
|
||||
template: '#connected',
|
||||
async mounted() {
|
||||
ipcRenderer.send('get-connected-url')
|
||||
ipcRenderer.on('send-connected-url', (event, url) => {
|
||||
this.url = url
|
||||
app.webview.src = url
|
||||
document.getElementById('foo').src = url;
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
|
||||
}
|
||||
});
|
||||
</script>
|
||||
Vue.component('connected', {
|
||||
template: '#connected',
|
||||
async mounted() {
|
||||
ipcRenderer.send('get-connected-url')
|
||||
ipcRenderer.on('send-connected-url', (event, url) => {
|
||||
this.url = url
|
||||
app.webview.src = url
|
||||
document.getElementById('foo').src = url;
|
||||
})
|
||||
},
|
||||
methods: {}
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -1,69 +1,84 @@
|
|||
<script type="text/x-template" id="cider-groupings">
|
||||
<div class="content-inner">
|
||||
<template v-if="data != null">
|
||||
<h1 class="header-text">{{data.attributes?.name}}</h1>
|
||||
<div class="content-inner">
|
||||
<template v-if="data != null">
|
||||
<h1 class="header-text">{{data.attributes?.name}}</h1>
|
||||
|
||||
<template v-if="data.relationships && data.relationships.tabs">
|
||||
<template v-for="(recom,index) in data.relationships.tabs.data[0].relationships.children.data">
|
||||
<div class="row">
|
||||
<div class="col" v-if="recom.attributes.name != 'Chart Set'">
|
||||
<h3>{{ recom.attributes.name ?? ""}}</h3>
|
||||
</div>
|
||||
<div class="col-auto cider-flex-center" v-if="index != 0 && recom.relationships && ((recom.relationships.children && recom.relationships.children.data.length > 10) || (recom.relationships.contents && recom.relationships.contents.data.length > 10))">
|
||||
<button class="cd-btn-seeall" v-if="recom.relationships.room" @click="app.showRoom(recom.relationships.room?.data[0].href)" >{{app.getLz('term.seeAll')}}</button>
|
||||
<button class="cd-btn-seeall" v-else @click="app.showCollection(recom.relationships.children ? recom.relationships.children : recom.relationships.contents, recom.attributes.name ?? '', 'listen_now')" >{{app.getLz('term.seeAll')}}</button>
|
||||
</div>
|
||||
</div>
|
||||
<template v-if="(recom.relationships != null && ((recom.relationships.children && recom.relationships.children.data) || (recom.relationships.contents && recom.relationships.contents.data)))">
|
||||
<template v-if="index === 0|| (data.relationships.tabs.data[0].relationships.children.data[0].relationships == null && index === 1)">
|
||||
<mediaitem-scroller-horizontal-mvview :imagesize="800" :browsesp="index == 0|| (data.relationships.tabs.data[0].relationships.children.data[0].relationships == null && index === 1)" :kind="recom.attributes.editorialElementKind"
|
||||
:items="recom.relationships.children ? recom.relationships.children.data : recom.relationships.contents.data"></mediaitem-scroller-horizontal-mvview>
|
||||
</template>
|
||||
<template v-else-if="(['327']).includes(recom.attributes.editorialElementKind)">
|
||||
<div class="mediaitem-list-item__grid">
|
||||
<listitem-horizontal :items="recom.relationships.contents.data.limit(20)">
|
||||
</listitem-horizontal>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else-if="(['385']).includes(recom.attributes.editorialElementKind)">
|
||||
<mediaitem-scroller-horizontal-mvview :imagesize="800" :kind="recom.attributes.editorialElementKind"
|
||||
:items="recom.relationships.children ? recom.relationships.children.data.limit(10) : recom.relationships.contents.data.limit(10)"></mediaitem-scroller-horizontal-mvview>
|
||||
</template>
|
||||
<template v-else-if="recom.attributes.name == 'Chart Set'">
|
||||
<!-- ignored -->
|
||||
</template>
|
||||
<template v-else>
|
||||
<mediaitem-scroller-horizontal-large
|
||||
:items="recom.relationships.children ? recom.relationships.children.data.limit(10) : recom.relationships.contents.data.limit(10)"></mediaitem-scroller-horizontal-large>
|
||||
</template>
|
||||
</template>
|
||||
<template v-else>
|
||||
<template v-if="recom.attributes.links && recom.attributes.editorialElementKind.includes('391')">
|
||||
<div class="grouping-container">
|
||||
<button class="grouping-btn" @click="$root.goToGrouping(link.url)" v-for="link in recom.attributes.links">{{ link.label }}</button>
|
||||
<template v-if="data.relationships && data.relationships.tabs">
|
||||
<template v-for="(recom,index) in data.relationships.tabs.data[0].relationships.children.data">
|
||||
<div class="row">
|
||||
<div class="col" v-if="recom.attributes.name != 'Chart Set'">
|
||||
<h3>{{ recom.attributes.name ?? ""}}</h3>
|
||||
</div>
|
||||
<div class="col-auto cider-flex-center"
|
||||
v-if="index != 0 && recom.relationships && ((recom.relationships.children && recom.relationships.children.data.length > 10) || (recom.relationships.contents && recom.relationships.contents.data.length > 10))">
|
||||
<button class="cd-btn-seeall" v-if="recom.relationships.room"
|
||||
@click="app.showRoom(recom.relationships.room?.data[0].href)">
|
||||
{{app.getLz('term.seeAll')}}
|
||||
</button>
|
||||
<button class="cd-btn-seeall" v-else
|
||||
@click="app.showCollection(recom.relationships.children ? recom.relationships.children : recom.relationships.contents, recom.attributes.name ?? '', 'listen_now')">
|
||||
{{app.getLz('term.seeAll')}}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<template
|
||||
v-if="(recom.relationships != null && ((recom.relationships.children && recom.relationships.children.data) || (recom.relationships.contents && recom.relationships.contents.data)))">
|
||||
<template
|
||||
v-if="index === 0|| (data.relationships.tabs.data[0].relationships.children.data[0].relationships == null && index === 1)">
|
||||
<mediaitem-scroller-horizontal-mvview :imagesize="800"
|
||||
:browsesp="index == 0|| (data.relationships.tabs.data[0].relationships.children.data[0].relationships == null && index === 1)"
|
||||
:kind="recom.attributes.editorialElementKind"
|
||||
:items="recom.relationships.children ? recom.relationships.children.data : recom.relationships.contents.data"></mediaitem-scroller-horizontal-mvview>
|
||||
</template>
|
||||
<template v-else-if="(['327']).includes(recom.attributes.editorialElementKind)">
|
||||
<div class="mediaitem-list-item__grid">
|
||||
<listitem-horizontal :items="recom.relationships.contents.data.limit(20)">
|
||||
</listitem-horizontal>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else-if="(['385']).includes(recom.attributes.editorialElementKind)">
|
||||
<mediaitem-scroller-horizontal-mvview :imagesize="800"
|
||||
:kind="recom.attributes.editorialElementKind"
|
||||
:items="recom.relationships.children ? recom.relationships.children.data.limit(10) : recom.relationships.contents.data.limit(10)"></mediaitem-scroller-horizontal-mvview>
|
||||
</template>
|
||||
<template v-else-if="recom.attributes.name == 'Chart Set'">
|
||||
<!-- ignored -->
|
||||
</template>
|
||||
<template v-else>
|
||||
<mediaitem-scroller-horizontal-large
|
||||
:items="recom.relationships.children ? recom.relationships.children.data.limit(10) : recom.relationships.contents.data.limit(10)"></mediaitem-scroller-horizontal-large>
|
||||
</template>
|
||||
</template>
|
||||
<template v-else>
|
||||
<template
|
||||
v-if="recom.attributes.links && recom.attributes.editorialElementKind.includes('391')">
|
||||
<div class="grouping-container">
|
||||
<button class="grouping-btn" @click="$root.goToGrouping(link.url)"
|
||||
v-for="link in recom.attributes.links">{{ link.label }}
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
</template>
|
||||
</template>
|
||||
</template>
|
||||
</template>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script>
|
||||
Vue.component("cider-groupings", {
|
||||
template: "#cider-groupings",
|
||||
data: function () {
|
||||
data: function() {
|
||||
return {
|
||||
data: null,
|
||||
app: this.$root,
|
||||
query: "",
|
||||
};
|
||||
},
|
||||
async mounted() {
|
||||
async mounted() {
|
||||
const queryDefaults = {
|
||||
"platform": "web",
|
||||
"l" : this.$root.mklang,
|
||||
"l": this.$root.mklang,
|
||||
"extend": "editorialArtwork,artistUrl",
|
||||
"omit[resource:artists]": "relationships",
|
||||
"include[groupings]": "curator",
|
||||
|
@ -82,7 +97,7 @@
|
|||
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.query.includes("&") ? queryDefaults : { "platform": "web" });
|
||||
this.data = result.data.data[0];
|
||||
|
||||
console.log(this.data);
|
||||
|
|
|
@ -8,8 +8,10 @@
|
|||
<h3>{{app.getLz('home.recentlyPlayed')}}</h3>
|
||||
</div>
|
||||
<div class="col-auto nopadding cider-flex-center">
|
||||
<button class="cd-btn-seeall" @click="seeAllHistory()">{{app.getLz('term.history')}}</button>
|
||||
<button class="cd-btn-seeall" @click="seeAllRecentlyPlayed()">{{app.getLz('term.seeAll')}}</button>
|
||||
<button class="cd-btn-seeall" @click="seeAllHistory()">{{app.getLz('term.history')}}
|
||||
</button>
|
||||
<button class="cd-btn-seeall" @click="seeAllRecentlyPlayed()">{{app.getLz('term.seeAll')}}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="well artistfeed-well">
|
||||
|
@ -26,9 +28,13 @@
|
|||
<h3>{{app.getLz('home.artistsFeed')}}</h3>
|
||||
</div>
|
||||
<div class="col-auto nopadding cider-flex-center">
|
||||
<button class="cd-btn-seeall" @click="syncFavorites()" v-if="!syncingFavs">{{app.getLz('home.syncFavorites')}}</button>
|
||||
<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>
|
||||
<button class="cd-btn-seeall" @click="app.appRoute('artist-feed')">
|
||||
{{app.getLz('term.seeAll')}}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="well artistfeed-well" style="margin-top:0;">
|
||||
|
@ -54,7 +60,9 @@
|
|||
<!-- </div>-->
|
||||
<div class="row" v-if="!seenReplay">
|
||||
<div class="col">
|
||||
<button class="md-btn md-btn-block md-btn-replay--hero" @click="$root.appRoute('replay')">{{$root.getLz('term.replay')}} {{ year }}</button>
|
||||
<button class="md-btn md-btn-block md-btn-replay--hero" @click="$root.appRoute('replay')">
|
||||
{{$root.getLz('term.replay')}} {{ year }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
|
@ -64,7 +72,9 @@
|
|||
<h3>{{app.getLz('home.madeForYou')}}</h3>
|
||||
</div>
|
||||
<div class="col-auto nopadding cider-flex-center">
|
||||
<button class="md-btn md-btn-replay" v-if="seenReplay" @click="$root.appRoute('replay')">{{$root.getLz('term.replay')}} {{ year }}</button>
|
||||
<button class="md-btn md-btn-replay" v-if="seenReplay" @click="$root.appRoute('replay')">
|
||||
{{$root.getLz('term.replay')}} {{ year }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="well">
|
||||
|
@ -81,11 +91,14 @@
|
|||
<h3>{{app.getLz('home.friendsListeningTo')}}</h3>
|
||||
</div>
|
||||
<div class="col-auto nopadding cider-flex-center">
|
||||
<button class="cd-btn-seeall" @click="app.showSocialListeningTo()">{{app.getLz('term.seeAll')}}</button>
|
||||
<button class="cd-btn-seeall" @click="app.showSocialListeningTo()">
|
||||
{{app.getLz('term.seeAll')}}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="well">
|
||||
<mediaitem-scroller-horizontal :items="friendsListeningTo" v-if="isSectionReady('friendsListeningTo')">
|
||||
<mediaitem-scroller-horizontal :items="friendsListeningTo"
|
||||
v-if="isSectionReady('friendsListeningTo')">
|
||||
</mediaitem-scroller-horizontal>
|
||||
<div class="spinner" v-else></div>
|
||||
</div>
|
||||
|
@ -96,167 +109,172 @@
|
|||
</script>
|
||||
|
||||
<script>
|
||||
Vue.component('cider-home', {
|
||||
template: '#cider-home',
|
||||
data: function() {
|
||||
return {
|
||||
app: this.$root,
|
||||
followedArtists: this.$root.cfg.home.followedArtists,
|
||||
favoriteItems: this.$root.cfg.home.favoriteItems,
|
||||
madeForYou: [],
|
||||
recentlyPlayed: [],
|
||||
friendsListeningTo: [],
|
||||
replayPlaylists: [],
|
||||
favorites: [],
|
||||
profile: {},
|
||||
modify: 0,
|
||||
artistFeed: [],
|
||||
showingArtistFeed: false,
|
||||
page: "main",
|
||||
sectionsReady: [],
|
||||
year: new Date().getFullYear(),
|
||||
seenReplay: localStorage.getItem('seenReplay'),
|
||||
syncingFavs: false
|
||||
}
|
||||
},
|
||||
async mounted() {
|
||||
let self = this
|
||||
this.getListenNowData()
|
||||
await this.getArtistFeed()
|
||||
await this.getFavorites()
|
||||
await this.getRecentlyPlayed()
|
||||
if (new Date().getMonth() == 11) {
|
||||
this.seenReplay = false
|
||||
localStorage.setItem('seenReplay', false)
|
||||
}
|
||||
},
|
||||
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,
|
||||
include: 'tracks',
|
||||
'include[albums]': 'catalog,tracks,artists',
|
||||
'include[songs]': 'catalog,artists',
|
||||
})
|
||||
app.showCollection(hist.data, app.getLz('home.recentlyPlayed'))
|
||||
},
|
||||
async seeAllHistory() {
|
||||
let hist = await app.mk.api.v3.music(`/v1/me/recent/played/tracks`, {
|
||||
l: this.$root.mklang
|
||||
})
|
||||
app.showCollection(hist.data, app.getLz('term.history'))
|
||||
},
|
||||
isSectionReady(section) {
|
||||
return this.sectionsReady.includes(section)
|
||||
},
|
||||
removeFavoriteContext() {
|
||||
let self = this
|
||||
return {
|
||||
name: "Remove from Favorites",
|
||||
action: function(item) {
|
||||
let index = self.favoriteItems.findIndex(x => x.id == item.id)
|
||||
if (index > -1) {
|
||||
self.favoriteItems.splice(index, 1)
|
||||
self.app.cfg.home.favoriteItems = self.favoriteItems
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
async getFavorites() {
|
||||
let self = this
|
||||
let libraryPlaylists = []
|
||||
let playlists = []
|
||||
for (let item of this.favoriteItems) {
|
||||
if (item.type == "library-playlists") {
|
||||
libraryPlaylists.push(item.id)
|
||||
} else if (item.type == "playlists") {
|
||||
playlists.push(item.id)
|
||||
}
|
||||
}
|
||||
if (playlists.length != 0) {
|
||||
this.app.mk.api.v3.music(`/v1/catalog/${app.mk.storefrontId}/playlists/${playlists.toString()}`, {
|
||||
l: this.$root.mklang
|
||||
}).then(playlistsData => {
|
||||
self.favorites.push(...playlistsData.data)
|
||||
})
|
||||
}
|
||||
if (libraryPlaylists.length != 0) {
|
||||
this.app.mk.api.v3.music(`v1/me/library/playlists/${playlists.toString()}`, {
|
||||
l: this.$root.mklang
|
||||
}).then(playlistsData => {
|
||||
self.favorites.push(...playlistsData.data)
|
||||
})
|
||||
}
|
||||
},
|
||||
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));
|
||||
}
|
||||
try {
|
||||
const chunkArtistData = await Promise.all(chunks.map(chunk =>
|
||||
this.app.mk.api.v3.music(`/v1/catalog/${app.mk.storefrontId}/artists?ids=${chunk.toString()}&views=latest-release&include[songs]=albums&fields[albums]=artistName,artistUrl,artwork,contentRating,editorialArtwork,editorialVideo,name,playParams,releaseDate,url,trackCount&limit[artists:top-songs]=2&art[url]=f`)))
|
||||
chunkArtistData.forEach(chunkResult =>
|
||||
chunkResult.data.data.forEach(item => {
|
||||
if (item.views["latest-release"].data.length != 0) {
|
||||
self.artistFeed.push(item.views["latest-release"].data[0])
|
||||
}
|
||||
}))
|
||||
// sort artistFeed by attributes.releaseDate descending, date is formatted as "YYYY-MM-DD"
|
||||
this.artistFeed.sort((a, b) => {
|
||||
let dateA = new Date(a.attributes.releaseDate)
|
||||
let dateB = new Date(b.attributes.releaseDate)
|
||||
return dateB - dateA
|
||||
})
|
||||
} catch (error) { }
|
||||
},
|
||||
async getRecentlyPlayed() {
|
||||
let hist = await app.mk.api.v3.music(`/v1/me/recent/played`, {
|
||||
l: this.$root.mklang,
|
||||
include: 'tracks',
|
||||
'include[albums]': 'catalog,tracks,artists',
|
||||
'include[songs]': 'catalog,artists',
|
||||
})
|
||||
this.recentlyPlayed = hist.data.data
|
||||
},
|
||||
async getListenNowData() {
|
||||
let self = this
|
||||
this.app.mk.api.v3.music(`/v1/me/recommendations?timezone=${encodeURIComponent(app.formatTimezoneOffset())}&name=listen-now&with=friendsMix,library,social&art[social-profiles:url]=c&art[url]=c,f&omit[resource]=autos&relate[editorial-items]=contents&extend=editorialCard,editorialVideo&extend[albums]=artistUrl&extend[library-albums]=artistUrl,editorialVideo&extend[playlists]=artistNames,editorialArtwork,editorialVideo&extend[library-playlists]=artistNames,editorialArtwork,editorialVideo&extend[social-profiles]=topGenreNames&include[albums]=artists&include[songs]=artists&include[music-videos]=artists&fields[albums]=artistName,artistUrl,artwork,contentRating,editorialArtwork,editorialVideo,name,playParams,releaseDate,url&fields[artists]=name,url&extend[stations]=airDate,supportsAirTimeUpdates&meta[stations]=inflectionPoints&types=artists,albums,editorial-items,library-albums,library-playlists,music-movies,music-videos,playlists,stations,uploaded-audios,uploaded-videos,activities,apple-curators,curators,tv-shows,social-upsells&platform=web&l=${this.$root.mklang}`).then((data) => {
|
||||
console.log(data.data.data[1])
|
||||
try {
|
||||
self.madeForYou = data.data.data.filter(section => {
|
||||
if (section.meta.metrics.moduleType == "6") {
|
||||
return section
|
||||
};
|
||||
})[0].relationships.contents.data
|
||||
} catch (err) {}
|
||||
self.sectionsReady.push("madeForYou")
|
||||
|
||||
try {
|
||||
self.friendsListeningTo = data.data.data.filter(section => {
|
||||
if (section.meta.metrics.moduleType == "11") {
|
||||
return section
|
||||
};
|
||||
})[0].relationships.contents.data
|
||||
} catch (err) {}
|
||||
self.sectionsReady.push("recentlyPlayed")
|
||||
self.sectionsReady.push("friendsListeningTo")
|
||||
});
|
||||
|
||||
app.mk.api.v3.music("/v1/me/social/profile/").then((response) => {
|
||||
self.profile = response.data.data[0]
|
||||
})
|
||||
|
||||
Vue.component('cider-home', {
|
||||
template: '#cider-home',
|
||||
data: function() {
|
||||
return {
|
||||
app: this.$root,
|
||||
followedArtists: this.$root.cfg.home.followedArtists,
|
||||
favoriteItems: this.$root.cfg.home.favoriteItems,
|
||||
madeForYou: [],
|
||||
recentlyPlayed: [],
|
||||
friendsListeningTo: [],
|
||||
replayPlaylists: [],
|
||||
favorites: [],
|
||||
profile: {},
|
||||
modify: 0,
|
||||
artistFeed: [],
|
||||
showingArtistFeed: false,
|
||||
page: "main",
|
||||
sectionsReady: [],
|
||||
year: new Date().getFullYear(),
|
||||
seenReplay: localStorage.getItem('seenReplay'),
|
||||
syncingFavs: false
|
||||
}
|
||||
},
|
||||
async mounted() {
|
||||
let self = this
|
||||
this.getListenNowData()
|
||||
await this.getArtistFeed()
|
||||
await this.getFavorites()
|
||||
await this.getRecentlyPlayed()
|
||||
if (new Date().getMonth() == 11) {
|
||||
this.seenReplay = false
|
||||
localStorage.setItem('seenReplay', false)
|
||||
}
|
||||
},
|
||||
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,
|
||||
include: 'tracks',
|
||||
'include[albums]': 'catalog,tracks,artists',
|
||||
'include[songs]': 'catalog,artists',
|
||||
})
|
||||
app.showCollection(hist.data, app.getLz('home.recentlyPlayed'))
|
||||
},
|
||||
async seeAllHistory() {
|
||||
let hist = await app.mk.api.v3.music(`/v1/me/recent/played/tracks`, {
|
||||
l: this.$root.mklang
|
||||
})
|
||||
app.showCollection(hist.data, app.getLz('term.history'))
|
||||
},
|
||||
isSectionReady(section) {
|
||||
return this.sectionsReady.includes(section)
|
||||
},
|
||||
removeFavoriteContext() {
|
||||
let self = this
|
||||
return {
|
||||
name: "Remove from Favorites",
|
||||
action: function(item) {
|
||||
let index = self.favoriteItems.findIndex(x => x.id == item.id)
|
||||
if (index > -1) {
|
||||
self.favoriteItems.splice(index, 1)
|
||||
self.app.cfg.home.favoriteItems = self.favoriteItems
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
},
|
||||
async getFavorites() {
|
||||
let self = this
|
||||
let libraryPlaylists = []
|
||||
let playlists = []
|
||||
for (let item of this.favoriteItems) {
|
||||
if (item.type == "library-playlists") {
|
||||
libraryPlaylists.push(item.id)
|
||||
} else if (item.type == "playlists") {
|
||||
playlists.push(item.id)
|
||||
}
|
||||
}
|
||||
if (playlists.length != 0) {
|
||||
this.app.mk.api.v3.music(`/v1/catalog/${app.mk.storefrontId}/playlists/${playlists.toString()}`, {
|
||||
l: this.$root.mklang
|
||||
}).then(playlistsData => {
|
||||
self.favorites.push(...playlistsData.data)
|
||||
})
|
||||
}
|
||||
if (libraryPlaylists.length != 0) {
|
||||
this.app.mk.api.v3.music(`v1/me/library/playlists/${playlists.toString()}`, {
|
||||
l: this.$root.mklang
|
||||
}).then(playlistsData => {
|
||||
self.favorites.push(...playlistsData.data)
|
||||
})
|
||||
}
|
||||
},
|
||||
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));
|
||||
}
|
||||
try {
|
||||
const chunkArtistData = await Promise.all(chunks.map(chunk =>
|
||||
this.app.mk.api.v3.music(`/v1/catalog/${app.mk.storefrontId}/artists?ids=${chunk.toString()}&views=latest-release&include[songs]=albums&fields[albums]=artistName,artistUrl,artwork,contentRating,editorialArtwork,editorialVideo,name,playParams,releaseDate,url,trackCount&limit[artists:top-songs]=2&art[url]=f`)))
|
||||
chunkArtistData.forEach(chunkResult =>
|
||||
chunkResult.data.data.forEach(item => {
|
||||
if (item.views["latest-release"].data.length != 0) {
|
||||
self.artistFeed.push(item.views["latest-release"].data[0])
|
||||
}
|
||||
}))
|
||||
// sort artistFeed by attributes.releaseDate descending, date is formatted as "YYYY-MM-DD"
|
||||
this.artistFeed.sort((a, b) => {
|
||||
let dateA = new Date(a.attributes.releaseDate)
|
||||
let dateB = new Date(b.attributes.releaseDate)
|
||||
return dateB - dateA
|
||||
})
|
||||
} catch (error) {
|
||||
}
|
||||
},
|
||||
async getRecentlyPlayed() {
|
||||
let hist = await app.mk.api.v3.music(`/v1/me/recent/played`, {
|
||||
l: this.$root.mklang,
|
||||
include: 'tracks',
|
||||
'include[albums]': 'catalog,tracks,artists',
|
||||
'include[songs]': 'catalog,artists',
|
||||
})
|
||||
this.recentlyPlayed = hist.data.data
|
||||
},
|
||||
async getListenNowData() {
|
||||
let self = this
|
||||
this.app.mk.api.v3.music(`/v1/me/recommendations?timezone=${encodeURIComponent(app.formatTimezoneOffset())}&name=listen-now&with=friendsMix,library,social&art[social-profiles:url]=c&art[url]=c,f&omit[resource]=autos&relate[editorial-items]=contents&extend=editorialCard,editorialVideo&extend[albums]=artistUrl&extend[library-albums]=artistUrl,editorialVideo&extend[playlists]=artistNames,editorialArtwork,editorialVideo&extend[library-playlists]=artistNames,editorialArtwork,editorialVideo&extend[social-profiles]=topGenreNames&include[albums]=artists&include[songs]=artists&include[music-videos]=artists&fields[albums]=artistName,artistUrl,artwork,contentRating,editorialArtwork,editorialVideo,name,playParams,releaseDate,url&fields[artists]=name,url&extend[stations]=airDate,supportsAirTimeUpdates&meta[stations]=inflectionPoints&types=artists,albums,editorial-items,library-albums,library-playlists,music-movies,music-videos,playlists,stations,uploaded-audios,uploaded-videos,activities,apple-curators,curators,tv-shows,social-upsells&platform=web&l=${this.$root.mklang}`).then((data) => {
|
||||
console.log(data.data.data[1])
|
||||
try {
|
||||
self.madeForYou = data.data.data.filter(section => {
|
||||
if (section.meta.metrics.moduleType == "6") {
|
||||
return section
|
||||
}
|
||||
;
|
||||
})[0].relationships.contents.data
|
||||
} catch (err) {
|
||||
}
|
||||
self.sectionsReady.push("madeForYou")
|
||||
|
||||
try {
|
||||
self.friendsListeningTo = data.data.data.filter(section => {
|
||||
if (section.meta.metrics.moduleType == "11") {
|
||||
return section
|
||||
}
|
||||
;
|
||||
})[0].relationships.contents.data
|
||||
} catch (err) {
|
||||
}
|
||||
self.sectionsReady.push("recentlyPlayed")
|
||||
self.sectionsReady.push("friendsListeningTo")
|
||||
});
|
||||
|
||||
app.mk.api.v3.music("/v1/me/social/profile/").then((response) => {
|
||||
self.profile = response.data.data[0]
|
||||
})
|
||||
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -6,7 +6,8 @@
|
|||
</div>
|
||||
<div class="col-auto">
|
||||
<button v-if="library.albums.downloadState == 2" @click="$root.getLibraryAlbumsFull(true, 1)"
|
||||
class="reload-btn" :aria-label="app.getLz('menubar.options.reload')"><%- include('../svg/redo.svg') %></button>
|
||||
class="reload-btn"
|
||||
:aria-label="app.getLz('menubar.options.reload')"><%- include('../svg/redo.svg') %></button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
|
@ -24,14 +25,18 @@
|
|||
<div class="col-auto cider-flex-center">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<select class="md-select" v-model="prefs.sort" @change="library.albums.sorting[1] = prefs.sort; $root.searchLibraryAlbums(1)">
|
||||
<select class="md-select" v-model="prefs.sort"
|
||||
@change="library.albums.sorting[1] = prefs.sort; $root.searchLibraryAlbums(1)">
|
||||
<optgroup :label="$root.getLz('term.sortBy')">
|
||||
<option v-for="(sort, index) in library.albums.sortingOptions" :value="index">{{ sort }}</option>
|
||||
<option v-for="(sort, index) in library.albums.sortingOptions" :value="index">{{ sort
|
||||
}}
|
||||
</option>
|
||||
</optgroup>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col">
|
||||
<select class="md-select" v-model="prefs.sortOrder" @change="library.albums.sortOrder[1] = prefs.sortOrder; $root.searchLibraryAlbums(1)">
|
||||
<select class="md-select" v-model="prefs.sortOrder"
|
||||
@change="library.albums.sortOrder[1] = prefs.sortOrder; $root.searchLibraryAlbums(1)">
|
||||
<optgroup :label="$root.getLz('term.sortOrder')">
|
||||
<option value="asc">{{$root.getLz('term.sortOrder.ascending')}}</option>
|
||||
<option value="desc">{{$root.getLz('term.sortOrder.descending')}}</option>
|
||||
|
@ -50,7 +55,9 @@
|
|||
<select class="md-select" v-model="prefs.scroll">
|
||||
<optgroup :label="app.getLz('term.scroll')">
|
||||
<option value="infinite">{{app.getLz('term.scroll.infinite')}}</option>
|
||||
<option value="paged">{{app.getLz('term.scroll.paged').replace("${songsPerPage}", pageSize)}}</option>
|
||||
<option value="paged">{{app.getLz('term.scroll.paged').replace("${songsPerPage}",
|
||||
pageSize)}}
|
||||
</option>
|
||||
</optgroup>
|
||||
</select>
|
||||
</div>
|
||||
|
@ -58,57 +65,59 @@
|
|||
</div>
|
||||
</div>
|
||||
<pagination
|
||||
:length="app.library.albums.displayListing.length
|
||||
:length="app.library.albums.displayListing.length
|
||||
"
|
||||
:pageSize="pageSize"
|
||||
:scroll="prefs.scroll"
|
||||
scrollSelector="#app-content"
|
||||
@onRangeChange="onRangeChange"
|
||||
:pageSize="pageSize"
|
||||
:scroll="prefs.scroll"
|
||||
scrollSelector="#app-content"
|
||||
@onRangeChange="onRangeChange"
|
||||
/>
|
||||
<div class="well">
|
||||
<div class="albums-square-container">
|
||||
<div>
|
||||
<mediaitem-square v-if="prefs.viewAs == 'covers'" :size="'300'" :item="item" v-for="item in currentSlice">
|
||||
<mediaitem-square v-if="prefs.viewAs == 'covers'" :size="'300'" :item="item"
|
||||
v-for="item in currentSlice">
|
||||
</mediaitem-square>
|
||||
</div>
|
||||
</div>
|
||||
<mediaitem-list-item v-if="prefs.viewAs == 'list'" :show-duration="false" :show-meta-data="true" :show-library-status="false" :item="item" v-for="item in currentSlice">
|
||||
<mediaitem-list-item v-if="prefs.viewAs == 'list'" :show-duration="false" :show-meta-data="true"
|
||||
:show-library-status="false" :item="item" v-for="item in currentSlice">
|
||||
</mediaitem-list-item>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
<script>
|
||||
Vue.component('cider-library-albums', {
|
||||
template: '#cider-library-albums',
|
||||
data: function () {
|
||||
const pageSize = this.$root.cfg.libraryPrefs.pageSize;
|
||||
return {
|
||||
library: this.$root.library,
|
||||
mediaItemSize: "compact",
|
||||
prefs: this.$root.cfg.libraryPrefs.albums,
|
||||
app: this.$root,
|
||||
pageSize: pageSize,
|
||||
start: 0,
|
||||
end: pageSize
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.$root.getLibraryAlbumsFull(null, 1);
|
||||
this.$root.getAlbumSort();
|
||||
this.$root.searchLibraryAlbums(1);
|
||||
this.$root.getLibrarySongsFull();
|
||||
this.$root.searchLibraryAlbums(1);
|
||||
},
|
||||
computed: {
|
||||
currentSlice: function () {
|
||||
return this.library.albums.displayListing.slice(this.start, this.end);
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onRangeChange: function (newRange) {
|
||||
this.start = newRange[0];
|
||||
this.end = newRange[1];
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
Vue.component('cider-library-albums', {
|
||||
template: '#cider-library-albums',
|
||||
data: function() {
|
||||
const pageSize = this.$root.cfg.libraryPrefs.pageSize;
|
||||
return {
|
||||
library: this.$root.library,
|
||||
mediaItemSize: "compact",
|
||||
prefs: this.$root.cfg.libraryPrefs.albums,
|
||||
app: this.$root,
|
||||
pageSize: pageSize,
|
||||
start: 0,
|
||||
end: pageSize
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.$root.getLibraryAlbumsFull(null, 1);
|
||||
this.$root.getAlbumSort();
|
||||
this.$root.searchLibraryAlbums(1);
|
||||
this.$root.getLibrarySongsFull();
|
||||
this.$root.searchLibraryAlbums(1);
|
||||
},
|
||||
computed: {
|
||||
currentSlice: function() {
|
||||
return this.library.albums.displayListing.slice(this.start, this.end);
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onRangeChange: function(newRange) {
|
||||
this.start = newRange[0];
|
||||
this.end = newRange[1];
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -4,84 +4,88 @@
|
|||
<div class="col" style="padding:0;">
|
||||
<h1 class="header-text">{{$root.getLz('term.artists')}}</h1>
|
||||
</div>
|
||||
|
||||
|
||||
</div> -->
|
||||
<div class="inner-container">
|
||||
<div class="list-container">
|
||||
<div class="col" style="padding:0;">
|
||||
<div class="search-input-container" style="width:calc(100%-20px);margin: 16px 10px 10px 10px;">
|
||||
<div class="search-input--icon"></div>
|
||||
<input type="search" style="width:100%;" spellcheck="false" :placeholder="$root.getLz('term.search') + '...'" @input="$root.searchLibraryArtists" v-model="library.artists.search" class="search-input">
|
||||
<input type="search" style="width:100%;" spellcheck="false"
|
||||
:placeholder="$root.getLz('term.search') + '...'" @input="$root.searchLibraryArtists"
|
||||
v-model="library.artists.search" class="search-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="podcasts-list">
|
||||
<libraryartist-item :show-duration="false" :show-meta-data="true" :show-library-status="false" :item="item" v-for="item in library.artists.displayListing">
|
||||
<libraryartist-item :show-duration="false" :show-meta-data="true" :show-library-status="false"
|
||||
:item="item" v-for="item in library.artists.displayListing">
|
||||
</libraryartist-item>
|
||||
</div>
|
||||
</div>
|
||||
<div class="episodes-list" >
|
||||
<div class="episodes-inline-info" v-if="clready">
|
||||
<inline-collection-list :parentSelector="'.episodes-list'" :data="clresponse" :type="cltype" :title="cltitle"></inline-collection-list>
|
||||
</div>
|
||||
<div class="episodes-list">
|
||||
<div class="episodes-inline-info" v-if="clready">
|
||||
<inline-collection-list :parentSelector="'.episodes-list'" :data="clresponse" :type="cltype"
|
||||
:title="cltitle"></inline-collection-list>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</script>
|
||||
<script>
|
||||
Vue.component('cider-library-artists', {
|
||||
template: '#cider-library-artists',
|
||||
data: function () {
|
||||
return {
|
||||
library: this.$root.library,
|
||||
app: this.$root,
|
||||
ciderPodcasts: [],
|
||||
podcasts: [],
|
||||
episodes: [],
|
||||
search: {
|
||||
term: "",
|
||||
loading: false,
|
||||
results: [],
|
||||
resultsLibrary: [],
|
||||
next: ""
|
||||
},
|
||||
podcastSelected: {
|
||||
id: -1
|
||||
},
|
||||
selected: {
|
||||
id: -1
|
||||
},
|
||||
collectionList: {
|
||||
response: null, title: null, type: null, requestBody: null
|
||||
},
|
||||
clresponse: [],
|
||||
clready: false,
|
||||
cltitle: '',
|
||||
cltype: "artists",
|
||||
Vue.component('cider-library-artists', {
|
||||
template: '#cider-library-artists',
|
||||
data: function() {
|
||||
return {
|
||||
library: this.$root.library,
|
||||
app: this.$root,
|
||||
ciderPodcasts: [],
|
||||
podcasts: [],
|
||||
episodes: [],
|
||||
search: {
|
||||
term: "",
|
||||
loading: false,
|
||||
results: [],
|
||||
resultsLibrary: [],
|
||||
next: ""
|
||||
},
|
||||
podcastSelected: {
|
||||
id: -1
|
||||
},
|
||||
selected: {
|
||||
id: -1
|
||||
},
|
||||
collectionList: {
|
||||
response: null, title: null, type: null, requestBody: null
|
||||
},
|
||||
clresponse: [],
|
||||
clready: false,
|
||||
cltitle: '',
|
||||
cltype: "artists",
|
||||
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
let self = this;
|
||||
this.$root.getLibraryArtistsFull(null, 0);
|
||||
this.$root.$on('ap-inlinecollection', function(e){
|
||||
console.log("hey",e)
|
||||
self.clready = true;
|
||||
self.clresponse = e.response;
|
||||
self.cltitle = e.title ?? '';
|
||||
self.cltype = e.type ;
|
||||
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
getInlineCollection(e){
|
||||
console.log("hey",e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
let self = this;
|
||||
this.$root.getLibraryArtistsFull(null, 0);
|
||||
this.$root.$on('ap-inlinecollection', function(e) {
|
||||
console.log("hey", e)
|
||||
self.clready = true;
|
||||
self.clresponse = e.response;
|
||||
self.cltitle = e.title ?? '';
|
||||
self.cltype = e.type;
|
||||
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
getInlineCollection(e) {
|
||||
console.log("hey", e);
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<script type="text/x-template" id="libraryartist-item">
|
||||
<div v-observe-visibility="{callback: visibilityChanged}"
|
||||
<div v-observe-visibility="{callback: visibilityChanged}"
|
||||
@click="select"
|
||||
class="cd-mediaitem-list-item"
|
||||
:class="{'mediaitem-selected': app.select_hasMediaItem(guid)}"
|
||||
|
@ -104,179 +108,182 @@
|
|||
</script>
|
||||
|
||||
<script>
|
||||
Vue.component('libraryartist-item', {
|
||||
template: '#libraryartist-item',
|
||||
data: function () {
|
||||
return {
|
||||
isVisible: false,
|
||||
addedToLibrary: false,
|
||||
guid: this.uuidv4(),
|
||||
app: this.$root,
|
||||
}
|
||||
},
|
||||
props: {
|
||||
'item': {type: Object, required: true},
|
||||
'parent': {type: String, required: false},
|
||||
'index': {type: Number, required: false, default: -1},
|
||||
'show-artwork': {type: Boolean, default: true},
|
||||
'show-library-status': {type: Boolean, default: true},
|
||||
'show-meta-data': {type: Boolean, default: false},
|
||||
'show-duration': {type: Boolean, default: true},
|
||||
'contextExt': {type: Object, required: false},
|
||||
},
|
||||
methods: {
|
||||
uuidv4() {
|
||||
return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, c =>
|
||||
(c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16)
|
||||
);
|
||||
},
|
||||
msToMinSec(ms) {
|
||||
var minutes = Math.floor(ms / 60000);
|
||||
var seconds = ((ms % 60000) / 1000).toFixed(0);
|
||||
return minutes + ":" + (seconds < 10 ? '0' : '') + seconds;
|
||||
},
|
||||
getDataType() {
|
||||
return this.item.type
|
||||
},
|
||||
async select(e) {
|
||||
let u = this.item
|
||||
let u1 = await app.mk.api.v3.music(`/v1/me/library/artists/${u.id}/albums`, {
|
||||
"platform": "web",
|
||||
"include[library-albums]": "artists,tracks",
|
||||
"include[library-artists]": "catalog",
|
||||
"fields[artists]": "url",
|
||||
"includeOnly": "catalog,artists"
|
||||
})
|
||||
this.showCollection({data : Object.assign({},u1.data.data)}, u.attributes.name?? '', '');
|
||||
//app.select_selectMediaItem(u.id, this.getDataType(), this.index, this.guid, true)
|
||||
},
|
||||
showCollection(response, title, type, requestBody = {}){
|
||||
this.$root.$emit('ap-inlinecollection', {
|
||||
response: response, title: title, type: type, requestBody: {}}
|
||||
);
|
||||
},
|
||||
getArtwork(){
|
||||
let u = ""
|
||||
try{
|
||||
u = this.item.relationships.catalog.data[0].attributes.artwork.url}
|
||||
catch (e){};
|
||||
return u;
|
||||
},
|
||||
contextMenu(event) {
|
||||
|
||||
let self = this
|
||||
let data_type = this.getDataType()
|
||||
|
||||
let item = self.item
|
||||
item.attributes.artistName = item.attributes.name;
|
||||
|
||||
let useMenu = "normal"
|
||||
if (app.selectedMediaItems.length <= 1) {
|
||||
app.selectedMediaItems = []
|
||||
app.select_selectMediaItem(this.item.id, data_type, this.index, this.guid, true)
|
||||
} else {
|
||||
useMenu = "multiple"
|
||||
}
|
||||
|
||||
let menus = {
|
||||
multiple: {
|
||||
items: [] //
|
||||
},
|
||||
normal: {
|
||||
items: [
|
||||
{
|
||||
"name": app.getLz('action.goToArtist'),
|
||||
"icon": "./assets/feather/user.svg",
|
||||
"action": function () {
|
||||
app.searchAndNavigate(self.item, 'artist')
|
||||
console.log(self.item)
|
||||
}
|
||||
},
|
||||
{
|
||||
"icon": "./assets/feather/radio.svg",
|
||||
"name": app.getLz('action.startRadio'),
|
||||
"action": function () {
|
||||
app.mk.setStationQueue({song: self.item.attributes.playParams.id ?? self.item.id}).then(() => {
|
||||
app.mk.play()
|
||||
app.selectedMediaItems = []
|
||||
})
|
||||
}
|
||||
},
|
||||
// Hidden for now, as it's not implemented yet
|
||||
/*{
|
||||
"icon": "./assets/feather/share.svg",
|
||||
"name": app.getLz('action.share'),
|
||||
"action": function () {
|
||||
if (!self.item.attributes.url && self.item.relationships){
|
||||
if (self.item.relationships.catalog){
|
||||
app.mkapi(self.item.attributes.playParams.kind, false, self.item.relationships.catalog.data[0].id).then(u => {self.app.copyToClipboard((u.data.data.length && u.data.data.length > 0)? u.data.data[0].attributes.url : u.data.data.attributes.url)})
|
||||
}
|
||||
} else {
|
||||
self.app.copyToClipboard(self.item.attributes.url)}
|
||||
}
|
||||
},*/
|
||||
]
|
||||
}
|
||||
}
|
||||
if (this.contextExt) {
|
||||
// if this.context-ext.normal is true append all options to the 'normal' menu which is a kvp of arrays
|
||||
if (this.contextExt.normal) {
|
||||
menus.normal.items = menus.normal.items.concat(this.contextExt.normal)
|
||||
}
|
||||
if (this.contextExt.multiple) {
|
||||
menus.multiple.items = menus.multiple.items.concat(this.contextExt.multiple)
|
||||
}
|
||||
}
|
||||
//CiderContextMenu.Create(event, menus[useMenu]); // Depreciated Context Menu
|
||||
app.showMenuPanel(menus[useMenu], event);
|
||||
|
||||
},
|
||||
visibilityChanged: function (isVisible, entry) {
|
||||
this.isVisible = isVisible
|
||||
},
|
||||
addToLibrary() {
|
||||
let item = this.item
|
||||
if (item.attributes.playParams.id) {
|
||||
console.log('adding to library', item.attributes.playParams.id)
|
||||
app.addToLibrary(item.attributes.playParams.id.toString())
|
||||
this.addedToLibrary = true
|
||||
} else if (item.id) {
|
||||
console.log('adding to library', item.id)
|
||||
app.addToLibrary(item.id.toString())
|
||||
this.addedToLibrary = true
|
||||
}
|
||||
},
|
||||
async removeFromLibrary() {
|
||||
let item = this.item
|
||||
let params = {"fields[songs]": "inLibrary", "fields[albums]": "inLibrary", "relate": "library"}
|
||||
let id = item.id ?? item.attributes.playParams.id
|
||||
let res = await app.mkapi(item.attributes.playParams.kind ?? item.type, item.attributes.playParams.isLibrary ?? false, item.attributes.playParams.id ?? item.id, params);
|
||||
if (res && res.relationships && res.relationships.library && res.relationships.library.data && res.relationships.library.data.length > 0) {
|
||||
id = res.relationships.library.data[0].id
|
||||
}
|
||||
let kind = this.item.attributes.playParams.kind ?? this.data.item ?? '';
|
||||
let truekind = (!kind.endsWith("s")) ? (kind + "s") : kind;
|
||||
if (item.attributes.playParams.id) {
|
||||
console.log('remove from library', id)
|
||||
app.removeFromLibrary(truekind, id)
|
||||
this.addedToLibrary = false
|
||||
} else if (item.id) {
|
||||
console.log('remove from library', id)
|
||||
app.removeFromLibrary(truekind, id)
|
||||
this.addedToLibrary = false
|
||||
}
|
||||
},
|
||||
playTrack() {
|
||||
let item = this.item
|
||||
let parent = this.parent
|
||||
let childIndex = this.index
|
||||
console.log(item, parent, childIndex)
|
||||
if (parent != null && childIndex != null) {
|
||||
app.queueParentandplayChild(parent, childIndex, item);
|
||||
} else {
|
||||
app.playMediaItemById(item.attributes.playParams.id ?? item.id, item.attributes.playParams.kind ?? item.type, item.attributes.playParams.isLibrary ?? false, item.attributes.url)
|
||||
}
|
||||
}
|
||||
Vue.component('libraryartist-item', {
|
||||
template: '#libraryartist-item',
|
||||
data: function() {
|
||||
return {
|
||||
isVisible: false,
|
||||
addedToLibrary: false,
|
||||
guid: this.uuidv4(),
|
||||
app: this.$root,
|
||||
}
|
||||
},
|
||||
props: {
|
||||
'item': { type: Object, required: true },
|
||||
'parent': { type: String, required: false },
|
||||
'index': { type: Number, required: false, default: -1 },
|
||||
'show-artwork': { type: Boolean, default: true },
|
||||
'show-library-status': { type: Boolean, default: true },
|
||||
'show-meta-data': { type: Boolean, default: false },
|
||||
'show-duration': { type: Boolean, default: true },
|
||||
'contextExt': { type: Object, required: false },
|
||||
},
|
||||
methods: {
|
||||
uuidv4() {
|
||||
return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, c =>
|
||||
(c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16)
|
||||
);
|
||||
},
|
||||
msToMinSec(ms) {
|
||||
var minutes = Math.floor(ms / 60000);
|
||||
var seconds = ((ms % 60000) / 1000).toFixed(0);
|
||||
return minutes + ":" + (seconds < 10 ? '0' : '') + seconds;
|
||||
},
|
||||
getDataType() {
|
||||
return this.item.type
|
||||
},
|
||||
async select(e) {
|
||||
let u = this.item
|
||||
let u1 = await app.mk.api.v3.music(`/v1/me/library/artists/${u.id}/albums`, {
|
||||
"platform": "web",
|
||||
"include[library-albums]": "artists,tracks",
|
||||
"include[library-artists]": "catalog",
|
||||
"fields[artists]": "url",
|
||||
"includeOnly": "catalog,artists"
|
||||
})
|
||||
this.showCollection({ data: Object.assign({}, u1.data.data) }, u.attributes.name ?? '', '');
|
||||
//app.select_selectMediaItem(u.id, this.getDataType(), this.index, this.guid, true)
|
||||
},
|
||||
showCollection(response, title, type, requestBody = {}) {
|
||||
this.$root.$emit('ap-inlinecollection', {
|
||||
response: response, title: title, type: type, requestBody: {}
|
||||
}
|
||||
);
|
||||
},
|
||||
getArtwork() {
|
||||
let u = ""
|
||||
try {
|
||||
u = this.item.relationships.catalog.data[0].attributes.artwork.url
|
||||
} catch (e) {
|
||||
}
|
||||
});
|
||||
</script>
|
||||
;
|
||||
return u;
|
||||
},
|
||||
contextMenu(event) {
|
||||
|
||||
let self = this
|
||||
let data_type = this.getDataType()
|
||||
|
||||
let item = self.item
|
||||
item.attributes.artistName = item.attributes.name;
|
||||
|
||||
let useMenu = "normal"
|
||||
if (app.selectedMediaItems.length <= 1) {
|
||||
app.selectedMediaItems = []
|
||||
app.select_selectMediaItem(this.item.id, data_type, this.index, this.guid, true)
|
||||
} else {
|
||||
useMenu = "multiple"
|
||||
}
|
||||
|
||||
let menus = {
|
||||
multiple: {
|
||||
items: [] //
|
||||
},
|
||||
normal: {
|
||||
items: [
|
||||
{
|
||||
"name": app.getLz('action.goToArtist'),
|
||||
"icon": "./assets/feather/user.svg",
|
||||
"action": function() {
|
||||
app.searchAndNavigate(self.item, 'artist')
|
||||
console.log(self.item)
|
||||
}
|
||||
},
|
||||
{
|
||||
"icon": "./assets/feather/radio.svg",
|
||||
"name": app.getLz('action.startRadio'),
|
||||
"action": function() {
|
||||
app.mk.setStationQueue({ song: self.item.attributes.playParams.id ?? self.item.id }).then(() => {
|
||||
app.mk.play()
|
||||
app.selectedMediaItems = []
|
||||
})
|
||||
}
|
||||
},
|
||||
// Hidden for now, as it's not implemented yet
|
||||
/*{
|
||||
"icon": "./assets/feather/share.svg",
|
||||
"name": app.getLz('action.share'),
|
||||
"action": function () {
|
||||
if (!self.item.attributes.url && self.item.relationships){
|
||||
if (self.item.relationships.catalog){
|
||||
app.mkapi(self.item.attributes.playParams.kind, false, self.item.relationships.catalog.data[0].id).then(u => {self.app.copyToClipboard((u.data.data.length && u.data.data.length > 0)? u.data.data[0].attributes.url : u.data.data.attributes.url)})
|
||||
}
|
||||
} else {
|
||||
self.app.copyToClipboard(self.item.attributes.url)}
|
||||
}
|
||||
},*/
|
||||
]
|
||||
}
|
||||
}
|
||||
if (this.contextExt) {
|
||||
// if this.context-ext.normal is true append all options to the 'normal' menu which is a kvp of arrays
|
||||
if (this.contextExt.normal) {
|
||||
menus.normal.items = menus.normal.items.concat(this.contextExt.normal)
|
||||
}
|
||||
if (this.contextExt.multiple) {
|
||||
menus.multiple.items = menus.multiple.items.concat(this.contextExt.multiple)
|
||||
}
|
||||
}
|
||||
//CiderContextMenu.Create(event, menus[useMenu]); // Depreciated Context Menu
|
||||
app.showMenuPanel(menus[useMenu], event);
|
||||
|
||||
},
|
||||
visibilityChanged: function(isVisible, entry) {
|
||||
this.isVisible = isVisible
|
||||
},
|
||||
addToLibrary() {
|
||||
let item = this.item
|
||||
if (item.attributes.playParams.id) {
|
||||
console.log('adding to library', item.attributes.playParams.id)
|
||||
app.addToLibrary(item.attributes.playParams.id.toString())
|
||||
this.addedToLibrary = true
|
||||
} else if (item.id) {
|
||||
console.log('adding to library', item.id)
|
||||
app.addToLibrary(item.id.toString())
|
||||
this.addedToLibrary = true
|
||||
}
|
||||
},
|
||||
async removeFromLibrary() {
|
||||
let item = this.item
|
||||
let params = { "fields[songs]": "inLibrary", "fields[albums]": "inLibrary", "relate": "library" }
|
||||
let id = item.id ?? item.attributes.playParams.id
|
||||
let res = await app.mkapi(item.attributes.playParams.kind ?? item.type, item.attributes.playParams.isLibrary ?? false, item.attributes.playParams.id ?? item.id, params);
|
||||
if (res && res.relationships && res.relationships.library && res.relationships.library.data && res.relationships.library.data.length > 0) {
|
||||
id = res.relationships.library.data[0].id
|
||||
}
|
||||
let kind = this.item.attributes.playParams.kind ?? this.data.item ?? '';
|
||||
let truekind = (!kind.endsWith("s")) ? (kind + "s") : kind;
|
||||
if (item.attributes.playParams.id) {
|
||||
console.log('remove from library', id)
|
||||
app.removeFromLibrary(truekind, id)
|
||||
this.addedToLibrary = false
|
||||
} else if (item.id) {
|
||||
console.log('remove from library', id)
|
||||
app.removeFromLibrary(truekind, id)
|
||||
this.addedToLibrary = false
|
||||
}
|
||||
},
|
||||
playTrack() {
|
||||
let item = this.item
|
||||
let parent = this.parent
|
||||
let childIndex = this.index
|
||||
console.log(item, parent, childIndex)
|
||||
if (parent != null && childIndex != null) {
|
||||
app.queueParentandplayChild(parent, childIndex, item);
|
||||
} else {
|
||||
app.playMediaItemById(item.attributes.playParams.id ?? item.id, item.attributes.playParams.kind ?? item.type, item.attributes.playParams.isLibrary ?? false, item.attributes.url)
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -5,66 +5,68 @@
|
|||
<mediaitem-square v-for="item in items" :item="item"></mediaitem-square>
|
||||
</div>
|
||||
<div class="well itemContainer collection-list-square" 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>
|
||||
<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 itemContainer collection-list-square" 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 v-if="nextUrl && !loading" style="opacity:0;height: 32px;"
|
||||
v-observe-visibility="{callback: visibilityChanged}">{{$root.getLz('term.showMore')}}
|
||||
</button>
|
||||
</div>
|
||||
</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
|
||||
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
|
||||
}
|
||||
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>
|
||||
|
|
|
@ -15,18 +15,22 @@
|
|||
</div>
|
||||
<div class="col-auto cider-flex-center">
|
||||
<div class="row">
|
||||
<button class="col md-btn md-btn-primary md-btn-icon" style="min-width: 100px;margin-right: 3px;"
|
||||
@click="app.mk.shuffleMode = 0; play()"> <img class="md-ico-play">
|
||||
<button class="col md-btn md-btn-primary md-btn-icon"
|
||||
style="min-width: 100px;margin-right: 3px;"
|
||||
@click="app.mk.shuffleMode = 0; play()"><img class="md-ico-play">
|
||||
{{app.getLz('term.play')}}
|
||||
</button>
|
||||
<button class="col md-btn md-btn-primary md-btn-icon" style="min-width: 100px;margin-right: 3px;"
|
||||
@click="app.mk.shuffleMode = 1;play()"> <img class="md-ico-shuffle">
|
||||
<button class="col md-btn md-btn-primary md-btn-icon"
|
||||
style="min-width: 100px;margin-right: 3px;"
|
||||
@click="app.mk.shuffleMode = 1;play()"><img class="md-ico-shuffle">
|
||||
{{app.getLz('term.shuffle')}}
|
||||
</button>
|
||||
</button>
|
||||
<div class="col">
|
||||
<select class="md-select" v-model="prefs.sort" @change="$root.searchLibrarySongs()">
|
||||
<optgroup :label="app.getLz('term.sortBy')">
|
||||
<option v-for="(sort, index) in library.songs.sortingOptions" :value="index">{{ sort }}</option>
|
||||
<option v-for="(sort, index) in library.songs.sortingOptions" :value="index">{{ sort
|
||||
}}
|
||||
</option>
|
||||
</optgroup>
|
||||
</select>
|
||||
</div>
|
||||
|
@ -50,7 +54,9 @@
|
|||
<select class="md-select" v-model="prefs.scroll">
|
||||
<optgroup :label="app.getLz('term.scroll')">
|
||||
<option value="infinite">{{app.getLz('term.scroll.infinite')}}</option>
|
||||
<option value="paged">{{app.getLz('term.scroll.paged').replace("${songsPerPage}", pageSize)}}</option>
|
||||
<option value="paged">{{app.getLz('term.scroll.paged').replace("${songsPerPage}",
|
||||
pageSize)}}
|
||||
</option>
|
||||
</optgroup>
|
||||
</select>
|
||||
</div>
|
||||
|
@ -58,81 +64,87 @@
|
|||
</div>
|
||||
<div class="col-auto cider-flex-center">
|
||||
<button v-if="library.songs.downloadState == 2" @click="$root.getLibrarySongsFull(true)"
|
||||
class="reload-btn" :aria-label="app.getLz('menubar.options.reload')"><%- include('../svg/redo.svg') %></button>
|
||||
<button v-else class="reload-btn" style="opacity: 0.8;pointer-events: none" :aria-label="app.getLz('menubar.options.reload')">
|
||||
class="reload-btn"
|
||||
:aria-label="app.getLz('menubar.options.reload')"><%- include('../svg/redo.svg') %></button>
|
||||
<button v-else class="reload-btn" style="opacity: 0.8;pointer-events: none"
|
||||
:aria-label="app.getLz('menubar.options.reload')">
|
||||
<div class="spinner"></div>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<pagination
|
||||
:length="library.songs.displayListing.length"
|
||||
:pageSize="pageSize"
|
||||
:scroll="prefs.scroll"
|
||||
scrollSelector="#app-content"
|
||||
@onRangeChange="onRangeChange"
|
||||
:length="library.songs.displayListing.length"
|
||||
:pageSize="pageSize"
|
||||
:scroll="prefs.scroll"
|
||||
scrollSelector="#app-content"
|
||||
@onRangeChange="onRangeChange"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div v-if="library.songs.downloadState == 3">Library contains no songs.</div>
|
||||
<div class="well" :key="1" v-if="prefs.size == 'compact'">
|
||||
<mediaitem-list-item class-list="compact" :item="item" :parent="'librarysongs'" :index="index" :show-meta-data="true" :show-library-status="false" v-for="(item, index) in currentSlice"></mediaitem-list-item>
|
||||
<mediaitem-list-item class-list="compact" :item="item" :parent="'librarysongs'" :index="index"
|
||||
:show-meta-data="true" :show-library-status="false"
|
||||
v-for="(item, index) in currentSlice"></mediaitem-list-item>
|
||||
</div>
|
||||
<div class="well" :key="2" v-else>
|
||||
<mediaitem-list-item :item="item" :parent="'librarysongs'" :index="index" :show-meta-data="true" :show-library-status="false" v-for="(item, index) in currentSlice"></mediaitem-list-item>
|
||||
<mediaitem-list-item :item="item" :parent="'librarysongs'" :index="index" :show-meta-data="true"
|
||||
:show-library-status="false"
|
||||
v-for="(item, index) in currentSlice"></mediaitem-list-item>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script>
|
||||
Vue.component('cider-library-songs', {
|
||||
template: '#cider-library-songs',
|
||||
data: function () {
|
||||
const pageSize = this.$root.cfg.libraryPrefs.pageSize;
|
||||
return {
|
||||
// currentPage is oneIndexed
|
||||
library: this.$root.library,
|
||||
mediaItemSize: "compact",
|
||||
prefs: this.$root.cfg.libraryPrefs.songs,
|
||||
app: this.$root,
|
||||
pageSize: pageSize,
|
||||
start: 0,
|
||||
end: pageSize
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.$root.getLibrarySongsFull()
|
||||
},
|
||||
computed: {
|
||||
currentSlice: function () {
|
||||
return this.library.songs.displayListing.slice(this.start, this.end);
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onRangeChange: function (newRange) {
|
||||
this.start = newRange[0];
|
||||
this.end = newRange[1];
|
||||
},
|
||||
play: function () {
|
||||
function shuffleArray(array) {
|
||||
for (var i = array.length - 1; i > 0; i--) {
|
||||
var j = Math.floor(Math.random() * (i + 1));
|
||||
var temp = array[i];
|
||||
array[i] = array[j];
|
||||
array[j] = temp;
|
||||
}
|
||||
}
|
||||
|
||||
let query = this.app.library.songs.displayListing.map(item => new MusicKit.MediaItem(item));
|
||||
if (!app.mk.queue.isEmpty)
|
||||
app.mk.queue.splice(0, app.mk.queue._itemIDs.length);
|
||||
app.mk.stop().then(() => {
|
||||
if (app.mk.shuffleMode == 1) {
|
||||
shuffleArray(query)
|
||||
}
|
||||
app.mk.queue.append(query)
|
||||
app.mk.changeToMediaAtIndex(0)
|
||||
});
|
||||
}
|
||||
Vue.component('cider-library-songs', {
|
||||
template: '#cider-library-songs',
|
||||
data: function() {
|
||||
const pageSize = this.$root.cfg.libraryPrefs.pageSize;
|
||||
return {
|
||||
// currentPage is oneIndexed
|
||||
library: this.$root.library,
|
||||
mediaItemSize: "compact",
|
||||
prefs: this.$root.cfg.libraryPrefs.songs,
|
||||
app: this.$root,
|
||||
pageSize: pageSize,
|
||||
start: 0,
|
||||
end: pageSize
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.$root.getLibrarySongsFull()
|
||||
},
|
||||
computed: {
|
||||
currentSlice: function() {
|
||||
return this.library.songs.displayListing.slice(this.start, this.end);
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onRangeChange: function(newRange) {
|
||||
this.start = newRange[0];
|
||||
this.end = newRange[1];
|
||||
},
|
||||
play: function() {
|
||||
function shuffleArray(array) {
|
||||
for (var i = array.length - 1; i > 0; i--) {
|
||||
var j = Math.floor(Math.random() * (i + 1));
|
||||
var temp = array[i];
|
||||
array[i] = array[j];
|
||||
array[j] = temp;
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
let query = this.app.library.songs.displayListing.map(item => new MusicKit.MediaItem(item));
|
||||
if (!app.mk.queue.isEmpty)
|
||||
app.mk.queue.splice(0, app.mk.queue._itemIDs.length);
|
||||
app.mk.stop().then(() => {
|
||||
if (app.mk.shuffleMode == 1) {
|
||||
shuffleArray(query)
|
||||
}
|
||||
app.mk.queue.append(query)
|
||||
app.mk.changeToMediaAtIndex(0)
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -1,39 +1,38 @@
|
|||
<script type="text/x-template" id="cider-library-videos">
|
||||
<div class="content-inner">
|
||||
<div class="row">
|
||||
<div class="col" style="padding:0">
|
||||
<h1 class="header-text">{{$root.getLz('term.videos')}}</h1>
|
||||
</div>
|
||||
</div>
|
||||
<div class="madeforyou-body">
|
||||
<template v-if="videos.length > 0">
|
||||
<mediaitem-square :size="300" :item="item" v-for="item in videos">
|
||||
</mediaitem-square>
|
||||
</template>
|
||||
<template v-else-if="loaded == true">
|
||||
<div>{{$root.getLz('term.noVideos')}}</div>
|
||||
</template>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col" style="padding:0">
|
||||
<h1 class="header-text">{{$root.getLz('term.videos')}}</h1>
|
||||
</div>
|
||||
</div>
|
||||
<div class="madeforyou-body">
|
||||
<template v-if="videos.length > 0">
|
||||
<mediaitem-square :size="300" :item="item" v-for="item in videos">
|
||||
</mediaitem-square>
|
||||
</template>
|
||||
<template v-else-if="loaded == true">
|
||||
<div>{{$root.getLz('term.noVideos')}}</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script>
|
||||
Vue.component('cider-library-videos', {
|
||||
template: "#cider-library-videos",
|
||||
props: ["data"],
|
||||
data: function(){
|
||||
return {
|
||||
videos: [],
|
||||
loaded: false
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.$nextTick(async function () {
|
||||
if (this.$data.videos == null || this.$data.videos.length == 0)
|
||||
this.$data.videos = (await this.$root.mk.api.v3.music('/v1/me/library/music-videos')).data?.data ?? []
|
||||
this.$data.loaded = true
|
||||
})
|
||||
}
|
||||
})
|
||||
Vue.component('cider-library-videos', {
|
||||
template: "#cider-library-videos",
|
||||
props: ["data"],
|
||||
data: function() {
|
||||
return {
|
||||
videos: [],
|
||||
loaded: false
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.$nextTick(async function() {
|
||||
if (this.$data.videos == null || this.$data.videos.length == 0)
|
||||
this.$data.videos = (await this.$root.mk.api.v3.music('/v1/me/library/music-videos')).data?.data ?? []
|
||||
this.$data.loaded = true
|
||||
})
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
|
@ -2,22 +2,22 @@
|
|||
<div class="content-inner">
|
||||
<h1 class="header-text">{{app.getLz('term.listenNow')}}</h1>
|
||||
<template v-for="(recom,index) in data.data">
|
||||
<listennow-child :recom="recom" :index="index"></listennow-child>
|
||||
<listennow-child :recom="recom" :index="index"></listennow-child>
|
||||
</template>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script>
|
||||
Vue.component('cider-listen-now', {
|
||||
Vue.component('cider-listen-now', {
|
||||
template: "#cider-listen-now",
|
||||
props: ["data"],
|
||||
data: function(){
|
||||
return {
|
||||
app : this.$root
|
||||
}
|
||||
data: function() {
|
||||
return {
|
||||
app: this.$root
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.$root.getListenNow()
|
||||
this.$root.getListenNow()
|
||||
}
|
||||
})
|
||||
})
|
||||
</script>
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
<div class="content-inner">
|
||||
<div class="row">
|
||||
<div class="col" style="padding:0">
|
||||
<h1 class="header-text">{{$root.getLz('home.madeForYou')}}</h1>
|
||||
</div>
|
||||
</div>
|
||||
<div class="madeforyou-body">
|
||||
<mediaitem-square :item="item" v-for="item in madeforyou.data">
|
||||
</mediaitem-square>
|
||||
</div>
|
||||
</div>
|
||||
<div class="content-inner">
|
||||
<div class="row">
|
||||
<div class="col" style="padding:0">
|
||||
<h1 class="header-text">{{$root.getLz('home.madeForYou')}}</h1>
|
||||
</div>
|
||||
</div>
|
||||
<div class="madeforyou-body">
|
||||
<mediaitem-square :item="item" v-for="item in madeforyou.data">
|
||||
</mediaitem-square>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,123 +1,127 @@
|
|||
<script type="text/x-template" id="cider-oobe">
|
||||
<div class="content-inner oobe">
|
||||
<!-- before_we_start-->
|
||||
<!-- 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 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 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 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 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>
|
||||
</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 class="card-footer">
|
||||
Mojave
|
||||
</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>
|
||||
</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">
|
||||
{{$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 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">
|
||||
{{$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 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 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">
|
||||
|
@ -139,28 +143,28 @@
|
|||
</div>
|
||||
</script>
|
||||
<script>
|
||||
Vue.component('cider-oobe', {
|
||||
template: '#cider-oobe',
|
||||
data: function () {
|
||||
return {
|
||||
screen: "before_we_start"
|
||||
}
|
||||
},
|
||||
async mounted() {
|
||||
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);
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
signIn() {
|
||||
if (localStorage.getItem("music.ampwebplay.media-user-token")) {
|
||||
localStorage.setItem("seenOOBE", 1)
|
||||
window.location.reload()
|
||||
}
|
||||
});
|
||||
</script>
|
||||
this.screen = "signin"
|
||||
capiInit()
|
||||
},
|
||||
getLz() {
|
||||
return this.$root.getLz.apply(this.$root, arguments);
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
aria-role="presentation" focusable="false">
|
||||
<path
|
||||
d="M10.5 21C4.724 21 0 16.275 0 10.5S4.724 0 10.5 0 21 4.725 21 10.5 16.276 21 10.5 21zm-3.543-5.967a.96.96 0 00.693-.295l2.837-2.842 2.85 2.842c.167.167.41.295.693.295.552 0 1.001-.461 1.001-1.012 0-.281-.115-.512-.295-.704L11.899 10.5l2.85-2.855a.875.875 0 00.295-.68c0-.55-.45-.998-1.001-.998a.871.871 0 00-.668.295l-2.888 2.855-2.862-2.843a.891.891 0 00-.668-.281.99.99 0 00-1.001.986c0 .269.116.512.295.678L9.088 10.5l-2.837 2.843a.926.926 0 00-.295.678c0 .551.45 1.012 1.001 1.012z"
|
||||
fill-rule="nonzero"/>
|
||||
fill-rule="nonzero" />
|
||||
</svg>
|
||||
</div>
|
||||
<template v-if="app.playlists.loadingState == 0">
|
||||
|
@ -46,7 +46,7 @@
|
|||
v-model="data.attributes.name"
|
||||
@blur="editPlaylist"
|
||||
@change="editPlaylist"
|
||||
@keydown.enter="editPlaylist"/>
|
||||
@keydown.enter="editPlaylist" />
|
||||
</div>
|
||||
<div class="playlist-time genre" style="margin: 0px;">{{getAlbumGenre()}}</div>
|
||||
<div class="playlist-artist item-navigate"
|
||||
|
@ -58,11 +58,15 @@
|
|||
<artist-chip v-for="artist in data.relationships.artists?.data"
|
||||
:item="artist"></artist-chip>
|
||||
</template>
|
||||
<div class="playlist-desc" v-if="(data.attributes.description && (data.attributes.description.standard || data.attributes.description.short)) || (data.attributes.editorialNotes && (data.attributes.editorialNotes.standard || data.attributes.editorialNotes.short))">
|
||||
<div v-if="(data.attributes.description?.short ?? data.attributes.editorialNotes?.short) != null" class="content"
|
||||
v-html="data.attributes.description?.short ?? data.attributes.editorialNotes?.short" @click="openInfoModal()"></div>
|
||||
<div v-else-if="(data.attributes.description?.standard ?? data.attributes.editorialNotes?.standard) != null" class="content"
|
||||
v-html="data.attributes.description?.standard ?? data.attributes.editorialNotes?.standard" ></div>
|
||||
<div class="playlist-desc"
|
||||
v-if="(data.attributes.description && (data.attributes.description.standard || data.attributes.description.short)) || (data.attributes.editorialNotes && (data.attributes.editorialNotes.standard || data.attributes.editorialNotes.short))">
|
||||
<div v-if="(data.attributes.description?.short ?? data.attributes.editorialNotes?.short) != null"
|
||||
class="content"
|
||||
v-html="data.attributes.description?.short ?? data.attributes.editorialNotes?.short"
|
||||
@click="openInfoModal()"></div>
|
||||
<div v-else-if="(data.attributes.description?.standard ?? data.attributes.editorialNotes?.standard) != null"
|
||||
class="content"
|
||||
v-html="data.attributes.description?.standard ?? data.attributes.editorialNotes?.standard"></div>
|
||||
<!-- <button v-if="(data.attributes.description?.short ?? data.attributes.editorialNotes?.short ) != null" class="more-btn"
|
||||
@click="openInfoModal()">
|
||||
{{app.getLz('term.showMore')}}
|
||||
|
@ -101,7 +105,8 @@
|
|||
<img :class="(!inLibrary) ? 'md-ico-add' : 'md-ico-remove'">
|
||||
{{app.getLz('term.confirm')}}
|
||||
</button>
|
||||
<button class="more-btn-round" style="float:right;" @click="menu" :aria-label="app.getLz('term.more')">
|
||||
<button class="more-btn-round" style="float:right;" @click="menu"
|
||||
:aria-label="app.getLz('term.more')">
|
||||
<div class="svg-icon"></div>
|
||||
</button>
|
||||
</div>
|
||||
|
@ -158,25 +163,30 @@
|
|||
<div class="">
|
||||
<div style="width:100%">
|
||||
<draggable :sort="data.attributes.canEdit && data.type == 'library-playlists'"
|
||||
v-model="data.relationships.tracks.data" @start="drag=true" @end="drag=false;put()">
|
||||
<template v-if="nestedPlaylist == [] || nestedPlaylist.length <= 1">
|
||||
<mediaitem-list-item :item="item" :parent="getItemParent(data)" :index="index"
|
||||
v-model="data.relationships.tracks.data" @start="drag=true"
|
||||
@end="drag=false;put()">
|
||||
<template v-if="nestedPlaylist == [] || nestedPlaylist.length <= 1">
|
||||
<mediaitem-list-item :item="item" :parent="getItemParent(data)"
|
||||
:index="index"
|
||||
:showIndex="true"
|
||||
:showIndexPlaylist="(data.attributes.playParams.kind ?? data.type ?? '').includes('playlist')"
|
||||
:context-ext="buildContextMenu()"
|
||||
v-for="(item,index) in data.relationships.tracks.data"></mediaitem-list-item>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div v-for="disc in nestedPlaylist">
|
||||
<div class="playlist-time">{{($root.getLz("term.discNumber") ??
|
||||
"").replace("${discNumber}",disc.disc)}}
|
||||
</div>
|
||||
<mediaitem-list-item :item="item" :parent="getItemParent(data)"
|
||||
:index="index"
|
||||
:showIndex="true"
|
||||
:showIndexPlaylist="(data.attributes.playParams.kind ?? data.type ?? '').includes('playlist')"
|
||||
:context-ext="buildContextMenu()"
|
||||
v-for="(item,index) in data.relationships.tracks.data"></mediaitem-list-item>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div v-for="disc in nestedPlaylist">
|
||||
<div class="playlist-time">{{($root.getLz("term.discNumber") ?? "").replace("${discNumber}",disc.disc)}}</div>
|
||||
<mediaitem-list-item :item="item" :parent="getItemParent(data)" :index="index"
|
||||
:showIndex="true"
|
||||
:showIndexPlaylist="(data.attributes.playParams.kind ?? data.type ?? '').includes('playlist')"
|
||||
:context-ext="buildContextMenu()"
|
||||
v-for="(item,index) in disc.tracks"></mediaitem-list-item>
|
||||
</div>
|
||||
v-for="(item,index) in disc.tracks"></mediaitem-list-item>
|
||||
</div>
|
||||
|
||||
</template>
|
||||
</template>
|
||||
</draggable>
|
||||
|
||||
</div>
|
||||
|
@ -185,7 +195,8 @@
|
|||
<div class="friends-info" v-if="itemBadges.length != 0">
|
||||
<div class="well">
|
||||
<div class="badge-container">
|
||||
<div class="socialBadge" :title="`${badge.attributes.name} - @${badge.attributes.handle}`"
|
||||
<div class="socialBadge"
|
||||
:title="`${badge.attributes.name} - @${badge.attributes.handle}`"
|
||||
v-for="badge in itemBadges">
|
||||
<mediaitem-artwork
|
||||
:url="badge.attributes.artwork.url"
|
||||
|
@ -204,7 +215,8 @@
|
|||
</div>
|
||||
<template
|
||||
v-if="(data.attributes?.playParams?.kind ?? data.type ?? '').includes('album') && data.relationships.catalog != null && data.relationships.catalog != null && data.relationships.catalog.data.length > 0">
|
||||
<div class="playlist-time showExtended item-navigate" style="color:#fa586a; font-weight: bold"
|
||||
<div class="playlist-time showExtended item-navigate"
|
||||
style="color:#fa586a; font-weight: bold"
|
||||
@click="app.routeView(data.relationships.catalog.data[0])">
|
||||
{{$root.getLz("action.showAlbum")}}
|
||||
</div>
|
||||
|
@ -212,21 +224,22 @@
|
|||
<hr>
|
||||
</b-tab>
|
||||
<template v-if="typeof data.views != 'undefined'">
|
||||
<b-tab lazy :title="data.views[view].attributes.title" v-for="view in data.meta.views.order" v-if="data.views[view].data.length != 0">
|
||||
<div>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<h3>{{ data.views[view].attributes.title }}</h3>
|
||||
<b-tab lazy :title="data.views[view].attributes.title" v-for="view in data.meta.views.order"
|
||||
v-if="data.views[view].data.length != 0">
|
||||
<div>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<h3>{{ data.views[view].attributes.title }}</h3>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<mediaitem-scroller-horizontal
|
||||
:items="data.views[view].data"></mediaitem-scroller-horizontal>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<mediaitem-scroller-horizontal
|
||||
:items="data.views[view].data"></mediaitem-scroller-horizontal>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</b-tab>
|
||||
</b-tab>
|
||||
</template>
|
||||
|
||||
</b-tabs>
|
||||
|
@ -239,7 +252,7 @@
|
|||
aria-role="presentation" focusable="false">
|
||||
<path
|
||||
d="M10.5 21C4.724 21 0 16.275 0 10.5S4.724 0 10.5 0 21 4.725 21 10.5 16.276 21 10.5 21zm-3.543-5.967a.96.96 0 00.693-.295l2.837-2.842 2.85 2.842c.167.167.41.295.693.295.552 0 1.001-.461 1.001-1.012 0-.281-.115-.512-.295-.704L11.899 10.5l2.85-2.855a.875.875 0 00.295-.68c0-.55-.45-.998-1.001-.998a.871.871 0 00-.668.295l-2.888 2.855-2.862-2.843a.891.891 0 00-.668-.281.99.99 0 00-1.001.986c0 .269.116.512.295.678L9.088 10.5l-2.837 2.843a.926.926 0 00-.295.678c0 .551.45 1.012 1.001 1.012z"
|
||||
fill-rule="nonzero"/>
|
||||
fill-rule="nonzero" />
|
||||
</svg>
|
||||
</div>
|
||||
<template v-if="app.playlists.loadingState == 0">
|
||||
|
@ -252,408 +265,411 @@
|
|||
</script>
|
||||
|
||||
<script>
|
||||
Vue.component('playlist-inline', {
|
||||
template: "#playlist-inline",
|
||||
props: ["data"],
|
||||
|
||||
data: function () {
|
||||
return {
|
||||
editorialNotesExpanded: false,
|
||||
drag: false,
|
||||
nameEditing: false,
|
||||
inLibrary: null,
|
||||
confirm: false,
|
||||
app: this.$root,
|
||||
itemBadges: [],
|
||||
badgesRequested: false,
|
||||
headerVisible: true,
|
||||
useArtistChip: false,
|
||||
nestedPlaylist: [],
|
||||
}
|
||||
},
|
||||
mounted: function () {
|
||||
this.$nextTick(function () {
|
||||
this.isInLibrary()
|
||||
})
|
||||
},
|
||||
watch: {
|
||||
data: function () {
|
||||
this.nestedPlaylist = [];
|
||||
this.isInLibrary()
|
||||
this.getBadges()
|
||||
this.generateNestedPlaylist()
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
openInfoModal(){
|
||||
app.moreinfodata = [];
|
||||
app.moreinfodata = {
|
||||
title : this.data?.attributes ? (this.data?.attributes?.name ??
|
||||
(this.data?.attributes?.title ?? '') ?? '') : '',
|
||||
subtitle: this.data?.attributes?.artistName ?? '',
|
||||
content: ((this.data?.attributes?.editorialNotes != null ) ? (this.data?.attributes?.editorialNotes?.standard ?? (this.data?.attributes?.editorialNotes?.short ?? '') ) : (data.attributes?.description ? (this.data.attributes?.description?.standard ?? (this.data?.attributes?.description?.short ?? '')) : ''))
|
||||
}
|
||||
app.modals.moreInfo = true;
|
||||
},
|
||||
generateNestedPlaylist(){
|
||||
this.nestedPlaylist = [];
|
||||
if (this.data?.type?.includes("album")){
|
||||
console.log(this.data.relationships.tracks.data)
|
||||
let songlists = this.data.relationships.tracks.data;
|
||||
let discs = songlists.map(x => {return x.attributes.discNumber}).filter((item, i, ar) => ar.indexOf(item) === i);
|
||||
if (discs && discs.length > 1){
|
||||
for (disc of discs){
|
||||
let songs = songlists.filter(x => x.attributes.discNumber == disc);
|
||||
this.nestedPlaylist.push({disc: disc, tracks: songs})
|
||||
}
|
||||
}
|
||||
console.log(this.nestedPlaylist)
|
||||
|
||||
}},
|
||||
isHeaderVisible(visible) {
|
||||
this.headerVisible = visible
|
||||
},
|
||||
getBadges() {
|
||||
return
|
||||
if (this.badgesRequested) {
|
||||
return
|
||||
}
|
||||
this.badgesRequested = true
|
||||
this.itemBadges = []
|
||||
let self = this
|
||||
var id = 0
|
||||
try {
|
||||
id = this.data.attributes.playParams.id
|
||||
} catch (e) {
|
||||
id = this.data.id
|
||||
}
|
||||
this.$root.getSocialBadges((badges) => {
|
||||
let friends = badges[id]
|
||||
if (friends) {
|
||||
friends.forEach(function (friend) {
|
||||
self.app.mk.api.v3.music(`/v1/social/${app.mk.storefrontId}/social-profiles/${friend}`).then(data => {
|
||||
self.itemBadges.push(data.data.data[0])
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
confirmButton() {
|
||||
// Return button to normal state after 3 seconds
|
||||
|
||||
this.confirm = true
|
||||
setTimeout(() => this.confirm = false, 3000);
|
||||
},
|
||||
getArtistName(data) {
|
||||
if (data.attributes.artistName) {
|
||||
this.useArtistChip = true
|
||||
return data.attributes.artistName
|
||||
} else if (data.attributes.artist) {
|
||||
this.useArtistChip = true
|
||||
return data.attributes.artist.attributes.name
|
||||
} else if (data.attributes.curatorName) {
|
||||
return data.attributes.curatorName
|
||||
} else {
|
||||
return ""
|
||||
}
|
||||
},
|
||||
getAlbumGenre: function () {
|
||||
if (this.data.type.includes('albums')) {
|
||||
let date = this.data.attributes.releaseDate;
|
||||
if (date == null || date === "") return "";
|
||||
return `${this.data.relationships.tracks.data[0].attributes.genreNames[0]} · ${new Date(date).getFullYear()}`
|
||||
}
|
||||
},
|
||||
async isInLibrary() {
|
||||
if (this.data.type && !this.data.type.includes("library")) {
|
||||
// please keep using vars here
|
||||
const params = {
|
||||
"fields[playlists]": "inLibrary",
|
||||
"fields[albums]": "inLibrary",
|
||||
"relate": "library"
|
||||
};
|
||||
const res = await app.mkapi(this.data.attributes.playParams.kind ?? this.data.type, this.data.attributes.playParams.isLibrary ?? false, this.data.attributes.playParams.id ?? this.data.id, params);
|
||||
this.inLibrary = (res.data.data[0] && res.data.data[0].attributes && res.data.data[0].attributes.inLibrary) ? res.data.data[0].attributes.inLibrary : false
|
||||
console.log(res)
|
||||
} else {
|
||||
this.inLibrary = true
|
||||
}
|
||||
},
|
||||
editPlaylist() {
|
||||
this.app.editPlaylist(this.data.id, this.data.attributes.name);
|
||||
this.app.playlists.listing.forEach(playlist => {
|
||||
if (playlist.id === this.data.id) {
|
||||
playlist.attributes.name = this.data.attributes.name
|
||||
}
|
||||
})
|
||||
this.nameEditing = false
|
||||
},
|
||||
addToLibrary(id) {
|
||||
app.mk.addToLibrary(id)
|
||||
this.inLibrary = true
|
||||
this.confirm = false
|
||||
},
|
||||
async removeFromLibrary(id) {
|
||||
const params = {"fields[songs]": "inLibrary", "fields[albums]": "inLibrary", "relate": "library"};
|
||||
var id = this.data.id ?? this.data.attributes.playParams.id
|
||||
const res = await app.mkapi(this.data.attributes.playParams.kind ?? this.data.type, this.data.attributes.playParams.isLibrary ?? false, this.data.attributes.playParams.id ?? this.data.id, params);
|
||||
if (res.data.data[0] && res.data.data[0].relationships && res.data.data[0].relationships.library && res.data.data[0].relationships.library.data && res.data.data[0].relationships.library.data.length > 0) {
|
||||
id = res.data.data[0].relationships.library.data[0].id
|
||||
}
|
||||
let kind = this.data.attributes.playParams.kind ?? this.data.type ?? '';
|
||||
const truekind = (!kind.endsWith("s")) ? (kind + "s") : kind;
|
||||
app.mk.api.v3.music(`v1/me/library/${truekind}/${id.toString()}`, {},
|
||||
{
|
||||
fetchOptions: {
|
||||
method: "DELETE"
|
||||
}
|
||||
})
|
||||
this.inLibrary = false
|
||||
this.confirm = false
|
||||
},
|
||||
editPlaylistName() {
|
||||
if (this.data.attributes.canEdit && this.data.type === "library-playlists") {
|
||||
this.nameEditing = true
|
||||
setTimeout(() => {
|
||||
document.querySelector(".nameEdit").focus()
|
||||
}, 100)
|
||||
}
|
||||
},
|
||||
buildContextMenu(index) {
|
||||
let self = this
|
||||
if (!this.data.attributes.canEdit) {
|
||||
return
|
||||
}
|
||||
return {
|
||||
normal: [
|
||||
{
|
||||
name: app.getLz('action.removeFromPlaylist'),
|
||||
action: () => {
|
||||
self.remove()
|
||||
}
|
||||
},
|
||||
],
|
||||
multiple: [
|
||||
{
|
||||
name: app.getLz('action.removeFromPlaylist'),
|
||||
action: () => {
|
||||
self.remove()
|
||||
}
|
||||
},
|
||||
]
|
||||
}
|
||||
},
|
||||
async put() {
|
||||
if (!this.data.attributes.canEdit) {
|
||||
return
|
||||
}
|
||||
console.log('sds', this.convert())
|
||||
await app.mk.api.v3.music(
|
||||
`/v1/me/library/playlists/${this.data.attributes.playParams.id}/tracks`,
|
||||
{},
|
||||
{
|
||||
fetchOptions: {
|
||||
method: "PUT",
|
||||
body: JSON.stringify({
|
||||
data: this.convert()
|
||||
})
|
||||
}
|
||||
}
|
||||
)
|
||||
},
|
||||
async remove() {
|
||||
if (!this.data.attributes.canEdit) {
|
||||
return
|
||||
}
|
||||
// for each app.selectedMediaItems splice the items from the playlist
|
||||
for (let i = 0; i < app.selectedMediaItems.length; i++) {
|
||||
let item = app.selectedMediaItems[i]
|
||||
let index = this.data.relationships.tracks.data.findIndex(x => x.id == item.id)
|
||||
if (index > -1) {
|
||||
this.data.relationships.tracks.data.splice(index, 1)
|
||||
}
|
||||
}
|
||||
await this.put()
|
||||
},
|
||||
convert() {
|
||||
let pl_tracks = []
|
||||
for (let i = 0; i < this.data.relationships.tracks.data.length; i++) {
|
||||
pl_tracks.push({
|
||||
id: this.data.relationships.tracks.data[i].id,
|
||||
type: this.data.relationships.tracks.data[i].type
|
||||
})
|
||||
}
|
||||
return pl_tracks
|
||||
},
|
||||
getRecursive(url) {
|
||||
app.apiCall(app.musicBaseUrl + "/v1/me/library/playlists/p.V7VYlrDso6kkYY/tracks?offset=100", res => {
|
||||
this.data.relationships.tracks.data = this.data.relationships.tracks.data.concat(res.data.data)
|
||||
if (res.data.next) {
|
||||
this.getRecursive(res.data.next)
|
||||
}
|
||||
})
|
||||
},
|
||||
menu(event) {
|
||||
let self = this
|
||||
let artistId = null
|
||||
|
||||
if (typeof this.data.relationships.artists != "undefined") {
|
||||
artistId = this.data.relationships.artists.data[0].id
|
||||
if (this.data.relationships.artists.data[0].type == "library-artists") {
|
||||
artistId = this.data.relationships.artists.data[0].relationships.catalog.data[0].id
|
||||
}
|
||||
}
|
||||
|
||||
let menuItems = {
|
||||
items: {
|
||||
"share": {
|
||||
name: app.getLz('term.share'),
|
||||
icon: "./assets/feather/share.svg",
|
||||
action: () => {
|
||||
let route = ""
|
||||
switch (this.data.type) {
|
||||
case 'albums':
|
||||
route = `/v1/catalog/${app.mk.storefrontId}/albums/${this.data.id}`
|
||||
break;
|
||||
case 'playlists':
|
||||
route = `/v1/catalog/${app.mk.storefrontId}/playlists/${this.data.id}`
|
||||
break;
|
||||
case "library-playlists":
|
||||
route = `/v1/me/library/playlists/${this.data.id}/catalog`
|
||||
break
|
||||
case "library-albums":
|
||||
route = `/v1/me/library/albums/${this.data.id}/catalog`
|
||||
break
|
||||
}
|
||||
if (route === '') {
|
||||
return
|
||||
}
|
||||
app.mk.api.v3.music(route).then(res => {
|
||||
console.log(res.data.data[0].attributes.url)
|
||||
app.copyToClipboard(res.data.data[0].attributes.url)
|
||||
})
|
||||
}
|
||||
},
|
||||
"follow": {
|
||||
name: app.getLz('action.follow'),
|
||||
icon: "./assets/feather/plus-circle.svg",
|
||||
hidden: false,
|
||||
action: () => {
|
||||
app.setArtistFavorite(artistId, true)
|
||||
}
|
||||
},
|
||||
"unfollow": {
|
||||
name: app.getLz('action.unfollow'),
|
||||
icon: "./assets/feather/x-circle.svg",
|
||||
hidden: true,
|
||||
action: () => {
|
||||
app.setArtistFavorite(artistId, false)
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
|
||||
app.showMenuPanel(menuItems, event)
|
||||
|
||||
},
|
||||
getItemParent: function (data) {
|
||||
kind = data.attributes.playParams.kind;
|
||||
id = data.attributes.playParams.id;
|
||||
return `${kind}:${id}`
|
||||
},
|
||||
getFormattedDate: function () {
|
||||
let date = (this.data.attributes.releaseDate ?? (this.data.attributes.lastModifiedDate ?? (this.data.attributes.dateAdded ?? '')))
|
||||
let prefix = '';
|
||||
if (date == null || date === "") return "";
|
||||
switch (date) {
|
||||
case this.data.attributes.releaseDate:
|
||||
prefix = this.app.getLz('term.time.released') + ' '
|
||||
break;
|
||||
case this.data.attributes.lastModifiedDate:
|
||||
prefix = this.app.getLz('term.time.updated') + ' '
|
||||
break;
|
||||
case this.data.attributes.dateAdded:
|
||||
prefix = this.app.getLz('term.time.added') + ' '
|
||||
break;
|
||||
}
|
||||
let month, year;
|
||||
try {
|
||||
const releaseDate = new Date(date);
|
||||
// month = new Intl.DateTimeFormat(this.app.cfg.general.language.replace('_','-'), {month: 'long'}).format(releaseDate);
|
||||
// date = releaseDate.getDate();
|
||||
// year = releaseDate.getFullYear();
|
||||
let formatted = ''
|
||||
try {
|
||||
formatted = new Intl.DateTimeFormat(this.app.cfg.general.language?.replace('_', '-') ?? 'en-US', {
|
||||
day: 'numeric',
|
||||
month: 'long',
|
||||
year: 'numeric'
|
||||
}).format(releaseDate);
|
||||
} catch (e) {
|
||||
// use the format in json instead
|
||||
if (this.app.getLz('date.format') != null) {
|
||||
formatted = new this.app.getLz('date.format').replace("${d}", releaseDate.getDate()).replace("${m}", releaseDate.getMonth()).replace("${y}", releaseDate.getFullYear());
|
||||
} else {
|
||||
formatted = new Intl.DateTimeFormat('en-US', {
|
||||
day: 'numeric',
|
||||
month: 'long',
|
||||
year: 'numeric'
|
||||
}).format(releaseDate);
|
||||
}
|
||||
}
|
||||
return prefix + formatted
|
||||
} catch (e) {
|
||||
return ""
|
||||
}
|
||||
},
|
||||
play() {
|
||||
function shuffleArray(array) {
|
||||
for (var i = array.length - 1; i > 0; i--) {
|
||||
var j = Math.floor(Math.random() * (i + 1));
|
||||
var temp = array[i];
|
||||
array[i] = array[j];
|
||||
array[j] = temp;
|
||||
}
|
||||
}
|
||||
|
||||
const id = this.data.attributes.playParams.id ?? this.data.id;
|
||||
//console.log("1")
|
||||
const kind = this.data.attributes.playParams.kind ?? this.data.type ?? '';
|
||||
//console.log("1")
|
||||
const truekind = (!kind.endsWith("s")) ? (kind + "s") : kind;
|
||||
|
||||
let query = (this.data ?? app.showingPlaylist).relationships.tracks.data.map(item => new MusicKit.MediaItem(item));
|
||||
app.mk.stop().then(function () {
|
||||
app.mk.setQueue({[truekind]: [id], parameters: {l: app.mklang}}).then(function () {
|
||||
app.mk.play().then(function () {
|
||||
if (query.length > 100) {
|
||||
let u = query.slice(100);
|
||||
if (app.mk.shuffleMode == 1) {
|
||||
shuffleArray(u)
|
||||
}
|
||||
app.mk.queue.append(u)
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Vue.component('playlist-inline', {
|
||||
template: "#playlist-inline",
|
||||
props: ["data"],
|
||||
|
||||
data: function() {
|
||||
return {
|
||||
editorialNotesExpanded: false,
|
||||
drag: false,
|
||||
nameEditing: false,
|
||||
inLibrary: null,
|
||||
confirm: false,
|
||||
app: this.$root,
|
||||
itemBadges: [],
|
||||
badgesRequested: false,
|
||||
headerVisible: true,
|
||||
useArtistChip: false,
|
||||
nestedPlaylist: [],
|
||||
}
|
||||
},
|
||||
mounted: function() {
|
||||
this.$nextTick(function() {
|
||||
this.isInLibrary()
|
||||
})
|
||||
},
|
||||
watch: {
|
||||
data: function() {
|
||||
this.nestedPlaylist = [];
|
||||
this.isInLibrary()
|
||||
this.getBadges()
|
||||
this.generateNestedPlaylist()
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
openInfoModal() {
|
||||
app.moreinfodata = [];
|
||||
app.moreinfodata = {
|
||||
title: this.data?.attributes ? (this.data?.attributes?.name ??
|
||||
(this.data?.attributes?.title ?? '') ?? '') : '',
|
||||
subtitle: this.data?.attributes?.artistName ?? '',
|
||||
content: ((this.data?.attributes?.editorialNotes != null) ? (this.data?.attributes?.editorialNotes?.standard ?? (this.data?.attributes?.editorialNotes?.short ?? '')) : (data.attributes?.description ? (this.data.attributes?.description?.standard ?? (this.data?.attributes?.description?.short ?? '')) : ''))
|
||||
}
|
||||
app.modals.moreInfo = true;
|
||||
},
|
||||
generateNestedPlaylist() {
|
||||
this.nestedPlaylist = [];
|
||||
if (this.data?.type?.includes("album")) {
|
||||
console.log(this.data.relationships.tracks.data)
|
||||
let songlists = this.data.relationships.tracks.data;
|
||||
let discs = songlists.map(x => {
|
||||
return x.attributes.discNumber
|
||||
}).filter((item, i, ar) => ar.indexOf(item) === i);
|
||||
if (discs && discs.length > 1) {
|
||||
for (disc of discs) {
|
||||
let songs = songlists.filter(x => x.attributes.discNumber == disc);
|
||||
this.nestedPlaylist.push({ disc: disc, tracks: songs })
|
||||
}
|
||||
}
|
||||
console.log(this.nestedPlaylist)
|
||||
|
||||
}
|
||||
})
|
||||
},
|
||||
isHeaderVisible(visible) {
|
||||
this.headerVisible = visible
|
||||
},
|
||||
getBadges() {
|
||||
return
|
||||
if (this.badgesRequested) {
|
||||
return
|
||||
}
|
||||
this.badgesRequested = true
|
||||
this.itemBadges = []
|
||||
let self = this
|
||||
var id = 0
|
||||
try {
|
||||
id = this.data.attributes.playParams.id
|
||||
} catch (e) {
|
||||
id = this.data.id
|
||||
}
|
||||
this.$root.getSocialBadges((badges) => {
|
||||
let friends = badges[id]
|
||||
if (friends) {
|
||||
friends.forEach(function(friend) {
|
||||
self.app.mk.api.v3.music(`/v1/social/${app.mk.storefrontId}/social-profiles/${friend}`).then(data => {
|
||||
self.itemBadges.push(data.data.data[0])
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
confirmButton() {
|
||||
// Return button to normal state after 3 seconds
|
||||
|
||||
this.confirm = true
|
||||
setTimeout(() => this.confirm = false, 3000);
|
||||
},
|
||||
getArtistName(data) {
|
||||
if (data.attributes.artistName) {
|
||||
this.useArtistChip = true
|
||||
return data.attributes.artistName
|
||||
} else if (data.attributes.artist) {
|
||||
this.useArtistChip = true
|
||||
return data.attributes.artist.attributes.name
|
||||
} else if (data.attributes.curatorName) {
|
||||
return data.attributes.curatorName
|
||||
} else {
|
||||
return ""
|
||||
}
|
||||
},
|
||||
getAlbumGenre: function() {
|
||||
if (this.data.type.includes('albums')) {
|
||||
let date = this.data.attributes.releaseDate;
|
||||
if (date == null || date === "") return "";
|
||||
return `${this.data.relationships.tracks.data[0].attributes.genreNames[0]} · ${new Date(date).getFullYear()}`
|
||||
}
|
||||
},
|
||||
async isInLibrary() {
|
||||
if (this.data.type && !this.data.type.includes("library")) {
|
||||
// please keep using vars here
|
||||
const params = {
|
||||
"fields[playlists]": "inLibrary",
|
||||
"fields[albums]": "inLibrary",
|
||||
"relate": "library"
|
||||
};
|
||||
const res = await app.mkapi(this.data.attributes.playParams.kind ?? this.data.type, this.data.attributes.playParams.isLibrary ?? false, this.data.attributes.playParams.id ?? this.data.id, params);
|
||||
this.inLibrary = (res.data.data[0] && res.data.data[0].attributes && res.data.data[0].attributes.inLibrary) ? res.data.data[0].attributes.inLibrary : false
|
||||
console.log(res)
|
||||
} else {
|
||||
this.inLibrary = true
|
||||
}
|
||||
},
|
||||
editPlaylist() {
|
||||
this.app.editPlaylist(this.data.id, this.data.attributes.name);
|
||||
this.app.playlists.listing.forEach(playlist => {
|
||||
if (playlist.id === this.data.id) {
|
||||
playlist.attributes.name = this.data.attributes.name
|
||||
}
|
||||
})
|
||||
this.nameEditing = false
|
||||
},
|
||||
addToLibrary(id) {
|
||||
app.mk.addToLibrary(id)
|
||||
this.inLibrary = true
|
||||
this.confirm = false
|
||||
},
|
||||
async removeFromLibrary(id) {
|
||||
const params = { "fields[songs]": "inLibrary", "fields[albums]": "inLibrary", "relate": "library" };
|
||||
var id = this.data.id ?? this.data.attributes.playParams.id
|
||||
const res = await app.mkapi(this.data.attributes.playParams.kind ?? this.data.type, this.data.attributes.playParams.isLibrary ?? false, this.data.attributes.playParams.id ?? this.data.id, params);
|
||||
if (res.data.data[0] && res.data.data[0].relationships && res.data.data[0].relationships.library && res.data.data[0].relationships.library.data && res.data.data[0].relationships.library.data.length > 0) {
|
||||
id = res.data.data[0].relationships.library.data[0].id
|
||||
}
|
||||
let kind = this.data.attributes.playParams.kind ?? this.data.type ?? '';
|
||||
const truekind = (!kind.endsWith("s")) ? (kind + "s") : kind;
|
||||
app.mk.api.v3.music(`v1/me/library/${truekind}/${id.toString()}`, {},
|
||||
{
|
||||
fetchOptions: {
|
||||
method: "DELETE"
|
||||
}
|
||||
})
|
||||
this.inLibrary = false
|
||||
this.confirm = false
|
||||
},
|
||||
editPlaylistName() {
|
||||
if (this.data.attributes.canEdit && this.data.type === "library-playlists") {
|
||||
this.nameEditing = true
|
||||
setTimeout(() => {
|
||||
document.querySelector(".nameEdit").focus()
|
||||
}, 100)
|
||||
}
|
||||
},
|
||||
buildContextMenu(index) {
|
||||
let self = this
|
||||
if (!this.data.attributes.canEdit) {
|
||||
return
|
||||
}
|
||||
return {
|
||||
normal: [
|
||||
{
|
||||
name: app.getLz('action.removeFromPlaylist'),
|
||||
action: () => {
|
||||
self.remove()
|
||||
}
|
||||
},
|
||||
],
|
||||
multiple: [
|
||||
{
|
||||
name: app.getLz('action.removeFromPlaylist'),
|
||||
action: () => {
|
||||
self.remove()
|
||||
}
|
||||
},
|
||||
]
|
||||
}
|
||||
},
|
||||
async put() {
|
||||
if (!this.data.attributes.canEdit) {
|
||||
return
|
||||
}
|
||||
console.log('sds', this.convert())
|
||||
await app.mk.api.v3.music(
|
||||
`/v1/me/library/playlists/${this.data.attributes.playParams.id}/tracks`,
|
||||
{},
|
||||
{
|
||||
fetchOptions: {
|
||||
method: "PUT",
|
||||
body: JSON.stringify({
|
||||
data: this.convert()
|
||||
})
|
||||
}
|
||||
}
|
||||
)
|
||||
},
|
||||
async remove() {
|
||||
if (!this.data.attributes.canEdit) {
|
||||
return
|
||||
}
|
||||
// for each app.selectedMediaItems splice the items from the playlist
|
||||
for (let i = 0; i < app.selectedMediaItems.length; i++) {
|
||||
let item = app.selectedMediaItems[i]
|
||||
let index = this.data.relationships.tracks.data.findIndex(x => x.id == item.id)
|
||||
if (index > -1) {
|
||||
this.data.relationships.tracks.data.splice(index, 1)
|
||||
}
|
||||
}
|
||||
await this.put()
|
||||
},
|
||||
convert() {
|
||||
let pl_tracks = []
|
||||
for (let i = 0; i < this.data.relationships.tracks.data.length; i++) {
|
||||
pl_tracks.push({
|
||||
id: this.data.relationships.tracks.data[i].id,
|
||||
type: this.data.relationships.tracks.data[i].type
|
||||
})
|
||||
}
|
||||
return pl_tracks
|
||||
},
|
||||
getRecursive(url) {
|
||||
app.apiCall(app.musicBaseUrl + "/v1/me/library/playlists/p.V7VYlrDso6kkYY/tracks?offset=100", res => {
|
||||
this.data.relationships.tracks.data = this.data.relationships.tracks.data.concat(res.data.data)
|
||||
if (res.data.next) {
|
||||
this.getRecursive(res.data.next)
|
||||
}
|
||||
})
|
||||
},
|
||||
menu(event) {
|
||||
let self = this
|
||||
let artistId = null
|
||||
|
||||
if (typeof this.data.relationships.artists != "undefined") {
|
||||
artistId = this.data.relationships.artists.data[0].id
|
||||
if (this.data.relationships.artists.data[0].type == "library-artists") {
|
||||
artistId = this.data.relationships.artists.data[0].relationships.catalog.data[0].id
|
||||
}
|
||||
}
|
||||
|
||||
let menuItems = {
|
||||
items: {
|
||||
"share": {
|
||||
name: app.getLz('term.share'),
|
||||
icon: "./assets/feather/share.svg",
|
||||
action: () => {
|
||||
let route = ""
|
||||
switch (this.data.type) {
|
||||
case 'albums':
|
||||
route = `/v1/catalog/${app.mk.storefrontId}/albums/${this.data.id}`
|
||||
break;
|
||||
case 'playlists':
|
||||
route = `/v1/catalog/${app.mk.storefrontId}/playlists/${this.data.id}`
|
||||
break;
|
||||
case "library-playlists":
|
||||
route = `/v1/me/library/playlists/${this.data.id}/catalog`
|
||||
break
|
||||
case "library-albums":
|
||||
route = `/v1/me/library/albums/${this.data.id}/catalog`
|
||||
break
|
||||
}
|
||||
if (route === '') {
|
||||
return
|
||||
}
|
||||
app.mk.api.v3.music(route).then(res => {
|
||||
console.log(res.data.data[0].attributes.url)
|
||||
app.copyToClipboard(res.data.data[0].attributes.url)
|
||||
})
|
||||
}
|
||||
},
|
||||
"follow": {
|
||||
name: app.getLz('action.follow'),
|
||||
icon: "./assets/feather/plus-circle.svg",
|
||||
hidden: false,
|
||||
action: () => {
|
||||
app.setArtistFavorite(artistId, true)
|
||||
}
|
||||
},
|
||||
"unfollow": {
|
||||
name: app.getLz('action.unfollow'),
|
||||
icon: "./assets/feather/x-circle.svg",
|
||||
hidden: true,
|
||||
action: () => {
|
||||
app.setArtistFavorite(artistId, false)
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
|
||||
app.showMenuPanel(menuItems, event)
|
||||
|
||||
},
|
||||
getItemParent: function(data) {
|
||||
kind = data.attributes.playParams.kind;
|
||||
id = data.attributes.playParams.id;
|
||||
return `${kind}:${id}`
|
||||
},
|
||||
getFormattedDate: function() {
|
||||
let date = (this.data.attributes.releaseDate ?? (this.data.attributes.lastModifiedDate ?? (this.data.attributes.dateAdded ?? '')))
|
||||
let prefix = '';
|
||||
if (date == null || date === "") return "";
|
||||
switch (date) {
|
||||
case this.data.attributes.releaseDate:
|
||||
prefix = this.app.getLz('term.time.released') + ' '
|
||||
break;
|
||||
case this.data.attributes.lastModifiedDate:
|
||||
prefix = this.app.getLz('term.time.updated') + ' '
|
||||
break;
|
||||
case this.data.attributes.dateAdded:
|
||||
prefix = this.app.getLz('term.time.added') + ' '
|
||||
break;
|
||||
}
|
||||
let month, year;
|
||||
try {
|
||||
const releaseDate = new Date(date);
|
||||
// month = new Intl.DateTimeFormat(this.app.cfg.general.language.replace('_','-'), {month: 'long'}).format(releaseDate);
|
||||
// date = releaseDate.getDate();
|
||||
// year = releaseDate.getFullYear();
|
||||
let formatted = ''
|
||||
try {
|
||||
formatted = new Intl.DateTimeFormat(this.app.cfg.general.language?.replace('_', '-') ?? 'en-US', {
|
||||
day: 'numeric',
|
||||
month: 'long',
|
||||
year: 'numeric'
|
||||
}).format(releaseDate);
|
||||
} catch (e) {
|
||||
// use the format in json instead
|
||||
if (this.app.getLz('date.format') != null) {
|
||||
formatted = new this.app.getLz('date.format').replace("${d}", releaseDate.getDate()).replace("${m}", releaseDate.getMonth()).replace("${y}", releaseDate.getFullYear());
|
||||
} else {
|
||||
formatted = new Intl.DateTimeFormat('en-US', {
|
||||
day: 'numeric',
|
||||
month: 'long',
|
||||
year: 'numeric'
|
||||
}).format(releaseDate);
|
||||
}
|
||||
}
|
||||
return prefix + formatted
|
||||
} catch (e) {
|
||||
return ""
|
||||
}
|
||||
},
|
||||
play() {
|
||||
function shuffleArray(array) {
|
||||
for (var i = array.length - 1; i > 0; i--) {
|
||||
var j = Math.floor(Math.random() * (i + 1));
|
||||
var temp = array[i];
|
||||
array[i] = array[j];
|
||||
array[j] = temp;
|
||||
}
|
||||
}
|
||||
|
||||
const id = this.data.attributes.playParams.id ?? this.data.id;
|
||||
//console.log("1")
|
||||
const kind = this.data.attributes.playParams.kind ?? this.data.type ?? '';
|
||||
//console.log("1")
|
||||
const truekind = (!kind.endsWith("s")) ? (kind + "s") : kind;
|
||||
|
||||
let query = (this.data ?? app.showingPlaylist).relationships.tracks.data.map(item => new MusicKit.MediaItem(item));
|
||||
app.mk.stop().then(function() {
|
||||
app.mk.setQueue({ [truekind]: [id], parameters: { l: app.mklang } }).then(function() {
|
||||
app.mk.play().then(function() {
|
||||
if (query.length > 100) {
|
||||
let u = query.slice(100);
|
||||
if (app.mk.shuffleMode == 1) {
|
||||
shuffleArray(u)
|
||||
}
|
||||
app.mk.queue.append(u)
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
|
|
@ -1,22 +1,22 @@
|
|||
<script>
|
||||
Vue.component('plugin-renderer', {
|
||||
/*html*/
|
||||
template: `
|
||||
Vue.component('plugin-renderer', {
|
||||
/*html*/
|
||||
template: `
|
||||
<component :is="getPage()"></component>
|
||||
`,
|
||||
data: function () {
|
||||
return {
|
||||
app: this.$root,
|
||||
}
|
||||
},
|
||||
props: {},
|
||||
mounted() {
|
||||
},
|
||||
methods: {
|
||||
getPage() {
|
||||
return this.$root.pluginPages.page
|
||||
}
|
||||
},
|
||||
data: function() {
|
||||
return {
|
||||
app: this.$root,
|
||||
}
|
||||
},
|
||||
props: {},
|
||||
mounted() {
|
||||
},
|
||||
methods: {
|
||||
getPage() {
|
||||
return this.$root.pluginPages.page
|
||||
}
|
||||
},
|
||||
}
|
||||
);
|
||||
</script>
|
||||
);
|
||||
</script>
|
||||
|
|
|
@ -19,17 +19,20 @@
|
|||
<div class="podcast-list-header" v-if="podcasts.length != 0">
|
||||
{{$root.getLz('podcast.subscribedOnItunes')}}
|
||||
</div>
|
||||
<podcast-tab :isselected="podcastSelected.id == podcast.id" @click.native="selectPodcast(podcast)" v-for="podcast in podcasts" :item="podcast"></podcast-tab>
|
||||
<podcast-tab :isselected="podcastSelected.id == podcast.id" @click.native="selectPodcast(podcast)"
|
||||
v-for="podcast in podcasts" :item="podcast"></podcast-tab>
|
||||
</div>
|
||||
<div v-else>
|
||||
<div class="podcast-list-header" v-if="podcasts.length != 0">
|
||||
{{$root.getLz('term.library')}}
|
||||
</div>
|
||||
<podcast-tab :isselected="podcastSelected.id == podcast.id" @click.native="selectPodcast(podcast)" v-for="podcast in search.resultsLibrary" :item="podcast"></podcast-tab>
|
||||
<podcast-tab :isselected="podcastSelected.id == podcast.id" @click.native="selectPodcast(podcast)"
|
||||
v-for="podcast in search.resultsLibrary" :item="podcast"></podcast-tab>
|
||||
<div class="podcast-list-header" v-if="podcasts.length != 0">
|
||||
{{$root.getLz('podcast.itunesStore')}}
|
||||
</div>
|
||||
<podcast-tab :isselected="podcastSelected.id == podcast.id" @click.native="selectPodcast(podcast)" v-for="podcast in search.results" :item="podcast"></podcast-tab>
|
||||
<podcast-tab :isselected="podcastSelected.id == podcast.id" @click.native="selectPodcast(podcast)"
|
||||
v-for="podcast in search.results" :item="podcast"></podcast-tab>
|
||||
</div>
|
||||
</div>
|
||||
<div class="episodes-list">
|
||||
|
@ -37,13 +40,15 @@
|
|||
<div class="row">
|
||||
<div class="col-auto cider-flex-center">
|
||||
<div class="podcast-artwork">
|
||||
<mediaitem-artwork shadow="large" :url="podcastSelected.attributes.artwork.url" size="300"></mediaitem-artwork>
|
||||
<mediaitem-artwork shadow="large" :url="podcastSelected.attributes.artwork.url"
|
||||
size="300"></mediaitem-artwork>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col podcast-show-info">
|
||||
<h1>{{ podcastSelected.attributes.name }}</h1>
|
||||
<small>{{ podcastSelected.attributes.releaseFrequency }}</small>
|
||||
<small>Created: {{ new Date(podcastSelected.attributes.createdDate).toLocaleDateString() }}</small>
|
||||
<small>Created: {{ new Date(podcastSelected.attributes.createdDate).toLocaleDateString()
|
||||
}}</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -62,32 +67,44 @@
|
|||
<h3>{{$root.getLz('error.noResults')}}</h3>
|
||||
<p>{{$root.getLz('error.noResults.description')}}</p>
|
||||
</div>
|
||||
<podcast-episode :isselected="selected.id == episode.id" @dblclick.native="playEpisode(episode)" @click.native="selectEpisode(episode)" :item="episode"
|
||||
<podcast-episode :isselected="selected.id == episode.id" @dblclick.native="playEpisode(episode)"
|
||||
@click.native="selectEpisode(episode)" :item="episode"
|
||||
v-for="episode in episodes"></podcast-episode>
|
||||
</div>
|
||||
<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="$root.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>
|
||||
<mediaitem-artwork shadow="large" :url="selected.attributes.artwork.url"
|
||||
size="300"></mediaitem-artwork>
|
||||
</div>
|
||||
<h3 class="podcast-header">{{ selected.attributes.name }}</h3>
|
||||
<button @click="playEpisode(selected)" class="md-btn podcast-play-btn">{{$root.getLz('podcast.playEpisode')}}</button>
|
||||
<button @click="playEpisode(selected)" class="md-btn podcast-play-btn">
|
||||
{{$root.getLz('podcast.playEpisode')}}
|
||||
</button>
|
||||
<div class="podcast-genre">
|
||||
{{ selected.attributes.genreNames[0] }}
|
||||
</div>
|
||||
<div class="podcast-metainfo">
|
||||
{{ msToMinSec(selected.attributes.durationInMilliseconds) }} • {{ new Date(selected.attributes.releaseDateTime).toLocaleString() }}
|
||||
{{ msToMinSec(selected.attributes.durationInMilliseconds) }} • {{ new
|
||||
Date(selected.attributes.releaseDateTime).toLocaleString() }}
|
||||
</div>
|
||||
<div class="well podcast-description" v-if="selected.attributes.description.standard">{{
|
||||
selected.attributes.description.standard }}
|
||||
</div>
|
||||
<div class="well podcast-description" v-if="selected.attributes.description.standard">{{ selected.attributes.description.standard }}</div>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<button class="md-btn md-btn-block meta-btn" @click="openUrl(selected.attributes.websiteUrl)">{{$root.getLz('podcast.website')}}</button>
|
||||
<button class="md-btn md-btn-block meta-btn" @click="openUrl(selected.attributes.websiteUrl)">
|
||||
{{$root.getLz('podcast.website')}}
|
||||
</button>
|
||||
</div>
|
||||
<div class="col">
|
||||
<button class="md-btn md-btn-block meta-btn" @click="$root.share(selected.attributes.websiteUrl)">{{$root.getLz('action.share')}}</button>
|
||||
<button class="md-btn md-btn-block meta-btn"
|
||||
@click="$root.share(selected.attributes.websiteUrl)">{{$root.getLz('action.share')}}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -120,130 +137,137 @@
|
|||
{{ item.attributes.description.standard }}
|
||||
</div>
|
||||
<div class="subtitle text-overflow-elipsis">
|
||||
{{ msToMinSec(item.attributes.durationInMilliseconds) }} • {{ new Date(item.attributes.releaseDateTime).toLocaleString() }}
|
||||
{{ msToMinSec(item.attributes.durationInMilliseconds) }} • {{ new
|
||||
Date(item.attributes.releaseDateTime).toLocaleString() }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
<script>
|
||||
Vue.component('podcast-episode', {
|
||||
template: '#podcast-episode',
|
||||
props: ['item', 'isselected'],
|
||||
methods: {
|
||||
msToMinSec(ms) {
|
||||
var minutes = Math.floor(ms / 60000);
|
||||
var seconds = ((ms % 60000) / 1000).toFixed(0);
|
||||
return minutes + ":" + (seconds < 10 ? '0' : '') + seconds;
|
||||
}
|
||||
}
|
||||
});
|
||||
Vue.component('podcast-tab', {
|
||||
template: '#podcast-tab',
|
||||
props: ['item', 'isselected'],
|
||||
methods: {}
|
||||
});
|
||||
Vue.component('apple-podcasts', {
|
||||
template: '#apple-podcasts',
|
||||
data: function () {
|
||||
return {
|
||||
ciderPodcasts: [],
|
||||
podcasts: [],
|
||||
episodes: [],
|
||||
search: {
|
||||
term: "",
|
||||
loading: false,
|
||||
results: [],
|
||||
resultsLibrary: [],
|
||||
next: ""
|
||||
},
|
||||
podcastSelected: {
|
||||
id: -1
|
||||
},
|
||||
selected: {
|
||||
id: -1
|
||||
}
|
||||
}
|
||||
Vue.component('podcast-episode', {
|
||||
template: '#podcast-episode',
|
||||
props: ['item', 'isselected'],
|
||||
methods: {
|
||||
msToMinSec(ms) {
|
||||
var minutes = Math.floor(ms / 60000);
|
||||
var seconds = ((ms % 60000) / 1000).toFixed(0);
|
||||
return minutes + ":" + (seconds < 10 ? '0' : '') + seconds;
|
||||
}
|
||||
}
|
||||
});
|
||||
Vue.component('podcast-tab', {
|
||||
template: '#podcast-tab',
|
||||
props: ['item', 'isselected'],
|
||||
methods: {}
|
||||
});
|
||||
Vue.component('apple-podcasts', {
|
||||
template: '#apple-podcasts',
|
||||
data: function() {
|
||||
return {
|
||||
ciderPodcasts: [],
|
||||
podcasts: [],
|
||||
episodes: [],
|
||||
search: {
|
||||
term: "",
|
||||
loading: false,
|
||||
results: [],
|
||||
resultsLibrary: [],
|
||||
next: ""
|
||||
},
|
||||
async mounted() {
|
||||
let podcastShow = await app.mk.api.v3.podcasts(`/v1/me/library/podcasts?include=episodes`)
|
||||
this.podcasts = podcastShow.data.data
|
||||
if (podcastShow.data.next) {
|
||||
await this.getNext(podcastShow.data.next)
|
||||
}
|
||||
// this.episodes = podcastShow.data.data[0].relationships.episodes.data
|
||||
podcastSelected: {
|
||||
id: -1
|
||||
},
|
||||
methods: {
|
||||
searchTriggerVis(visible) {
|
||||
|
||||
},
|
||||
librarySearch() {
|
||||
this.search.resultsLibrary = []
|
||||
if (this.search.term.length > 2) {
|
||||
this.search.resultsLibrary = this.podcasts.filter(podcast => podcast.attributes.name.toLowerCase().includes(this.search.term.toLowerCase()))
|
||||
}
|
||||
},
|
||||
isSubscribed(id) {
|
||||
return this.podcasts.filter(podcast => podcast.id == id).length > 0
|
||||
},
|
||||
searchPodcasts() {
|
||||
let self = this
|
||||
if (this.search.term == "") {
|
||||
return
|
||||
}
|
||||
app.mk.api.v3.podcasts("/v1/catalog/us/search", {term: this.search.term, types: ["podcasts"], limit: 25}).then(response => {
|
||||
console.log(response)
|
||||
self.search.results = response.data.results.podcasts.data
|
||||
})
|
||||
},
|
||||
openUrl(url) {
|
||||
window.open(url)
|
||||
},
|
||||
msToMinSec(ms) {
|
||||
var minutes = Math.floor(ms / 60000);
|
||||
var seconds = ((ms % 60000) / 1000).toFixed(0);
|
||||
return minutes + ":" + (seconds < 10 ? '0' : '') + seconds;
|
||||
},
|
||||
playEpisode(episode) {
|
||||
app.mk.setQueue({'episode': episode.id, parameters : {l : app.mklang}}).then(() => {app.mk.play()})
|
||||
},
|
||||
selectPodcast(podcast) {
|
||||
this.podcastSelected = podcast
|
||||
this.getEpisodes(podcast)
|
||||
},
|
||||
selectEpisode(episode) {
|
||||
this.selected = Clone(episode)
|
||||
},
|
||||
async getEpisodes(podcast) {
|
||||
this.episodes = []
|
||||
let eps = await app.mk.api.v3.podcasts(`/v1/catalog/${app.mk.storefrontId}/podcasts/${podcast.id}?include=episodes`)
|
||||
|
||||
eps.data.data[0].relationships.episodes.data.forEach(ep => {
|
||||
this.episodes.push(ep)
|
||||
})
|
||||
if (eps.data.data[0].relationships.episodes.next) {
|
||||
await this.getNextEpisodes(eps.data.data[0].relationships.episodes.next, podcast.id)
|
||||
}
|
||||
},
|
||||
async getNextEpisodes(next, podcastId) {
|
||||
|
||||
let podcastShow = await app.mk.api.v3.podcasts(next)
|
||||
if (podcastId != this.podcastSelected.id) {
|
||||
return
|
||||
}
|
||||
podcastShow.data.data.forEach(ep => {
|
||||
this.episodes.push(ep)
|
||||
})
|
||||
if (podcastShow.data.next) {
|
||||
await this.getNextEpisodes(podcastShow.data.next, podcastId)
|
||||
}
|
||||
},
|
||||
async getNext(next) {
|
||||
let podcastShow = await app.mk.api.v3.podcasts(next)
|
||||
this.podcasts = this.podcasts.concat(podcastShow.data.data)
|
||||
if (podcastShow.data.next) {
|
||||
await this.getNext(podcastShow.data.next)
|
||||
}
|
||||
}
|
||||
selected: {
|
||||
id: -1
|
||||
}
|
||||
});
|
||||
</script>
|
||||
}
|
||||
},
|
||||
async mounted() {
|
||||
let podcastShow = await app.mk.api.v3.podcasts(`/v1/me/library/podcasts?include=episodes`)
|
||||
this.podcasts = podcastShow.data.data
|
||||
if (podcastShow.data.next) {
|
||||
await this.getNext(podcastShow.data.next)
|
||||
}
|
||||
// this.episodes = podcastShow.data.data[0].relationships.episodes.data
|
||||
},
|
||||
methods: {
|
||||
searchTriggerVis(visible) {
|
||||
|
||||
},
|
||||
librarySearch() {
|
||||
this.search.resultsLibrary = []
|
||||
if (this.search.term.length > 2) {
|
||||
this.search.resultsLibrary = this.podcasts.filter(podcast => podcast.attributes.name.toLowerCase().includes(this.search.term.toLowerCase()))
|
||||
}
|
||||
},
|
||||
isSubscribed(id) {
|
||||
return this.podcasts.filter(podcast => podcast.id == id).length > 0
|
||||
},
|
||||
searchPodcasts() {
|
||||
let self = this
|
||||
if (this.search.term == "") {
|
||||
return
|
||||
}
|
||||
app.mk.api.v3.podcasts("/v1/catalog/us/search", {
|
||||
term: this.search.term,
|
||||
types: ["podcasts"],
|
||||
limit: 25
|
||||
}).then(response => {
|
||||
console.log(response)
|
||||
self.search.results = response.data.results.podcasts.data
|
||||
})
|
||||
},
|
||||
openUrl(url) {
|
||||
window.open(url)
|
||||
},
|
||||
msToMinSec(ms) {
|
||||
var minutes = Math.floor(ms / 60000);
|
||||
var seconds = ((ms % 60000) / 1000).toFixed(0);
|
||||
return minutes + ":" + (seconds < 10 ? '0' : '') + seconds;
|
||||
},
|
||||
playEpisode(episode) {
|
||||
app.mk.setQueue({ 'episode': episode.id, parameters: { l: app.mklang } }).then(() => {
|
||||
app.mk.play()
|
||||
})
|
||||
},
|
||||
selectPodcast(podcast) {
|
||||
this.podcastSelected = podcast
|
||||
this.getEpisodes(podcast)
|
||||
},
|
||||
selectEpisode(episode) {
|
||||
this.selected = Clone(episode)
|
||||
},
|
||||
async getEpisodes(podcast) {
|
||||
this.episodes = []
|
||||
let eps = await app.mk.api.v3.podcasts(`/v1/catalog/${app.mk.storefrontId}/podcasts/${podcast.id}?include=episodes`)
|
||||
|
||||
eps.data.data[0].relationships.episodes.data.forEach(ep => {
|
||||
this.episodes.push(ep)
|
||||
})
|
||||
if (eps.data.data[0].relationships.episodes.next) {
|
||||
await this.getNextEpisodes(eps.data.data[0].relationships.episodes.next, podcast.id)
|
||||
}
|
||||
},
|
||||
async getNextEpisodes(next, podcastId) {
|
||||
|
||||
let podcastShow = await app.mk.api.v3.podcasts(next)
|
||||
if (podcastId != this.podcastSelected.id) {
|
||||
return
|
||||
}
|
||||
podcastShow.data.data.forEach(ep => {
|
||||
this.episodes.push(ep)
|
||||
})
|
||||
if (podcastShow.data.next) {
|
||||
await this.getNextEpisodes(podcastShow.data.next, podcastId)
|
||||
}
|
||||
},
|
||||
async getNext(next) {
|
||||
let podcastShow = await app.mk.api.v3.podcasts(next)
|
||||
this.podcasts = this.podcasts.concat(podcastShow.data.data)
|
||||
if (podcastShow.data.next) {
|
||||
await this.getNext(podcastShow.data.next)
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -6,10 +6,10 @@
|
|||
<h3>{{ app.getLz('term.personalStations') }}</h3>
|
||||
</div>
|
||||
</div>
|
||||
<!-- <mediaitem-square :kind="'385'" size="600"-->
|
||||
<!-- :item="item ? (item.attributes.kind ? item : ((item.relationships && item.relationships.contents ) ? item.relationships.contents.data[0] : item)) : []"-->
|
||||
<!-- :imagesize="800"-->
|
||||
<!-- v-for="item of getFlattenedCategories()">-->
|
||||
<!-- <mediaitem-square :kind="'385'" size="600"-->
|
||||
<!-- :item="item ? (item.attributes.kind ? item : ((item.relationships && item.relationships.contents ) ? item.relationships.contents.data[0] : item)) : []"-->
|
||||
<!-- :imagesize="800"-->
|
||||
<!-- v-for="item of getFlattenedCategories()">-->
|
||||
<mediaitem-square :item="item" v-for="item in radio.personal"></mediaitem-square>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
|
@ -27,65 +27,65 @@
|
|||
</script>
|
||||
|
||||
<script>
|
||||
Vue.component('cider-radio', {
|
||||
template: "#cider-radio",
|
||||
props: ["data"],
|
||||
data: function () {
|
||||
return {
|
||||
app: this.$root,
|
||||
radio: {personal: [], recent: [], am: []}
|
||||
}
|
||||
},
|
||||
async mounted() {
|
||||
this.radio.personal = await this.getPersonalStations()
|
||||
this.radio.recent = await this.getRecentStations()
|
||||
this.radio.am = await this.getAmStations()
|
||||
console.log(this.radio)
|
||||
// this.getPersonalStations();
|
||||
// this.getAmStations();
|
||||
},
|
||||
methods: {
|
||||
async getPersonalStations(attempts = 0) {
|
||||
if (attempts > 3) {
|
||||
return []
|
||||
}
|
||||
try {
|
||||
return (await app.mk.api.v3.music(`/v1/catalog/${app.mk.api.v3.storefrontId}/stations`, {
|
||||
"filter[identity]": "personal",
|
||||
})).data.data
|
||||
} catch (e) {
|
||||
console.error(`Failed to get personal stations: ${e}`)
|
||||
await this.getPersonalStations(attempts + 1)
|
||||
}
|
||||
},
|
||||
async getRecentStations(attempts = 0) {
|
||||
if (attempts > 3) {
|
||||
return []
|
||||
}
|
||||
try {
|
||||
return (await app.mk.api.v3.music(`/v1/me/recent/radio-stations`, {
|
||||
"platform": "web",
|
||||
"art[url]": "f",
|
||||
l: app.mklang
|
||||
})).data.data
|
||||
} catch (e) {
|
||||
console.error(`Failed to get recent stations: ${e}`)
|
||||
await this.getRecentStations(attempts + 1)
|
||||
}
|
||||
},
|
||||
async getAmStations(attempt = 0) {
|
||||
if (attempt > 3) {
|
||||
return []
|
||||
}
|
||||
try {
|
||||
return (await app.mk.api.v3.music(`/v1/catalog/${app.mk.api.v3.storefrontId}/stations`, {
|
||||
"filter[featured]": "apple-music-live-radio",
|
||||
})).data.data
|
||||
} catch (e) {
|
||||
console.error(`Failed to get AM stations: ${e}`)
|
||||
await this.getAmStations(attempt + 1)
|
||||
}
|
||||
},
|
||||
}
|
||||
})
|
||||
</script>
|
||||
Vue.component('cider-radio', {
|
||||
template: "#cider-radio",
|
||||
props: ["data"],
|
||||
data: function() {
|
||||
return {
|
||||
app: this.$root,
|
||||
radio: { personal: [], recent: [], am: [] }
|
||||
}
|
||||
},
|
||||
async mounted() {
|
||||
this.radio.personal = await this.getPersonalStations()
|
||||
this.radio.recent = await this.getRecentStations()
|
||||
this.radio.am = await this.getAmStations()
|
||||
console.log(this.radio)
|
||||
// this.getPersonalStations();
|
||||
// this.getAmStations();
|
||||
},
|
||||
methods: {
|
||||
async getPersonalStations(attempts = 0) {
|
||||
if (attempts > 3) {
|
||||
return []
|
||||
}
|
||||
try {
|
||||
return (await app.mk.api.v3.music(`/v1/catalog/${app.mk.api.v3.storefrontId}/stations`, {
|
||||
"filter[identity]": "personal",
|
||||
})).data.data
|
||||
} catch (e) {
|
||||
console.error(`Failed to get personal stations: ${e}`)
|
||||
await this.getPersonalStations(attempts + 1)
|
||||
}
|
||||
},
|
||||
async getRecentStations(attempts = 0) {
|
||||
if (attempts > 3) {
|
||||
return []
|
||||
}
|
||||
try {
|
||||
return (await app.mk.api.v3.music(`/v1/me/recent/radio-stations`, {
|
||||
"platform": "web",
|
||||
"art[url]": "f",
|
||||
l: app.mklang
|
||||
})).data.data
|
||||
} catch (e) {
|
||||
console.error(`Failed to get recent stations: ${e}`)
|
||||
await this.getRecentStations(attempts + 1)
|
||||
}
|
||||
},
|
||||
async getAmStations(attempt = 0) {
|
||||
if (attempt > 3) {
|
||||
return []
|
||||
}
|
||||
try {
|
||||
return (await app.mk.api.v3.music(`/v1/catalog/${app.mk.api.v3.storefrontId}/stations`, {
|
||||
"filter[featured]": "apple-music-live-radio",
|
||||
})).data.data
|
||||
} catch (e) {
|
||||
console.error(`Failed to get AM stations: ${e}`)
|
||||
await this.getAmStations(attempt + 1)
|
||||
}
|
||||
},
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
|
|
@ -76,36 +76,36 @@
|
|||
</div>
|
||||
</script>
|
||||
<script>
|
||||
Vue.component('cider-recordlabel', {
|
||||
template: "#cider-recordlabel",
|
||||
props: ['data'],
|
||||
data: function () {
|
||||
return {
|
||||
topSongsExpanded: false,
|
||||
$root: this.$root
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getArtistPalette(artist) {
|
||||
if (artist?.attributes?.artwork != null) {
|
||||
return {
|
||||
"background": "#" + artist["attributes"]["artwork"]["bgColor"],
|
||||
"color": "#" + artist["attributes"]["artwork"]["textColor1"],
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
"background": "#000000",
|
||||
"color": "#ffffff",
|
||||
}
|
||||
}
|
||||
},
|
||||
getTopResult() {
|
||||
if (this.search.results["meta"]) {
|
||||
return this.search.results[this.search.results.meta.results.order[0]]["data"][0]
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
Vue.component('cider-recordlabel', {
|
||||
template: "#cider-recordlabel",
|
||||
props: ['data'],
|
||||
data: function() {
|
||||
return {
|
||||
topSongsExpanded: false,
|
||||
$root: this.$root
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getArtistPalette(artist) {
|
||||
if (artist?.attributes?.artwork != null) {
|
||||
return {
|
||||
"background": "#" + artist["attributes"]["artwork"]["bgColor"],
|
||||
"color": "#" + artist["attributes"]["artwork"]["textColor1"],
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
"background": "#000000",
|
||||
"color": "#ffffff",
|
||||
}
|
||||
}
|
||||
},
|
||||
getTopResult() {
|
||||
if (this.search.results["meta"]) {
|
||||
return this.search.results[this.search.results.meta.results.order[0]]["data"][0]
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
|
|
@ -4,18 +4,16 @@
|
|||
</div>
|
||||
</script>
|
||||
<script>
|
||||
Vue.component('remote-pair', {
|
||||
template: '#remote-pair',
|
||||
async mounted() {
|
||||
ipcRenderer.send('get-remote-pair-url')
|
||||
ipcRenderer.on('send-remote-pair-url', (event, url) => {
|
||||
this.url = url
|
||||
app.webview.src = url
|
||||
document.getElementById('foo').src = url;
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
|
||||
}
|
||||
});
|
||||
</script>
|
||||
Vue.component('remote-pair', {
|
||||
template: '#remote-pair',
|
||||
async mounted() {
|
||||
ipcRenderer.send('get-remote-pair-url')
|
||||
ipcRenderer.on('send-remote-pair-url', (event, url) => {
|
||||
this.url = url
|
||||
app.webview.src = url
|
||||
document.getElementById('foo').src = url;
|
||||
})
|
||||
},
|
||||
methods: {}
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -3,158 +3,167 @@
|
|||
<vue-horizontal style="height: 300px;">
|
||||
<div class="replay-period" v-for="year in years" @click="getReplayYear(year.attributes.year)">
|
||||
<div class="artwork-container">
|
||||
<mediaitem-artwork :size="200" :url="year.relationships.playlist.data[0].attributes.artwork.url"></mediaitem-artwork>
|
||||
<mediaitem-artwork :size="200"
|
||||
:url="year.relationships.playlist.data[0].attributes.artwork.url"></mediaitem-artwork>
|
||||
</div>
|
||||
{{ year.attributes.year }}
|
||||
</div>
|
||||
</vue-horizontal>
|
||||
<hr>
|
||||
<transition name="replaycard">
|
||||
<div class="replay-viewport" v-if="loaded.id != -1">
|
||||
<!-- Stats -->
|
||||
<div class="replay-video" v-if="false">
|
||||
<mediaitem-artwork
|
||||
:url="loaded.playlist.attributes.editorialVideo.motionWideVideo21x9.previewFrame.url"
|
||||
:video="loaded.playlist.attributes.editorialVideo.motionWideVideo21x9.video"
|
||||
:video-priority="true"></mediaitem-artwork>
|
||||
</div>
|
||||
<h1 class="replay-header">{{ loaded.attributes.year }} {{$root.getLz('term.replay')}}</h1>
|
||||
<hr>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<h4>{{ convertToHours(loaded.attributes.listenTimeInMinutes) }} {{$root.getLz('term.time.hours')}}</h4>
|
||||
<h4>{{ loaded.attributes.uniqueAlbumCount }} {{$root.getLz('term.uniqueAlbums')}}</h4>
|
||||
<h4>{{ loaded.attributes.uniqueArtistCount }} {{$root.getLz('term.uniqueArtists')}}</h4>
|
||||
<h4>{{ loaded.attributes.uniqueSongCount }} {{$root.getLz('term.uniqueSongs')}}</h4>
|
||||
<div class="replay-viewport" v-if="loaded.id != -1">
|
||||
<!-- Stats -->
|
||||
<div class="replay-video" v-if="false">
|
||||
<mediaitem-artwork
|
||||
:url="loaded.playlist.attributes.editorialVideo.motionWideVideo21x9.previewFrame.url"
|
||||
:video="loaded.playlist.attributes.editorialVideo.motionWideVideo21x9.video"
|
||||
:video-priority="true"></mediaitem-artwork>
|
||||
</div>
|
||||
<div class="col-auto replay-playlist-container">
|
||||
<mediaitem-square kind="card" :no-scale="true" :force-video="true" :item="loaded.playlist"></mediaitem-square>
|
||||
<h1 class="replay-header">{{ loaded.attributes.year }} {{$root.getLz('term.replay')}}</h1>
|
||||
<hr>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<h4>{{ convertToHours(loaded.attributes.listenTimeInMinutes) }}
|
||||
{{$root.getLz('term.time.hours')}}</h4>
|
||||
<h4>{{ loaded.attributes.uniqueAlbumCount }} {{$root.getLz('term.uniqueAlbums')}}</h4>
|
||||
<h4>{{ loaded.attributes.uniqueArtistCount }} {{$root.getLz('term.uniqueArtists')}}</h4>
|
||||
<h4>{{ loaded.attributes.uniqueSongCount }} {{$root.getLz('term.uniqueSongs')}}</h4>
|
||||
</div>
|
||||
<div class="col-auto replay-playlist-container">
|
||||
<mediaitem-square kind="card" :no-scale="true" :force-video="true"
|
||||
:item="loaded.playlist"></mediaitem-square>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Top Artists-->
|
||||
<h3>{{$root.getLz('term.topArtists')}}</h3>
|
||||
<div class="well">
|
||||
<mediaitem-scroller-horizontal>
|
||||
<div class="card replay-card" v-for="artistData in loaded.views['top-artists'].data">
|
||||
<div class="card-body">
|
||||
<mediaitem-square :item="artistData.relationships.artist.data[0]"></mediaitem-square>
|
||||
<!-- Top Artists-->
|
||||
<h3>{{$root.getLz('term.topArtists')}}</h3>
|
||||
<div class="well">
|
||||
<mediaitem-scroller-horizontal>
|
||||
<div class="card replay-card" v-for="artistData in loaded.views['top-artists'].data">
|
||||
<div class="card-body">
|
||||
<mediaitem-square :item="artistData.relationships.artist.data[0]"></mediaitem-square>
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
{{ convertToHours(artistData.attributes.listenTimeInMinutes) }}
|
||||
{{$root.getLz('term.time.hours', {'count':
|
||||
convertToHours(artistData.attributes.listenTimeInMinutes) })}}<br>
|
||||
{{$root.getLz('term.listenedTo')}} {{ artistData.attributes.playCount }}
|
||||
{{$root.getLz('term.times')}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
{{ convertToHours(artistData.attributes.listenTimeInMinutes) }} {{$root.getLz('term.time.hours', {'count': convertToHours(artistData.attributes.listenTimeInMinutes) })}}<br>
|
||||
{{$root.getLz('term.listenedTo')}} {{ artistData.attributes.playCount }} {{$root.getLz('term.times')}}
|
||||
</mediaitem-scroller-horizontal>
|
||||
</div>
|
||||
<!-- Top Albums-->
|
||||
<h3>{{$root.getLz('term.topAlbums')}}</h3>
|
||||
<div class="well">
|
||||
<mediaitem-scroller-horizontal>
|
||||
<div class="card replay-card" v-for="albumData in loaded.views['top-albums'].data">
|
||||
<div class="card-body">
|
||||
<mediaitem-square :item="albumData.relationships.album.data[0]"></mediaitem-square>
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
{{ convertToHours(albumData.attributes.listenTimeInMinutes) }}
|
||||
{{$root.getLz('term.time.hours', {'count':
|
||||
convertToHours(albumData.attributes.listenTimeInMinutes)})}}<br>
|
||||
{{ albumData.attributes.playCount }} {{$root.getLz('term.plays')}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</mediaitem-scroller-horizontal>
|
||||
</div>
|
||||
<!-- Top Albums-->
|
||||
<h3>{{$root.getLz('term.topAlbums')}}</h3>
|
||||
<div class="well">
|
||||
<mediaitem-scroller-horizontal>
|
||||
<div class="card replay-card" v-for="albumData in loaded.views['top-albums'].data">
|
||||
<div class="card-body">
|
||||
<mediaitem-square :item="albumData.relationships.album.data[0]"></mediaitem-square>
|
||||
</mediaitem-scroller-horizontal>
|
||||
</div>
|
||||
<!-- Top Songs-->
|
||||
<h3>{{$root.getLz('term.topSongs')}}</h3>
|
||||
<div class="well">
|
||||
<listitem-horizontal :show-library-status="false"
|
||||
:items="songsToArray(loaded.views['top-songs'].data)"></listitem-horizontal>
|
||||
</div>
|
||||
<h3>{{$root.getLz('term.topGenres')}}</h3>
|
||||
<div class="top-genres-container">
|
||||
<div v-for="genre in loaded.topGenres" class="replay-genre-display">
|
||||
<div class="genre-name">
|
||||
{{ genre.genre }}
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
{{ convertToHours(albumData.attributes.listenTimeInMinutes) }} {{$root.getLz('term.time.hours', {'count': convertToHours(albumData.attributes.listenTimeInMinutes)})}}<br>
|
||||
{{ albumData.attributes.playCount }} {{$root.getLz('term.plays')}}
|
||||
</div>
|
||||
</div>
|
||||
</mediaitem-scroller-horizontal>
|
||||
</div>
|
||||
<!-- Top Songs-->
|
||||
<h3>{{$root.getLz('term.topSongs')}}</h3>
|
||||
<div class="well">
|
||||
<listitem-horizontal :show-library-status="false" :items="songsToArray(loaded.views['top-songs'].data)"></listitem-horizontal>
|
||||
</div>
|
||||
<h3>{{$root.getLz('term.topGenres')}}</h3>
|
||||
<div class="top-genres-container">
|
||||
<div v-for="genre in loaded.topGenres" class="replay-genre-display">
|
||||
<div class="genre-name">
|
||||
{{ genre.genre }}
|
||||
</div>
|
||||
<div class="genre-count">
|
||||
<div class="genre-count-bar" :style="{'width': genre.count + '%'}">
|
||||
{{ genre.count }}%
|
||||
<div class="genre-count">
|
||||
<div class="genre-count-bar" :style="{'width': genre.count + '%'}">
|
||||
{{ genre.count }}%
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
</div>
|
||||
</script>
|
||||
<script>
|
||||
Vue.component('replay-page', {
|
||||
template: '#replay-page',
|
||||
data: function () {
|
||||
return {
|
||||
years: [],
|
||||
loaded: {
|
||||
id: -1
|
||||
},
|
||||
musicTypeGenre: ""
|
||||
}
|
||||
Vue.component('replay-page', {
|
||||
template: '#replay-page',
|
||||
data: function() {
|
||||
return {
|
||||
years: [],
|
||||
loaded: {
|
||||
id: -1
|
||||
},
|
||||
async mounted() {
|
||||
// Get available years
|
||||
let year = await app.mk.api.v3.music("/v1/me/music-summaries/search?extend=inLibrary&period=year&fields[music-summaries]=period%2Cyear&include[music-summaries]=playlist")
|
||||
this.years = year.data.data
|
||||
this.years.reverse()
|
||||
localStorage.setItem("seenReplay", true)
|
||||
this.getReplayYear();
|
||||
const musicGenre = await app.mk.api.v3.music(`/v1/catalog/${app.mk.storefrontId}/genres/34`)
|
||||
this.musicTypeGenre = musicGenre.data.data[0].attributes.name
|
||||
},
|
||||
methods: {
|
||||
songsToArray(songsData) {
|
||||
let self = this
|
||||
let songs = []
|
||||
let topGenres = {}
|
||||
let genrePlayCount = 0;
|
||||
songsData.forEach(function (songData) {
|
||||
let song = songData.relationships.song.data[0]
|
||||
song.attributes.playCount = songData.attributes.playCount
|
||||
songs.push(song)
|
||||
genrePlayCount += song.attributes.playCount
|
||||
song.attributes.genreNames.forEach(function (genre) {
|
||||
if (genre != self.musicTypeGenre) {
|
||||
if (topGenres[genre] == undefined) {
|
||||
topGenres[genre] = song.attributes.playCount
|
||||
} else {
|
||||
topGenres[genre] += song.attributes.playCount
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
let topGenresArray = []
|
||||
for (let genre in topGenres) {
|
||||
topGenresArray.push({
|
||||
genre: genre,
|
||||
count: topGenres[genre]
|
||||
})
|
||||
}
|
||||
topGenresArray.sort(function (a, b) {
|
||||
return b.count - a.count
|
||||
})
|
||||
topGenresArray.forEach(function (genre) {
|
||||
genre.count = Math.round(genre.count / genrePlayCount * 100)
|
||||
})
|
||||
this.loaded.topGenres = topGenresArray
|
||||
|
||||
return songs
|
||||
},
|
||||
async getReplayYear(year = new Date().getFullYear()) {
|
||||
this.loaded.id = -1
|
||||
let response = await app.mk.api.v3.music(`/v1/me/music-summaries/year-${year}?extend=inLibrary&views=top-artists%2Ctop-albums%2Ctop-songs&include[music-summaries]=playlist&include[playlists]=tracks&includeOnly=playlist%2Ctracks%2Csong%2Cartist%2Calbum`)
|
||||
let replayData = response.data.data[0]
|
||||
// extended playlist
|
||||
let playlist = await app.mk.api.v3.music(replayData.relationships.playlist.data[0].href, {extend: "editorialArtwork,editorialVideo"})
|
||||
replayData.playlist = playlist.data.data[0]
|
||||
this.loaded = replayData
|
||||
},
|
||||
convertToHours(minutes) {
|
||||
return Math.floor(minutes / 60)
|
||||
musicTypeGenre: ""
|
||||
}
|
||||
},
|
||||
async mounted() {
|
||||
// Get available years
|
||||
let year = await app.mk.api.v3.music("/v1/me/music-summaries/search?extend=inLibrary&period=year&fields[music-summaries]=period%2Cyear&include[music-summaries]=playlist")
|
||||
this.years = year.data.data
|
||||
this.years.reverse()
|
||||
localStorage.setItem("seenReplay", true)
|
||||
this.getReplayYear();
|
||||
const musicGenre = await app.mk.api.v3.music(`/v1/catalog/${app.mk.storefrontId}/genres/34`)
|
||||
this.musicTypeGenre = musicGenre.data.data[0].attributes.name
|
||||
},
|
||||
methods: {
|
||||
songsToArray(songsData) {
|
||||
let self = this
|
||||
let songs = []
|
||||
let topGenres = {}
|
||||
let genrePlayCount = 0;
|
||||
songsData.forEach(function(songData) {
|
||||
let song = songData.relationships.song.data[0]
|
||||
song.attributes.playCount = songData.attributes.playCount
|
||||
songs.push(song)
|
||||
genrePlayCount += song.attributes.playCount
|
||||
song.attributes.genreNames.forEach(function(genre) {
|
||||
if (genre != self.musicTypeGenre) {
|
||||
if (topGenres[genre] == undefined) {
|
||||
topGenres[genre] = song.attributes.playCount
|
||||
} else {
|
||||
topGenres[genre] += song.attributes.playCount
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
let topGenresArray = []
|
||||
for (let genre in topGenres) {
|
||||
topGenresArray.push({
|
||||
genre: genre,
|
||||
count: topGenres[genre]
|
||||
})
|
||||
}
|
||||
});
|
||||
</script>
|
||||
topGenresArray.sort(function(a, b) {
|
||||
return b.count - a.count
|
||||
})
|
||||
topGenresArray.forEach(function(genre) {
|
||||
genre.count = Math.round(genre.count / genrePlayCount * 100)
|
||||
})
|
||||
this.loaded.topGenres = topGenresArray
|
||||
|
||||
return songs
|
||||
},
|
||||
async getReplayYear(year = new Date().getFullYear()) {
|
||||
this.loaded.id = -1
|
||||
let response = await app.mk.api.v3.music(`/v1/me/music-summaries/year-${year}?extend=inLibrary&views=top-artists%2Ctop-albums%2Ctop-songs&include[music-summaries]=playlist&include[playlists]=tracks&includeOnly=playlist%2Ctracks%2Csong%2Cartist%2Calbum`)
|
||||
let replayData = response.data.data[0]
|
||||
// extended playlist
|
||||
let playlist = await app.mk.api.v3.music(replayData.relationships.playlist.data[0].href, { extend: "editorialArtwork,editorialVideo" })
|
||||
replayData.playlist = playlist.data.data[0]
|
||||
this.loaded = replayData
|
||||
},
|
||||
convertToHours(minutes) {
|
||||
return Math.floor(minutes / 60)
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<script type="text/x-template" id="cider-search">
|
||||
<div class="content-inner search-page">
|
||||
<div class="search-input-container fs-search" v-if="$root.appMode == 'fullscreen'" >
|
||||
<div class="search-input-container fs-search" v-if="$root.appMode == 'fullscreen'">
|
||||
<div class="search-input--icon"></div>
|
||||
<input type="search" spellcheck="false" @focus="$root.search.showHints = true"
|
||||
@blur="$root.setTimeout(()=>{$root.search.showHints = false}, 300)"
|
||||
|
@ -20,10 +20,14 @@
|
|||
<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>
|
||||
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>
|
||||
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 != ''">
|
||||
<template v-if="searchType == 'catalog'">
|
||||
|
@ -55,14 +59,16 @@
|
|||
|
||||
<template v-if="search.results['meta'] != null">
|
||||
<template
|
||||
v-for="section in search.results.meta.results.order" v-if="section != 'song' && section != 'top'">
|
||||
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 cider-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')}}
|
||||
@click="app.showSearchView(app.search.term, section, app.friendlyTypes(section))">
|
||||
{{app.getLz('term.seeAll')}}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -83,7 +89,8 @@
|
|||
</div>
|
||||
<div class="col-auto cider-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')}}
|
||||
@click="app.showCollection(search.resultsSocial.playlist, 'Shared Playlists', 'default')">
|
||||
{{app.getLz('term.seeAll')}}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -97,7 +104,8 @@
|
|||
</div>
|
||||
<div class="col-auto cider-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')}}
|
||||
@click="app.showCollection(search.resultsSocial.profile, 'People', 'default')">
|
||||
{{app.getLz('term.seeAll')}}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -119,79 +127,83 @@
|
|||
</div>
|
||||
</template>
|
||||
</div>
|
||||
<div v-else >
|
||||
<div v-if="categoriesReady || getCategories()">
|
||||
<div v-else>
|
||||
<div v-if="categoriesReady || getCategories()">
|
||||
<div>
|
||||
<div class="col" v-if="categoriesView != null && categoriesView != [] && categoriesView[0].attributes != null && categoriesView[0].attributes.title != null">
|
||||
<div class="col"
|
||||
v-if="categoriesView != null && categoriesView != [] && categoriesView[0].attributes != null && categoriesView[0].attributes.title != null">
|
||||
<h3>{{$root.getLz('home.recentlyPlayed')}}</h3>
|
||||
<div class="mediaitem-list-item__grid">
|
||||
<listitem-horizontal :items="recentlyPlayed.limit(10)">
|
||||
</listitem-horizontal>
|
||||
</div>
|
||||
<!-- <mediaitem-square :kind="'385'" size="600" v-for="item in recentlyPlayed.limit(10)" :item="item" :imagesize="800"></mediaitem-square>-->
|
||||
<listitem-horizontal :items="recentlyPlayed.limit(10)">
|
||||
</listitem-horizontal>
|
||||
</div>
|
||||
<!-- <mediaitem-square :kind="'385'" size="600" v-for="item in recentlyPlayed.limit(10)" :item="item" :imagesize="800"></mediaitem-square>-->
|
||||
<h3>{{categoriesView[0].attributes.title.stringForDisplay ?? ""}}</h3>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="categories">
|
||||
<mediaitem-square :kind="'385'" :imageformat="'bb'" size="600"
|
||||
:item="item ? (item.attributes.kind ? item : ((item.relationships && item.relationships.contents ) ? item.relationships.contents.data[0] : item)) : []"
|
||||
:imagesize="800"
|
||||
v-for="item of getFlattenedCategories()">
|
||||
:item="item ? (item.attributes.kind ? item : ((item.relationships && item.relationships.contents ) ? item.relationships.contents.data[0] : item)) : []"
|
||||
:imagesize="800"
|
||||
v-for="item of getFlattenedCategories()">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script>
|
||||
Vue.component('cider-search', {
|
||||
template: "#cider-search",
|
||||
props: ['search'],
|
||||
data: function () {
|
||||
return {
|
||||
app: this.$root,
|
||||
recentlyPlayed: [],
|
||||
categoriesView: [],
|
||||
categoriesReady: false,
|
||||
searchType: "catalog",
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getTopResult() {
|
||||
try {
|
||||
return this.search.results[this.search.results.meta.results.order[0]]["data"][0]
|
||||
} catch (error) {
|
||||
return false
|
||||
}
|
||||
},
|
||||
async seeAllHistory() {
|
||||
let hist = await app.mk.api.v3.music(`/v1/me/recent/played/tracks`, {
|
||||
l: this.$root.mklang
|
||||
})
|
||||
this.recentlyPlayed = hist.data.data
|
||||
},
|
||||
async getCategories() {
|
||||
if (this.categoriesView != [] && this.categoriesView.length > 0) { this.categoriesReady = true; return await true; } else {
|
||||
await this.seeAllHistory()
|
||||
let response = await this.app.mk.api.v3.music(`/v1/recommendations/${this.app.mk.storefrontId}?timezone=${encodeURIComponent(this.app.formatTimezoneOffset())}&name=search-landing&platform=web&extend=editorialArtwork&art%5Burl%5D=f%2Cc&types=editorial-items%2Capple-curators%2Cactivities&l=${this.$root.mklang}`);
|
||||
this.categoriesView = response.data.data;
|
||||
console.log(this.categoriesView)
|
||||
this.categoriesReady = true;
|
||||
return await true;
|
||||
}
|
||||
},
|
||||
getFlattenedCategories() {
|
||||
let flattened = [];
|
||||
for (let i = 0; i < this.categoriesView.length; i++) {
|
||||
if (this.categoriesView[i].relationships && this.categoriesView[i].relationships.contents && this.categoriesView[i].relationships.contents.data) {
|
||||
for (let j = 0; j < this.categoriesView[i].relationships.contents.data.length; j++) {
|
||||
if (this.categoriesView[i].relationships.contents.data[j].type != 'editorial-items')
|
||||
flattened.push(this.categoriesView[i].relationships.contents.data[j])
|
||||
}
|
||||
}
|
||||
}
|
||||
return flattened;
|
||||
}
|
||||
Vue.component('cider-search', {
|
||||
template: "#cider-search",
|
||||
props: ['search'],
|
||||
data: function() {
|
||||
return {
|
||||
app: this.$root,
|
||||
recentlyPlayed: [],
|
||||
categoriesView: [],
|
||||
categoriesReady: false,
|
||||
searchType: "catalog",
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getTopResult() {
|
||||
try {
|
||||
return this.search.results[this.search.results.meta.results.order[0]]["data"][0]
|
||||
} catch (error) {
|
||||
return false
|
||||
}
|
||||
})
|
||||
</script>
|
||||
},
|
||||
async seeAllHistory() {
|
||||
let hist = await app.mk.api.v3.music(`/v1/me/recent/played/tracks`, {
|
||||
l: this.$root.mklang
|
||||
})
|
||||
this.recentlyPlayed = hist.data.data
|
||||
},
|
||||
async getCategories() {
|
||||
if (this.categoriesView != [] && this.categoriesView.length > 0) {
|
||||
this.categoriesReady = true;
|
||||
return await true;
|
||||
} else {
|
||||
await this.seeAllHistory()
|
||||
let response = await this.app.mk.api.v3.music(`/v1/recommendations/${this.app.mk.storefrontId}?timezone=${encodeURIComponent(this.app.formatTimezoneOffset())}&name=search-landing&platform=web&extend=editorialArtwork&art%5Burl%5D=f%2Cc&types=editorial-items%2Capple-curators%2Cactivities&l=${this.$root.mklang}`);
|
||||
this.categoriesView = response.data.data;
|
||||
console.log(this.categoriesView)
|
||||
this.categoriesReady = true;
|
||||
return await true;
|
||||
}
|
||||
},
|
||||
getFlattenedCategories() {
|
||||
let flattened = [];
|
||||
for (let i = 0; i < this.categoriesView.length; i++) {
|
||||
if (this.categoriesView[i].relationships && this.categoriesView[i].relationships.contents && this.categoriesView[i].relationships.contents.data) {
|
||||
for (let j = 0; j < this.categoriesView[i].relationships.contents.data.length; j++) {
|
||||
if (this.categoriesView[i].relationships.contents.data[j].type != 'editorial-items')
|
||||
flattened.push(this.categoriesView[i].relationships.contents.data[j])
|
||||
}
|
||||
}
|
||||
}
|
||||
return flattened;
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
|
|
@ -1,48 +1,46 @@
|
|||
<script type="text/x-template" id="cider-zoo">
|
||||
<div class="content-inner">
|
||||
<svg-icon/>
|
||||
<svg-icon />
|
||||
<h3>Welcome to element park. *BERR NERR NERR NERR NERRRRR BERR NER NER NER NERRR BERRR NR NR NRRRR*</h3>
|
||||
<button @click="app.playMediaItemById('1592151778', 'album')">Play Test Album</button>
|
||||
{{ $store.state.test }}
|
||||
<div class="spinner"></div>
|
||||
<button class="md-btn">Cider Button</button>
|
||||
<artist-chip
|
||||
v-if="artistLoaded"
|
||||
:item="artist"
|
||||
v-if="artistLoaded"
|
||||
:item="artist"
|
||||
></artist-chip>
|
||||
|
||||
<amp-chrome-player/>
|
||||
<amp-chrome-player />
|
||||
<!-- <amp-footer-player/> -->
|
||||
<hr>
|
||||
<amp-lcd-progress/>
|
||||
<amp-lcd-progress />
|
||||
<hr>
|
||||
<amp-playback-controls-shuffle/>
|
||||
<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/>
|
||||
<amp-user-menu />
|
||||
<amp-tv-overlay />
|
||||
<amp-podcast-playback-controls />
|
||||
<amp-lcd />
|
||||
</div>
|
||||
</script>
|
||||
<script>
|
||||
Vue.component('cider-zoo', {
|
||||
template: '#cider-zoo',
|
||||
data: function () {
|
||||
return {
|
||||
artistLoaded: false,
|
||||
artist: {}
|
||||
}
|
||||
},
|
||||
async mounted() {
|
||||
app.mk.api.v3.music("/v1/catalog/us/artists/669831761").then(response => {
|
||||
this.artist = response.data.data[0];
|
||||
this.artistLoaded = true;
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
|
||||
}
|
||||
});
|
||||
</script>
|
||||
Vue.component('cider-zoo', {
|
||||
template: '#cider-zoo',
|
||||
data: function() {
|
||||
return {
|
||||
artistLoaded: false,
|
||||
artist: {}
|
||||
}
|
||||
},
|
||||
async mounted() {
|
||||
app.mk.api.v3.music("/v1/catalog/us/artists/669831761").then(response => {
|
||||
this.artist = response.data.data[0];
|
||||
this.artistLoaded = true;
|
||||
});
|
||||
},
|
||||
methods: {}
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -1 +1,5 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512" fill="currentColor"><!-- Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) --><path d="M34.9 289.5l-22.2-22.2c-9.4-9.4-9.4-24.6 0-33.9L207 39c9.4-9.4 24.6-9.4 33.9 0l194.3 194.3c9.4 9.4 9.4 24.6 0 33.9L413 289.4c-9.5 9.5-25 9.3-34.3-.4L264 168.6V456c0 13.3-10.7 24-24 24h-32c-13.3 0-24-10.7-24-24V168.6L69.2 289.1c-9.3 9.8-24.8 10-34.3.4z"/></svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"
|
||||
fill="currentColor"><!-- Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) -->
|
||||
<path
|
||||
d="M34.9 289.5l-22.2-22.2c-9.4-9.4-9.4-24.6 0-33.9L207 39c9.4-9.4 24.6-9.4 33.9 0l194.3 194.3c9.4 9.4 9.4 24.6 0 33.9L413 289.4c-9.5 9.5-25 9.3-34.3-.4L264 168.6V456c0 13.3-10.7 24-24 24h-32c-13.3 0-24-10.7-24-24V168.6L69.2 289.1c-9.3 9.8-24.8 10-34.3.4z"/>
|
||||
</svg>
|
||||
|
|
Before Width: | Height: | Size: 531 B After Width: | Height: | Size: 545 B |
|
@ -1 +1,6 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-cast"><path d="M2 16.1A5 5 0 0 1 5.9 20M2 12.05A9 9 0 0 1 9.95 20M2 8V6a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2h-6"/><line x1="2" y1="20" x2="2.01" y2="20"/></svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor"
|
||||
stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-cast">
|
||||
<path
|
||||
d="M2 16.1A5 5 0 0 1 5.9 20M2 12.05A9 9 0 0 1 9.95 20M2 8V6a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2h-6"/>
|
||||
<line x1="2" y1="20" x2="2.01" y2="20"/>
|
||||
</svg>
|
||||
|
|
Before Width: | Height: | Size: 375 B After Width: | Height: | Size: 392 B |
|
@ -1 +1,4 @@
|
|||
<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-check"><polyline points="20 6 9 17 4 12"></polyline></svg>
|
||||
<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-check">
|
||||
<polyline points="20 6 9 17 4 12"></polyline>
|
||||
</svg>
|
||||
|
|
Before Width: | Height: | Size: 262 B After Width: | Height: | Size: 272 B |
|
@ -1 +1,5 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 320 512"><!-- Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) --><path d="M34.52 239.03L228.87 44.69c9.37-9.37 24.57-9.37 33.94 0l22.67 22.67c9.36 9.36 9.37 24.52.04 33.9L131.49 256l154.02 154.75c9.34 9.38 9.32 24.54-.04 33.9l-22.67 22.67c-9.37 9.37-24.57 9.37-33.94 0L34.52 272.97c-9.37-9.37-9.37-24.57 0-33.94z"/></svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="currentColor"
|
||||
viewBox="0 0 320 512"><!-- Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) -->
|
||||
<path
|
||||
d="M34.52 239.03L228.87 44.69c9.37-9.37 24.57-9.37 33.94 0l22.67 22.67c9.36 9.36 9.37 24.52.04 33.9L131.49 256l154.02 154.75c9.34 9.38 9.32 24.54-.04 33.9l-22.67 22.67c-9.37 9.37-24.57 9.37-33.94 0L34.52 272.97c-9.37-9.37-9.37-24.57 0-33.94z"/>
|
||||
</svg>
|
||||
|
|
Before Width: | Height: | Size: 518 B After Width: | Height: | Size: 532 B |
|
@ -1 +1,6 @@
|
|||
<svg aria-hidden="true" data-prefix="fas" data-icon="chevron-right" fill="currentColor" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512" class="svg-inline--fa fa-chevron-right fa-w-10 fa-7x"><path fill="currentColor" d="M285.476 272.971L91.132 467.314c-9.373 9.373-24.569 9.373-33.941 0l-22.667-22.667c-9.357-9.357-9.375-24.522-.04-33.901L188.505 256 34.484 101.255c-9.335-9.379-9.317-24.544.04-33.901l22.667-22.667c9.373-9.373 24.569-9.373 33.941 0L285.475 239.03c9.373 9.372 9.373 24.568.001 33.941z" class=""/></svg>
|
||||
<svg aria-hidden="true" data-prefix="fas" data-icon="chevron-right" fill="currentColor" role="img"
|
||||
xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512" class="svg-inline--fa fa-chevron-right fa-w-10 fa-7x">
|
||||
<path fill="currentColor"
|
||||
d="M285.476 272.971L91.132 467.314c-9.373 9.373-24.569 9.373-33.941 0l-22.667-22.667c-9.357-9.357-9.375-24.522-.04-33.901L188.505 256 34.484 101.255c-9.335-9.379-9.317-24.544.04-33.901l22.667-22.667c9.373-9.373 24.569-9.373 33.941 0L285.475 239.03c9.373 9.372 9.373 24.568.001 33.941z"
|
||||
class=""/>
|
||||
</svg>
|
||||
|
|
Before Width: | Height: | Size: 538 B After Width: | Height: | Size: 564 B |
|
@ -1 +1,4 @@
|
|||
<svg width="9" height="9" viewBox="0 0 9 9" xmlns="http://www.w3.org/2000/svg" class="glyph" aria-hidden="true"><path d="M1.59 8.991h5.82c1.043 0 1.582-.538 1.582-1.566v-5.85C8.992.547 8.453.008 7.41.008H1.59C.552.008.008.542.008 1.575v5.85c0 1.028.544 1.566 1.582 1.566zm1.812-2.273c-.332 0-.505-.211-.505-.553V2.753c0-.341.173-.553.505-.553h2.264c.245 0 .408.14.408.385 0 .235-.163.384-.408.384H3.854v1.106h1.71c.226 0 .38.125.38.355 0 .221-.154.346-.38.346h-1.71V5.95h1.812c.245 0 .408.14.408.385 0 .235-.163.384-.408.384H3.402z"></path></svg>
|
||||
<svg width="9" height="9" viewBox="0 0 9 9" xmlns="http://www.w3.org/2000/svg" class="glyph" aria-hidden="true">
|
||||
<path
|
||||
d="M1.59 8.991h5.82c1.043 0 1.582-.538 1.582-1.566v-5.85C8.992.547 8.453.008 7.41.008H1.59C.552.008.008.542.008 1.575v5.85c0 1.028.544 1.566 1.582 1.566zm1.812-2.273c-.332 0-.505-.211-.505-.553V2.753c0-.341.173-.553.505-.553h2.264c.245 0 .408.14.408.385 0 .235-.163.384-.408.384H3.854v1.106h1.71c.226 0 .38.125.38.355 0 .221-.154.346-.38.346h-1.71V5.95h1.812c.245 0 .408.14.408.385 0 .235-.163.384-.408.384H3.402z"></path>
|
||||
</svg>
|
||||
|
|
Before Width: | Height: | Size: 546 B After Width: | Height: | Size: 555 B |
|
@ -1 +1,6 @@
|
|||
<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>
|
||||
<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>
|
||||
|
|
Before Width: | Height: | Size: 388 B After Width: | Height: | Size: 404 B |
|
@ -1,4 +1,4 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="36" height="36" viewBox="0 0 36 36" fill="white">
|
||||
<path d="M0 0h36v36h-36z" fill="none"/>
|
||||
<path d="M10 21h-3v8h8v-3h-5v-5zm-3-6h3v-5h5v-3h-8v8zm19 11h-5v3h8v-8h-3v5zm-5-19v3h5v5h3v-8h-8z"/>
|
||||
<path d="M0 0h36v36h-36z" fill="none"/>
|
||||
<path d="M10 21h-3v8h8v-3h-5v-5zm-3-6h3v-5h5v-3h-8v8zm19 11h-5v3h8v-8h-3v5zm-5-19v3h5v5h3v-8h-8z"/>
|
||||
</svg>
|
||||
|
|
Before Width: | Height: | Size: 252 B After Width: | Height: | Size: 248 B |
|
@ -1 +1,7 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-grid"><rect x="3" y="3" width="7" height="7"></rect><rect x="14" y="3" width="7" height="7"></rect><rect x="14" y="14" width="7" height="7"></rect><rect x="3" y="14" width="7" height="7"></rect></svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor"
|
||||
stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-grid">
|
||||
<rect x="3" y="3" width="7" height="7"></rect>
|
||||
<rect x="14" y="3" width="7" height="7"></rect>
|
||||
<rect x="14" y="14" width="7" height="7"></rect>
|
||||
<rect x="3" y="14" width="7" height="7"></rect>
|
||||
</svg>
|
||||
|
|
Before Width: | Height: | Size: 404 B After Width: | Height: | Size: 423 B |
|
@ -1 +1,6 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-headphones"><path d="M3 18v-6a9 9 0 0 1 18 0v6"></path><path d="M21 19a2 2 0 0 1-2 2h-1a2 2 0 0 1-2-2v-3a2 2 0 0 1 2-2h3zM3 19a2 2 0 0 0 2 2h1a2 2 0 0 0 2-2v-3a2 2 0 0 0-2-2H3z"></path></svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor"
|
||||
stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-headphones">
|
||||
<path d="M3 18v-6a9 9 0 0 1 18 0v6"></path>
|
||||
<path
|
||||
d="M21 19a2 2 0 0 1-2 2h-1a2 2 0 0 1-2-2v-3a2 2 0 0 1 2-2h3zM3 19a2 2 0 0 0 2 2h1a2 2 0 0 0 2-2v-3a2 2 0 0 0-2-2H3z"></path>
|
||||
</svg>
|
||||
|
|
Before Width: | Height: | Size: 395 B After Width: | Height: | Size: 412 B |
|
@ -1,13 +1,21 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg width="100%" height="100%" viewBox="0 0 214 214" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
|
||||
<svg width="100%" height="100%" viewBox="0 0 214 214" version="1.1" xmlns="http://www.w3.org/2000/svg"
|
||||
xml:space="preserve"
|
||||
style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
|
||||
<g transform="matrix(1,0,0,1,-79.4309,9.53659)">
|
||||
<path d="M250.163,76.146C250.163,52.589 231.037,33.463 207.48,33.463L122.114,33.463C98.556,33.463 79.431,52.589 79.431,76.146L79.431,161.512C79.431,185.07 98.556,204.195 122.114,204.195L207.48,204.195C231.037,204.195 250.163,185.07 250.163,161.512L250.163,76.146ZM235.163,83.646C235.163,64.228 219.398,48.463 199.98,48.463L129.614,48.463C110.196,48.463 94.431,64.228 94.431,83.646L94.431,154.012C94.431,173.43 110.196,189.195 129.614,189.195L199.98,189.195C219.398,189.195 235.163,173.43 235.163,154.012L235.163,83.646Z" style="fill:currentColor;"/>
|
||||
<path
|
||||
d="M250.163,76.146C250.163,52.589 231.037,33.463 207.48,33.463L122.114,33.463C98.556,33.463 79.431,52.589 79.431,76.146L79.431,161.512C79.431,185.07 98.556,204.195 122.114,204.195L207.48,204.195C231.037,204.195 250.163,185.07 250.163,161.512L250.163,76.146ZM235.163,83.646C235.163,64.228 219.398,48.463 199.98,48.463L129.614,48.463C110.196,48.463 94.431,64.228 94.431,83.646L94.431,154.012C94.431,173.43 110.196,189.195 129.614,189.195L199.98,189.195C219.398,189.195 235.163,173.43 235.163,154.012L235.163,83.646Z"
|
||||
style="fill:currentColor;"/>
|
||||
</g>
|
||||
<g transform="matrix(0.906286,0,0,0.906286,-20.9871,-22.3274)">
|
||||
<path d="M250.163,76.146C250.163,52.589 231.037,33.463 207.48,33.463L122.114,33.463C98.556,33.463 79.431,52.589 79.431,76.146L79.431,161.512C79.431,185.07 98.556,204.195 122.114,204.195L207.48,204.195C231.037,204.195 250.163,185.07 250.163,161.512L250.163,76.146Z" style="fill:white;"/>
|
||||
<g transform="matrix(0.906286,0,0,0.906286,-20.9871,-22.3274)">
|
||||
<path
|
||||
d="M250.163,76.146C250.163,52.589 231.037,33.463 207.48,33.463L122.114,33.463C98.556,33.463 79.431,52.589 79.431,76.146L79.431,161.512C79.431,185.07 98.556,204.195 122.114,204.195L207.48,204.195C231.037,204.195 250.163,185.07 250.163,161.512L250.163,76.146Z"
|
||||
style="fill:white;"/>
|
||||
</g>
|
||||
<g transform="matrix(0.333526,0,0,0.333526,43.0167,0)">
|
||||
<path d="M511.8,130.7C511.8,115 510.5,99.3 506.7,84C500,56 484,34.7 460.2,19C448,11 434.5,6.1 420.1,3.5C409.1,1.5 397.9,0.6 386.8,0.3L384.1,0L127.6,0C124.4,0.3 121.1,0.4 117.9,0.6C102,1.5 86.2,3.2 71.1,9.2C42.7,20.4 22.1,40.1 10.1,68.4C5.9,78 3.8,88.2 2.3,98.5C1.1,106.8 0.4,115.3 0.1,123.7L-0.1,125.7L-0.1,386.4C0.1,389.4 0.2,392.4 0.4,395.4C1.5,412.8 3.7,430.1 11.1,446.1C24.9,476.4 48.2,496.3 80.1,505.8C89,508.6 98.3,509.8 107.7,510.6C119.5,511.8 131.4,511.9 143.2,511.9L378.5,511.9C389.7,511.9 400.8,511.2 412,509.7C429.6,507.5 446.1,502.3 461,492.5C478.9,480.7 492.4,465 501.1,445.4C505.1,436.4 507.3,426.8 509,417.2C511.4,402.8 511.9,388.2 511.9,373.6C511.8,292.6 511.9,211.6 511.8,130.6L511.8,130.7ZM374.8,93.4L374.8,337.6C374.8,346.5 373.6,355.3 369.6,363.3C363.4,375.9 353.4,383.8 340,387.6C332.6,389.8 324.9,390.9 317.2,391.3C297,392.3 279.4,378.6 275.8,358.6C272.7,342.1 280.6,323.9 298,315.4C304.8,312.1 312.2,310.1 319.7,308.6C327.8,306.9 335.9,305.3 343.9,303.4C349.8,302.1 353.6,298.5 354.8,292.4L355.2,288.3L355.2,172.1L354.6,168.2C353.8,165 351.4,163 348.1,163.2C344.7,163.4 341.4,163.9 338,164.6C321.7,167.8 305.5,171 289.3,174.3L210.4,190.2L209.3,190.5C203.4,192.2 201.3,194.8 201,201L201,203.7C200.9,259.2 201,314.7 200.9,370.2C200.9,379.2 199.9,388 196.3,396.4C190.4,410.1 179.9,418.7 165.7,422.7C158.2,424.9 150.5,426.1 142.7,426.4C122.3,427.2 105.3,413.6 101.8,393.5C98.8,376.2 106.7,357.5 126.4,349.2C134.1,346 142,344.3 150.1,342.6C156.2,341.4 162.4,340.1 168.4,338.9C176.6,337.2 180.8,332 181.2,323.7L181.2,131C181.2,128.3 181.5,125.7 182.1,123.1C183.6,117 187.9,113.5 193.8,112.1C199.2,110.7 204.8,109.7 210.3,108.5C226,105.3 241.5,102.2 257.2,99.1L305.6,89.3C319.9,86.5 334.2,83.6 348.5,80.7C353.2,79.8 357.9,78.8 362.7,78.4C369.3,77.8 373.9,82 374.5,88.7C374.7,90.3 374.8,91.9 374.8,93.4Z" style="fill:currentColor;fill-rule:nonzero;"/>
|
||||
<g transform="matrix(0.333526,0,0,0.333526,43.0167,0)">
|
||||
<path
|
||||
d="M511.8,130.7C511.8,115 510.5,99.3 506.7,84C500,56 484,34.7 460.2,19C448,11 434.5,6.1 420.1,3.5C409.1,1.5 397.9,0.6 386.8,0.3L384.1,0L127.6,0C124.4,0.3 121.1,0.4 117.9,0.6C102,1.5 86.2,3.2 71.1,9.2C42.7,20.4 22.1,40.1 10.1,68.4C5.9,78 3.8,88.2 2.3,98.5C1.1,106.8 0.4,115.3 0.1,123.7L-0.1,125.7L-0.1,386.4C0.1,389.4 0.2,392.4 0.4,395.4C1.5,412.8 3.7,430.1 11.1,446.1C24.9,476.4 48.2,496.3 80.1,505.8C89,508.6 98.3,509.8 107.7,510.6C119.5,511.8 131.4,511.9 143.2,511.9L378.5,511.9C389.7,511.9 400.8,511.2 412,509.7C429.6,507.5 446.1,502.3 461,492.5C478.9,480.7 492.4,465 501.1,445.4C505.1,436.4 507.3,426.8 509,417.2C511.4,402.8 511.9,388.2 511.9,373.6C511.8,292.6 511.9,211.6 511.8,130.6L511.8,130.7ZM374.8,93.4L374.8,337.6C374.8,346.5 373.6,355.3 369.6,363.3C363.4,375.9 353.4,383.8 340,387.6C332.6,389.8 324.9,390.9 317.2,391.3C297,392.3 279.4,378.6 275.8,358.6C272.7,342.1 280.6,323.9 298,315.4C304.8,312.1 312.2,310.1 319.7,308.6C327.8,306.9 335.9,305.3 343.9,303.4C349.8,302.1 353.6,298.5 354.8,292.4L355.2,288.3L355.2,172.1L354.6,168.2C353.8,165 351.4,163 348.1,163.2C344.7,163.4 341.4,163.9 338,164.6C321.7,167.8 305.5,171 289.3,174.3L210.4,190.2L209.3,190.5C203.4,192.2 201.3,194.8 201,201L201,203.7C200.9,259.2 201,314.7 200.9,370.2C200.9,379.2 199.9,388 196.3,396.4C190.4,410.1 179.9,418.7 165.7,422.7C158.2,424.9 150.5,426.1 142.7,426.4C122.3,427.2 105.3,413.6 101.8,393.5C98.8,376.2 106.7,357.5 126.4,349.2C134.1,346 142,344.3 150.1,342.6C156.2,341.4 162.4,340.1 168.4,338.9C176.6,337.2 180.8,332 181.2,323.7L181.2,131C181.2,128.3 181.5,125.7 182.1,123.1C183.6,117 187.9,113.5 193.8,112.1C199.2,110.7 204.8,109.7 210.3,108.5C226,105.3 241.5,102.2 257.2,99.1L305.6,89.3C319.9,86.5 334.2,83.6 348.5,80.7C353.2,79.8 357.9,78.8 362.7,78.4C369.3,77.8 373.9,82 374.5,88.7C374.7,90.3 374.8,91.9 374.8,93.4Z"
|
||||
style="fill:currentColor;fill-rule:nonzero;"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
|
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 3.3 KiB |
|
@ -1 +1,6 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-info"><circle cx="12" cy="12" r="10"></circle><line x1="12" y1="16" x2="12" y2="12"></line><line x1="12" y1="8" x2="12.01" y2="8"></line></svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor"
|
||||
stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-info">
|
||||
<circle cx="12" cy="12" r="10"></circle>
|
||||
<line x1="12" y1="16" x2="12" y2="12"></line>
|
||||
<line x1="12" y1="8" x2="12.01" y2="8"></line>
|
||||
</svg>
|
||||
|
|
Before Width: | Height: | Size: 347 B After Width: | Height: | Size: 363 B |
|
@ -1 +1,5 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!-- Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) --><path fill="white" d="M80 368H16a16 16 0 0 0-16 16v64a16 16 0 0 0 16 16h64a16 16 0 0 0 16-16v-64a16 16 0 0 0-16-16zm0-320H16A16 16 0 0 0 0 64v64a16 16 0 0 0 16 16h64a16 16 0 0 0 16-16V64a16 16 0 0 0-16-16zm0 160H16a16 16 0 0 0-16 16v64a16 16 0 0 0 16 16h64a16 16 0 0 0 16-16v-64a16 16 0 0 0-16-16zm416 176H176a16 16 0 0 0-16 16v32a16 16 0 0 0 16 16h320a16 16 0 0 0 16-16v-32a16 16 0 0 0-16-16zm0-320H176a16 16 0 0 0-16 16v32a16 16 0 0 0 16 16h320a16 16 0 0 0 16-16V80a16 16 0 0 0-16-16zm0 160H176a16 16 0 0 0-16 16v32a16 16 0 0 0 16 16h320a16 16 0 0 0 16-16v-32a16 16 0 0 0-16-16z"/></svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 512 512"><!-- Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) -->
|
||||
<path fill="white"
|
||||
d="M80 368H16a16 16 0 0 0-16 16v64a16 16 0 0 0 16 16h64a16 16 0 0 0 16-16v-64a16 16 0 0 0-16-16zm0-320H16A16 16 0 0 0 0 64v64a16 16 0 0 0 16 16h64a16 16 0 0 0 16-16V64a16 16 0 0 0-16-16zm0 160H16a16 16 0 0 0-16 16v64a16 16 0 0 0 16 16h64a16 16 0 0 0 16-16v-64a16 16 0 0 0-16-16zm416 176H176a16 16 0 0 0-16 16v32a16 16 0 0 0 16 16h320a16 16 0 0 0 16-16v-32a16 16 0 0 0-16-16zm0-320H176a16 16 0 0 0-16 16v32a16 16 0 0 0 16 16h320a16 16 0 0 0 16-16V80a16 16 0 0 0-16-16zm0 160H176a16 16 0 0 0-16 16v32a16 16 0 0 0 16 16h320a16 16 0 0 0 16-16v-32a16 16 0 0 0-16-16z"/>
|
||||
</svg>
|
||||
|
|
Before Width: | Height: | Size: 831 B After Width: | Height: | Size: 849 B |
|
@ -1 +1,6 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-log-out"><path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"></path><polyline points="16 17 21 12 16 7"></polyline><line x1="21" y1="12" x2="9" y2="12"></line></svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor"
|
||||
stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-log-out">
|
||||
<path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"></path>
|
||||
<polyline points="16 17 21 12 16 7"></polyline>
|
||||
<line x1="21" y1="12" x2="9" y2="12"></line>
|
||||
</svg>
|
||||
|
|
Before Width: | Height: | Size: 367 B After Width: | Height: | Size: 383 B |
|
@ -1,3 +1,4 @@
|
|||
<svg fill="white" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 27 27" class="glyph">
|
||||
<path d="M8.89547677 13.5330073c0-1.1057457-.97371638-2.0959657-2.09596577-2.0959657-1.13875305 0-2.0794621.99022-2.0794621 2.0959657 0 1.1222494.94070905 2.0794621 2.0794621 2.0794621 1.12224939 0 2.09596577-.9572127 2.09596577-2.0794621zm6.68398533 0c0-1.1057457-.9572127-2.0959657-2.0794621-2.0959657-1.1222494 0-2.0794621.99022-2.0794621 2.0959657 0 1.1222494.9572127 2.0794621 2.0794621 2.0794621 1.1222494 0 2.0794621-.9572127 2.0794621-2.0794621zm6.700489 0c0-1.1057457-.940709-2.0959657-2.0794621-2.0959657-1.1222494 0-2.0959658.99022-2.0959658 2.0959657 0 1.1222494.9737164 2.0794621 2.0959658 2.0794621 1.1387531 0 2.0794621-.9572127 2.0794621-2.0794621z"></path>
|
||||
</svg>
|
||||
<path
|
||||
d="M8.89547677 13.5330073c0-1.1057457-.97371638-2.0959657-2.09596577-2.0959657-1.13875305 0-2.0794621.99022-2.0794621 2.0959657 0 1.1222494.94070905 2.0794621 2.0794621 2.0794621 1.12224939 0 2.09596577-.9572127 2.09596577-2.0794621zm6.68398533 0c0-1.1057457-.9572127-2.0959657-2.0794621-2.0959657-1.1222494 0-2.0794621.99022-2.0794621 2.0959657 0 1.1222494.9572127 2.0794621 2.0794621 2.0794621 1.1222494 0 2.0794621-.9572127 2.0794621-2.0794621zm6.700489 0c0-1.1057457-.940709-2.0959657-2.0794621-2.0959657-1.1222494 0-2.0959658.99022-2.0959658 2.0959657 0 1.1222494.9737164 2.0794621 2.0959658 2.0794621 1.1387531 0 2.0794621-.9572127 2.0794621-2.0794621z"></path>
|
||||
</svg>
|
||||
|
|
Before Width: | Height: | Size: 772 B After Width: | Height: | Size: 775 B |
|
@ -1,7 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 24.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
fill="white" viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" x="0px"
|
||||
y="0px"
|
||||
fill="white" viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
|
||||
<path id="XMLID_11_" d="M418.5,139.4H232.4v139.8h186.1V139.4z M464.8,46.7H46.3C20.5,46.7,0,68.1,0,93.1v325.9
|
||||
c0,25.8,21.4,46.3,46.3,46.3h419.4c25.8,0,46.3-20.5,46.3-46.3V93.1C512,67.2,490.6,46.7,464.8,46.7z M464.8,418.9H46.3V92.2h419.4
|
||||
v326.8H464.8z"/>
|
||||
|
|
Before Width: | Height: | Size: 627 B After Width: | Height: | Size: 592 B |
|
@ -1,3 +1,4 @@
|
|||
<svg fill="white" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 27 27" class="glyph">
|
||||
<path d="M11.3545232,18.4180929 L18.4676039,14.242665 C19.0452323,13.9290954 19.0122249,13.1204156 18.4676039,12.806846 L11.3545232,8.63141809 C10.7603912,8.26833741 9.98471883,8.54889976 9.98471883,9.19254279 L9.98471883,17.8404645 C9.98471883,18.5006112 10.7108802,18.7976773 11.3545232,18.4180929 Z"></path>
|
||||
</svg>
|
||||
<path
|
||||
d="M11.3545232,18.4180929 L18.4676039,14.242665 C19.0452323,13.9290954 19.0122249,13.1204156 18.4676039,12.806846 L11.3545232,8.63141809 C10.7603912,8.26833741 9.98471883,8.54889976 9.98471883,9.19254279 L9.98471883,17.8404645 C9.98471883,18.5006112 10.7108802,18.7976773 11.3545232,18.4180929 Z"></path>
|
||||
</svg>
|
||||
|
|
Before Width: | Height: | Size: 409 B After Width: | Height: | Size: 412 B |