Merge remote-tracking branch 'swiftfork/main'
# Conflicts: # src/renderer/views/components/add-to-playlist.ejs
5
src/renderer/.jsbeautifyrc
Normal file
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"js": {
|
||||
"beautify.ignore": "src/renderer/index.js"
|
||||
}
|
||||
}
|
4
src/renderer/AppHeader.svg
Normal file
After Width: | Height: | Size: 14 KiB |
|
@ -27,6 +27,7 @@
|
|||
|
||||
.md-option-segment.md-option-segment_auto {
|
||||
width: auto;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.md-option-container .md-option-line:not(:last-child) {
|
||||
|
|
1
src/renderer/assets/feather/mic.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-mic"><path d="M12 1a3 3 0 0 0-3 3v8a3 3 0 0 0 6 0V4a3 3 0 0 0-3-3z"></path><path d="M19 10v2a7 7 0 0 1-14 0v-2"></path><line x1="12" y1="19" x2="12" y2="23"></line><line x1="8" y1="23" x2="16" y2="23"></line></svg>
|
After Width: | Height: | Size: 418 B |
1
src/renderer/assets/feather/plus-circle-white.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-plus-circle"><circle cx="12" cy="12" r="10"></circle><line x1="12" y1="8" x2="12" y2="16"></line><line x1="8" y1="12" x2="16" y2="12"></line></svg>
|
After Width: | Height: | Size: 344 B |
1
src/renderer/assets/feather/video.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-video"><polygon points="23 7 16 12 23 17 23 7"></polygon><rect x="1" y="5" width="15" height="14" rx="2" ry="2"></rect></svg>
|
After Width: | Height: | Size: 329 B |
1
src/renderer/assets/feather/volume-2.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" class="feather feather-volume-2"><polygon points="11 5 6 9 2 9 2 15 6 15 11 19 11 5"></polygon><path d="M19.07 4.93a10 10 0 0 1 0 14.14M15.54 8.46a5 5 0 0 1 0 7.07"></path></svg>
|
After Width: | Height: | Size: 354 B |
1
src/renderer/assets/feather/volume.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" class="feather feather-volume"><polygon points="11 5 6 9 2 9 2 15 6 15 11 19 11 5"></polygon></svg>
|
After Width: | Height: | Size: 275 B |
1
src/renderer/assets/feather/x-circle-white.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-x-circle"><circle cx="12" cy="12" r="10"></circle><line x1="15" y1="9" x2="9" y2="15"></line><line x1="9" y1="9" x2="15" y2="15"></line></svg>
|
After Width: | Height: | Size: 339 B |
BIN
src/renderer/assets/feather/x-circlePng.png
Normal file
After Width: | Height: | Size: 4.5 KiB |
1
src/renderer/assets/infinity.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 512" fill="white"><!-- 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="M471.1 96C405 96 353.3 137.3 320 174.6 286.7 137.3 235 96 168.9 96 75.8 96 0 167.8 0 256s75.8 160 168.9 160c66.1 0 117.8-41.3 151.1-78.6 33.3 37.3 85 78.6 151.1 78.6 93.1 0 168.9-71.8 168.9-160S564.2 96 471.1 96zM168.9 320c-40.2 0-72.9-28.7-72.9-64s32.7-64 72.9-64c38.2 0 73.4 36.1 94 64-20.4 27.6-55.9 64-94 64zm302.2 0c-38.2 0-73.4-36.1-94-64 20.4-27.6 55.9-64 94-64 40.2 0 72.9 28.7 72.9 64s-32.7 64-72.9 64z"/></svg>
|
After Width: | Height: | Size: 684 B |
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 12 KiB |
8
src/renderer/assets/pip.svg
Normal file
|
@ -0,0 +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">
|
||||
<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"/>
|
||||
</svg>
|
After Width: | Height: | Size: 627 B |
33
src/renderer/assets/repeatOne.svg
Normal file
|
@ -0,0 +1,33 @@
|
|||
<svg width="512" height="512" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" fill="white" version="1.1">
|
||||
|
||||
<g>
|
||||
<title>Layer 1</title>
|
||||
<g id="svg_1">
|
||||
<g id="svg_2">
|
||||
<g id="svg_3">
|
||||
<path id="svg_4" d="m482.197,374.266l-78.717,-45.448c-15.89,-9.174 -35.829,2.308 -35.829,20.686l0,27.587l-216.593,0c-63.597,-0.001 -115.337,-51.74 -115.337,-115.338c0,-9.864 -7.997,-17.86 -17.86,-17.86c-9.864,0 -17.86,7.997 -17.86,17.86c0,83.294 67.765,151.058 151.058,151.058l216.591,0l0,27.587c0,18.347 19.913,29.876 35.829,20.686l78.717,-45.447c15.89,-9.172 15.917,-32.181 0.001,-41.371z"/>
|
||||
<path id="svg_5" d="m360.942,99.189l-216.593,0l0,-27.588c0,-18.347 -19.913,-29.876 -35.829,-20.686l-78.717,45.447c-15.889,9.173 -15.917,32.182 0,41.372l78.717,45.448c15.89,9.174 35.829,-2.309 35.829,-20.686l0,-27.587l216.593,0c63.598,0 115.337,51.739 115.337,115.337c0,9.864 7.997,17.86 17.86,17.86c9.864,0 17.86,-7.997 17.86,-17.86c0.001,-83.293 -67.764,-151.057 -151.057,-151.057z"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g id="svg_6"/>
|
||||
<g id="svg_7"/>
|
||||
<g id="svg_8"/>
|
||||
<g id="svg_9"/>
|
||||
<g id="svg_10"/>
|
||||
<g id="svg_11"/>
|
||||
<g id="svg_12"/>
|
||||
<g id="svg_13"/>
|
||||
<g id="svg_14"/>
|
||||
<g id="svg_15"/>
|
||||
<g id="svg_16"/>
|
||||
<g id="svg_17"/>
|
||||
<g id="svg_18"/>
|
||||
<g id="svg_19"/>
|
||||
<g id="svg_20"/>
|
||||
<g id="svg_24">
|
||||
<path id="svg_21" d="m118,511.5c-65.19337,0 -118,-52.80663 -118,-118c0,-65.19337 52.80663,-118 118,-118c65.19337,0 118,52.80663 118,118c0,65.19337 -52.80663,118 -118,118z" opacity="undefined" stroke-width="0" stroke="#000" fill="#fff"/>
|
||||
<text font-weight="bold" xml:space="preserve" text-anchor="start" font-family="Noto Sans JP" font-size="250" id="svg_23" y="470" x="54.64063" stroke-width="0" stroke="#000" fill="#000000">1</text>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 1.7 KiB |
|
@ -1 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 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="M215.03 72.04L126.06 161H24c-13.26 0-24 10.74-24 24v144c0 13.25 10.74 24 24 24h102.06l88.97 88.95c15.03 15.03 40.97 4.47 40.97-16.97V89.02c0-21.47-25.96-31.98-40.97-16.98zm123.2 108.08c-11.58-6.33-26.19-2.16-32.61 9.45-6.39 11.61-2.16 26.2 9.45 32.61C327.98 229.28 336 242.62 336 257c0 14.38-8.02 27.72-20.92 34.81-11.61 6.41-15.84 21-9.45 32.61 6.43 11.66 21.05 15.8 32.61 9.45 28.23-15.55 45.77-45 45.77-76.88s-17.54-61.32-45.78-76.87z"/></svg>
|
Before Width: | Height: | Size: 710 B |
|
@ -1 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 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="M215.03 71.05L126.06 160H24c-13.26 0-24 10.74-24 24v144c0 13.25 10.74 24 24 24h102.06l88.97 88.95c15.03 15.03 40.97 4.47 40.97-16.97V88.02c0-21.46-25.96-31.98-40.97-16.97zm233.32-51.08c-11.17-7.33-26.18-4.24-33.51 6.95-7.34 11.17-4.22 26.18 6.95 33.51 66.27 43.49 105.82 116.6 105.82 195.58 0 78.98-39.55 152.09-105.82 195.58-11.17 7.32-14.29 22.34-6.95 33.5 7.04 10.71 21.93 14.56 33.51 6.95C528.27 439.58 576 351.33 576 256S528.27 72.43 448.35 19.97zM480 256c0-63.53-32.06-121.94-85.77-156.24-11.19-7.14-26.03-3.82-33.12 7.46s-3.78 26.21 7.41 33.36C408.27 165.97 432 209.11 432 256s-23.73 90.03-63.48 115.42c-11.19 7.14-14.5 22.07-7.41 33.36 6.51 10.36 21.12 15.14 33.12 7.46C447.94 377.94 480 319.54 480 256zm-141.77-76.87c-11.58-6.33-26.19-2.16-32.61 9.45-6.39 11.61-2.16 26.2 9.45 32.61C327.98 228.28 336 241.63 336 256c0 14.38-8.02 27.72-20.92 34.81-11.61 6.41-15.84 21-9.45 32.61 6.43 11.66 21.05 15.8 32.61 9.45 28.23-15.55 45.77-45 45.77-76.88s-17.54-61.32-45.78-76.86z"/></svg>
|
Before Width: | Height: | Size: 1.2 KiB |
|
@ -5,6 +5,8 @@ var CiderAudio = {
|
|||
gainNode : null,
|
||||
spatialNode : null,
|
||||
spatialInput: null,
|
||||
audioBands : null,
|
||||
preampNode : null,
|
||||
},
|
||||
init: function (cb = function () { }) {
|
||||
//AudioOutputs.fInit = true;
|
||||
|
@ -21,8 +23,14 @@ var CiderAudio = {
|
|||
},
|
||||
off: function(){
|
||||
try{
|
||||
CiderAudio.audioNodes.gainNode.disconnect();
|
||||
CiderAudio.audioNodes.spatialNode.disconnect();
|
||||
try{
|
||||
CiderAudio.audioNodes.gainNode.disconnect(); } catch(e){}
|
||||
try{ CiderAudio.audioNodes.spatialNode.disconnect();} catch(e){}
|
||||
try{
|
||||
CiderAudio.audioNodes.preampNode.disconnect();
|
||||
CiderAudio.audioNodes.audioBands[0].disconnect();
|
||||
CiderAudio.audioNodes.audioBands[9].disconnect();
|
||||
} catch(e){}
|
||||
CiderAudio.source.connect(CiderAudio.context.destination);} catch(e){}
|
||||
},
|
||||
connectContext: function (mediaElem){
|
||||
|
@ -42,6 +50,7 @@ var CiderAudio = {
|
|||
if (app.cfg.audio.spatial){
|
||||
CiderAudio.spatialOn()
|
||||
}
|
||||
CiderAudio.equalizer()
|
||||
},
|
||||
normalizerOn: function (){},
|
||||
normalizerOff: function (){
|
||||
|
@ -49,7 +58,7 @@ var CiderAudio = {
|
|||
},
|
||||
spatialOn: function (){
|
||||
try{
|
||||
CiderAudio.audioNodes.gainNode.connect(CiderAudio.context.destination);} catch(e){}
|
||||
CiderAudio.audioNodes.gainNode.disconnect(CiderAudio.context.destination);} catch(e){}
|
||||
CiderAudio.audioNodes.spatialNode = new ResonanceAudio(CiderAudio.context);
|
||||
CiderAudio.audioNodes.spatialNode.output.connect(CiderAudio.context.destination);
|
||||
let roomDimensions = {
|
||||
|
@ -90,6 +99,42 @@ var CiderAudio = {
|
|||
}
|
||||
);
|
||||
}
|
||||
},
|
||||
equalizer: function (){
|
||||
let BANDS = app.cfg.audio.equalizer.frequencies;
|
||||
let GAIN = app.cfg.audio.equalizer.gain;
|
||||
let Q = app.cfg.audio.equalizer.Q;
|
||||
CiderAudio.audioNodes.audioBands = [];
|
||||
|
||||
for (i = 0; i < BANDS.length; i++) {
|
||||
CiderAudio.audioNodes.audioBands[i] = CiderAudio.context.createBiquadFilter();
|
||||
CiderAudio.audioNodes.audioBands[i].type = 'peaking'; // 'peaking';
|
||||
CiderAudio.audioNodes.audioBands[i].frequency.value = BANDS[i];
|
||||
CiderAudio.audioNodes.audioBands[i].Q.value = Q[i];
|
||||
CiderAudio.audioNodes.audioBands[i].gain.value = GAIN[i] * app.cfg.audio.equalizer.mix;
|
||||
}
|
||||
|
||||
CiderAudio.audioNodes.preampNode = CiderAudio.context.createBiquadFilter();
|
||||
CiderAudio.audioNodes.preampNode.type = 'highshelf';
|
||||
CiderAudio.audioNodes.preampNode.frequency.value = 0; // allow all
|
||||
CiderAudio.audioNodes.preampNode.gain.value = app.cfg.audio.equalizer.preamp;
|
||||
|
||||
if (app.cfg.audio.spatial) {
|
||||
try{
|
||||
CiderAudio.audioNodes.spatialNode.output.disconnect(CiderAudio.context.destination); } catch(e){}
|
||||
CiderAudio.audioNodes.spatialNode.output.connect(CiderAudio.audioNodes.preampNode);
|
||||
} else {
|
||||
try{
|
||||
CiderAudio.audioNodes.gainNode.disconnect(CiderAudio.context.destination);} catch(e){}
|
||||
CiderAudio.audioNodes.gainNode.connect(CiderAudio.audioNodes.preampNode);
|
||||
}
|
||||
|
||||
CiderAudio.audioNodes.preampNode.connect(CiderAudio.audioNodes.audioBands[0]);
|
||||
|
||||
for (i = 1; i < BANDS.length; i ++) {
|
||||
CiderAudio.audioNodes.audioBands[i-1].connect(CiderAudio.audioNodes.audioBands[i]);
|
||||
}
|
||||
CiderAudio.audioNodes.audioBands[BANDS.length-1].connect(CiderAudio.context.destination);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
108
src/renderer/js/WSAPI_Interop.js
Normal file
|
@ -0,0 +1,108 @@
|
|||
const wsapi = {
|
||||
cache: {playParams: {id: 0}, status: null, remainingTime: 0},
|
||||
playbackCache: {status: null, time: Date.now()},
|
||||
search(term, limit) {
|
||||
MusicKit.getInstance().api.search(term, {limit: limit, types: 'songs,artists,albums,playlists'}).then((results)=>{
|
||||
ipcRenderer.send('wsapi-returnSearch', JSON.stringify(results))
|
||||
})
|
||||
},
|
||||
searchLibrary(term, limit) {
|
||||
MusicKit.getInstance().api.library.search(term, {limit: limit, types: 'library-songs,library-artists,library-albums,library-playlists'}).then((results)=>{
|
||||
ipcRenderer.send('wsapi-returnSearchLibrary', JSON.stringify(results))
|
||||
})
|
||||
},
|
||||
getAttributes: function () {
|
||||
const mk = MusicKit.getInstance();
|
||||
const nowPlayingItem = mk.nowPlayingItem;
|
||||
const isPlayingExport = mk.isPlaying;
|
||||
const remainingTimeExport = mk.currentPlaybackTimeRemaining;
|
||||
const attributes = (nowPlayingItem != null ? nowPlayingItem.attributes : {});
|
||||
|
||||
attributes.status = isPlayingExport ? isPlayingExport : false;
|
||||
attributes.name = attributes.name ? attributes.name : 'No Title Found';
|
||||
attributes.artwork = attributes.artwork ? attributes.artwork : {url: ''};
|
||||
attributes.artwork.url = attributes.artwork.url ? attributes.artwork.url : '';
|
||||
attributes.playParams = attributes.playParams ? attributes.playParams : {id: 'no-id-found'};
|
||||
attributes.playParams.id = attributes.playParams.id ? attributes.playParams.id : 'no-id-found';
|
||||
attributes.albumName = attributes.albumName ? attributes.albumName : '';
|
||||
attributes.artistName = attributes.artistName ? attributes.artistName : '';
|
||||
attributes.genreNames = attributes.genreNames ? attributes.genreNames : [];
|
||||
attributes.remainingTime = remainingTimeExport ? (remainingTimeExport * 1000) : 0;
|
||||
attributes.durationInMillis = attributes.durationInMillis ? attributes.durationInMillis : 0;
|
||||
attributes.startTime = Date.now();
|
||||
attributes.endTime = attributes.endTime ? attributes.endTime : Date.now();
|
||||
attributes.volume = mk.volume;
|
||||
attributes.shuffleMode = mk.shuffleMode;
|
||||
attributes.repeatMode = mk.repeatMode;
|
||||
attributes.autoplayEnabled = mk.autoplayEnabled;
|
||||
return attributes
|
||||
},
|
||||
moveQueueItem(oldPosition, newPosition) {
|
||||
MusicKit.getInstance().queue._queueItems.splice(newPosition,0,MusicKit.getInstance().queue._queueItems.splice(oldPosition,1)[0])
|
||||
MusicKit.getInstance().queue._reindex()
|
||||
},
|
||||
setAutoplay(value) {
|
||||
MusicKit.getInstance().autoplayEnabled = value
|
||||
},
|
||||
returnDynamic(data, type) {
|
||||
ipcRenderer.send('wsapi-returnDynamic', JSON.stringify(data), type)
|
||||
},
|
||||
musickitApi(method, id, params, library = false) {
|
||||
if (library) {
|
||||
MusicKit.getInstance().api.library[method](id, params).then((results)=>{
|
||||
ipcRenderer.send('wsapi-returnMusicKitApi', JSON.stringify(results), method)
|
||||
})
|
||||
} else {
|
||||
MusicKit.getInstance().api[method](id, params).then((results)=>{
|
||||
ipcRenderer.send('wsapi-returnMusicKitApi', JSON.stringify(results), method)
|
||||
})
|
||||
}
|
||||
},
|
||||
getPlaybackState () {
|
||||
ipcRenderer.send('wsapi-updatePlaybackState', MusicKitInterop.getAttributes());
|
||||
},
|
||||
getLyrics() {
|
||||
ipcRenderer.send('wsapi-returnLyrics',JSON.stringify(app.lyrics));
|
||||
},
|
||||
getQueue() {
|
||||
ipcRenderer.send('wsapi-returnQueue', JSON.stringify(MusicKit.getInstance().queue))
|
||||
},
|
||||
playNext(type, id) {
|
||||
var request = {}
|
||||
request[type] = id
|
||||
MusicKit.getInstance().playNext(request)
|
||||
},
|
||||
playLater(type, id) {
|
||||
var request = {}
|
||||
request[type] = id
|
||||
MusicKit.getInstance().playLater(request)
|
||||
},
|
||||
love() {
|
||||
|
||||
},
|
||||
playTrackById(id, kind = "song") {
|
||||
MusicKit.getInstance().setQueue({ [kind]: id }).then(function (queue) {
|
||||
MusicKit.getInstance().play()
|
||||
})
|
||||
},
|
||||
quickPlay(term) {
|
||||
// Quick play by song name
|
||||
MusicKit.getInstance().api.search(term, { limit: 2, types: 'songs' }).then(function (data) {
|
||||
MusicKit.getInstance().setQueue({ song: data["songs"][0]["id"] }).then(function (queue) {
|
||||
MusicKit.getInstance().play()
|
||||
})
|
||||
})
|
||||
},
|
||||
toggleShuffle() {
|
||||
MusicKit.getInstance().shuffleMode = MusicKit.getInstance().shuffleMode === 0 ? 1 : 0
|
||||
},
|
||||
toggleRepeat() {
|
||||
if(MusicKit.getInstance().repeatMode == 0) {
|
||||
MusicKit.getInstance().repeatMode = 1
|
||||
}else if(MusicKit.getInstance().repeatMode == 1){
|
||||
MusicKit.getInstance().repeatMode = 2
|
||||
}else{
|
||||
MusicKit.getInstance().repeatMode = 0
|
||||
}
|
||||
}
|
||||
}
|
1
src/renderer/js/bootbox.min.js
vendored
Normal file
7
src/renderer/js/bootstrap.min.js
vendored
Normal file
4
src/renderer/js/jquery-3.2.1.slim.min.js
vendored
Normal file
1
src/renderer/js/notyf.min.js
vendored
Normal file
5
src/renderer/js/popper.min.js
vendored
Normal file
1107
src/renderer/less/bootstrap.less
vendored
Normal file
|
@ -45,7 +45,7 @@
|
|||
}
|
||||
|
||||
@media (max-width: 951px) {
|
||||
.content-inner {
|
||||
#app-content {
|
||||
zoom: 0.8;
|
||||
}
|
||||
}
|
||||
|
@ -53,7 +53,7 @@
|
|||
|
||||
// if page width is less than 951px
|
||||
@media (max-width: 951px) {
|
||||
.content-inner {
|
||||
#app-content {
|
||||
zoom: 0.8;
|
||||
}
|
||||
}
|
370
src/renderer/less/notyf.less
Normal file
|
@ -0,0 +1,370 @@
|
|||
@-webkit-keyframes notyf-fadeinup {
|
||||
0% {
|
||||
opacity: 0;
|
||||
transform: translateY(25%)
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0)
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes notyf-fadeinup {
|
||||
0% {
|
||||
opacity: 0;
|
||||
transform: translateY(25%)
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0)
|
||||
}
|
||||
}
|
||||
|
||||
@-webkit-keyframes notyf-fadeinleft {
|
||||
0% {
|
||||
opacity: 0;
|
||||
transform: translateX(25%)
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateX(0)
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes notyf-fadeinleft {
|
||||
0% {
|
||||
opacity: 0;
|
||||
transform: translateX(25%)
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateX(0)
|
||||
}
|
||||
}
|
||||
|
||||
@-webkit-keyframes notyf-fadeoutright {
|
||||
0% {
|
||||
opacity: 1;
|
||||
transform: translateX(0)
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 0;
|
||||
transform: translateX(25%)
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes notyf-fadeoutright {
|
||||
0% {
|
||||
opacity: 1;
|
||||
transform: translateX(0)
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 0;
|
||||
transform: translateX(25%)
|
||||
}
|
||||
}
|
||||
|
||||
@-webkit-keyframes notyf-fadeoutdown {
|
||||
0% {
|
||||
opacity: 1;
|
||||
transform: translateY(0)
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 0;
|
||||
transform: translateY(25%)
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes notyf-fadeoutdown {
|
||||
0% {
|
||||
opacity: 1;
|
||||
transform: translateY(0)
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 0;
|
||||
transform: translateY(25%)
|
||||
}
|
||||
}
|
||||
|
||||
@-webkit-keyframes ripple {
|
||||
0% {
|
||||
transform: scale(0) translateY(-45%) translateX(13%)
|
||||
}
|
||||
|
||||
to {
|
||||
transform: scale(1) translateY(-45%) translateX(13%)
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes ripple {
|
||||
0% {
|
||||
transform: scale(0) translateY(-45%) translateX(13%)
|
||||
}
|
||||
|
||||
to {
|
||||
transform: scale(1) translateY(-45%) translateX(13%)
|
||||
}
|
||||
}
|
||||
|
||||
.notyf {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
color: #fff;
|
||||
z-index: 9999;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-end;
|
||||
justify-content: flex-end;
|
||||
pointer-events: none;
|
||||
box-sizing: border-box;
|
||||
padding: 20px
|
||||
}
|
||||
|
||||
.notyf__icon--error,
|
||||
.notyf__icon--success {
|
||||
height: 21px;
|
||||
width: 21px;
|
||||
background: #fff;
|
||||
border-radius: 50%;
|
||||
display: block;
|
||||
margin: 0 auto;
|
||||
position: relative
|
||||
}
|
||||
|
||||
.notyf__icon--error:after,
|
||||
.notyf__icon--error:before {
|
||||
content: "";
|
||||
background: currentColor;
|
||||
display: block;
|
||||
position: absolute;
|
||||
width: 3px;
|
||||
border-radius: 3px;
|
||||
left: 9px;
|
||||
height: 12px;
|
||||
top: 5px
|
||||
}
|
||||
|
||||
.notyf__icon--error:after {
|
||||
transform: rotate(-45deg)
|
||||
}
|
||||
|
||||
.notyf__icon--error:before {
|
||||
transform: rotate(45deg)
|
||||
}
|
||||
|
||||
.notyf__icon--success:after,
|
||||
.notyf__icon--success:before {
|
||||
content: "";
|
||||
background: currentColor;
|
||||
display: block;
|
||||
position: absolute;
|
||||
width: 3px;
|
||||
border-radius: 3px
|
||||
}
|
||||
|
||||
.notyf__icon--success:after {
|
||||
height: 6px;
|
||||
transform: rotate(-45deg);
|
||||
top: 9px;
|
||||
left: 6px
|
||||
}
|
||||
|
||||
.notyf__icon--success:before {
|
||||
height: 11px;
|
||||
transform: rotate(45deg);
|
||||
top: 5px;
|
||||
left: 10px
|
||||
}
|
||||
|
||||
.notyf__toast {
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
pointer-events: auto;
|
||||
-webkit-animation: notyf-fadeinup .3s ease-in forwards;
|
||||
animation: notyf-fadeinup .3s ease-in forwards;
|
||||
box-shadow: 0 3px 7px 0 rgba(0, 0, 0, .25);
|
||||
position: relative;
|
||||
padding: 0 15px;
|
||||
border-radius: 2px;
|
||||
max-width: 300px;
|
||||
transform: translateY(25%);
|
||||
box-sizing: border-box;
|
||||
flex-shrink: 0
|
||||
}
|
||||
|
||||
.notyf__toast--disappear {
|
||||
transform: translateY(0);
|
||||
-webkit-animation: notyf-fadeoutdown .3s forwards;
|
||||
animation: notyf-fadeoutdown .3s forwards;
|
||||
-webkit-animation-delay: .25s;
|
||||
animation-delay: .25s
|
||||
}
|
||||
|
||||
.notyf__toast--disappear .notyf__icon,
|
||||
.notyf__toast--disappear .notyf__message {
|
||||
-webkit-animation: notyf-fadeoutdown .3s forwards;
|
||||
animation: notyf-fadeoutdown .3s forwards;
|
||||
opacity: 1;
|
||||
transform: translateY(0)
|
||||
}
|
||||
|
||||
.notyf__toast--disappear .notyf__dismiss {
|
||||
-webkit-animation: notyf-fadeoutright .3s forwards;
|
||||
animation: notyf-fadeoutright .3s forwards;
|
||||
opacity: 1;
|
||||
transform: translateX(0)
|
||||
}
|
||||
|
||||
.notyf__toast--disappear .notyf__message {
|
||||
-webkit-animation-delay: .05s;
|
||||
animation-delay: .05s
|
||||
}
|
||||
|
||||
.notyf__toast--upper {
|
||||
margin-bottom: 20px
|
||||
}
|
||||
|
||||
.notyf__toast--lower {
|
||||
margin-top: 20px
|
||||
}
|
||||
|
||||
.notyf__toast--dismissible .notyf__wrapper {
|
||||
padding-right: 30px
|
||||
}
|
||||
|
||||
.notyf__ripple {
|
||||
height: 400px;
|
||||
width: 400px;
|
||||
position: absolute;
|
||||
transform-origin: bottom right;
|
||||
right: 0;
|
||||
top: 0;
|
||||
border-radius: 50%;
|
||||
transform: scale(0) translateY(-51%) translateX(13%);
|
||||
z-index: 5;
|
||||
-webkit-animation: ripple .4s ease-out forwards;
|
||||
animation: ripple .4s ease-out forwards
|
||||
}
|
||||
|
||||
.notyf__wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-top: 17px;
|
||||
padding-bottom: 17px;
|
||||
padding-right: 15px;
|
||||
border-radius: 3px;
|
||||
position: relative;
|
||||
z-index: 10
|
||||
}
|
||||
|
||||
.notyf__icon {
|
||||
width: 22px;
|
||||
text-align: center;
|
||||
font-size: 1.3em;
|
||||
opacity: 0;
|
||||
-webkit-animation: notyf-fadeinup .3s forwards;
|
||||
animation: notyf-fadeinup .3s forwards;
|
||||
-webkit-animation-delay: .3s;
|
||||
animation-delay: .3s;
|
||||
margin-right: 13px
|
||||
}
|
||||
|
||||
.notyf__dismiss {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
height: 100%;
|
||||
width: 26px;
|
||||
margin-right: -15px;
|
||||
-webkit-animation: notyf-fadeinleft .3s forwards;
|
||||
animation: notyf-fadeinleft .3s forwards;
|
||||
-webkit-animation-delay: .35s;
|
||||
animation-delay: .35s;
|
||||
opacity: 0
|
||||
}
|
||||
|
||||
.notyf__dismiss-btn {
|
||||
background-color: rgba(0, 0, 0, .25);
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
transition: opacity .2s ease, background-color .2s ease;
|
||||
outline: none;
|
||||
opacity: .35;
|
||||
height: 100%;
|
||||
width: 100%
|
||||
}
|
||||
|
||||
.notyf__dismiss-btn:after,
|
||||
.notyf__dismiss-btn:before {
|
||||
content: "";
|
||||
background: #fff;
|
||||
height: 12px;
|
||||
width: 2px;
|
||||
border-radius: 3px;
|
||||
position: absolute;
|
||||
left: calc(50% - 1px);
|
||||
top: calc(50% - 5px)
|
||||
}
|
||||
|
||||
.notyf__dismiss-btn:after {
|
||||
transform: rotate(-45deg)
|
||||
}
|
||||
|
||||
.notyf__dismiss-btn:before {
|
||||
transform: rotate(45deg)
|
||||
}
|
||||
|
||||
.notyf__dismiss-btn:hover {
|
||||
opacity: .7;
|
||||
background-color: rgba(0, 0, 0, .15)
|
||||
}
|
||||
|
||||
.notyf__dismiss-btn:active {
|
||||
opacity: .8
|
||||
}
|
||||
|
||||
.notyf__message {
|
||||
vertical-align: middle;
|
||||
position: relative;
|
||||
opacity: 0;
|
||||
-webkit-animation: notyf-fadeinup .3s forwards;
|
||||
animation: notyf-fadeinup .3s forwards;
|
||||
-webkit-animation-delay: .25s;
|
||||
animation-delay: .25s;
|
||||
line-height: 1.5em
|
||||
}
|
||||
|
||||
@media only screen and (max-width:480px) {
|
||||
.notyf {
|
||||
padding: 0
|
||||
}
|
||||
|
||||
.notyf__ripple {
|
||||
height: 600px;
|
||||
width: 600px;
|
||||
-webkit-animation-duration: .5s;
|
||||
animation-duration: .5s
|
||||
}
|
||||
|
||||
.notyf__toast {
|
||||
max-width: none;
|
||||
border-radius: 0;
|
||||
box-shadow: 0 -2px 7px 0 rgba(0, 0, 0, .13);
|
||||
width: 100%
|
||||
}
|
||||
|
||||
.notyf__dismiss {
|
||||
width: 56px
|
||||
}
|
||||
}
|
Before Width: | Height: | Size: 33 KiB |
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
12492
src/renderer/vibrant.min.js
vendored
37
src/renderer/views/components/artwork-material.ejs
Normal 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>
|
82
src/renderer/views/components/cider-modal.ejs
Normal 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>
|
390
src/renderer/views/components/equalizer.ejs
Normal 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>
|
|
@ -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>
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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'">
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
0
src/renderer/views/components/mediaitem-info.ejs
Normal 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) {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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 => {
|
||||
|
|
|
@ -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)}
|
||||
}
|
||||
}
|
||||
]
|
||||
|
|
163
src/renderer/views/components/miniplayer.ejs
Normal 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>
|
34
src/renderer/views/components/qrcode-modal.ejs
Normal 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>
|
|
@ -48,7 +48,7 @@
|
|||
let self = this
|
||||
CiderContextMenu.Create(event, {
|
||||
items: [{
|
||||
"name": "Remove from queue",
|
||||
"name": $root.getLz('action.removeFromQueue'),
|
||||
"action": function () {
|
||||
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -16,17 +16,20 @@
|
|||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no, viewport-fit=cover">
|
||||
<title>Cider</title>
|
||||
<link rel="stylesheet/less" type="text/css" href="style.less"/>
|
||||
<script src="less.js"></script>
|
||||
<script src="<%- (env.dev ? "vue.js" : "vue.dev.js") %>"></script>
|
||||
<script src="vuex.min.js"></script>
|
||||
<script src="sortable.min.js"></script>
|
||||
<script src="vue-observe-visibility.min.js"></script>
|
||||
<script src="sortable.min.js"></script>
|
||||
<script src="vibrant.min.js"></script>
|
||||
<script src="vuedraggable.umd.min.js"></script>
|
||||
<script src="./js/less.js"></script>
|
||||
<script src="<%- (env.dev ? "./js/vue.js" : "./js/vue.dev.js") %>"></script>
|
||||
<script src="./js/vuex.min.js"></script>
|
||||
<script src="./js/sortable.min.js"></script>
|
||||
<script src="./js/vue-observe-visibility.min.js"></script>
|
||||
<script src="./js/vuedraggable.umd.min.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="./js/jquery-3.2.1.slim.min.js"></script>
|
||||
<script src="./js/popper.min.js"></script>
|
||||
<script src="./js/bootstrap.min.js"></script>
|
||||
<script src="./js/bootbox.min.js"></script>
|
||||
<script src="./js/notyf.min.js"></script>
|
||||
</head>
|
||||
|
||||
<body oncontextmenu="return false;" loading="1" platform="<%= env.platform %>">
|
||||
|
@ -38,9 +41,10 @@
|
|||
<div class="app-chrome--left">
|
||||
<div class="app-chrome-item full-height" v-if="chrome.windowControlPosition == 'left'">
|
||||
<div class="window-controls">
|
||||
<div class="close" @click="ipcRenderer.send('close')"></div>
|
||||
<div class="close" @click="closeWindow()"></div>
|
||||
<div class="minimize" @click="ipcRenderer.send('minimize')"></div>
|
||||
<div class="minmax restore" v-if="chrome.maximized" @click="ipcRenderer.send('maximize')">
|
||||
<div class="minmax restore" v-if="chrome.maximized"
|
||||
@click="ipcRenderer.send('maximize')">
|
||||
</div>
|
||||
<div class="minmax" v-else @click="ipcRenderer.send('maximize')"></div>
|
||||
</div>
|
||||
|
@ -67,9 +71,9 @@
|
|||
<div class="app-chrome-item display--large">
|
||||
<button class="playback-button--small repeat" v-if="mk.repeatMode == 0"
|
||||
@click="mk.repeatMode = 1"></button>
|
||||
<button class="playback-button--small repeat active" @click="mk.repeatMode = 2"
|
||||
<button class="playback-button--small repeat repeatOne" @click="mk.repeatMode = 2"
|
||||
v-else-if="mk.repeatMode == 1"></button>
|
||||
<button class="playback-button--small repeat repeatOne" @click="mk.repeatMode = 0"
|
||||
<button class="playback-button--small repeat active" @click="mk.repeatMode = 0"
|
||||
v-else-if="mk.repeatMode == 2"></button>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -83,29 +87,38 @@
|
|||
</div>
|
||||
<div class="playback-info">
|
||||
<div class="song-name" style="-webkit-box-orient: horizontal;"
|
||||
:style="[mk.nowPlayingItem['attributes']['contentRating'] == 'explicit' ? {'margin-left' : '23px'} : {'margin-left' : '0px'} ]">
|
||||
:class="[isElementOverflowing('#app-main > div.app-chrome > div.app-chrome--center > div > div > div.playback-info > div.song-name') ? 'marquee' : '']"
|
||||
:style="[mk.nowPlayingItem['attributes']['contentRating'] == 'explicit' ? {'margin-left' : '23px'} : {'margin-left' : '0px'} ]">
|
||||
{{ mk.nowPlayingItem["attributes"]["name"] }}
|
||||
<div class="explicit-icon" v-if="mk.nowPlayingItem['attributes']['contentRating'] == 'explicit'" style="display: inline-block"></div>
|
||||
<div class="explicit-icon"
|
||||
v-if="mk.nowPlayingItem['attributes']['contentRating'] == 'explicit'"
|
||||
style="display: inline-block"></div>
|
||||
</div>
|
||||
<div class="song-artist"
|
||||
<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;"
|
||||
<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="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 class="song-progress">
|
||||
<div class="song-duration" style="justify-content: space-between; height: 1px;"
|
||||
<div class="song-duration"
|
||||
style="justify-content: space-between; height: 1px;"
|
||||
:style="[chrome.progresshover ? {'display': 'flex'} : {'display' : 'none'} ]">
|
||||
<p style="width: auto">{{ convertToMins(getSongProgress()) }}</p>
|
||||
<p style="width: auto">{{ convertToMins(mk.currentPlaybackDuration) }}</p>
|
||||
<p style="width: auto">{{ convertToMins(mk.currentPlaybackDuration) }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<input type="range" step="0.01" min="0" :style="progressBarStyle()"
|
||||
|
@ -115,11 +128,11 @@
|
|||
</div>
|
||||
</div>
|
||||
<template v-if="mk.nowPlayingItem['attributes']['playParams']">
|
||||
<div class="actions"
|
||||
v-if="isInLibrary(mk.nowPlayingItem['attributes']['playParams'])">
|
||||
❤️
|
||||
<div class="actions">
|
||||
<button class="lcdMenu" @click="nowPlayingContextMenu">
|
||||
<div class="svg-icon"></div>
|
||||
</button>
|
||||
</div>
|
||||
<div class="actions" v-else>🖤</div>
|
||||
</template>
|
||||
|
||||
</div>
|
||||
|
@ -129,34 +142,40 @@
|
|||
</div>
|
||||
<div class="app-chrome--right">
|
||||
<div class="app-chrome-item volume display--large">
|
||||
<div class="app-chrome-item volume-icon"></div>
|
||||
<input type="range" class="" @wheel="volumeWheel" step="0.01" min="0" max="1"
|
||||
v-model="mk.volume"
|
||||
v-if="typeof mk.volume != 'undefined'">
|
||||
<button class="volume-button--small volume" @click="muteButtonPressed()"
|
||||
:class="{'active': this.cfg.audio.volume == 0}"></button>
|
||||
<input type="range" class="" @wheel="volumeWheel" step="0.01" min="0" :max="cfg.audio.maxVolume"
|
||||
v-model="mk.volume" v-if="typeof mk.volume != 'undefined'" @change="checkMuteChange()">
|
||||
</div>
|
||||
<div class="app-chrome-item generic" v-if="false">
|
||||
<button class="playback-button--small">
|
||||
<%- include("svg/cast.svg") %>
|
||||
</button>
|
||||
</div>
|
||||
<div class="app-chrome-item generic">
|
||||
<button class="playback-button--small miniplayer"
|
||||
@click="drawer.open = false; miniPlayer(true)"></button>
|
||||
</div>
|
||||
<div class="app-chrome-item generic">
|
||||
<button class="playback-button--small queue" :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" :class="{'active': drawer.panel == 'lyrics'}"
|
||||
@click="invokeDrawer('lyrics')"></button>
|
||||
</template>
|
||||
|
||||
<button class="playback-button--small lyrics"
|
||||
:class="{'active': drawer.panel == 'lyrics'}"
|
||||
@click="invokeDrawer('lyrics')"></button>
|
||||
</template>
|
||||
|
||||
</div>
|
||||
<div class="app-chrome-item full-height" v-if="chrome.windowControlPosition == 'right'">
|
||||
<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 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 class="close" @click="closeWindow()"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -169,11 +188,9 @@
|
|||
<input type="search" spellcheck="false" @click="showSearch()"
|
||||
@focus="search.showHints = true"
|
||||
@blur="setTimeout(()=>{search.showHints = false}, 300)"
|
||||
v-on:keyup.enter="searchQuery();search.showHints = false"
|
||||
@change="showSearch();" @input="getSearchHints()" placeholder="Search..."
|
||||
v-model="search.term"
|
||||
ref="searchInput"
|
||||
class="search-input">
|
||||
v-on:keyup.enter="searchQuery();search.showHints = false" @change="showSearch();"
|
||||
@input="getSearchHints()" :placeholder="$root.getLz('term.search') + '...'" v-model="search.term"
|
||||
ref="searchInput" class="search-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="search-hints-container" v-if="search.showHints && search.hints.length != 0">
|
||||
|
@ -186,40 +203,53 @@
|
|||
</div>
|
||||
<div class="app-sidebar-content">
|
||||
<div class="app-sidebar-header-text">
|
||||
Apple Music
|
||||
Cider
|
||||
</div>
|
||||
<sidebar-library-item name="Home" svg-icon="./assets/feather/home.svg"
|
||||
page="home"></sidebar-library-item>
|
||||
<sidebar-library-item name="Listen Now" svg-icon="./assets/feather/play-circle.svg"
|
||||
page="listen_now"></sidebar-library-item>
|
||||
<sidebar-library-item name="Browse" svg-icon="./assets/feather/globe.svg"
|
||||
page="browse"></sidebar-library-item>
|
||||
<sidebar-library-item name="Radio" svg-icon="./assets/feather/radio.svg"
|
||||
page="radio"></sidebar-library-item>
|
||||
<sidebar-library-item :name="$root.getLz('home.title')" svg-icon="./assets/feather/home.svg" page="home">
|
||||
</sidebar-library-item>
|
||||
<div class="app-sidebar-header-text">
|
||||
Library
|
||||
{{$root.getLz('term.appleMusic')}}
|
||||
</div>
|
||||
<sidebar-library-item name="Recently Added" svg-icon="./assets/feather/plus-circle.svg"
|
||||
<sidebar-library-item :name="$root.getLz('term.listenNow')" svg-icon="./assets/feather/play-circle.svg"
|
||||
page="listen_now"></sidebar-library-item>
|
||||
<sidebar-library-item :name="$root.getLz('term.browse')" svg-icon="./assets/feather/globe.svg" page="browse">
|
||||
</sidebar-library-item>
|
||||
<sidebar-library-item :name="$root.getLz('term.radio')" svg-icon="./assets/feather/radio.svg" page="radio">
|
||||
</sidebar-library-item>
|
||||
<div class="app-sidebar-header-text">
|
||||
{{$root.getLz('term.library')}}
|
||||
</div>
|
||||
<sidebar-library-item :name="$root.getLz('term.recentlyAdded')" svg-icon="./assets/feather/plus-circle.svg"
|
||||
page="library-recentlyadded"></sidebar-library-item>
|
||||
<sidebar-library-item name="Songs" svg-icon="./assets/feather/music.svg"
|
||||
<sidebar-library-item :name="$root.getLz('term.songs')" svg-icon="./assets/feather/music.svg"
|
||||
page="library-songs"></sidebar-library-item>
|
||||
<sidebar-library-item name="Albums" svg-icon="./assets/feather/disc.svg"
|
||||
<sidebar-library-item :name="$root.getLz('term.albums')" svg-icon="./assets/feather/disc.svg"
|
||||
page="library-albums"></sidebar-library-item>
|
||||
<sidebar-library-item name="Artists" svg-icon="./assets/feather/user.svg"
|
||||
<sidebar-library-item :name="$root.getLz('term.artists')" svg-icon="./assets/feather/user.svg"
|
||||
page="library-artists"></sidebar-library-item>
|
||||
<sidebar-library-item :name="$root.getLz('term.videos')" svg-icon="./assets/feather/video.svg" page="library-videos"></sidebar-library-item>
|
||||
<sidebar-library-item :name="$root.getLz('term.podcasts')" svg-icon="./assets/feather/mic.svg" page="podcasts">
|
||||
</sidebar-library-item>
|
||||
<div class="app-sidebar-header-text" @contextmenu="playlistHeaderContextMenu">
|
||||
Playlists
|
||||
{{ $root.getLz('term.playlists') }}
|
||||
</div>
|
||||
<sidebar-playlist v-for="item in getPlaylistFolderChildren('p.playlistsroot')"
|
||||
:item="item"></sidebar-playlist>
|
||||
<sidebar-playlist v-for="item in getPlaylistFolderChildren('p.playlistsroot')" :item="item">
|
||||
</sidebar-playlist>
|
||||
</div>
|
||||
<transition name="wpfade">
|
||||
<div class="usermenu-container" v-if="chrome.menuOpened">
|
||||
<div class="usermenu-body">
|
||||
<button class="usermenu-item" @click="chrome.hideUserInfo = !chrome.hideUserInfo">
|
||||
<button class="usermenu-item" @click="showWebRemoteQR()">
|
||||
<div class="row nopadding">
|
||||
<div class="col nopadding">
|
||||
Show Personal Info
|
||||
{{$root.getLz('action.showWebRemoteQR')}}
|
||||
</div>
|
||||
</div>
|
||||
</button>
|
||||
<button class="usermenu-item" @click="toggleHideUserInfo()">
|
||||
<div class="row nopadding">
|
||||
<div class="col nopadding">
|
||||
{{$root.getLz('settings.option.visual.showPersonalInfo')}}
|
||||
</div>
|
||||
<div class="col-auto nopadding" v-if="!chrome.hideUserInfo">
|
||||
✔️
|
||||
|
@ -229,31 +259,35 @@
|
|||
<button class="usermenu-item" @click="mk.privateEnabled = !mk.privateEnabled">
|
||||
<div class="row nopadding">
|
||||
<div class="col nopadding">
|
||||
Private Session
|
||||
{{$root.getLz('term.privateSession')}}
|
||||
</div>
|
||||
<div class="col-auto nopadding" v-if="mk.privateEnabled">
|
||||
✔️
|
||||
</div>
|
||||
</div>
|
||||
</button>
|
||||
<button class="usermenu-item" v-if="cfg.advanced.AudioContext"
|
||||
@click="modals.equalizer = true">
|
||||
{{$root.getLz('term.equalizer')}}
|
||||
</button>
|
||||
<button class="usermenu-item" v-if="cfg.advanced.AudioContext && cfg.audio.spatial"
|
||||
@click="modals.spatialProperties = true">
|
||||
Spatialized Audio Settings
|
||||
{{$root.getLz('term.spacializedAudioSetting')}}
|
||||
</button>
|
||||
<button class="usermenu-item" @click="appRoute('apple-account-settings')">
|
||||
Account Settings
|
||||
{{$root.getLz('term.accountSettings')}}
|
||||
</button>
|
||||
<button class="usermenu-item" @click="appRoute('about')">
|
||||
About
|
||||
{{$root.getLz('term.about')}}
|
||||
</button>
|
||||
<button class="usermenu-item" @click="window.open('https://discord.gg/applemusic')">
|
||||
Discord
|
||||
{{$root.getLz('term.discord')}}
|
||||
</button>
|
||||
<button class="usermenu-item" @click="appRoute('settings')">
|
||||
Settings
|
||||
{{$root.getLz('term.settings')}}
|
||||
</button>
|
||||
<button class="usermenu-item" @click="mk.unauthorize()">
|
||||
Sign Out
|
||||
<button class="usermenu-item" @click="unauthorize()">
|
||||
{{$root.getLz('term.logout')}}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -283,23 +317,23 @@
|
|||
<div class="app-chrome-item">
|
||||
<button class="playback-button--small repeat" v-if="mk.repeatMode == 0"
|
||||
@click="mk.repeatMode = 1"></button>
|
||||
<button class="playback-button--small repeat active" @click="mk.repeatMode = 2"
|
||||
<button class="playback-button--small repeat repeatOne" @click="mk.repeatMode = 2"
|
||||
v-else-if="mk.repeatMode == 1"></button>
|
||||
<button class="playback-button--small repeat repeatOne" @click="mk.repeatMode = 0"
|
||||
v-else-if="mk.repeatMode == 2"></button>
|
||||
<button class="playback-button--small repeat active"
|
||||
@click="mk.repeatMode = 0" v-else-if="mk.repeatMode == 2"></button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="app-chrome-item volume">
|
||||
<div class="input-container">
|
||||
<div class="app-chrome-item volume-icon"></div>
|
||||
<input type="range" class="" @wheel="volumeWheel" step="0.01" min="0" max="1"
|
||||
v-model="mk.volume"
|
||||
v-if="typeof mk.volume != 'undefined'">
|
||||
<button class="volume-button--small volume" @click="muteButtonPressed()"
|
||||
:class="{'active': this.cfg.audio.volume == 0}"></button>
|
||||
<input type="range" class="" @wheel="volumeWheel" step="0.01" min="0" :max="cfg.audio.maxVolume"
|
||||
v-model="mk.volume" v-if="typeof mk.volume != 'undefined'"
|
||||
@change="checkMuteChange()">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<button class="app-sidebar-button" style="width:100%"
|
||||
:class="{active: chrome.menuOpened}"
|
||||
<button class="app-sidebar-button" style="width:100%" :class="{active: chrome.menuOpened}"
|
||||
@blur="setTimeout(()=>{chrome.menuOpened = false}, 100)"
|
||||
@click="(chrome.userinfo.id) ? chrome.menuOpened = !chrome.menuOpened : false">
|
||||
|
||||
|
@ -308,9 +342,11 @@
|
|||
|
||||
<div class="sidebar-user-text" v-if="!chrome.hideUserInfo">
|
||||
<template v-if="chrome.userinfo.id">
|
||||
<div class="fullname text-overflow-elipsis">{{ chrome.userinfo.attributes.name }}
|
||||
<div class="fullname text-overflow-elipsis">{{ chrome.userinfo.attributes.name
|
||||
}}
|
||||
</div>
|
||||
<div class="handle-text text-overflow-elipsis">@{{ chrome.userinfo.attributes.handle
|
||||
<div class="handle-text text-overflow-elipsis">{{
|
||||
chrome.userinfo.attributes.handle
|
||||
}}
|
||||
</div>
|
||||
</template>
|
||||
|
@ -325,18 +361,36 @@
|
|||
</div>
|
||||
</button>
|
||||
</div>
|
||||
<div class="app-sidebar-notification libraryNotification" v-if="library.downloadNotification.show">
|
||||
<div class="message">{{ library.downloadNotification.message }} ({{
|
||||
library.downloadNotification.progress }} / {{ library.downloadNotification.total }})
|
||||
<div class="app-sidebar-notification backgroundNotification"
|
||||
v-if="library.backgroundNotification.show">
|
||||
<div class="message">{{ library.backgroundNotification.message }} ({{
|
||||
library.backgroundNotification.progress }} / {{ library.backgroundNotification.total }})
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="app-content">
|
||||
<div id="navigation-bar">
|
||||
<button class="nav-item" @click="navigateBack()"><%- include('svg/chevron-left.svg') %></button>
|
||||
<button class="nav-item"
|
||||
@click="navigateForward()"><%- include('svg/chevron-right.svg') %></button>
|
||||
<button class="nav-item" @click="navigateBack()">
|
||||
<%- include('svg/chevron-left.svg') %>
|
||||
</button>
|
||||
<button class="nav-item" @click="navigateForward()">
|
||||
<%- include('svg/chevron-right.svg') %>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Podcasts -->
|
||||
<transition name="wpfade">
|
||||
<template v-if="page == 'podcasts'">
|
||||
<apple-podcasts></apple-podcasts>
|
||||
</template>
|
||||
</transition>
|
||||
<!-- Library - Library Videos -->
|
||||
<transition name="wpfade" >
|
||||
<template v-if="page == 'library-videos'">
|
||||
<cider-library-videos></cider-library-videos>
|
||||
</template>
|
||||
</transition>
|
||||
|
||||
<!-- Apple Setings Page -->
|
||||
<transition name="wpfade">
|
||||
<template v-if="page == 'apple-account-settings'">
|
||||
|
@ -407,53 +461,53 @@
|
|||
<template v-if="page == 'browse'">
|
||||
<!-- <div class="content-inner">
|
||||
|
||||
<button id="apple-music-authorize" class="md-btn md-btn-primary" @click="init()">Start
|
||||
MusicKit
|
||||
</button>
|
||||
<button id="apple-music-unauthorize" class="md-btn md-btn-primary"
|
||||
@click="unauthorize()">
|
||||
Stop
|
||||
MusicKit
|
||||
</button>
|
||||
<button id="apple-music-authorize" class="md-btn md-btn-primary" @click="init()">Start
|
||||
MusicKit
|
||||
</button>
|
||||
<button id="apple-music-unauthorize" class="md-btn md-btn-primary"
|
||||
@click="unauthorize()">
|
||||
Stop
|
||||
MusicKit
|
||||
</button>
|
||||
<br>
|
||||
<template v-if="mk.nowPlayingItem">
|
||||
currentPlaybackProgress: {{ app.mk.currentPlaybackProgress }}
|
||||
<br>
|
||||
<template v-if="mk.nowPlayingItem">
|
||||
currentPlaybackProgress: {{ app.mk.currentPlaybackProgress }}
|
||||
<br>
|
||||
currentPlaybackDuration: {{ app.mk.currentPlaybackDuration }}
|
||||
</template>
|
||||
<div><input type="text" v-model="quickPlayQuery">
|
||||
<button @click="quickPlay(quickPlayQuery)">Play</button>
|
||||
</div>
|
||||
<h1 class="header-text">Browse</h1>
|
||||
<p>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed euismod, urna eu
|
||||
tincidunt
|
||||
consectetur, nisl nunc euismod nisi, eu porttitor nisl nisi euismod nisi.
|
||||
</p>
|
||||
<div class="media-item--small">
|
||||
<div class="artwork">
|
||||
currentPlaybackDuration: {{ app.mk.currentPlaybackDuration }}
|
||||
</template>
|
||||
<div><input type="text" v-model="quickPlayQuery">
|
||||
<button @click="quickPlay(quickPlayQuery)">Play</button>
|
||||
</div>
|
||||
<h1 class="header-text">{{$root.getLz('term.browse')}}</h1>
|
||||
<p>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed euismod, urna eu
|
||||
tincidunt
|
||||
consectetur, nisl nunc euismod nisi, eu porttitor nisl nisi euismod nisi.
|
||||
</p>
|
||||
<div class="media-item--small">
|
||||
<div class="artwork">
|
||||
|
||||
</div>
|
||||
<div class="text">
|
||||
Text
|
||||
</div>
|
||||
<div class="subtext">
|
||||
Subtext
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
<br>
|
||||
<h1 class="header-text">Listen Now</h1>
|
||||
<div class="winbox">
|
||||
<div class="fancy">990kbps</div>
|
||||
<div class="">
|
||||
<button class="md-btn md-btn-primary">Audio Quality Settings</button>
|
||||
</div>
|
||||
<div class="text">
|
||||
Text
|
||||
</div>
|
||||
<button class="md-btn" @click="drawertest = !drawertest">Toggle Drawer</button>
|
||||
<button class="md-btn">Button</button>
|
||||
<button class="md-btn md-btn-primary">Button</button>
|
||||
</div> -->
|
||||
<div class="subtext">
|
||||
Subtext
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
<br>
|
||||
<h1 class="header-text">{{$root.getLz('term.listenNow')}}</h1>
|
||||
<div class="winbox">
|
||||
<div class="fancy">990kbps</div>
|
||||
<div class="">
|
||||
<button class="md-btn md-btn-primary">Audio Quality Settings</button>
|
||||
</div>
|
||||
</div>
|
||||
<button class="md-btn" @click="drawertest = !drawertest">Toggle Drawer</button>
|
||||
<button class="md-btn">Button</button>
|
||||
<button class="md-btn md-btn-primary">Button</button>
|
||||
</div> -->
|
||||
<cider-browse :data="browsepage"></cider-browse>
|
||||
</template>
|
||||
</transition>
|
||||
|
@ -467,8 +521,8 @@
|
|||
<transition v-on:enter="getRadioStations()" name="wpfade">
|
||||
<template v-if="page == 'radio'" @created="console.log('radio')">
|
||||
<div class="content-inner">
|
||||
<h1 class="header-text">Radio</h1>
|
||||
<h3>Recent Stations</h3>
|
||||
<h1 class="header-text">{{$root.getLz('term.radio')}}</h1>
|
||||
<h3>{{$root.getLz('term.recentStations')}}</h3>
|
||||
<mediaitem-square :item="item" v-for="item in radio.personal"></mediaitem-square>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -522,7 +576,8 @@
|
|||
|
||||
</div>
|
||||
<transition name="drawertransition">
|
||||
<div class="app-drawer" v-if="drawer.open && drawer.panel == 'lyrics' && lyrics && lyrics != [] && lyrics.length > 0">
|
||||
<div class="app-drawer"
|
||||
v-if="drawer.open && drawer.panel == 'lyrics' && lyrics && lyrics != [] && lyrics.length > 0">
|
||||
<div class="bgArtworkMaterial">
|
||||
<div class="bg-artwork-container">
|
||||
<img class="bg-artwork a" :src="$store.state.artwork.playerLCD">
|
||||
|
@ -533,7 +588,7 @@
|
|||
:richlyrics="richlyrics"></lyrics-view>
|
||||
<div v-if="drawer.panel == 'lyrics'" class="lyric-footer">
|
||||
<button class="md-btn" @click="modularUITest(!fullscreenLyrics)">{{fullscreenLyrics ?
|
||||
"Default View":'Fullscreen View'}}
|
||||
$root.getLz('term.defaultView'): $root.getLz('term.fullscreenView')}}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -543,25 +598,28 @@
|
|||
<cider-queue ref="queue" v-if="drawer.panel == 'queue'"></cider-queue>
|
||||
</div>
|
||||
</transition>
|
||||
<cider-menu-panel v-if="menuPanel.visible">
|
||||
</cider-menu-panel>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
<cider-menu-panel v-if="menuPanel.visible">
|
||||
</cider-menu-panel>
|
||||
<transition name="fsModeSwitch">
|
||||
<div class="fullscreen-view-container" v-if="appMode == 'fullscreen'">
|
||||
<fullscreen-view :image="currentArtUrl.replace('50x50', '600x600')" :time="lyriccurrenttime"
|
||||
:lyrics="lyrics" :richlyrics="richlyrics"></fullscreen-view>
|
||||
</div>
|
||||
</transition>
|
||||
<transition name="fsModeSwitch">
|
||||
<div class="fullscreen-view-container" v-if="appMode == 'mini'">
|
||||
<mini-view :image="currentArtUrl.replace('50x50', '600x600')" :time="lyriccurrenttime"
|
||||
:lyrics="lyrics" :richlyrics="richlyrics"></mini-view>
|
||||
</div>
|
||||
</transition>
|
||||
<transition name="wpfade">
|
||||
<div class="bg-artwork-container"
|
||||
<div class="bg-artwork-container" v-if="cfg.visual.window_background_style == 'artwork'"
|
||||
:class="{noanimation: (!cfg.visual.bg_artwork_rotation || !animateBackground)}">
|
||||
<img @load="chrome.artworkReady = true" class="bg-artwork a "
|
||||
>
|
||||
<img class="bg-artwork b"
|
||||
>
|
||||
<img @load="chrome.artworkReady = true" class="bg-artwork a ">
|
||||
<img class="bg-artwork b">
|
||||
</div>
|
||||
</transition>
|
||||
<transition name="wpfade">
|
||||
|
@ -573,6 +631,12 @@
|
|||
<transition name="modal">
|
||||
<spatial-properties v-if="modals.spatialProperties"></spatial-properties>
|
||||
</transition>
|
||||
<transition name="modal">
|
||||
<eq-view v-if="modals.equalizer"></eq-view>
|
||||
</transition>
|
||||
<transition name="modal">
|
||||
<qrcode-modal v-if="modals.qrcode" :src="webremoteqr" :url="webremoteurl"></qrcode-modal>
|
||||
</transition>
|
||||
<div id="apple-music-video-container">
|
||||
<div id="apple-music-video-player-controls">
|
||||
<div id="player-exit" title="Close" @click="exitMV()">
|
||||
|
@ -585,9 +649,11 @@
|
|||
</div>
|
||||
<div id="captions">{{((lyricon) ? ((lyrics.length > 0 && lyrics[currentLyricsLine] &&
|
||||
lyrics[currentLyricsLine].line ) ?
|
||||
lyrics[currentLyricsLine].line.replace('lrcInstrumental','') : "") : '') + ((lyricon) ? ((lyrics.length
|
||||
lyrics[currentLyricsLine].line.replace('lrcInstrumental','') : "") : '') + ((lyricon) ?
|
||||
((lyrics.length
|
||||
> 0 && lyrics[currentLyricsLine] && lyrics[currentLyricsLine].line ) ?
|
||||
(lyrics[currentLyricsLine].translation ? ('\n\r' + lyrics[currentLyricsLine].translation) : ""): "") :
|
||||
(lyrics[currentLyricsLine].translation ? ('\n\r' + lyrics[currentLyricsLine].translation) : ""): "")
|
||||
:
|
||||
'')}}
|
||||
</div>
|
||||
<div id="player-pip"
|
||||
|
@ -605,6 +671,9 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- Apple Settings Page -->
|
||||
<%- include('pages/podcasts') %>
|
||||
<!-- Apple Settings Page -->
|
||||
<%- include('pages/apple-account-settings') %>
|
||||
<!-- Library - Songs -->
|
||||
|
@ -648,12 +717,17 @@
|
|||
<!-- About -->
|
||||
<%- include('pages/about') %>
|
||||
|
||||
<script type="text/x-template" id="am-musiccovershelf">
|
||||
|
||||
<%- include('pages/library-videos') %>
|
||||
|
||||
<script type="text/x-template"
|
||||
id="am-musiccovershelf">
|
||||
<h1>{{ component.attributes.title.stringForDisplay }}</h1>
|
||||
</script>
|
||||
|
||||
<!-- Sidebar Item -->
|
||||
<script type="text/x-template" id="sidebar-library-item">
|
||||
<script type="text/x-template"
|
||||
id="sidebar-library-item">
|
||||
<button class="app-sidebar-item"
|
||||
:class="$parent.getSidebarItemClass(page)" @click="$root.appRoute(page)">
|
||||
<div class="sidebar-icon" v-html="svgIconData" v-if="svgIconData != ''"></div>
|
||||
|
@ -661,56 +735,95 @@
|
|||
</button>
|
||||
</script>
|
||||
|
||||
<!-- Artwork Material -->
|
||||
<%- include('components/artwork-material') %>
|
||||
<!-- Menu Panel -->
|
||||
<%- include('components/menu-panel') %>
|
||||
<!-- Playlist Listing -->
|
||||
<%- include('components/sidebar-playlist') %>
|
||||
<%- include('components/sidebar-playlist')
|
||||
%>
|
||||
<!-- Spatial Properties -->
|
||||
<%- include('components/spatial-properties') %>
|
||||
<%- include('components/spatial-properties')
|
||||
%>
|
||||
<!-- QRCode Modal -->
|
||||
<%- include('components/qrcode-modal')
|
||||
%>
|
||||
<!-- Equalizer -->
|
||||
<%- include('components/equalizer')
|
||||
%>
|
||||
<!-- Add to playlist -->
|
||||
<%- include('components/add-to-playlist') %>
|
||||
<%- include('components/add-to-playlist')
|
||||
%>
|
||||
<!-- Queue -->
|
||||
<%- include('components/queue') %>
|
||||
<%- include('components/queue')
|
||||
%>
|
||||
<!-- Queue Item -->
|
||||
<%- include('components/queue-item') %>
|
||||
<%- include('components/queue-item')
|
||||
%>
|
||||
<!-- Horizontal MediaItem Scroller -->
|
||||
<%- include('components/mediaitem-scroller-horizontal') %>
|
||||
<%- include('components/mediaitem-scroller-horizontal')
|
||||
%>
|
||||
<!-- Horizontal MediaItem Scroller (Large) -->
|
||||
<%- include('components/mediaitem-scroller-horizontal-large') %>
|
||||
<%- include('components/mediaitem-scroller-horizontal-large')
|
||||
%>
|
||||
<!-- Horizontal MediaItem Scroller (SP : Special) -->
|
||||
<%- include('components/mediaitem-scroller-horizontal-sp') %>
|
||||
<%- include('components/mediaitem-scroller-horizontal-sp')
|
||||
%>
|
||||
<!-- Horizontal MediaItem Scroller (MV) -->
|
||||
<%- include('components/mediaitem-scroller-horizontal-mvview') %>
|
||||
<%- include('components/mediaitem-scroller-horizontal-mvview')
|
||||
%>
|
||||
<!-- MediaItem List Item -->
|
||||
<%- include('components/mediaitem-list-item') %>
|
||||
<%- include('components/mediaitem-list-item')
|
||||
%>
|
||||
<!-- MediaItem Horizontal Rectangle -->
|
||||
<%- include('components/mediaitem-hrect') %>
|
||||
<%- include('components/mediaitem-hrect')
|
||||
%>
|
||||
<!-- MediaItem Square -->
|
||||
<%- include('components/mediaitem-square') %>
|
||||
<%- include('components/mediaitem-square')
|
||||
%>
|
||||
<!-- MediaItem Square SP -->
|
||||
<%- include('components/mediaitem-square-sp') %>
|
||||
<%- include('components/mediaitem-square-sp')
|
||||
%>
|
||||
<!-- MediaItem MusicVideo -->
|
||||
<%- include('components/mediaitem-mvview') %>
|
||||
<%- include('components/mediaitem-mvview')
|
||||
%>
|
||||
<!-- MediaItem MusicVideo -->
|
||||
<%- include('components/libraryartist-item') %>
|
||||
<%- include('components/listennow-child') %>
|
||||
<%- include('components/libraryartist-item')
|
||||
%>
|
||||
<%- include('components/listennow-child')
|
||||
%>
|
||||
<!-- MediaItem MusicVideo SP -->
|
||||
<%- include('components/mediaitem-mvview-sp') %>
|
||||
<%- include('components/mediaitem-mvview-sp')
|
||||
%>
|
||||
<!-- Animated Artwork View -->
|
||||
<%- include('components/animatedartwork-view') %>
|
||||
<%- include('components/animatedartwork-view')
|
||||
%>
|
||||
<!-- Lyrics View -->
|
||||
<%- include('components/lyrics-view') %>
|
||||
<%- include('components/lyrics-view')
|
||||
%>
|
||||
<!-- Fullscreen View -->
|
||||
<%- include('components/fullscreen') %>
|
||||
<%- include('components/fullscreen')
|
||||
%>
|
||||
|
||||
<script src="musickit.js?v=1"></script>
|
||||
<!-- Miniplayer View -->
|
||||
<%- include('components/miniplayer')
|
||||
%>
|
||||
|
||||
<script
|
||||
src="musickit.js?v=1"></script>
|
||||
<script>
|
||||
if (typeof MusicKit == 'undefined') {
|
||||
document.write(unescape("%3Cscript src='https://js-cdn.music.apple.com/musickit/v2/amp/musickit.js' type='text/javascript'%3E%3C/script%3E"));
|
||||
}
|
||||
</script>
|
||||
<script src="index.js?v=1"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/resonance-audio/build/resonance-audio.min.js"></script>
|
||||
<script src="/audio/audio.js?v=1"></script>
|
||||
<script
|
||||
src="index.js?v=1"></script>
|
||||
<script
|
||||
src="https://cdn.jsdelivr.net/npm/resonance-audio/build/resonance-audio.min.js"></script>
|
||||
<script
|
||||
src="/audio/audio.js?v=1"></script>
|
||||
<script
|
||||
src="./js/WSAPI_Interop.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
|
|
@ -3,15 +3,14 @@
|
|||
<div class="row">
|
||||
<div class="col">
|
||||
<img src="assets/banner.png" alt="Cider Logo" style="display:block;margin:0 auto;width: 500px;">
|
||||
<p style="text-align: center">Major thanks to the Cider Collective Team and all of our contributors.</p>
|
||||
<p style="text-align: center"> {{$root.getLz('about.thanks')}} </p>
|
||||
|
||||
<p style="text-align: center">"Apple Music" - Copyright © 2021 <a href="https://www.apple.com/" class="dt-footer__link"
|
||||
<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="">Apple Inc.</a>
|
||||
All Rights
|
||||
Reserved.</p>
|
||||
rel="noopener" data-dt-link-to-exclude="">{{$root.getLz('term.appleInc')}}</a>
|
||||
{{$root.getLz('term.rightsReserved')}}</p>
|
||||
<hr>
|
||||
<h3>Sponsor this project</h3>
|
||||
<h3>{{$root.getLz('term.sponsor')}}</h3>
|
||||
<button onclick="window.open('https://ko-fi.com/cryptofyre')" class="md-btn sponsorBtn"><img src="./assets/ko_fi.svg"/>Ko-fi</button>
|
||||
<button onclick="window.open('https://opencollective.com/ciderapp')" class="md-btn sponsorBtn"><img src="./assets/open_collective.svg"/>Open Collective</button>
|
||||
|
||||
|
@ -19,7 +18,7 @@
|
|||
<div class="col">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<h3>Cider Team</h3>
|
||||
<h3>{{$root.getLz('term.ciderTeam')}}</h3>
|
||||
<button class="md-btn teamBtn" @click="window.open(member.link)" v-for="member in team">
|
||||
<img :src="member.avatar"/>
|
||||
<div class="row" style="width:100%;">
|
||||
|
@ -36,7 +35,7 @@
|
|||
<div class="row">
|
||||
<div class="col">
|
||||
<h3></h3>
|
||||
<h3>Contributors</h3>
|
||||
<h3>{{$root.getLz('term.contributors')}}</h3>
|
||||
<img class="md-contributors"
|
||||
style="cursor:pointer;width:100%;"
|
||||
onclick="window.open('https://github.com/ciderapp/Cider/graphs/contributors')"
|
||||
|
@ -58,43 +57,43 @@
|
|||
{
|
||||
name: 'cryptofyre',
|
||||
link: 'https://github.com/cryptofyre',
|
||||
role: 'Developer',
|
||||
role: app.getLz('term.developer'),
|
||||
avatar: 'https://avatars.githubusercontent.com/u/33162551?v=4'
|
||||
},
|
||||
{
|
||||
name: 'Core',
|
||||
link: 'https://github.com/coredev-uk',
|
||||
role: 'Developer',
|
||||
role: app.getLz('term.developer'),
|
||||
avatar: 'https://avatars.githubusercontent.com/u/64542347?v=4'
|
||||
},
|
||||
{
|
||||
name: 'Quacksire',
|
||||
link: 'https://github.com/quacksire',
|
||||
role: 'Developer',
|
||||
role: app.getLz('term.developer'),
|
||||
avatar: 'https://avatars.githubusercontent.com/u/19170969?v=4'
|
||||
},
|
||||
{
|
||||
name: 'booploops',
|
||||
link: 'https://github.com/booploops',
|
||||
role: 'Developer',
|
||||
role: app.getLz('term.developer'),
|
||||
avatar: 'https://avatars.githubusercontent.com/u/49113086?v=4'
|
||||
},
|
||||
{
|
||||
name: 'vapormusic',
|
||||
link: 'https://github.com/vapormusic',
|
||||
role: 'Developer',
|
||||
role: app.getLz('term.developer'),
|
||||
avatar: 'https://avatars.githubusercontent.com/u/27716185?v=4'
|
||||
},
|
||||
{
|
||||
name: 'Void',
|
||||
link: 'https://twitter.com/MoonyVoid',
|
||||
role: 'Social Team',
|
||||
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: 'Social Team',
|
||||
role: app.getLz('term.socialTeam'),
|
||||
avatar: 'https://pbs.twimg.com/profile_images/1422541289837535239/qg-aaoP9_400x400.jpg'
|
||||
}
|
||||
]
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
<h3>{{ recom.attributes.name ?? ""}}</h3>
|
||||
</div>
|
||||
<div class="col-auto 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')" >See All</button>
|
||||
<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))">
|
||||
|
|
|
@ -5,7 +5,32 @@
|
|||
<div class="col">
|
||||
<div class="row nopadding">
|
||||
<div class="col nopadding">
|
||||
<h3>Your Artists Feed</h3>
|
||||
<h3>{{app.getLz('home.followedArtists')}}</h3>
|
||||
</div>
|
||||
</div>
|
||||
<div class="well">
|
||||
<mediaitem-scroller-horizontal>
|
||||
<div v-for="artist in artists" style="margin: 6px;">
|
||||
<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.unfollow')}}
|
||||
</button>
|
||||
</div>
|
||||
</mediaitem-scroller-horizontal>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<div class="row nopadding">
|
||||
<div class="col nopadding">
|
||||
<h3>{{app.getLz('home.artistsFeed')}}</h3>
|
||||
</div>
|
||||
</div>
|
||||
<div class="well" style="margin-top:0;">
|
||||
|
@ -30,6 +55,7 @@
|
|||
app: this.$root,
|
||||
followedArtists: this.$root.cfg.home.followedArtists,
|
||||
artistFeed: [],
|
||||
artists: []
|
||||
}
|
||||
},
|
||||
async mounted() {
|
||||
|
@ -37,19 +63,26 @@
|
|||
await this.getArtistFeed()
|
||||
},
|
||||
methods: {
|
||||
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)
|
||||
}
|
||||
this.getArtistFeed()
|
||||
},
|
||||
async getArtistFeed() {
|
||||
let artists = this.followedArtists
|
||||
let self = this
|
||||
this.app.mk.api.artists(artists, {
|
||||
"views": "featured-release,full-albums,appears-on-albums,featured-albums,featured-on-albums,singles,compilation-albums,live-albums,latest-release,top-music-videos,similar-artists,top-songs,playlists,more-to-hear,more-to-see",
|
||||
"extend": "artistBio,bornOrFormed,editorialArtwork,editorialVideo,isGroup,origin,hero",
|
||||
"extend[playlists]": "trackCount",
|
||||
"include[songs]": "albums",
|
||||
"fields[albums]": "artistName,artistUrl,artwork,contentRating,editorialArtwork,editorialVideo,name,playParams,releaseDate,url,trackCount",
|
||||
"limit[artists:top-songs]": 20,
|
||||
"art[url]": "f"
|
||||
}, {includeResponseMeta: !0}).then(artistData => {
|
||||
artistData.data.forEach(item => {
|
||||
this.artists = []
|
||||
this.artistFeed = []
|
||||
this.app.mk.api.v3.music(`/v1/catalog/${app.mk.storefrontId}/artists?ids=${artists.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`).then(artistData => {
|
||||
artistData.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])
|
||||
}
|
||||
|
|
|
@ -1,49 +1,66 @@
|
|||
<script type="text/x-template" id="cider-artist">
|
||||
<div class="content-inner artist-page">
|
||||
<div class="artist-header" :style="getArtistPalette(data)" :key="data.id">
|
||||
<div class="content-inner artist-page" :class="[data.attributes.editorialVideo && (data.attributes.editorialVideo.motionArtistWide16x9 || data.attributes.editorialVideo.motionArtistFullscreen16x9) ? 'animated' : '']">
|
||||
<div class="artist-header" :key="data.id" v-observe-visibility="{callback: isHeaderVisible}">
|
||||
<animatedartwork-view
|
||||
:priority="true"
|
||||
v-if="data.attributes.editorialVideo && (data.attributes.editorialVideo.motionArtistWide16x9 || data.attributes.editorialVideo.motionArtistFullscreen16x9)"
|
||||
:video="data.attributes.editorialVideo.motionArtistWide16x9.video ?? (data.attributes.editorialVideo.motionArtistFullscreen16x9.video ?? '')">
|
||||
</animatedartwork-view>
|
||||
<div class="row">
|
||||
<div class="col-sm" style="width: auto;">
|
||||
<div class="artist-image" v-if="!(data.attributes.editorialVideo && (data.attributes.editorialVideo.motionArtistWide16x9 || data.attributes.editorialVideo.motionArtistFullscreen16x9))">
|
||||
<mediaitem-artwork
|
||||
shadow="large"
|
||||
:url="data.attributes.artwork ? data.attributes.artwork.url : ''"
|
||||
size="190" type="artists"></mediaitem-artwork>
|
||||
<button class="overlay-play" @click="app.mk.setStationQueue({artist:'a-'+data.id}).then(()=>{
|
||||
<div class="header-content" style="pointer-events: all;">
|
||||
<div class="row">
|
||||
<div class="col-sm" style="width: auto;">
|
||||
<div class="artist-image" v-if="!(data.attributes.editorialVideo && (data.attributes.editorialVideo.motionArtistWide16x9 || data.attributes.editorialVideo.motionArtistFullscreen16x9))">
|
||||
<mediaitem-artwork
|
||||
shadow="large"
|
||||
:url="data.attributes.artwork ? data.attributes.artwork.url : ''"
|
||||
size="190" type="artists"></mediaitem-artwork>
|
||||
<button class="overlay-play" @click="app.mk.setStationQueue({artist:'a-'+data.id}).then(()=>{
|
||||
app.mk.play()
|
||||
})">
|
||||
<%- include("../svg/play.svg") %>
|
||||
</button>
|
||||
<%- include("../svg/play.svg") %>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col flex-center artist-title"
|
||||
:class="{'artist-animation-on': (data.attributes.editorialVideo && (data.attributes.editorialVideo.motionArtistWide16x9 || data.attributes.editorialVideo.motionArtistFullscreen16x9)) }"
|
||||
>
|
||||
<button class="artist-play" @click="app.mk.setStationQueue({artist:'a-'+data.id}).then(()=>{
|
||||
<div class="col flex-center artist-title"
|
||||
:class="{'artist-animation-on': (data.attributes.editorialVideo && (data.attributes.editorialVideo.motionArtistWide16x9 || data.attributes.editorialVideo.motionArtistFullscreen16x9)) }"
|
||||
>
|
||||
<button class="artist-play" @click="app.mk.setStationQueue({artist:'a-'+data.id}).then(()=>{
|
||||
app.mk.play()
|
||||
})"><%- include("../svg/play.svg") %></button>
|
||||
<h1>{{ data.attributes.name }}</h1>
|
||||
<h1>{{ data.attributes.name }}</h1>
|
||||
</div>
|
||||
</div>
|
||||
<button class="more-btn-round" @click="artistMenu" style="pointer-events: all;">
|
||||
<div class="svg-icon"></div>
|
||||
</button>
|
||||
</div>
|
||||
<div class="artworkContainer" v-if="!(data.attributes.editorialVideo && (data.attributes.editorialVideo.motionArtistWide16x9 || data.attributes.editorialVideo.motionArtistFullscreen16x9))">
|
||||
<artwork-material :url="data.attributes.artwork.url" size="190" images="1"></artwork-material>
|
||||
</div>
|
||||
</div>
|
||||
<div class="floating-header" :style="{opacity: (headerVisible ? 0 : 1),'pointer-events': (headerVisible ? 'none' : '')}">
|
||||
<div class="row">
|
||||
<div class="col-auto flex-center">
|
||||
<button class="artist-play" style="display:block;" @click="app.mk.setStationQueue({artist:'a-'+data.id}).then(()=>{
|
||||
app.mk.play()
|
||||
})"><%- include("../svg/play.svg") %></button>
|
||||
</div>
|
||||
<div class="col">
|
||||
<h3>{{ data.attributes.name }}</h3>
|
||||
</div>
|
||||
<div class="col-auto flex-center">
|
||||
<button class="more-btn-round" @click="artistMenu">
|
||||
<div class="svg-icon"></div>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<button class="artist-more" @click="artistMenu">
|
||||
<div style=" margin-top: -1px;
|
||||
margin-left: -6px;
|
||||
width: 36px;
|
||||
height: 36px;">
|
||||
<%- include("../svg/more.svg") %>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
<div class="artist-body">
|
||||
<div class="row well">
|
||||
<div class="col">
|
||||
<div class="row">
|
||||
<div class="col-auto" v-if="data.views['latest-release'].data.length != 0">
|
||||
<h3>Latest Release</h3>
|
||||
<h3>{{app.getLz('term.latestReleases')}}</h3>
|
||||
<div style="width: auto;margin: 0 auto;">
|
||||
<mediaitem-square kind="card" v-for="song in data.views['latest-release'].data"
|
||||
:item="song">
|
||||
|
@ -53,25 +70,20 @@
|
|||
<div class="col" v-if="data.views['top-songs']">
|
||||
<div class="row">
|
||||
<div class="col" style="padding:0;">
|
||||
<h3>Top Songs</h3>
|
||||
<h3>{{app.getLz('term.topSongs')}}</h3>
|
||||
</div>
|
||||
<div class="col-auto flex-center" v-if="data.views['top-songs'].data.length >= 10" style="padding:0;">
|
||||
<button class="cd-btn-seeall" @click="app.showArtistView(data.id, data.attributes.name + ' - Top Songs', 'top-songs')">See All</button>
|
||||
<div class="col-auto flex-center" v-if="data.views['top-songs'].data.length >= 16" style="padding:0;">
|
||||
<button class="cd-btn-seeall" @click="app.showArtistView(data.id, data.attributes.name + ' - Top Songs', 'top-songs')">{{app.getLz('term.seeAll')}}</button>
|
||||
</div>
|
||||
</div>
|
||||
<mediaitem-list-item
|
||||
v-for="(song, index) in data.views['top-songs'].data.limit(topSongsExpanded ? 10 : 5)"
|
||||
<div class="mediaitem-list-item__grid">
|
||||
<div class="grid-body">
|
||||
<mediaitem-list-item
|
||||
v-for="(song, index) in data.views['top-songs'].data.limit(16)"
|
||||
:index="index"
|
||||
:item="song"></mediaitem-list-item>
|
||||
<button class="showmoreless"
|
||||
@click="topSongsExpanded = !topSongsExpanded">
|
||||
<template v-if="!topSongsExpanded">
|
||||
Show more
|
||||
</template>
|
||||
<template v-else>
|
||||
Show less
|
||||
</template>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -87,7 +99,7 @@
|
|||
</h3>
|
||||
</div>
|
||||
<div class="col-auto flex-center" v-if="data.views[view].data.length >= 10">
|
||||
<button class="cd-btn-seeall" @click="app.showArtistView(data.id, data.attributes.name + ' - ' + data.views[view].attributes.title, view)">See All</button>
|
||||
<button class="cd-btn-seeall" @click="app.showArtistView(data.id, data.attributes.name + ' - ' + data.views[view].attributes.title, view)">{{app.getLz('term.seeAll')}}</button>
|
||||
</div>
|
||||
</div>
|
||||
<template v-if="!((data.views[view].attributes.title ?
|
||||
|
@ -103,7 +115,7 @@
|
|||
</template>
|
||||
<div class="row">
|
||||
<div class="col" v-if="data.attributes.artistBio">
|
||||
<h3>About {{ data.attributes.name }}</h3>
|
||||
<h3>{{ app.getLz('term.about') }} {{ data.attributes.name }}</h3>
|
||||
<p v-html="data.attributes.artistBio"></p>
|
||||
</div>
|
||||
<div class="col">
|
||||
|
@ -116,7 +128,7 @@
|
|||
{{ data.attributes.bornOrFormed }}
|
||||
</div>
|
||||
<div v-if="data.attributes.genreNames">
|
||||
<h3>Genre</h3>
|
||||
<h3>{{app.getLz('term.sortBy.genre')}}</h3>
|
||||
{{ data.attributes.genreNames.join(', ') }}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -133,24 +145,28 @@
|
|||
data: function () {
|
||||
return {
|
||||
topSongsExpanded: false,
|
||||
app: this.$root
|
||||
app: this.$root,
|
||||
headerVisible: true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
isHeaderVisible(visible) {
|
||||
this.headerVisible = visible
|
||||
},
|
||||
artistMenu (event) {
|
||||
let self = this
|
||||
let followAction = "follow"
|
||||
let followActions = {
|
||||
follow: {
|
||||
icon: "./assets/feather/plus-circle.svg",
|
||||
name: "Follow Artist",
|
||||
name: app.getLz('action.follow'),
|
||||
action: ()=>{
|
||||
self.app.cfg.home.followedArtists.push(self.data.id)
|
||||
}
|
||||
},
|
||||
unfollow: {
|
||||
icon: "./assets/feather/x-circle.svg",
|
||||
name: "Unfollow Artist",
|
||||
name: app.getLz('action.unfollow'),
|
||||
action: ()=>{
|
||||
let index = self.app.cfg.home.followedArtists.indexOf(self.data.id)
|
||||
if (index > -1) {
|
||||
|
@ -166,7 +182,7 @@
|
|||
items: [
|
||||
{
|
||||
icon: "./assets/feather/play.svg",
|
||||
name: "Play Artist Radio",
|
||||
name: app.getLz('action.startRadio'),
|
||||
action: ()=>{
|
||||
app.mk.setStationQueue({artist:self.data.id}).then(()=>{
|
||||
app.mk.play()
|
||||
|
@ -176,7 +192,7 @@
|
|||
followActions[followAction],
|
||||
{
|
||||
icon: "./assets/feather/share.svg",
|
||||
name: "Share",
|
||||
name: app.getLz('term.share'),
|
||||
action: ()=>{
|
||||
self.app.copyToClipboard(self.data.attributes.url)
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<script type="text/x-template" id="cider-browse">
|
||||
<div class="content-inner">
|
||||
<h1 class="header-text">Browse</h1>
|
||||
<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">
|
||||
|
@ -8,7 +8,7 @@
|
|||
<h3>{{ recom.attributes.name ?? ""}}</h3>
|
||||
</div>
|
||||
<div class="col-auto 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')" >See All</button>
|
||||
<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))">
|
||||
|
|
|
@ -7,81 +7,118 @@
|
|||
</div>
|
||||
</template>
|
||||
<template v-if="app.playlists.loadingState == 1">
|
||||
<div class="playlist-display row"
|
||||
<div class="playlist-display"
|
||||
:style="{
|
||||
background: (data.attributes.artwork != null && data.attributes.artwork['bgColor'] != null) ? ('#' + data.attributes.artwork.bgColor) : '',
|
||||
color: (data.attributes.artwork != null && data.attributes.artwork['textColor1'] != null) ? ('#' + data.attributes.artwork.textColor1) : ''
|
||||
'--bgColor': (data.attributes.artwork != null && data.attributes.artwork['bgColor'] != null) ? ('#' + data.attributes.artwork.bgColor) : '',
|
||||
'--textColor': (data.attributes.artwork != null && data.attributes.artwork['textColor1'] != null) ? ('#' + data.attributes.artwork.textColor1) : ''
|
||||
}">
|
||||
<div class="col-auto flex-center">
|
||||
<div style="width: 260px;height:260px;">
|
||||
<mediaitem-artwork
|
||||
:video-priority="true"
|
||||
:url="(data.attributes != null && data.attributes.artwork != null) ? data.attributes.artwork.url : ((data.relationships != null && data.relationships.tracks.data.length > 0 && data.relationships.tracks.data[0].attributes != null) ? ((data.relationships.tracks.data[0].attributes.artwork != null)? data.relationships.tracks.data[0].attributes.artwork.url : ''):'')"
|
||||
:video="(data.attributes != null && data.attributes.editorialVideo != null) ? (data.attributes.editorialVideo.motionDetailSquare ? data.attributes.editorialVideo.motionDetailSquare.video : (data.attributes.editorialVideo.motionSquareVideo1x1 ? data.attributes.editorialVideo.motionSquareVideo1x1.video : '')) : '' "
|
||||
size="260"
|
||||
></mediaitem-artwork>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col playlist-info">
|
||||
<template v-if="!editorialNotesExpanded">
|
||||
<div>
|
||||
<div class="playlist-name" @click="editPlaylistName()" v-show="!nameEditing">
|
||||
{{data.attributes ? (data.attributes.name ??
|
||||
(data.attributes.title ?? '') ?? '') : ''}}
|
||||
<div class="playlistInfo">
|
||||
<div class="row">
|
||||
<div class="col-auto flex-center">
|
||||
<div style="width: 260px;height:260px;">
|
||||
<mediaitem-artwork
|
||||
shadow="large"
|
||||
:video-priority="true"
|
||||
:url="(data.attributes != null && data.attributes.artwork != null) ? data.attributes.artwork.url : ((data.relationships != null && data.relationships.tracks.data.length > 0 && data.relationships.tracks.data[0].attributes != null) ? ((data.relationships.tracks.data[0].attributes.artwork != null)? data.relationships.tracks.data[0].attributes.artwork.url : ''):'')"
|
||||
:video="(data.attributes != null && data.attributes.editorialVideo != null) ? (data.attributes.editorialVideo.motionDetailSquare ? data.attributes.editorialVideo.motionDetailSquare.video : (data.attributes.editorialVideo.motionSquareVideo1x1 ? data.attributes.editorialVideo.motionSquareVideo1x1.video : '')) : '' "
|
||||
size="260"
|
||||
></mediaitem-artwork>
|
||||
</div>
|
||||
<div class="playlist-name" v-show="nameEditing"><input type="text" spellcheck="false"
|
||||
class="nameEdit"
|
||||
v-model="data.attributes.name"
|
||||
@blur="editPlaylist"
|
||||
@change="editPlaylist"
|
||||
@keydown.enter="editPlaylist"/></div>
|
||||
<div class="playlist-artist item-navigate"
|
||||
v-if="getArtistName(data) != ''"
|
||||
@click="data.attributes && data.attributes.artistName ? app.searchAndNavigate(data,'artist') : ''">
|
||||
{{getArtistName(data)}}
|
||||
</div>
|
||||
<div class="playlist-desc" v-if="data.attributes.description && (data.attributes.description.standard || data.attributes.description.short)">
|
||||
<div v-if="data.attributes.description.short" class="content" v-html="data.attributes.description.short"></div>
|
||||
<div v-else-if="data.attributes.description.standard" class="content" v-html="data.attributes.description.standard"></div>
|
||||
<button v-if="data.attributes.description.short" class="more-btn"
|
||||
@click="editorialNotesExpanded = !editorialNotesExpanded">
|
||||
More
|
||||
</div>
|
||||
<div class="col playlist-info">
|
||||
<template v-if="!editorialNotesExpanded">
|
||||
<div>
|
||||
<div class="playlist-name" @click="editPlaylistName()" v-show="!nameEditing">
|
||||
{{data.attributes ? (data.attributes.name ??
|
||||
(data.attributes.title ?? '') ?? '') : ''}}
|
||||
</div>
|
||||
<div class="playlist-name" v-show="nameEditing"><input type="text" spellcheck="false"
|
||||
class="nameEdit"
|
||||
v-model="data.attributes.name"
|
||||
@blur="editPlaylist"
|
||||
@change="editPlaylist"
|
||||
@keydown.enter="editPlaylist"/></div>
|
||||
<div class="playlist-artist item-navigate"
|
||||
v-if="getArtistName(data) != ''"
|
||||
@click="data.attributes && data.attributes.artistName ? app.searchAndNavigate(data,'artist') : ''">
|
||||
{{getArtistName(data)}}
|
||||
</div>
|
||||
<div class="playlist-desc" v-if="data.attributes.description && (data.attributes.description.standard || data.attributes.description.short)">
|
||||
<div v-if="data.attributes.description.short" class="content" v-html="data.attributes.description.short"></div>
|
||||
<div v-else-if="data.attributes.description.standard" class="content" v-html="data.attributes.description.standard"></div>
|
||||
<button v-if="data.attributes.description.short" class="more-btn"
|
||||
@click="editorialNotesExpanded = !editorialNotesExpanded">
|
||||
{{app.getLz('term.showMore')}}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template v-if="editorialNotesExpanded">
|
||||
<div class="playlist-desc-expanded">
|
||||
<div class="content"
|
||||
v-html="((data.attributes.editorialNotes) ? (data.attributes.editorialNotes.standard ?? (data.attributes.editorialNotes.short ?? '') ) : (data.attributes.description ? (data.attributes.description.standard ?? (data.attributes.description.short ?? '')) : ''))"></div>
|
||||
<button class="more-btn" @click="editorialNotesExpanded = !editorialNotesExpanded">{{app.getLz('term.showLess')}}
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
<div class="playlist-controls" v-observe-visibility="{callback: isHeaderVisible}">
|
||||
<button class="md-btn md-btn-primary md-btn-icon" style="min-width: 100px;"
|
||||
@click="app.mk.shuffleMode = 0; play()"> <img class="md-ico-play">
|
||||
{{app.getLz('term.play')}}
|
||||
</button>
|
||||
<button class="md-btn md-btn-primary md-btn-icon" style="min-width: 100px;"
|
||||
@click="app.mk.shuffleMode = 1;play()"> <img class="md-ico-shuffle">
|
||||
{{app.getLz('term.shuffle')}}
|
||||
</button>
|
||||
<button class="md-btn md-btn-icon" style="min-width: 180px;" v-if="inLibrary!=null && confirm!=true"
|
||||
@click="confirmButton()"> <img :class="(!inLibrary) ? 'md-ico-add' : 'md-ico-remove'">
|
||||
{{ (!inLibrary) ? app.getLz('action.addToLibrary') : app.getLz("action.removeFromLibrary") }}
|
||||
</button>
|
||||
<button class="md-btn md-btn-icon" style="min-width: 180px;" v-if="confirm==true"
|
||||
@click="(!inLibrary) ? addToLibrary(data.attributes.playParams.id.toString()) : removeFromLibrary(data.attributes.playParams.id.toString()) "> <img :class="(!inLibrary) ? 'md-ico-add' : 'md-ico-remove'">
|
||||
{{app.getLz('term.confirm')}}
|
||||
</button>
|
||||
<button class="more-btn-round" style="float:right;" @click="menu">
|
||||
<div class="svg-icon"></div>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template v-if="editorialNotesExpanded">
|
||||
<div class="playlist-desc-expanded">
|
||||
<div class="content"
|
||||
v-html="((data.attributes.editorialNotes) ? (data.attributes.editorialNotes.standard ?? (data.attributes.editorialNotes.short ?? '') ) : (data.attributes.description ? (data.attributes.description.standard ?? (data.attributes.description.short ?? '')) : ''))"></div>
|
||||
<button class="more-btn" @click="editorialNotesExpanded = !editorialNotesExpanded">Less
|
||||
</div>
|
||||
</div>
|
||||
<div class="artworkContainer" v-if="data.attributes.artwork != null">
|
||||
<artwork-material :url="data.attributes.artwork.url" size="260" images="1"></artwork-material>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="floating-header" :style="{opacity: (headerVisible ? 0 : 1),'pointer-events': (headerVisible ? 'none' : '')}">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<h3>{{data.attributes ? (data.attributes.name ??
|
||||
(data.attributes.title ?? '') ?? '') : ''}}</h3>
|
||||
</div>
|
||||
<div class="col-auto flex-center">
|
||||
<div>
|
||||
<button class="md-btn md-btn-primary md-btn-icon" style="min-width: 100px;"
|
||||
@click="app.mk.shuffleMode = 0; play()"> <img class="md-ico-play">
|
||||
{{app.getLz('term.play')}}
|
||||
</button>
|
||||
<button class="md-btn md-btn-primary md-btn-icon" style="min-width: 100px;"
|
||||
@click="app.mk.shuffleMode = 1;play()"> <img class="md-ico-shuffle">
|
||||
{{app.getLz('term.shuffle')}}
|
||||
</button>
|
||||
<button class="md-btn md-btn-icon" style="min-width: 180px;" v-if="inLibrary!=null && confirm!=true"
|
||||
@click="confirmButton()"> <img :class="(!inLibrary) ? 'md-ico-add' : 'md-ico-remove'">
|
||||
{{ (!inLibrary) ? app.getLz('action.addToLibrary') : app.getLz("action.removeFromLibrary") }}
|
||||
</button>
|
||||
<button class="md-btn md-btn-icon" style="min-width: 180px;" v-if="confirm==true"
|
||||
@click="(!inLibrary) ? addToLibrary(data.attributes.playParams.id.toString()) : removeFromLibrary(data.attributes.playParams.id.toString()) "> <img :class="(!inLibrary) ? 'md-ico-add' : 'md-ico-remove'">
|
||||
{{app.getLz('term.confirm')}}
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
<div class="playlist-controls">
|
||||
<button class="md-btn" style="min-width: 120px;"
|
||||
@click="app.mk.shuffleMode = 0; play()">
|
||||
Play
|
||||
</button>
|
||||
<button class="md-btn" style="min-width: 120px;"
|
||||
@click="app.mk.shuffleMode = 1;play()">
|
||||
Shuffle
|
||||
</button>
|
||||
<button class="md-btn" style="min-width: 120px;" v-if="inLibrary!=null && confirm!=true"
|
||||
@click="confirmButton()">
|
||||
{{ (!inLibrary) ? "Add to Library" : "Remove from Library" }}
|
||||
</button>
|
||||
<button class="md-btn" style="min-width: 120px;" v-if="confirm==true"
|
||||
@click="(!inLibrary) ? addToLibrary(data.attributes.playParams.id.toString()) : removeFromLibrary(data.attributes.playParams.id.toString()) ">
|
||||
Confirm?
|
||||
</button>
|
||||
<button class="playlist-more" @click="menu">
|
||||
<div style=" margin-top: -1px;
|
||||
margin-left: -5px;
|
||||
width: 36px;
|
||||
height: 36px;">
|
||||
<%- include("../svg/more.svg") %>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-auto flex-center">
|
||||
<button class="more-btn-round" style="float:right;" @click="menu">
|
||||
<div class="svg-icon"></div>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -91,7 +128,7 @@
|
|||
<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()">
|
||||
<mediaitem-list-item :item="item" :parent="getItemParent(data)" :index="index"
|
||||
<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>
|
||||
</draggable>
|
||||
|
@ -118,6 +155,25 @@
|
|||
style="width: 50%;">
|
||||
{{data.attributes.copyright}}
|
||||
</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" @click="app.routeView(data.relationships.catalog.data[0])">
|
||||
{{$root.getLz("term.showAlbum")}}
|
||||
</div>
|
||||
</template>
|
||||
<hr>
|
||||
<template v-if="typeof data.meta != 'undefined'">
|
||||
<div v-for="view in data.meta.views.order" v-if="data.views[view].data.length != 0">
|
||||
<div class="row" >
|
||||
<div class="col">
|
||||
<h3>{{ data.views[view].attributes.title }}</h3>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<mediaitem-scroller-horizontal :items="data.views[view].data"></mediaitem-scroller-horizontal>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
|
@ -138,7 +194,8 @@
|
|||
confirm: false,
|
||||
app: this.$root,
|
||||
itemBadges: [],
|
||||
badgesRequested: false
|
||||
badgesRequested: false,
|
||||
headerVisible: true
|
||||
}
|
||||
},
|
||||
mounted: function () {
|
||||
|
@ -153,6 +210,9 @@
|
|||
}
|
||||
},
|
||||
methods: {
|
||||
isHeaderVisible(visible) {
|
||||
this.headerVisible = visible
|
||||
},
|
||||
getBadges() {
|
||||
return
|
||||
if (this.badgesRequested) {
|
||||
|
@ -171,8 +231,8 @@
|
|||
let friends = 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])
|
||||
})
|
||||
})
|
||||
}
|
||||
|
@ -205,7 +265,7 @@
|
|||
"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 && res.attributes && res.attributes.inLibrary) ? res.attributes.inLibrary : false
|
||||
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
|
||||
|
@ -229,12 +289,16 @@
|
|||
const params = {"fields[somgs]": "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 && res.relationships && res.relationships.library && res.relationships.library.data && res.relationships.library.data.length > 0) {
|
||||
id = res.relationships.library.data[0].id
|
||||
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.library.remove({[truekind]: id})
|
||||
app.mk.api.v3.music(`v1/me/library/${truekind}/${id.toString()}`,{},
|
||||
{
|
||||
fetchOptions: {
|
||||
method: "DELETE"
|
||||
}})
|
||||
this.inLibrary = false
|
||||
this.confirm = false
|
||||
},
|
||||
|
@ -254,7 +318,7 @@
|
|||
return {
|
||||
normal: [
|
||||
{
|
||||
name: 'Remove from Playlist',
|
||||
name: app.getLz('action.removeFromPlaylist'),
|
||||
action: () => {
|
||||
self.remove()
|
||||
}
|
||||
|
@ -262,7 +326,7 @@
|
|||
],
|
||||
multiple: [
|
||||
{
|
||||
name: 'Remove selected tracks from Playlist',
|
||||
name: app.getLz('action.removeFromPlaylist'),
|
||||
action: () => {
|
||||
self.remove()
|
||||
}
|
||||
|
@ -274,7 +338,19 @@
|
|||
if (!this.data.attributes.canEdit) {
|
||||
return
|
||||
}
|
||||
await app.mk.api.library.putPlaylistTracklisting(this.data.attributes.playParams.id, this.convert())
|
||||
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) {
|
||||
|
@ -312,7 +388,7 @@
|
|||
app.showMenuPanel({
|
||||
items: {
|
||||
"share": {
|
||||
name: "Share",
|
||||
name: app.getLz('term.share'),
|
||||
icon: "./assets/feather/share.svg",
|
||||
action: () => {
|
||||
let route = ""
|
||||
|
@ -353,24 +429,32 @@
|
|||
if (date == null || date === "") return "";
|
||||
switch (date) {
|
||||
case this.data.attributes.releaseDate:
|
||||
prefix = 'Released '
|
||||
prefix = this.app.getLz('term.time.released')+ ' '
|
||||
break;
|
||||
case this.data.attributes.lastModifiedDate:
|
||||
prefix = 'Updated '
|
||||
prefix = this.app.getLz('term.time.updated')+ ' '
|
||||
break;
|
||||
case this.data.attributes.dateAdded:
|
||||
prefix = 'Added '
|
||||
prefix = this.app.getLz('term.time.added')+ ' '
|
||||
break;
|
||||
}
|
||||
let month, year;
|
||||
try {
|
||||
const releaseDate = new Date(date);
|
||||
console.log(date, releaseDate)
|
||||
month = new Intl.DateTimeFormat('en-US', {month: 'long'}).format(releaseDate);
|
||||
date = releaseDate.getDate();
|
||||
year = releaseDate.getFullYear();
|
||||
|
||||
return prefix + date + " " + month + " " + year;
|
||||
// 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 ""
|
||||
}
|
||||
|
@ -411,4 +495,4 @@
|
|||
|
||||
}
|
||||
})
|
||||
</script>
|
||||
</script>
|
||||
|
|
|
@ -14,13 +14,16 @@
|
|||
<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}">Show More</button>
|
||||
<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()">
|
||||
<%- include("../svg/arrow-up.svg") %>
|
||||
</button>
|
||||
</transition>
|
||||
<div class="well" v-show="loading"><div class="spinner"></div></div>
|
||||
</div>
|
||||
</script>
|
||||
<script>
|
||||
|
@ -47,16 +50,18 @@
|
|||
canSeeTrigger: false,
|
||||
showFab: false,
|
||||
commonKind: "song",
|
||||
api: this.$root.mk.api
|
||||
api: this.$root.mk.api,
|
||||
loading: false,
|
||||
app: this.$root,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getKind(item) {
|
||||
if(typeof item.kind != "undefined") {
|
||||
if (typeof item.kind != "undefined") {
|
||||
this.commonKind = item.kind;
|
||||
return item.kind
|
||||
}
|
||||
if(typeof item.attributes.playParams != "undefined") {
|
||||
if (typeof item.attributes.playParams != "undefined") {
|
||||
this.commonKind = item.attributes.playParams.kind
|
||||
return item.attributes.playParams.kind
|
||||
}
|
||||
|
@ -71,73 +76,48 @@
|
|||
})
|
||||
},
|
||||
getNext() {
|
||||
// if this.data.next is not null, then we can run this.data.next() and concat to this.data.data to get the next page
|
||||
switch(this.type) {
|
||||
default:
|
||||
case "artists":
|
||||
if (this.data.next && this.triggerEnabled) {
|
||||
this.triggerEnabled = false;
|
||||
|
||||
let nextFn = (data => {
|
||||
console.log(data);
|
||||
this.data.next = data.next;
|
||||
this.data.data = this.data.data.concat(data.data);
|
||||
this.triggerEnabled = true;
|
||||
});
|
||||
if(typeof this.data.next == "function") {
|
||||
this.data.next().then(data => nextFn(data));
|
||||
}else{
|
||||
this.api.v3.music(this.data.next).then(data => nextFn(data));
|
||||
}
|
||||
}else{
|
||||
console.log("No next page");
|
||||
this.triggerEnabled = false;
|
||||
}
|
||||
break;
|
||||
case "search":
|
||||
if (this.data.next && this.triggerEnabled) {
|
||||
this.triggerEnabled = false;
|
||||
this.data.next().then(data => {
|
||||
console.log(data);
|
||||
this.data.next = data[this.data.groups].next;
|
||||
this.data.data = this.data.data.concat(data[this.data.groups].data.data);
|
||||
this.triggerEnabled = true;
|
||||
});
|
||||
}else{
|
||||
console.log("No next page");
|
||||
this.triggerEnabled = false;
|
||||
}
|
||||
break;
|
||||
case "listen_now":
|
||||
case "curator":
|
||||
if (this.data.next && this.triggerEnabled) {
|
||||
this.triggerEnabled = false;
|
||||
app.mk.api.v3.music(this.data.next).then(data => {
|
||||
console.log(data);
|
||||
this.data.next = data.data.next;
|
||||
this.data.data = this.data.data.concat(data.data.data);
|
||||
this.triggerEnabled = true;
|
||||
});
|
||||
}else{
|
||||
console.log("No next page");
|
||||
this.triggerEnabled = false;
|
||||
}
|
||||
break;
|
||||
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) {
|
||||
if (isVisible) {
|
||||
this.showFab = false;
|
||||
}else{
|
||||
} else {
|
||||
this.showFab = true;
|
||||
}
|
||||
},
|
||||
visibilityChanged: function (isVisible, entry) {
|
||||
if(isVisible) {
|
||||
if (isVisible) {
|
||||
this.canSeeTrigger = true;
|
||||
this.getNext();
|
||||
}else{
|
||||
} else {
|
||||
this.canSeeTrigger = false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<div v-if="page == 'main'">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<h3>Recently Played</h3>
|
||||
<h3>{{app.getLz('home.recentlyPlayed')}}</h3>
|
||||
<div class="well artistfeed-well">
|
||||
<template v-if="isSectionReady('recentlyPlayed')">
|
||||
<mediaitem-list-item v-for="item in recentlyPlayed.limit(6)"
|
||||
|
@ -15,10 +15,10 @@
|
|||
<div class="col">
|
||||
<div class="row nopadding">
|
||||
<div class="col nopadding">
|
||||
<h3>Your Artists Feed</h3>
|
||||
<h3>{{app.getLz('home.artistsFeed')}}</h3>
|
||||
</div>
|
||||
<div class="col-auto nopadding flex-center">
|
||||
<button class="cd-btn-seeall" @click="app.appRoute('artist-feed')">See All</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;">
|
||||
|
@ -26,7 +26,7 @@
|
|||
<mediaitem-list-item v-for="item in artistFeed.limit(6)" :item="item"></mediaitem-list-item>
|
||||
</template>
|
||||
<div class="spinner" v-else-if="followedArtists.length > 0"></div>
|
||||
<div class="no-artist" v-else> Follow some artists first and their latest releases will be here</div>
|
||||
<div class="no-artist" v-else> {{app.getLz('home.artistsFeed.noArtist')}}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -44,7 +44,7 @@
|
|||
<!-- </div>-->
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<h3>Made For You</h3>
|
||||
<h3>{{app.getLz('home.madeForYou')}}</h3>
|
||||
<div class="well">
|
||||
<template v-if="isSectionReady('madeForYou')">
|
||||
<mediaitem-square kind="small" v-for="item in madeForYou" :item="item"></mediaitem-square>
|
||||
|
@ -57,10 +57,10 @@
|
|||
<div class="col">
|
||||
<div class="row">
|
||||
<div class="col nopadding">
|
||||
<h3>Friends Listening To</h3>
|
||||
<h3>{{app.getLz('home.friendsListeningTo')}}</h3>
|
||||
</div>
|
||||
<div class="col-auto nopadding flex-center">
|
||||
<button class="cd-btn-seeall" @click="app.showSocialListeningTo()">See All</button>
|
||||
<button class="cd-btn-seeall" @click="app.showSocialListeningTo()">{{app.getLz('term.seeAll')}}</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="well">
|
||||
|
@ -131,32 +131,22 @@
|
|||
playlists.push(item.id)
|
||||
}
|
||||
}
|
||||
if (playlists.length != 0) {
|
||||
this.app.mk.api.playlists(playlists).then(playlistsData => {
|
||||
self.favorites.push(...playlistsData)
|
||||
if (playlists.length != 0) {
|
||||
this.app.mk.api.v3.music(`/v1/catalog/${app.mk.storefrontId}/playlists/${playlists.toString()}`).then(playlistsData => {
|
||||
self.favorites.push(...playlistsData.data)
|
||||
})
|
||||
}
|
||||
if (libraryPlaylists.length != 0) {
|
||||
this.app.mk.api.library.playlists(libraryPlaylists).then(playlistsData => {
|
||||
self.favorites.push(...playlistsData)
|
||||
if (libraryPlaylists.length != 0) {
|
||||
this.app.mk.api.v3.music(`v1/me/library/playlists/${playlists.toString()}`).then(playlistsData => {
|
||||
self.favorites.push(...playlistsData.data)
|
||||
})
|
||||
}
|
||||
},
|
||||
async getArtistFeed() {
|
||||
let artists = this.followedArtists
|
||||
let self = this
|
||||
this.app.mk.api.artists(artists, {
|
||||
"views": "featured-release,full-albums,appears-on-albums,featured-albums,featured-on-albums,singles,compilation-albums,live-albums,latest-release,top-music-videos,similar-artists,top-songs,playlists,more-to-hear,more-to-see",
|
||||
"extend": "artistBio,bornOrFormed,editorialArtwork,editorialVideo,isGroup,origin,hero",
|
||||
"extend[playlists]": "trackCount",
|
||||
"include[songs]": "albums",
|
||||
"fields[albums]": "artistName,artistUrl,artwork,contentRating,editorialArtwork,editorialVideo,name,playParams,releaseDate,url,trackCount",
|
||||
"limit[artists:top-songs]": 20,
|
||||
"art[url]": "f"
|
||||
}, {
|
||||
includeResponseMeta: !0
|
||||
}).then(artistData => {
|
||||
artistData.data.forEach(item => {
|
||||
this.app.mk.api.v3.music(`/v1/catalog/${app.mk.storefrontId}/artists?ids=${artists.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`).then(artistData => {
|
||||
artistData.data.data.forEach(item => {
|
||||
if (item.views["latest-release"].data.length != 0) {
|
||||
self.artistFeed.push(item.views["latest-release"].data[0])
|
||||
}
|
||||
|
@ -176,35 +166,10 @@
|
|||
},
|
||||
async getListenNowData() {
|
||||
let self = this
|
||||
this.app.mk.api.personalRecommendations("", {
|
||||
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-profiles,social-upsells",
|
||||
platform: "web"
|
||||
}, {
|
||||
includeResponseMeta: !0,
|
||||
reload: !0
|
||||
}).then((data) => {
|
||||
console.log(data.data[1])
|
||||
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`).then((data) => {
|
||||
console.log(data.data.data[1])
|
||||
try {
|
||||
self.madeForYou = data.data.filter(section => {
|
||||
self.madeForYou = data.data.data.filter(section => {
|
||||
if (section.meta.metrics.moduleType == "6") {
|
||||
return section
|
||||
};
|
||||
|
@ -213,8 +178,8 @@
|
|||
self.sectionsReady.push("madeForYou")
|
||||
|
||||
try {
|
||||
self.recentlyPlayed = data.data[1].relationships.contents.data
|
||||
self.friendsListeningTo = data.data.filter(section => {
|
||||
self.recentlyPlayed = data.data.data[1].relationships.contents.data
|
||||
self.friendsListeningTo = data.data.data.filter(section => {
|
||||
if (section.meta.metrics.moduleType == "11") {
|
||||
return section
|
||||
};
|
||||
|
@ -228,7 +193,7 @@
|
|||
self.profile = response.data.data[0]
|
||||
})
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
|
@ -2,7 +2,7 @@
|
|||
<div class="content-inner">
|
||||
<div class="row">
|
||||
<div class="col" style="padding:0;">
|
||||
<h1 class="header-text">Albums</h1>
|
||||
<h1 class="header-text">{{$root.getLz('term.albums')}}</h1>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<button v-if="library.albums.downloadState == 2" @click="getLibraryAlbumsFull(true, 1)" class="reload-btn"><%- include('../svg/redo.svg') %></button>
|
||||
|
@ -15,7 +15,7 @@
|
|||
<input type="search"
|
||||
style="width:100%;"
|
||||
spellcheck="false"
|
||||
placeholder="Search..."
|
||||
:placeholder="$root.getLz('term.search') + '...'"
|
||||
@input="searchLibraryAlbums"
|
||||
v-model="library.albums.search" class="search-input">
|
||||
</div>
|
||||
|
@ -24,24 +24,24 @@
|
|||
<div class="row">
|
||||
<div class="col">
|
||||
<select class="md-select" v-model="library.albums.sorting[1]" @change="searchLibraryAlbums(1)">
|
||||
<optgroup label="Sort By">
|
||||
<optgroup :label="$root.getLz('term.sortBy')">
|
||||
<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="library.albums.sortOrder[1]" @change="searchLibraryAlbums(1)">
|
||||
<optgroup label="Sort Order">
|
||||
<option value="asc">Ascending</option>
|
||||
<option value="desc">Descending</option>
|
||||
<optgroup :label="$root.getLz('term.sortOrder')">
|
||||
<option value="asc">{{$root.getLz('term.sortOrder.ascending')}}</option>
|
||||
<option value="desc">{{$root.getLz('term.sortOrder.descending')}}</option>
|
||||
</optgroup>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col">
|
||||
<select class="md-select" v-model="library.albums.viewAs">
|
||||
<optgroup label="View As">
|
||||
<option value="covers">Cover Art</option>
|
||||
<option value="list">List</option>
|
||||
<optgroup :label="$root.getLz('term.viewAs')">
|
||||
<option value="covers">{{$root.getLz('term.viewAs.coverArt')}}</option>
|
||||
<option value="list">{{$root.getLz('term.viewAs.list')}}</option>
|
||||
</optgroup>
|
||||
</select>
|
||||
</div>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<div class="content-inner">
|
||||
<div class="row">
|
||||
<div class="col" style="padding:0;">
|
||||
<h1 class="header-text">Artists</h1>
|
||||
<h1 class="header-text">{{$root.getLz('term.artists')}}</h1>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
@ -12,7 +12,7 @@
|
|||
<input type="search"
|
||||
style="width:100%;"
|
||||
spellcheck="false"
|
||||
placeholder="Search..."
|
||||
:placeholder="$root.getLz('term.search') + '...'"
|
||||
@input="searchLibraryArtists"
|
||||
v-model="library.artists.search" class="search-input">
|
||||
</div>
|
||||
|
@ -28,9 +28,9 @@
|
|||
</div> -->
|
||||
<div class="col">
|
||||
<select class="md-select" v-model="library.artists.sortOrder[1]" @change="searchLibraryArtists(1)">
|
||||
<optgroup label="Sort Order">
|
||||
<option value="asc">Ascending</option>
|
||||
<option value="desc">Descending</option>
|
||||
<optgroup :label="$root.getLz('term.sortOrder')">
|
||||
<option value="asc">{{$root.getLz('term.sortOrder.ascending')}}</option>
|
||||
<option value="desc">{{$root.getLz('term.sortOrder.descending')}}</option>
|
||||
</optgroup>
|
||||
</select>
|
||||
</div>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<div class="content-inner">
|
||||
<div class="row">
|
||||
<div class="col" style="padding:0;">
|
||||
<h1 class="header-text">Recently Added</h1>
|
||||
<h1 class="header-text">{{$root.getLz('term.recentlyAdded')}}</h1>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<button v-if="library.albums.downloadState == 2" @click="getLibraryAlbumsFull(true, 0)"
|
||||
|
@ -16,7 +16,7 @@
|
|||
<input type="search"
|
||||
style="width:100%;"
|
||||
spellcheck="false"
|
||||
placeholder="Search..."
|
||||
:placeholder="$root.getLz('term.search') + '...'"
|
||||
@input="searchLibraryAlbums"
|
||||
v-model="library.albums.search" class="search-input">
|
||||
</div>
|
||||
|
@ -26,17 +26,17 @@
|
|||
<div class="col">
|
||||
<select class="md-select" v-model="library.albums.sortOrder[0]"
|
||||
@change="searchLibraryAlbums(0)">
|
||||
<optgroup label="Sort Order">
|
||||
<option value="asc">Ascending</option>
|
||||
<option value="desc">Descending</option>
|
||||
<optgroup :label="$root.getLz('term.sortOrder')">
|
||||
<option value="asc">{{$root.getLz('term.sortOrder.ascending')}}</option>
|
||||
<option value="desc">{{$root.getLz('term.sortOrder.descending')}}</option>
|
||||
</optgroup>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col">
|
||||
<select class="md-select" v-model="library.albums.viewAs">
|
||||
<optgroup label="View As">
|
||||
<option value="covers">Cover Art</option>
|
||||
<option value="list">List</option>
|
||||
<optgroup :label="$root.getLz('term.viewAs')">
|
||||
<option value="covers">{{$root.getLz('term.viewAs.coverArt')}}</option>
|
||||
<option value="list">{{$root.getLz('term.viewAs.list')}}</option>
|
||||
</optgroup>
|
||||
</select>
|
||||
</div>
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
<input type="search"
|
||||
style="width:100%;"
|
||||
spellcheck="false"
|
||||
placeholder="Search..."
|
||||
:placeholder="app.getLz('term.search') + '...'"
|
||||
@input="$root.searchLibrarySongs"
|
||||
v-model="library.songs.search" class="search-input">
|
||||
</div>
|
||||
|
@ -19,24 +19,24 @@
|
|||
<div class="row">
|
||||
<div class="col">
|
||||
<select class="md-select" v-model="prefs.sort" @change="$root.searchLibrarySongs()">
|
||||
<optgroup label="Sort By">
|
||||
<optgroup :label="app.getLz('term.sortBy')">
|
||||
<option v-for="(sort, index) in library.songs.sortingOptions" :value="index">{{ sort }}</option>
|
||||
</optgroup>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col">
|
||||
<select class="md-select" v-model="prefs.sortOrder" @change="$root.searchLibrarySongs()">
|
||||
<optgroup label="Sort Order">
|
||||
<option value="asc">Ascending</option>
|
||||
<option value="desc">Descending</option>
|
||||
<optgroup :label="app.getLz('term.sortOrder')">
|
||||
<option value="asc">{{app.getLz('term.sortOrder.ascending')}}</option>
|
||||
<option value="desc">{{app.getLz('term.sortOrder.descending')}}</option>
|
||||
</optgroup>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col">
|
||||
<select class="md-select" v-model="prefs.size" @change="$root.searchLibrarySongs()">
|
||||
<optgroup label="Size">
|
||||
<option value="normal">Normal</option>
|
||||
<option value="compact">Compact</option>
|
||||
<optgroup :label="app.getLz('term.size')">
|
||||
<option value="normal">{{app.getLz('term.size.normal')}}</option>
|
||||
<option value="compact">{{app.getLz('term.size.compact')}}</option>
|
||||
</optgroup>
|
||||
</select>
|
||||
</div>
|
||||
|
@ -68,7 +68,8 @@
|
|||
return {
|
||||
library: this.$root.library,
|
||||
mediaItemSize: "compact",
|
||||
prefs: this.$root.cfg.libraryPrefs.songs
|
||||
prefs: this.$root.cfg.libraryPrefs.songs,
|
||||
app : this.$root
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
|
32
src/renderer/views/pages/library-videos.ejs
Normal file
|
@ -0,0 +1,32 @@
|
|||
<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">
|
||||
<mediaitem-square :size="300" :item="item" v-for="item in videos">
|
||||
</mediaitem-square>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script>
|
||||
Vue.component('cider-library-videos', {
|
||||
template: "#cider-library-videos",
|
||||
props: ["data"],
|
||||
data: function(){
|
||||
return {
|
||||
videos: [],
|
||||
}
|
||||
},
|
||||
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 ?? []
|
||||
})
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
<script type="text/x-template" id="cider-listen-now">
|
||||
<div class="content-inner">
|
||||
<h1 class="header-text">Listen Now</h1>
|
||||
<h1 class="header-text">{{app.getLz('term.listenNow')}}</h1>
|
||||
<template v-for="recom in data.data">
|
||||
<listennow-child :recom="recom"></listennow-child>
|
||||
</template>
|
||||
|
@ -10,6 +10,11 @@
|
|||
<script>
|
||||
Vue.component('cider-listen-now', {
|
||||
template: "#cider-listen-now",
|
||||
props: ["data"]
|
||||
props: ["data"],
|
||||
data: function(){
|
||||
return {
|
||||
app : this.$root
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<div class="content-inner">
|
||||
<div class="row">
|
||||
<div class="col" style="padding:0">
|
||||
<h1 class="header-text">Made For You</h1>
|
||||
<h1 class="header-text">{{$root.getLz('home.madeForYou')}}</h1>
|
||||
</div>
|
||||
</div>
|
||||
<div class="madeforyou-body">
|
||||
|
|
249
src/renderer/views/pages/podcasts.ejs
Normal file
|
@ -0,0 +1,249 @@
|
|||
<script type="text/x-template" id="apple-podcasts">
|
||||
<div class="content-inner podcasts-page">
|
||||
<div class="podcasts-list">
|
||||
<div class="podcasts-search">
|
||||
<div class="search-input-container" style="width:100%;">
|
||||
<div class="search-input--icon"></div>
|
||||
<input type="search"
|
||||
style="width:100%;"
|
||||
spellcheck="false"
|
||||
:placeholder="$root.getLz('term.search') + '...'"
|
||||
@change="searchPodcasts();librarySearch()"
|
||||
v-model="search.term" class="search-input">
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="search.term == ''">
|
||||
<div class="podcast-list-header" v-if="ciderPodcasts.length != 0">
|
||||
{{$root.getLz('podcast.followedOnCider')}}
|
||||
</div>
|
||||
<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>
|
||||
</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>
|
||||
<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>
|
||||
</div>
|
||||
</div>
|
||||
<div class="episodes-list">
|
||||
<div v-if="podcastSelected.id != -1" class="episodes-inline-info">
|
||||
<div class="row">
|
||||
<div class="col-auto flex-center">
|
||||
<div class="podcast-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>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="well podcast-show-description">{{ podcastSelected.attributes.description.standard }}</div>
|
||||
<div class="row" v-if="!isSubscribed(podcastSelected.id)">
|
||||
<div class="col">
|
||||
<button class="md-btn md-btn-block">{{$root.getLz('podcast.followOnCider')}}</button>
|
||||
</div>
|
||||
<div class="col">
|
||||
<button class="md-btn md-btn-block">{{$root.getLz('podcast.subscribeOnItunes')}}</button>
|
||||
</div>
|
||||
</div>
|
||||
<h3>{{$root.getLz('podcast.episodes')}}</h3>
|
||||
</div>
|
||||
<div v-if="this.search.results.length == 0 && podcastSelected.id == -1" class="podcast-no-search-results">
|
||||
<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"
|
||||
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"></button>
|
||||
</div>
|
||||
<div class="podcast-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>
|
||||
<div class="podcast-genre">
|
||||
{{ selected.attributes.genreNames[0] }}
|
||||
</div>
|
||||
<div class="podcast-metainfo">
|
||||
{{ 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="row">
|
||||
<div class="col">
|
||||
<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">{{$root.getLz('action.share')}}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
|
||||
</div>
|
||||
</script>
|
||||
<script type="text/x-template" id="podcast-tab">
|
||||
<div class="cd-mediaitem-list-item list-flat" :class="{'mediaitem-selected': isselected}">
|
||||
<div class="artwork">
|
||||
<mediaitem-artwork
|
||||
:url="item.attributes.artwork.url"
|
||||
size="50"
|
||||
type="podcast"></mediaitem-artwork>
|
||||
</div>
|
||||
<div class="info-rect">
|
||||
<div class="title text-overflow-elipsis">
|
||||
{{ item.attributes.name }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
<script type="text/x-template" id="podcast-episode">
|
||||
<div class="cd-mediaitem-list-item list-flat" :class="{'mediaitem-selected': isselected}">
|
||||
<div class="info-rect" :style="{'padding-left':'16px'}">
|
||||
<div class="title text-overflow-elipsis">
|
||||
{{ item.attributes.name }}
|
||||
</div>
|
||||
<div class="subtitle text-overflow-elipsis">
|
||||
{{ item.attributes.description.standard }}
|
||||
</div>
|
||||
<div class="subtitle text-overflow-elipsis">
|
||||
{{ 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
|
||||
}
|
||||
}
|
||||
},
|
||||
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}).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>
|
|
@ -33,7 +33,7 @@
|
|||
<h3>{{ data.views["latest-releases"].attributes.title ?? ""}}</h3>
|
||||
</div>
|
||||
<div class="col-auto flex-center" v-if="data.views['latest-releases'].data.length >= 10">
|
||||
<button class="cd-btn-seeall" @click="app.showRecordLabelView(data.id, data.attributes.name + ' - Latest Releases', 'latest-releases')">See All</button>
|
||||
<button class="cd-btn-seeall" @click="app.showRecordLabelView(data.id, data.attributes.name + ' - Latest Releases', 'latest-releases')">{{app.getLz('term.seeAll')}}</button>
|
||||
</div>
|
||||
</div>
|
||||
<mediaitem-square :item="item" v-for="item in data.views['latest-releases'].data">
|
||||
|
@ -45,7 +45,7 @@
|
|||
<h3>{{ data.views["top-releases"].attributes.title ?? ""}}</h3>
|
||||
</div>
|
||||
<div class="col-auto flex-center" v-if="data.views['top-releases'].data.length >= 10">
|
||||
<button class="cd-btn-seeall" @click="app.showRecordLabelView(data.id, data.attributes.name + ' - Top Releases', 'top-releases')">See All</button>
|
||||
<button class="cd-btn-seeall" @click="app.showRecordLabelView(data.id, data.attributes.name + ' - Top Releases', 'top-releases')">{{app.getLz('term.seeAll')}}</button>
|
||||
</div>
|
||||
</div>
|
||||
<mediaitem-square :item="item" v-for="item in data.views['top-releases'].data">
|
||||
|
@ -57,7 +57,7 @@
|
|||
<h3>Playlists</h3>
|
||||
</div>
|
||||
<div class="col-auto flex-center" v-if="data.relationships.playlists.data.length >= 5">
|
||||
<button class="cd-btn-seeall" @click="app.showCollection(data.relationships.playlists, data.attributes.name + ' - Playlists', 'curator')">See All</button>
|
||||
<button class="cd-btn-seeall" @click="app.showCollection(data.relationships.playlists, data.attributes.name + ' - Playlists', 'curator')">{{app.getLz('term.seeAll')}}</button>
|
||||
</div>
|
||||
</div>
|
||||
<mediaitem-square :item="item" v-for="item in data.relationships.playlists.data.limit(5)">
|
||||
|
|
|
@ -1,86 +1,103 @@
|
|||
<script type="text/x-template" id="cider-search">
|
||||
<div class="content-inner">
|
||||
<div class="row">
|
||||
<div class="col-sm" style="width: auto;" v-if="getTopResult()">
|
||||
<template>
|
||||
<h3>Top Result</h3>
|
||||
<mediaitem-square :item="getTopResult()"></mediaitem-square>
|
||||
</template>
|
||||
</div>
|
||||
<div v-else style="text-align: center">
|
||||
<h3>No Results</h3>
|
||||
<p>Try a new search.</p>
|
||||
</div>
|
||||
<div class="col" v-if="search.results.song">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<h3>Songs</h3>
|
||||
<div v-if="search != null && search != [] && search.term != ''">
|
||||
<div class="row">
|
||||
<div class="col-sm" style="width: auto;" v-if="getTopResult()">
|
||||
<template>
|
||||
<h3>Top Result</h3>
|
||||
<mediaitem-square :item="getTopResult()"></mediaitem-square>
|
||||
</template>
|
||||
</div>
|
||||
<div v-else style="text-align: center">
|
||||
<h3>{{app.getLz('error.noResults')}}</h3>
|
||||
<p>{{app.getLz('error.noResults.description')}}</p>
|
||||
</div>
|
||||
<div class="col" v-if="search.results.song">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<h3>Songs</h3>
|
||||
</div>
|
||||
<div class="col-auto flex-center"
|
||||
@click="app.showSearchView(app.search.term, 'song', app.friendlyTypes('song'))"
|
||||
v-if="search.results.song.data.length >= 12">
|
||||
<button class="cd-btn-seeall">{{app.getLz('term.seeAll')}}</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-auto flex-center"
|
||||
@click="app.showSearchView(app.search.term, 'song', app.friendlyTypes('song'))"
|
||||
v-if="search.results.song.data.length >= 6">
|
||||
<button class="cd-btn-seeall">See All</button>
|
||||
<div class="mediaitem-list-item__grid">
|
||||
<div class="grid-body">
|
||||
<mediaitem-list-item :item="item" :index="index"
|
||||
v-for="(item, index) in search.results.song.data.limit(12)"></mediaitem-list-item>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<mediaitem-list-item :item="item" :index="index"
|
||||
v-for="(item, index) in search.results.song.data.limit(6)"></mediaitem-list-item>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<template v-if="search.results['meta']">
|
||||
<template
|
||||
v-for="section in search.results.meta.results.order" v-if="section != 'song' && section != 'top'">
|
||||
<template v-if="search.results['meta'] != null">
|
||||
<template
|
||||
v-for="section in search.results.meta.results.order" v-if="section != 'song' && section != 'top'">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<h3>{{ app.friendlyTypes(section) }}</h3>
|
||||
</div>
|
||||
<div class="col-auto flex-center" v-if="search.results[section].data.length >= 10">
|
||||
<button class="cd-btn-seeall"
|
||||
@click="app.showSearchView(app.search.term, section, app.friendlyTypes(section))">See
|
||||
All
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<template v-if="!app.friendlyTypes(section).includes('Video')">
|
||||
<mediaitem-scroller-horizontal-large
|
||||
:items="search.results[section].data.limit(10)"></mediaitem-scroller-horizontal-large>
|
||||
</template>
|
||||
<template v-else>
|
||||
<mediaitem-scroller-horizontal-mvview
|
||||
:items="search.results[section].data.limit(10)"></mediaitem-scroller-horizontal-mvview>
|
||||
</template>
|
||||
</template>
|
||||
</template>
|
||||
<template v-if="search.resultsSocial.playlist">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<h3>{{ app.friendlyTypes(section) }}</h3>
|
||||
<h3>Shared Playlists</h3>
|
||||
</div>
|
||||
<div class="col-auto flex-center" v-if="search.results[section].data.length >= 10">
|
||||
<div class="col-auto flex-center" v-if="search.resultsSocial.playlist.data.length >= 10">
|
||||
<button class="cd-btn-seeall"
|
||||
@click="app.showSearchView(app.search.term, section, app.friendlyTypes(section))">See
|
||||
All
|
||||
@click="app.showCollection(search.resultsSocial.playlist, 'Shared Playlists', 'default')">{{app.getLz('term.seeAll')}}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<template v-if="!app.friendlyTypes(section).includes('Video')">
|
||||
<mediaitem-scroller-horizontal-large
|
||||
:items="search.results[section].data.limit(10)"></mediaitem-scroller-horizontal-large>
|
||||
</template>
|
||||
<template v-else>
|
||||
<mediaitem-scroller-horizontal-mvview
|
||||
:items="search.results[section].data.limit(10)"></mediaitem-scroller-horizontal-mvview>
|
||||
</template>
|
||||
<mediaitem-scroller-horizontal-large
|
||||
:items="search.resultsSocial.playlist.data.limit(10)"></mediaitem-scroller-horizontal-large>
|
||||
</template>
|
||||
</template>
|
||||
<template v-if="search.resultsSocial.playlist">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<h3>Shared Playlists</h3>
|
||||
<template v-if="search.resultsSocial.profile">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<h3>People</h3>
|
||||
</div>
|
||||
<div class="col-auto flex-center" v-if="search.resultsSocial.profile.data.length >= 10">
|
||||
<button class="cd-btn-seeall"
|
||||
@click="app.showCollection(search.resultsSocial.profile, 'People', 'default')">{{app.getLz('term.seeAll')}}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-auto flex-center" v-if="search.resultsSocial.playlist.data.data.length >= 10">
|
||||
<button class="cd-btn-seeall"
|
||||
@click="app.showCollection(search.resultsSocial.playlist.data, 'Shared Playlists', 'default')">See All
|
||||
</button>
|
||||
<mediaitem-scroller-horizontal-large
|
||||
:items="search.resultsSocial.profile.data.limit(10)"></mediaitem-scroller-horizontal-large>
|
||||
</template>
|
||||
</div>
|
||||
<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">
|
||||
<h3>{{categoriesView[0].attributes.title.stringForDisplay ?? ""}}</h3>
|
||||
</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 in categoriesView[1].relationships.contents.data.filter(item => item.type != 'editorial-items')">
|
||||
</div>
|
||||
</div>
|
||||
<mediaitem-scroller-horizontal-large
|
||||
:items="search.resultsSocial.playlist.data.data.limit(10)"></mediaitem-scroller-horizontal-large>
|
||||
</template>
|
||||
<template v-if="search.resultsSocial.profile">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<h3>People</h3>
|
||||
</div>
|
||||
<div class="col-auto flex-center" v-if="search.resultsSocial.profile.data.data.length >= 10">
|
||||
<button class="cd-btn-seeall"
|
||||
@click="app.showCollection(search.resultsSocial.profile.data, 'People', 'default')">See All
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<mediaitem-scroller-horizontal-large
|
||||
:items="search.resultsSocial.profile.data.data.limit(10)"></mediaitem-scroller-horizontal-large>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
|
@ -90,16 +107,26 @@
|
|||
props: ['search'],
|
||||
data: function () {
|
||||
return {
|
||||
app: this.$root
|
||||
app: this.$root,
|
||||
categoriesView: [],
|
||||
categoriesReady: false,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getTopResult() {
|
||||
try {
|
||||
return this.search.results[this.search.results.meta.results.order[0]]["data"][0]
|
||||
} catch( error ) {
|
||||
} catch (error) {
|
||||
return false
|
||||
}
|
||||
},
|
||||
async getCategories() {
|
||||
if (this.categoriesView != [] && this.categoriesView.length > 0) { this.categoriesReady = true; return await true; } else {
|
||||
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`);
|
||||
this.categoriesView = response.data.data;
|
||||
this.categoriesReady = true;
|
||||
return await true;
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
|
@ -5,5 +5,8 @@
|
|||
{{ $store.state.test }}
|
||||
<div class="spinner"></div>
|
||||
<button class="md-btn">Cider Button</button>
|
||||
<div style="position: relative;width: 300px;height: 300px;">
|
||||
<artwork-material url="https://is3-ssl.mzstatic.com/image/thumb/Music126/v4/13/41/13/1341133b-560f-1aee-461f-c4b32ec049b4/cover.jpg/{w}x{h}bb.jpg"></artwork-material>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
|