Merge remote-tracking branch 'swiftfork/main'

# Conflicts:
#	src/renderer/views/components/add-to-playlist.ejs
This commit is contained in:
Swiftzerr 2022-01-29 21:57:17 -05:00
commit bde33c4324
175 changed files with 35181 additions and 23240 deletions

View file

@ -0,0 +1,37 @@
<script type="text/x-template" id="artwork-material">
<div class="artworkMaterial">
<img :src="src" 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>

View file

@ -0,0 +1,82 @@
<script type="text/x-template" id="add-to-playlist">
<template>
<div class="modal-fullscreen modal-generic" @click.self="app.resetState()" @contextmenu.self="app.resetState()">
<div class="modal-window">
<div class="modal-header">
<div class="modal-title">{{app.getLz('action.addToLibrary')}}</div>
<button class="close-btn" @click="app.resetState()"></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>
</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>
</template>
</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
}
}
},
}
});
</script>

View file

@ -0,0 +1,390 @@
<script type="text/x-template" id="eq-view">
<div class="modal-fullscreen equalizer-panel">
<div class="modal-window" >
<div class="modal-header">
<div class="modal-title">{{$root.getLz('term.equalizer')}}</div>
<button class="close-btn" @click="close()"></button>
<div class="md-option-segment md-option-segment_auto">
<select class="md-select" style="width:220px;text-align:center;margin-right:16.75em" v-model="$root.cfg.audio.equalizer.preset" v-on:change="changePreset($root.cfg.audio.equalizer.preset)">
<optgroup label="User Presets">
<option v-for="preset in $root.cfg.audio.equalizer.presets" :value="preset.preset">{{preset.name}}</option>
</optgroup>
<optgroup label="Default Presets">
<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">
<input tabindex="0" type="number" class="eq-freq" orient="vertical" min="-12" max="12" step="0.1" v-model="$root.cfg.audio.equalizer.preamp" @change="changePreamp()">
<input tabindex="0" type="range" class="eq-slider mini" orient="vertical" min="-12" max="12" step="0.1" v-model="$root.cfg.audio.equalizer.preamp" @change="changePreamp()">
Preamp
</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.preamp = 0
this.mix = 1
this.userGenerated = true
},
defaultPresets: [{
'preset': 'warmth',
'name': 'Warmth',
'frequencies': [32, 75, 125, 197, 500, 1000, 2000, 3040, 8000, 16000],
'gain': [0, 2.1, 0, 0.8, 0, 0, 0, -1.5, 0, 0],
'Q': [1, 0.7, 1, 1.5, 1, 1, 1, 2, 1, 1],
'preamp': 0,
'mix': 1,
'userGenerated': false
}, {
'preset': 'boostBrightness',
'name': 'Boost Brightness',
'frequencies': [32, 63, 125, 250, 466, 1000, 2000, 4000, 8000, 20000],
'gain': [0, 0, 0, 0, -2, 0, 0, 0, 0, 10],
'Q': [1, 1, 1, 1, 0.6, 1, 1, 1, 1, 0.1],
'preamp': 0,
'mix': 1,
'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],
'preamp': 0,
'mix': 1,
'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],
'preamp': 0,
'mix': 1,
'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],
'preamp': 0,
'mix': 1,
'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],
'preamp': 0,
'mix': 1,
'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],
'preamp': 0,
'mix': 1,
'userGenerated': false
},
{
'preset': 'bassBoostCrystal',
'name': 'Crystal Bass Boost',
'frequencies': [45.53,88.06,116.18,161.3,247.05,295.6,365.79,495.13,716.85,960.76],
'gain': [-0.36,4.07,-1.3,1.92,0.77,-0.53,-1.33,0.44,0.46,-0.5],
'Q': [1.768,0.625,5,8.409,10,16.82,5.946,7.071,20,10],
'preamp': -2,
'mix': 1,
'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],
'preamp': 0,
'mix': 1,
'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],
'preamp': 0,
'mix': 1,
'userGenerated': false
}]
}
},
props: ["src", "url"],
mounted() {
},
methods: {
presetOptions(event) {
let menu = {
items: {
"new": {
"icon": "./assets/feather/plus.svg",
name: "New Preset...",
action: () => {
this.addPreset()
}
},
"delete": {
"icon": "./assets/feather/x-circle.svg",
name: "Delete Preset",
action: () => {
this.deletePreset()
}
},
"import": {
"icon": "./assets/feather/share.svg",
"name": app.getLz('action.import'),
"action": function () {
notyf.error("Not implemented yet")
}
},
"export": {
"icon": "./assets/feather/share.svg",
"name": app.getLz('action.export'),
"action": function () {
notyf.error("Not implemented yet")
}
},
}
}
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
bootbox.confirm("Are you sure you want to delete this preset?", (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("Removed preset")
}
})
},
close() {
app.resetState()
},
changePreamp() {
CiderAudio.audioNodes.preampNode.gain.value = app.cfg.audio.equalizer.preamp;
},
changeMix() {
for (var i = 0; i < 10; i++) {
CiderAudio.audioNodes.audioBands[i].gain.value = app.cfg.audio.equalizer.gain[i] * app.cfg.audio.equalizer.mix
}
},
changeGain(i) {
CiderAudio.audioNodes.audioBands[i].gain.value = app.cfg.audio.equalizer.gain[i] * app.cfg.audio.equalizer.mix
},
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],
'preamp': 0,
'mix': 1,
})
if (app.cfg.audio.equalizer.userGenerated) {
this.saveSelectedPreset()
}
},
addPreset() {
let self = this
bootbox.prompt("New EQ Preset 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.preamp = eqSettings.preamp
newPreset.mix = eqSettings.mix
app.cfg.audio.equalizer.presets.push(newPreset)
notyf.success("Added Preset")
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.preamp = app.cfg.audio.equalizer.preamp
preset.mix = app.cfg.audio.equalizer.mix
notyf.success("Saved Preset")
},
applyPreset(preset) {
Object.assign(this.$root.cfg.audio.equalizer, preset)
this.changePreamp()
for (var i = 0; i < 10; i++) {
this.changeGain(i)
this.changeFreq(i)
this.changeQ(i)
}
},
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>

View file

@ -26,7 +26,7 @@
{{ app.mk.nowPlayingItem["attributes"]["name"] }}
</div>
<div
style="display: inline-block; -webkit-box-orient: horizontal; white-space: nowrap; margin-top: 0.25vh;">
style="display: inline-block; -webkit-box-orient: horizontal; white-space: nowrap; margin-top: 0.25vh; overflow: hidden;">
<div class="item-navigate song-artist" style="display: inline-block;"
@click="app.getNowPlayingItemDetailed(`artist`)">
{{ app.mk.nowPlayingItem["attributes"]["artistName"] }}
@ -71,17 +71,17 @@
<div class="app-chrome-item">
<button class="playback-button--small repeat" v-if="app.mk.repeatMode == 0"
@click="app.mk.repeatMode = 1"></button>
<button class="playback-button--small repeat active" @click="app.mk.repeatMode = 2"
<button class="playback-button--small repeat repeatOne" @click="app.mk.repeatMode = 2"
v-else-if="app.mk.repeatMode == 1"></button>
<button class="playback-button--small repeat repeatOne" @click="app.mk.repeatMode = 0"
<button class="playback-button--small repeat active" @click="app.mk.repeatMode = 0"
v-else-if="app.mk.repeatMode == 2"></button>
</div>
</div>
<div class="app-chrome-item volume display--large">
<div class="app-chrome-item volume-icon"></div>
<div class="input-container">
<input type="range" class="slider" @wheel="app.volumeWheel" step="0.01" min="0" max="1" v-model="app.mk.volume"
v-if="typeof app.mk.volume != 'undefined'">
<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="0.01" min="0" :max="$root.cfg.audio.maxVolume" v-model="app.mk.volume"
v-if="typeof app.mk.volume != 'undefined'" @change="app.checkMuteChange()">
</div>
</div>
</div>

View file

@ -2,28 +2,20 @@
<div v-observe-visibility="{callback: visibilityChanged}"
@click="select"
class="cd-mediaitem-list-item"
:class="{'mediaitem-selected': app.select_hasMediaItem(guid)}">
:class="{'mediaitem-selected': app.select_hasMediaItem(guid)}"
@contextmenu="contextMenu">
<template v-if="isVisible">
<div class="artwork" v-if="showArtwork == true">
<mediaitem-artwork
:url="getArtwork()"
size="50"
:type="item.type"></mediaitem-artwork>
<button class="overlay-play" @click="select"></button>
</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="subtitle text-overflow-elipsis" style="-webkit-box-orient: horizontal;">
<template v-if="item.attributes.name">
<div class="artist item-navigate text-overflow-elipsis"
@click="select">
{{ item.attributes.artistName }}
</div>
</template>
</div>
</div>
</template>
</div>
@ -62,22 +54,19 @@
return minutes + ":" + (seconds < 10 ? '0' : '') + seconds;
},
getDataType() {
if (this.item.attributes.playParams.isLibrary) {
return this.item.type
} else {
return this.item.attributes.playParams.kind
}
return this.item.type
},
async select(e) {
let u = this.item
let u1 = await app.mk.api.library.artistRelationship(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)}, u.attributes.name?? '', '');
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 = ""
@ -87,80 +76,38 @@
return u;
},
contextMenu(event) {
let self = this
let data_type = this.getDataType()
let item_id = this.item.attributes.playParams.id ?? this.item.id
let isLibrary = this.item.attributes.playParams.isLibrary ?? false
let item = self.item
item.attributes.artistName = item.attributes.name;
let useMenu = "normal"
if (app.selectedMediaItems.length <= 1) {
app.selectedMediaItems = []
app.select_selectMediaItem(item_id, data_type, this.index, this.guid, isLibrary)
app.select_selectMediaItem(this.item.id, data_type, this.index, this.guid, true)
} else {
useMenu = "multiple"
}
let menus = {
multiple: {
items: [
{
"name": "Add to Playlist...",
"action": function () {
app.promptAddToPlaylist()
}
},
{
name: `Play ${app.selectedMediaItems.length} tracks next`,
action: () => {
let itemsToPlay = {}
app.selectedMediaItems.forEach(item => {
if (!itemsToPlay[item.kind]) {
itemsToPlay[item.kind] = []
}
itemsToPlay[item.kind].push(item.id)
})
// loop through itemsToPlay
for (let kind in itemsToPlay) {
let ids = itemsToPlay[kind]
if (ids.length > 0) {
app.mk.playNext({[kind + "s"]: itemsToPlay[kind]})
}
}
console.log(itemsToPlay)
app.selectedMediaItems = []
}
},
{
name: `Play ${app.selectedMediaItems.length} tracks later`,
action: () => {
let itemsToPlay = {}
app.selectedMediaItems.forEach(item => {
if (!itemsToPlay[item.kind]) {
itemsToPlay[item.kind] = []
}
itemsToPlay[item.kind].push(item.id)
})
// loop through itemsToPlay
for (let kind in itemsToPlay) {
let ids = itemsToPlay[kind]
if (ids.length > 0) {
app.mk.playLater({[kind + "s"]: itemsToPlay[kind]})
}
}
app.selectedMediaItems = []
}
},
]
items: [] //
},
normal: {
items: [
{
"name": "Add to Playlist...",
"name": app.getLz('action.goToArtist'),
"icon": "./assets/feather/user.svg",
"action": function () {
app.promptAddToPlaylist()
app.searchAndNavigate(self.item, 'artist')
console.log(self.item)
}
},
{
"name": "Start Radio",
"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()
@ -169,31 +116,15 @@
}
},
{
"name": "Play Next",
"icon": "./assets/feather/share.svg",
"name": app.getLz('action.share'),
"action": function () {
app.mk.playNext({[self.item.attributes.playParams.kind ?? self.item.type]: self.item.attributes.playParams.id ?? self.item.id})
app.mk.queue._reindex()
app.selectedMediaItems = []
}
},
{
"name": "Play Later",
"action": function () {
app.mk.playLater({[self.item.attributes.playParams.kind ?? self.item.type]: self.item.attributes.playParams.id ?? self.item.id})
app.mk.queue._reindex()
app.selectedMediaItems = []
}
},
{
"name": "Go to Artist",
"action": function () {
app.searchAndNavigate(self.item, 'artist')
}
},
{
"name": "Go to Album",
"action": function () {
app.searchAndNavigate(self.item, 'album')
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)}
}
},
]
@ -208,7 +139,9 @@
menus.multiple.items = menus.multiple.items.concat(this.contextExt.multiple)
}
}
CiderContextMenu.Create(event, menus[useMenu])
//CiderContextMenu.Create(event, menus[useMenu]); // Depreciated Context Menu
app.showMenuPanel(menus[useMenu], event);
},
visibilityChanged: function (isVisible, entry) {
this.isVisible = isVisible

View file

@ -6,7 +6,7 @@
<h3>{{ recom.attributes.title ? recom.attributes.title.stringForDisplay : ""}}</h3>
</div>
<div class="col-auto flex-center" v-if="recom.relationships.contents.data.length >= 10">
<button class="cd-btn-seeall" @click="app.showCollection(recom.relationships.contents, recom.attributes.title ? recom.attributes.title.stringForDisplay : '', 'listen_now')" >See All</button>
<button class="cd-btn-seeall" @click="app.showCollection(recom.relationships.contents, recom.attributes.title ? recom.attributes.title.stringForDisplay : '', 'listen_now')" >{{app.getLz('term.seeAll')}}</button>
</div>
</div>
<template v-if="recom.attributes.display.kind == 'MusicCoverShelf'">

View file

@ -35,7 +35,7 @@
</template>
<template v-else>
<div class="no-lyrics">
Loading... / Lyrics not found./ Instrumental.</div>
{{app.getLz('term.noLyrics')}}</div>
</template>
</div>
</script>

View file

@ -1,10 +1,10 @@
<script type="text/x-template" id="mediaitem-artwork">
<div class="mediaitem-artwork" :class="[{'rounded': (type == 'artists')}, classes]" :key="url"
v-observe-visibility="{callback: visibilityChanged}">
<div class="mediaitem-artwork" :class="[{'rounded': (type == 'artists')}, classes]" :key="url">
<img :src="app.getMediaItemArtwork(url, size, width)"
decoding="async" loading="lazy"
decoding="async"
:style="{background: bgcolor}"
class="mediaitem-artwork--img">
<div v-if="video && isVisible && getVideoPriority()" class="animatedartwork-view-box">
<div v-if="video && getVideoPriority()" class="animatedartwork-view-box">
<animatedartwork-view :priority="getVideoPriority()" :video="video"></animatedartwork-view>
</div>
</div>
@ -22,6 +22,10 @@
type: [String, Number],
required: false
},
bgcolor: {
type: String,
default: ''
},
url: {
type: String,
default: ''
@ -88,9 +92,6 @@
width: this.size + 'px',
height: this.size + 'px'
};
},
visibilityChanged: function (isVisible, entry) {
this.isVisible = isVisible
}
}
});

View file

@ -14,17 +14,26 @@
@mouseleave="showInLibrary = false"
:class="[{'mediaitem-selected': app.select_hasMediaItem(guid)}, addClasses]">
<template v-if="isVisible">
<div class="isLibrary" :style="{opacity: (showInLibrary ? 1 : 0)}" v-if="showLibraryStatus == true">
<button @click="addToLibrary()"
v-if="!addedToLibrary">
<div class="svg-icon" :style="{'--color': 'var(--keyColor)', '--url': 'url(./assets/feather/plus.svg)'}"></div>
</button>
<button v-else style="opacity:0;">❤️</button>
<div class="isLibrary"" v-if="showLibraryStatus == true">
<div v-if="showInLibrary" :style="{display: (showInLibrary ? 'block' : 'none'), 'margin-left':'11px'}">
<button @click="addToLibrary()" v-if="!addedToLibrary">
<div class="svg-icon" :style="{'--color': 'var(--keyColor)', '--url': 'url(./assets/feather/plus.svg)'}"></div>
</button>
</div>
<div v-if="!(app.mk.isPlaying && (((app.mk.nowPlayingItem._songId ?? app.mk.nowPlayingItem.id ) == item.attributes.playParams.id) || (app.mk.nowPlayingItem.id == item.id ))) && showIndex" :style="{display: ((showIndex && !showInLibrary) ? 'block' : 'none'), 'margin-left':'11px'}">
<div>
<div>{{ (item.attributes && !showIndexPlaylist) ? (item.attributes.trackNumber ?? '') : ((index * 1 + 1 ) ?? '')}}</div>
</div>
</div>
<div v-if="app.mk.isPlaying && (((app.mk.nowPlayingItem._songId ?? app.mk.nowPlayingItem.id ) == item.attributes.playParams.id) || (app.mk.nowPlayingItem.id == item.id))" :style="{display: (showInLibrary ? 'none' : 'block')}">
<div class="loadbar-sound"></div>
</div>
</div>
<div class="artwork" v-if="showArtwork == true">
<mediaitem-artwork
:url="item.attributes.artwork ? item.attributes.artwork.url : ''"
:size="48"
:bgcolor="getBgColor()"
:type="item.type"></mediaitem-artwork>
<button class="overlay-play" @click="playTrack()"><%- include("../svg/play.svg") %></button>
</div>
@ -88,6 +97,8 @@
'show-library-status': {type: Boolean, default: true},
'show-meta-data': {type: Boolean, default: false},
'show-duration': {type: Boolean, default: true},
'showIndex': {type: Boolean, required: false},
'showIndexPlaylist': {type: Boolean, required: false},
'contextExt': {type: Object, required: false},
'class-list': {type: String, required: false, default: ""},
},
@ -99,6 +110,10 @@
this.getClasses()
},
methods: {
getBgColor() {
let color = `#${(this.item.attributes.artwork != null && this.item.attributes.artwork.bgColor != null) ? (this.item.attributes.artwork.bgColor) : ``}`
return color
},
async checkLibrary() {
if(this.addedToLibrary) {return this.addedToLibrary}
if(this.item.type.includes("library-playlists") || this.item.type.includes("station")) {
@ -223,14 +238,14 @@
multiple: {
items: [
{
"name": "Add to Playlist...",
"name": app.getLz('action.addToPlaylist'),
"icon": "./assets/feather/plus.svg",
"action": function () {
app.promptAddToPlaylist()
}
},
{
name: `Play ${app.selectedMediaItems.length} tracks next`,
name: app.getLz('action.playTracksNext').replace("${app.selectedMediaItems.length}", app.selectedMediaItems.length),
"icon": "./assets/arrow-bend-up.svg",
action: () => {
let itemsToPlay = {}
@ -252,7 +267,7 @@
}
},
{
name: `Play ${app.selectedMediaItems.length} tracks later`,
name: app.getLz('action.playTracksLater').replace("${app.selectedMediaItems.length}", app.selectedMediaItems.length),
"icon": "./assets/arrow-bend-down.svg",
action: () => {
let itemsToPlay = {}
@ -279,7 +294,7 @@
{
"icon": "./assets/feather/heart.svg",
"id": "love",
"name": "Love",
"name": this.app.getLz('action.love'),
"hidden": false,
"disabled": true,
"action": function () {
@ -290,7 +305,7 @@
"icon": "./assets/feather/heart.svg",
"id": "unlove",
"active": true,
"name": "Unlove",
"name": this.app.getLz('action.unload'),
"hidden": true,
"action": function () {
app.unlove(self.item)
@ -299,7 +314,7 @@
{
"icon": "./assets/feather/thumbs-down.svg",
"id": "dislike",
"name": "Dislike",
"name": this.app.getLz('action.dislike'),
"hidden": false,
"disabled": true,
"action": function () {
@ -309,7 +324,7 @@
{
"icon": "./assets/feather/thumbs-down.svg",
"id": "undo_dislike",
"name": "Undo dislike",
"name": this.app.getLz('action.undoDislike'),
"active": true,
"hidden": true,
"action": function () {
@ -321,7 +336,7 @@
{
"id": "addToLibrary",
"icon": "./assets/feather/plus.svg",
"name": "Add to library",
"name": this.app.getLz('action.addToLibrary'),
"hidden": false,
"disabled": true,
"action": function () {
@ -331,7 +346,7 @@
{
"id": "removeFromLibrary",
"icon": "./assets/feather/x-circle.svg",
"name": "Remove from library",
"name": app.getLz('action.removeFromLibrary'),
"hidden": true,
"action": function () {
self.removeFromLibrary()
@ -339,13 +354,13 @@
},
{
"icon": "./assets/feather/list.svg",
"name": "Add to Playlist...",
"name": app.getLz('action.addToPlaylist'),
"action": function () {
app.promptAddToPlaylist()
}
},
{
"name": "Play Next",
"name": app.getLz('action.playNext'),
"icon": "./assets/arrow-bend-up.svg",
"action": function () {
app.mk.playNext({[self.item.attributes.playParams.kind ?? self.item.type]: self.item.attributes.playParams.id ?? self.item.id})
@ -354,7 +369,7 @@
}
},
{
"name": "Play Later",
"name": app.getLz('action.playLater'),
"icon": "./assets/arrow-bend-down.svg",
"action": function () {
app.mk.playLater({[self.item.attributes.playParams.kind ?? self.item.type]: self.item.attributes.playParams.id ?? self.item.id})
@ -364,7 +379,7 @@
},
{
"icon": "./assets/feather/radio.svg",
"name": "Start Radio",
"name": app.getLz('action.startRadio'),
"action": function () {
app.mk.setStationQueue({song: self.item.attributes.playParams.id ?? self.item.id}).then(() => {
app.mk.play()
@ -374,25 +389,25 @@
},
{
"icon": "./assets/feather/user.svg",
"name": "Go to Artist",
"name": app.getLz('action.goToArtist'),
"action": function () {
app.searchAndNavigate(self.item, 'artist')
}
},
{
"icon": "./assets/feather/disc.svg",
"name": "Go to Album",
"name": app.getLz('action.goToAlbum'),
"action": function () {
app.searchAndNavigate(self.item, 'album')
}
},
{
"icon": "./assets/feather/share.svg",
"name": "Share",
"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.length && u.length > 0)? u[0].attributes.url : u.attributes.url)})
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)}
@ -502,22 +517,21 @@
app.mk.setQueue({[truekind]: [item.attributes.playParams.id ?? item.id]}).then(function () {
app.mk.play().then(function (){
var playlistId = id
function getPlaylist(id, params, isLibrary){
function getPlaylist(id, isLibrary){
if (isLibrary){
return app.mk.api.library.playlist(id, params)
} else { return app.mk.api.playlist(id, params)}
return this.app.mk.api.v3.music(`/v1/me/library/playlists/${id}`)
} else { return this.app.mk.api.v3.music(`/v1/catalog/${app.mk.storefrontId}/playlists/${id}`)}
}
try {
getPlaylist(id, params, isLibrary).then(res => {
getPlaylist(id, isLibrary).then(res => {
//let query = res.relationships.tracks.data.map(item => new MusicKit.MediaItem(item));
//if (app.mk.shuffleMode == 1){shuffleArray(query); }
// console.log(query)
// app.mk.queue.append(query)
if (!res.relationships.tracks.next) {
if (!res.data.relationships.tracks.next) {
return
} else {
getPlaylistTracks(res.relationships.tracks.next)
getPlaylistTracks(res.data.relationships.tracks.next)
}
function getPlaylistTracks(next) {

View file

@ -1,6 +1,7 @@
<script type="text/x-template" id="mediaitem-scroller-horizontal">
<template>
<div class="cd-hmedia-scroller" :class="kind">
<slot></slot>
<mediaitem-square :kind="kind" :item="item"
v-for="item in items"></mediaitem-square>
</div>
@ -13,7 +14,7 @@
props: {
'items': {
type: Array,
required: true
required: false
},
'kind': {
type: String,

View file

@ -122,7 +122,11 @@
}
let kind = this.item.attributes.playParams.kind ?? this.item.type ?? '';
var truekind = (!kind.endsWith("s")) ? (kind + "s") : kind;
app.mk.api.library.remove({[truekind]: id})
app.mk.api.v3.music(`v1/me/library/${truekind}/${id.toString()}`,{},
{
fetchOptions: {
method: "DELETE"
}})
this.addedToLibrary = true
},
async contextMenu(event) {
@ -140,7 +144,7 @@
multiple: {
items: [
{
name: `Play ${app.selectedMediaItems.length} tracks next`,
name: this.$root.getLz('action.playTracksNext').replace("${app.selectedMediaItems.length}", app.selectedMediaItems.length),
action: () => {
let itemsToPlay = {}
app.selectedMediaItems.forEach(item => {
@ -161,7 +165,7 @@
}
},
{
name: `Play ${app.selectedMediaItems.length} tracks later`,
name: app.getLz('action.playTracksLater').replace("${app.selectedMediaItems.length}", app.selectedMediaItems.length),
action: () => {
let itemsToPlay = {}
app.selectedMediaItems.forEach(item => {
@ -225,7 +229,7 @@
}
},
{
"name": "Share",
"name": this.$root.getLz('term.share'),
"action": function () {
self.app.copyToClipboard(self.item.attributes.url)
}

View file

@ -96,6 +96,7 @@
if (this.item.type && !this.item.type.includes("library")) {
var params = {"fields[playlists]": "inLibrary", "fields[albums]": "inLibrary", "relate": "library", "extend": this.revisedRandId()}
var res = await app.mkapi(this.item.attributes.playParams.kind ?? this.item.type, this.item.attributes.playParams.isLibrary ?? false, this.item.attributes.playParams.id ?? this.item.id, params);
res = res.data.data[0]
this.addedToLibrary = (res && res.attributes && res.attributes.inLibrary) ? res.attributes.inLibrary : false
} else {
this.addedToLibrary = true
@ -105,12 +106,17 @@
var params = {"fields[playlists]": "inLibrary","fields[songs]": "inLibrary", "fields[albums]": "inLibrary", "relate": "library", "extend": this.revisedRandId()}
var id = this.item.id ?? this.item.attributes.playParams.id
var res = await app.mkapi(this.item.attributes.playParams.kind ?? this.item.type, this.item.attributes.playParams.isLibrary ?? false, this.item.attributes.playParams.id ?? this.item.id, params);
res = res.data.data[0]
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.item.type ?? '';
var truekind = (!kind.endsWith("s")) ? (kind + "s") : kind;
app.mk.api.library.remove({[truekind]: id})
app.mk.api.v3.music(`v1/me/library/${truekind}/${id.toString()}`,{},
{
fetchOptions: {
method: "DELETE"
}})
this.addedToLibrary = true
},
subtitleSearchNavigate(item) {
@ -152,7 +158,7 @@
multiple: {
items: [
{
name: `Play ${app.selectedMediaItems.length} tracks next`,
name: app.getLz('action.playTracksNext').replace("${app.selectedMediaItems.length}", app.selectedMediaItems.length),
action: () => {
let itemsToPlay = {}
app.selectedMediaItems.forEach(item => {
@ -173,7 +179,7 @@
}
},
{
name: `Play ${app.selectedMediaItems.length} tracks later`,
name: app.getLz('action.playTracksLater').replace("${app.selectedMediaItems.length}", app.selectedMediaItems.length),
action: () => {
let itemsToPlay = {}
app.selectedMediaItems.forEach(item => {

View file

@ -11,6 +11,7 @@
:video="(item.attributes != null && item.attributes.editorialVideo != null) ? (item.attributes.editorialVideo.motionDetailSquare ? item.attributes.editorialVideo.motionDetailSquare.video : (item.attributes.editorialVideo.motionSquareVideo1x1 ? item.attributes.editorialVideo.motionSquareVideo1x1.video : '')) : '' "
:size="size"
shadow="subtle"
:bgcolor="getBgColor()"
:type="item.type"></mediaitem-artwork>
</div>
<button class="menu-btn" v-if="!nomenu.includes(item.type)"
@ -75,22 +76,8 @@
},
methods: {
getBgColor() {
let color = `#${(this.item.attributes.artwork != null && this.item.attributes.artwork.bgColor != null) ? (this.item.attributes.artwork.bgColor) : `333333`}`
let c = color.substring(1); // strip #
var rgb = parseInt(c, 16); // convert rrggbb to decimal
var r = (rgb >> 16) & 0xff; // extract red
var g = (rgb >> 8) & 0xff; // extract green
var b = (rgb >> 0) & 0xff; // extract blue
var luma = 0.2126 * r + 0.7152 * g + 0.0722 * b; // per ITU-R BT.709
if (luma > 140) {
return "#aaaaaa"
}else{
return color
}
let color = `#${(this.item.attributes.artwork != null && this.item.attributes.artwork.bgColor != null) ? (this.item.attributes.artwork.bgColor) : ``}`
return color
},
getSubtitle() {
if(this.kind == 'card') {
@ -145,8 +132,8 @@
let friends = this.badges[id]
if (friends) {
friends.forEach(function (friend) {
self.app.mk.api.socialProfile(friend).then(data => {
self.itemBadges.push(data)
self.app.mk.api.v3.music(`/v1/social/${app.mk.storefrontId}/social-profiles/${friend}`).then(data => {
self.itemBadges.push(data.data.data[0])
})
})
}
@ -164,6 +151,7 @@
"extend": this.revisedRandId()
}
var res = await app.mkapi(this.item.attributes.playParams.kind ?? this.item.type, this.item.attributes.playParams.isLibrary ?? false, this.item.attributes.playParams.id ?? this.item.id, params);
res = res.data.data[0]
this.addedToLibrary = (res && res.attributes && res.attributes.inLibrary) ? res.attributes.inLibrary : false
} else {
this.addedToLibrary = true
@ -179,12 +167,17 @@
}
var id = this.item.id ?? this.item.attributes.playParams.id
var res = await app.mkapi(this.item.attributes.playParams.kind ?? this.item.type, this.item.attributes.playParams.isLibrary ?? false, this.item.attributes.playParams.id ?? this.item.id, params);
res= res.data.data[0]
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.item.type ?? '';
var truekind = (!kind.endsWith("s")) ? (kind + "s") : kind;
app.mk.api.library.remove({[truekind]: id})
app.mk.api.v3.music(`v1/me/library/${truekind}/${id.toString()}`,{},
{
fetchOptions: {
method: "DELETE"
}})
this.addedToLibrary = true
},
uuidv4() {
@ -229,6 +222,7 @@
case "music-videos":
case "uploadedVideo":
case "uploaded-videos":
case "library-music-videos":
return "mediaitem-video";
break;
}
@ -257,7 +251,7 @@
multiple: {
items: [
{
name: `Play ${app.selectedMediaItems.length} tracks next`,
name: app.getLz('action.playTracksNext').replace("${app.selectedMediaItems.length}", app.selectedMediaItems.length),
"icon": "./assets/arrow-bend-up.svg",
action: () => {
let itemsToPlay = {}
@ -279,7 +273,7 @@
}
},
{
name: `Play ${app.selectedMediaItems.length} tracks later`,
name: app.getLz('action.playTracksLater').replace("${app.selectedMediaItems.length}", app.selectedMediaItems.length),
"icon": "./assets/arrow-bend-down.svg",
action: () => {
let itemsToPlay = {}
@ -306,7 +300,7 @@
{
"icon": "./assets/feather/heart.svg",
"id": "love",
"name": "Love",
"name": app.getLz('action.love'),
"hidden": false,
"disabled": true,
"action": function () {
@ -317,7 +311,7 @@
"icon": "./assets/feather/heart.svg",
"id": "unlove",
"active": true,
"name": "Unlove",
"name": app.getLz('action.unlove'),
"hidden": true,
"action": function () {
app.unlove(self.item)
@ -326,7 +320,7 @@
{
"icon": "./assets/feather/thumbs-down.svg",
"id": "dislike",
"name": "Dislike",
"name": app.getLz('action.dislike'),
"hidden": false,
"disabled": true,
"action": function () {
@ -336,7 +330,7 @@
{
"icon": "./assets/feather/thumbs-down.svg",
"id": "undo_dislike",
"name": "Undo dislike",
"name": app.getLz('action.undoDislike'),
"active": true,
"hidden": true,
"action": function () {
@ -348,7 +342,7 @@
{
"icon": "./assets/feather/list.svg",
"id": "addToPlaylist",
"name": "Add to Playlist...",
"name": app.getLz('action.addToPlaylist'),
"action": function () {
app.promptAddToPlaylist()
}
@ -356,7 +350,7 @@
{
"id": "addToLibrary",
"icon": "./assets/feather/plus.svg",
"name": "Add to library",
"name": app.getLz('action.addToLibrary'),
"hidden": false,
"disabled": true,
"action": function () {
@ -369,7 +363,7 @@
{
"id": "removeFromLibrary",
"icon": "./assets/feather/x-circle.svg",
"name": "Remove from library",
"name": app.getLz('action.removeFromLibrary'),
"hidden": true,
"action": async function () {
console.log("remove");
@ -380,7 +374,7 @@
}
},
{
"name": "Play Next",
"name": app.getLz('action.playNext'),
"icon": "./assets/arrow-bend-up.svg",
"action": function () {
app.mk.playNext({[self.item.attributes.playParams.kind ?? self.item.type]: self.item.attributes.playParams.id ?? self.item.id})
@ -389,7 +383,7 @@
}
},
{
"name": "Play Later",
"name": app.getLz('action.playLater'),
"icon": "./assets/arrow-bend-down.svg",
"action": function () {
app.mk.playLater({[self.item.attributes.playParams.kind ?? self.item.type]: self.item.attributes.playParams.id ?? self.item.id})
@ -399,9 +393,14 @@
},
{
"icon": "./assets/feather/share.svg",
"name": "Share",
"name": app.getLz('action.share'),
"action": function () {
self.app.copyToClipboard(self.item.attributes.url)
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)}
}
}
]

View file

@ -0,0 +1,163 @@
<script type="text/x-template" id="mini-view">
<div class="mini-view" tabindex="0">
<div class="background">
</div>
<div class="player-pin" title="Pin to Top" @click="app.pinMiniPlayer()">
<span id="mini-pin">📌</span>
</div>
<div class="player-exit" title="Close" @click="app.miniPlayer(false)">
<svg fill="#323232e3" xmlns="http://www.w3.org/2000/svg" width="21" height="21" viewBox="0 0 21 21"
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"/>
</svg>
</div>
<div class="col artwork-col">
<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"] }}
</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.convertToMins(app.getSongProgress()) }}</p>
<p style="width: auto">{{ app.convertToMins(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">
<button class="playback-button--small shuffle" v-if="app.mk.shuffleMode == 0"
@click="app.mk.shuffleMode = 1"></button>
<button class="playback-button--small shuffle active" v-else
@click="app.mk.shuffleMode = 0"></button>
</div>
<div class="app-chrome-item">
<button class="playback-button previous" @click="app.prevButton()"></button>
</div>
<div class="app-chrome-item">
<button class="playback-button pause" @click="app.mk.pause()" v-if="app.mk.isPlaying"></button>
<button class="playback-button play" @click="app.mk.play()" v-else></button>
</div>
<div class="app-chrome-item">
<button class="playback-button next" @click="app.mk.skipToNextItem()"></button>
</div>
<div class="app-chrome-item">
<button class="playback-button--small repeat" v-if="app.mk.repeatMode == 0"
@click="app.mk.repeatMode = 1"></button>
<button class="playback-button--small repeat repeatOne" @click="app.mk.repeatMode = 2"
v-else-if="app.mk.repeatMode == 1"></button>
<button class="playback-button--small repeat active" @click="app.mk.repeatMode = 0"
v-else-if="app.mk.repeatMode == 2"></button>
</div>
</div>
<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="0.01" min="0" max="1" v-model="app.mk.volume"
v-if="typeof app.mk.volume != 'undefined'" @change="app.checkMuteChange()">
</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> -->
<!-- <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)
},
methods: {
onEscapeKeyUp(event) {
if (event.which === 27) {
app.miniPlayer(false);
console.log('js')
}
},
}
});
</script>

View file

@ -0,0 +1,34 @@
<script type="text/x-template" id="qrcode-modal">
<div class="modal-fullscreen spatialproperties-panel">
<div class="modal-window" >
<div class="modal-header">
<div class="modal-title">{{`Web Remote QR : ` + url }}</div>
<button class="close-btn" @click="close()"></button>
</div>
<div class="modal-content">
<img class="qrimg" :src="src"/>
</div>
</div>
</div>
</script>
<script>
Vue.component('qrcode-modal', {
template: '#qrcode-modal',
data: function () {
return {
app: this.$root,
}
},
props: ["src","url"],
mounted() {
},
methods: {
close() {
app.resetState()
},
}
});
</script>

View file

@ -48,7 +48,7 @@
let self = this
CiderContextMenu.Create(event, {
items: [{
"name": "Remove from queue",
"name": $root.getLz('action.removeFromQueue'),
"action": function () {
}

View file

@ -2,10 +2,10 @@
<div class="queue-panel">
<div class="row">
<div class="col">
<h3 class="queue-header-text">Queue</h3>
<h3 class="queue-header-text">{{app.getLz('term.queue')}}</h3>
</div>
<div class="col-auto flex-center">
<button class="autoplay" :style="{'background': app.mk.autoplayEnabled ? 'var(--keyColor)' : ''}" @click="app.mk.autoplayEnabled = !app.mk.autoplayEnabled"></button>
<button class="autoplay" :style="{'background': app.mk.autoplayEnabled ? 'var(--keyColor)' : ''}" @click="app.mk.autoplayEnabled = !app.mk.autoplayEnabled"> <img class="infinity"></button>
</div>
</div>
<div class="queue-body">
@ -33,7 +33,7 @@
</draggable>
</div>
<div class="queue-footer">
<button class="md-btn" style="width:100%;" v-if="queueItems.length > 1" @click="app.mk.clearQueue();updateQueue()">Clear All</button>
<button class="md-btn" style="width:100%;" v-if="queueItems.length > 1" @click="app.mk.clearQueue();updateQueue()">{{app.getLz('term.clearAll')}}</button>
</div>
</div>
</script>
@ -76,7 +76,7 @@
let menus = {
single: {
items: [{
"name": "Remove from queue",
"name": app.getLz('action.removeFromQueue'),
"action": function () {
self.queueItems.splice(position, 1)
app.mk.queue._queueItems = self.queueItems;
@ -84,7 +84,7 @@
}
},
{
"name": "Start Radio",
"name": app.getLz('action.startRadio'),
"action": function () {
app.mk.setStationQueue({
song: item.attributes.playParams.id ?? item.id
@ -97,7 +97,7 @@
},
multiple: {
items: [{
"name": `Remove ${self.selectedItems.length} tracks from queue`,
"name": app.getLz('action.removeTracks'),
"action": function () {
// add property to items to be removed
self.selectedItems.forEach(function (item) {

View file

@ -7,7 +7,7 @@
@dragover="dragOver"
@drop="onDrop"
:href="item.href"
@click='item.type != "library-playlist-folders" ? openPlaylist(item) : getPlaylistChildren(item)'>
@click='clickEvent()'>
<template v-if="!renaming">
<div class="sidebar-icon" v-html="icon"></div> {{ item.attributes.name }}
</template>
@ -15,7 +15,7 @@
</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" :item="item" :key="item.id"></sidebar-playlist>
<sidebar-playlist v-for="item in children" :playlist-select="playlistSelect" :item="item" :key="item.id"></sidebar-playlist>
</template>
<template v-else>
<div class="spinner"></div>
@ -31,6 +31,10 @@
item: {
type: Object,
required: true
},
playlistSelect: {
type: Function,
required: false
}
},
data: function () {
@ -50,6 +54,17 @@
}
},
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
@ -105,7 +120,7 @@
let menu = {
items: {
"moveToParent": {
name: "Move to top",
name: this.$root.getLz('action.moveToTop'),
action: () => {
let self = this
this.move(this.item, {
@ -116,7 +131,7 @@
}
},
"rename": {
name: "Rename",
name: this.$root.getLz('action.rename'),
action: () => {
this.renaming = true
setTimeout(()=>{
@ -126,13 +141,13 @@
}
},
"deleteFromPlaylist": {
name: "Delete from library",
name: this.$root.getLz('action.removeFromLibrary'),
action: () => {
this.$root.deletePlaylist(playlist_id)
}
},
"addToFavorites": {
name: "Add to favorites",
name: this.$root.getLz('action.addToFavorites'),
disabled: true,
hidden: true,
action: () => {
@ -181,7 +196,9 @@
this.children = []
this.getChildren()
this.toggleFolder()
this.$root.mk.api.library.playlistFolderChildren(item.id).then(children => {
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

View file

@ -2,15 +2,15 @@
<div class="modal-fullscreen spatialproperties-panel">
<div class="modal-window" v-if="ready">
<div class="modal-header">
<div class="modal-title">Spatial Properties</div>
<div class="modal-title">{{$root.getLz('spatial.spatialProperties')}}</div>
<button class="close-btn" @click="close()"></button>
</div>
<div class="modal-content">
<template v-if="roomEditType == 'dimensions'">
<div class="row">
<div class="col"><h3>Room Dimensions</h3></div>
<div class="col"><h3>{{$root.getLz('spatial.roomDimensions')}}</h3></div>
<div class="col-auto flex-center">
<button class="md-btn" @click="roomEditType = 'positions'">Set Positions</button>
<button class="md-btn" @click="roomEditType = 'positions'">{{$root.getLz('spatial.setPositions')}}</button>
</div>
</div>
<div class="row">
@ -18,7 +18,7 @@
<div class="row">
<div class="col-3 flex-center">
Width
{{$root.getLz('spatial.width')}}
</div>
<div class="col flex-center">
<input type="range" class="md-slider" min="0" max="100" @change="setRoom()" style="width: 100%;"
@ -32,7 +32,7 @@
<div class="row">
<div class="col-3 flex-center">
Height
{{$root.getLz('spatial.height')}}
</div>
<div class="col flex-center">
<input type="range" class="md-slider" min="0" max="100" @change="setRoom()" style="width: 100%;"
@ -46,7 +46,7 @@
<div class="row">
<div class="col-3 flex-center">
Depth
{{$root.getLz('spatial.depth')}}
</div>
<div class="col flex-center">
<input type="range" class="md-slider" min="0" max="100" @change="setRoom()" style="width: 100%;"
@ -58,7 +58,7 @@
</div>
</div>
<label v-if="!app.cfg.audio.normalization">
Gain
{{$root.getLz('spatial.gain')}}
<input type="number" min="0" @change="setRoom()" style="width: 100%;"
v-model="app.cfg.audio.spatial_properties.gain" step="0.1"/>
</label>
@ -73,9 +73,9 @@
</template>
<template v-if="roomEditType == 'positions'">
<div class="row">
<div class="col"><h3>Room Positions</h3></div>
<div class="col"><h3>{{$root.getLz('spatial.roomPositions')}}</h3></div>
<div class="col-auto flex-center">
<button class="md-btn" @click="roomEditType = 'dimensions'">Set Dimensions</button>
<button class="md-btn" @click="roomEditType = 'dimensions'">{{$root.getLz('spatial.setDimensions')}}</button>
</div>
</div>
<div class="row">
@ -83,7 +83,7 @@
<div class="row">
<div class="col-3 flex-center">
X (Listener)
X ({{$root.getLz('spatial.listener')}})
</div>
<div class="col flex-center">
<input type="range" class="md-slider" min="0" max="100" @change="setRoom()" style="width: 100%;"
@ -97,7 +97,7 @@
<div class="row">
<div class="col-3 flex-center">
Y (Listener)
Y ({{$root.getLz('spatial.listener')}})
</div>
<div class="col flex-center">
<input type="range" class="md-slider" min="0" max="100" @change="setRoom()" style="width: 100%;"
@ -111,7 +111,7 @@
<div class="row">
<div class="col-3 flex-center">
Z (Listener)
Z ({{$root.getLz('spatial.listener')}})
</div>
<div class="col flex-center">
<input type="range" class="md-slider" min="0" max="100" @change="setRoom()" style="width: 100%;"
@ -125,7 +125,7 @@
<div class="row">
<div class="col-3 flex-center">
X (Audio Source)
X ({{$root.getLz('spatial.audioSource')}})
</div>
<div class="col flex-center">
<input type="range" class="md-slider" min="0" max="100" @change="setRoom()" style="width: 100%;"
@ -139,7 +139,7 @@
<div class="row">
<div class="col-3 flex-center">
Y (Audio Source)
Y ({{$root.getLz('spatial.audioSource')}})
</div>
<div class="col flex-center">
<input type="range" class="md-slider" min="0" max="100" @change="setRoom()" style="width: 100%;"
@ -153,7 +153,7 @@
<div class="row">
<div class="col-3 flex-center">
Z (Audio Source)
Z ({{$root.getLz('spatial.audioSource')}})
</div>
<div class="col flex-center">
<input type="range" class="md-slider" min="0" max="100" @change="setRoom()" style="width: 100%;"
@ -179,13 +179,13 @@
</template>
<div class="row">
<div class="col"><h3>Room Materials</h3></div>
<div class="col"><h3>{{$root.getLz('spatial.roomMaterials')}}</h3></div>
</div>
<div class="row">
<div class="col"></div>
<div class="col flex-center">
<label>
Up
{{$root.getLz('spatial.up')}}
<select class="md-select" @change="setRoom()"
v-model="room_materials.up">
<option v-for="prop in roomProps" :value="prop">{{ prop }}</option>
@ -197,7 +197,7 @@
<div class="row">
<div class="col flex-center">
<label>
Left
{{$root.getLz('spatial.left')}}
<select class="md-select" @change="setRoom()"
v-model="room_materials.left">
<option v-for="prop in roomProps" :value="prop">{{ prop }}</option>
@ -206,14 +206,14 @@
</div>
<div class="col flex-center">
<label>
Front
{{$root.getLz('spatial.front')}}
<select class="md-select" @change="setRoom()"
v-model="room_materials.front">
<option v-for="prop in roomProps" :value="prop">{{ prop }}</option>
</select>
</label>
<label>
Back
{{$root.getLz('spatial.back')}}
<select class="md-select" @change="setRoom()"
v-model="room_materials.back">
<option v-for="prop in roomProps" :value="prop">{{ prop }}</option>
@ -222,7 +222,7 @@
</div>
<div class="col flex-center">
<label>
Right
{{$root.getLz('spatial.right')}}
<select class="md-select" @change="setRoom()"
v-model="room_materials.right">
<option v-for="prop in roomProps" :value="prop">{{ prop }}</option>
@ -234,7 +234,7 @@
<div class="col"></div>
<div class="col flex-center">
<label>
Down
{{$root.getLz('spatial.down')}}
<select class="md-select" @change="setRoom()"
v-model="room_materials.down">
<option v-for="prop in roomProps" :value="prop">{{ prop }}</option>