Merge branch 'develop'
This commit is contained in:
commit
df2f7b7216
195 changed files with 62285 additions and 12895 deletions
6
src/renderer/assets/cider-round.svg
Normal file
6
src/renderer/assets/cider-round.svg
Normal file
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg width="100%" height="100%" viewBox="0 0 1002 1000" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
|
||||
<path d="M501,21C765.367,21 980,235.633 980,500C980,764.367 765.367,979 501,979C236.633,979 22,764.367 22,500C22,235.633 236.633,21 501,21ZM501,169C683.684,169 832,317.316 832,500C832,682.684 683.684,831 501,831C318.316,831 170,682.684 170,500C170,317.316 318.316,169 501,169Z" style="fill:rgb(255,38,84);"/>
|
||||
<path d="M501,224C653.053,224 776.5,347.447 776.5,499.5C776.5,651.553 653.053,775 501,775C348.947,775 225.5,651.553 225.5,499.5C225.5,347.447 348.947,224 501,224ZM589.165,492.207C595.163,495.672 595.163,504.328 589.165,507.793L439.502,594.256C433.502,597.722 426,593.392 426,586.463L426,413.537C426,406.608 433.502,402.278 439.502,405.744L589.165,492.207Z" style="fill:rgb(255,38,84);"/>
|
||||
</svg>
|
After Width: | Height: | Size: 1.1 KiB |
1
src/renderer/assets/feather/external-link.svg
Normal file
1
src/renderer/assets/feather/external-link.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-external-link"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path><polyline points="15 3 21 3 21 9"></polyline><line x1="10" y1="14" x2="21" y2="3"></line></svg>
|
After Width: | Height: | Size: 388 B |
3
src/renderer/assets/github.svg
Normal file
3
src/renderer/assets/github.svg
Normal file
|
@ -0,0 +1,3 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
|
||||
<path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"/>
|
||||
</svg>
|
After Width: | Height: | Size: 818 B |
1
src/renderer/assets/music.svg
Normal file
1
src/renderer/assets/music.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-music"><path d="M9 18V5l12-2v13"></path><circle cx="6" cy="18" r="3"></circle><circle cx="18" cy="16" r="3"></circle></svg>
|
After Width: | Height: | Size: 327 B |
1
src/renderer/assets/ppe.svg
Normal file
1
src/renderer/assets/ppe.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-codesandbox"><path d="M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z"></path><polyline points="7.5 4.21 12 6.81 16.5 4.21"></polyline><polyline points="7.5 19.79 7.5 14.6 3 12"></polyline><polyline points="21 12 16.5 14.6 16.5 19.79"></polyline><polyline points="3.27 6.96 12 12.01 20.73 6.96"></polyline><line x1="12" y1="22.08" x2="12" y2="12"></line></svg>
|
After Width: | Height: | Size: 638 B |
|
@ -1,4 +1,4 @@
|
|||
var CiderAudio = {
|
||||
const CiderAudio = {
|
||||
context : null,
|
||||
source : null,
|
||||
audioNodes : {
|
||||
|
@ -6,12 +6,16 @@ var CiderAudio = {
|
|||
spatialNode : null,
|
||||
spatialInput: null,
|
||||
audioBands : null,
|
||||
preampNode : null,
|
||||
vibrantbassNode: null,
|
||||
llpw: null,
|
||||
analogWarmth: null,
|
||||
recorderNode: null,
|
||||
},
|
||||
ccON: false,
|
||||
mediaRecorder: null,
|
||||
init: function (cb = function () { }) {
|
||||
//AudioOutputs.fInit = true;
|
||||
searchInt = setInterval(function () {
|
||||
let searchInt = setInterval(function () {
|
||||
if (document.getElementById("apple-music-player")) {
|
||||
//AudioOutputs.eqReady = true;
|
||||
document.getElementById("apple-music-player").crossOrigin = "anonymous";
|
||||
|
@ -28,15 +32,33 @@ var CiderAudio = {
|
|||
CiderAudio.audioNodes.gainNode.disconnect(); } catch(e){}
|
||||
try{ CiderAudio.audioNodes.spatialNode.disconnect();} catch(e){}
|
||||
try{
|
||||
CiderAudio.audioNodes.preampNode.disconnect();
|
||||
CiderAudio.audioNodes.vibrantbassNode.disconnect();
|
||||
CiderAudio.audioNodes.audioBands[0].disconnect();
|
||||
CiderAudio.audioNodes.audioBands[9].disconnect();
|
||||
for (var i of CiderAudio.audioNodes.analogWarmth){
|
||||
i.disconnect();
|
||||
}
|
||||
for (var i of CiderAudio.audioNodes.llpw){
|
||||
i.disconnect();
|
||||
}
|
||||
for (var i of CiderAudio.audioNodes.vibrantbassNode){
|
||||
i.disconnect();
|
||||
}
|
||||
for (var i of CiderAudio.audioNodes.audioBands){
|
||||
i.disconnect();
|
||||
}
|
||||
} catch(e){}
|
||||
try{
|
||||
CiderAudio.audioNodes = {
|
||||
gainNode : null,
|
||||
spatialNode : null,
|
||||
spatialInput: null,
|
||||
audioBands : null,
|
||||
vibrantbassNode: null,
|
||||
llpw: null,
|
||||
analogWarmth: null
|
||||
}
|
||||
} catch (e) {}
|
||||
CiderAudio.source.connect(CiderAudio.context.destination);} catch(e){}
|
||||
},
|
||||
connectContext: function (mediaElem){
|
||||
|
||||
if (!CiderAudio.context){
|
||||
CiderAudio.context = new (window.AudioContext || window.webkitAudioContext);
|
||||
}
|
||||
|
@ -54,64 +76,566 @@ var CiderAudio = {
|
|||
}
|
||||
CiderAudio.equalizer()
|
||||
},
|
||||
normalizerOn: function (){},
|
||||
normalizerOn: function (){
|
||||
},
|
||||
normalizerOff: function (){
|
||||
CiderAudio.audioNodes.gainNode.gain.setTargetAtTime(1, CiderAudio.context.currentTime+ 1, 0.5);
|
||||
},
|
||||
|
||||
spatialOn: function (){
|
||||
try{
|
||||
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 = {
|
||||
width: 32,
|
||||
height: 12,
|
||||
depth: 32,
|
||||
};
|
||||
let roomMaterials = {
|
||||
// Room wall materials
|
||||
left: 'metal',
|
||||
right: 'metal',
|
||||
front: 'brick-bare',
|
||||
back: 'brick-bare',
|
||||
down: 'acoustic-ceiling-tiles',
|
||||
up: 'acoustic-ceiling-tiles',
|
||||
};
|
||||
CiderAudio.audioNodes.spatialNode.setRoomProperties(roomDimensions, roomMaterials);
|
||||
CiderAudio.audioNodes.spatialInput = CiderAudio.audioNodes.spatialNode.createSource();
|
||||
CiderAudio.audioNodes.gainNode.connect(CiderAudio.audioNodes.spatialInput.input);
|
||||
if (app.cfg.audio.maikiwiAudio.spatial === true) {
|
||||
CiderAudio.audioNodes.spatialNode = CiderAudio.context.createConvolver();
|
||||
CiderAudio.audioNodes.spatialNode.normalize = true;
|
||||
switch (app.cfg.audio.maikiwiAudio.spatialType) {
|
||||
case 0:
|
||||
fetch('./audio/impulses/CiderSpatial_Conv.wav').then(async (impulseData) => {
|
||||
let bufferedImpulse = await impulseData.arrayBuffer();
|
||||
CiderAudio.audioNodes.spatialNode.buffer = await CiderAudio.context.decodeAudioData(bufferedImpulse);
|
||||
|
||||
});
|
||||
break;
|
||||
case 1:
|
||||
fetch('./audio/impulses/CiderSpatial_Conv_v2.wav').then(async (impulseData) => {
|
||||
let bufferedImpulse = await impulseData.arrayBuffer();
|
||||
CiderAudio.audioNodes.spatialNode.buffer = await CiderAudio.context.decodeAudioData(bufferedImpulse);
|
||||
|
||||
});
|
||||
break;
|
||||
default:
|
||||
fetch('./audio/impulses/CiderSpatial_Conv.wav').then(async (impulseData) => {
|
||||
let bufferedImpulse = await impulseData.arrayBuffer();
|
||||
CiderAudio.audioNodes.spatialNode.buffer = await CiderAudio.context.decodeAudioData(bufferedImpulse);
|
||||
|
||||
});
|
||||
app.cfg.audio.maikiwiAudio.spatialType = 0;
|
||||
break;
|
||||
}
|
||||
CiderAudio.audioNodes.spatialNode.connect(CiderAudio.context.destination);
|
||||
}
|
||||
else {
|
||||
try{
|
||||
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 = {
|
||||
width: 32,
|
||||
height: 12,
|
||||
depth: 32,
|
||||
};
|
||||
let roomMaterials = {
|
||||
// Room wall materials
|
||||
left: 'metal',
|
||||
right: 'metal',
|
||||
front: 'brick-bare',
|
||||
back: 'brick-bare',
|
||||
down: 'acoustic-ceiling-tiles',
|
||||
up: 'acoustic-ceiling-tiles',
|
||||
};
|
||||
CiderAudio.audioNodes.spatialNode.setRoomProperties(roomDimensions, roomMaterials);
|
||||
CiderAudio.audioNodes.spatialInput = CiderAudio.audioNodes.spatialNode.createSource();
|
||||
CiderAudio.audioNodes.gainNode.connect(CiderAudio.audioNodes.spatialInput.input);}
|
||||
},
|
||||
spatialOff: function (){
|
||||
try{
|
||||
CiderAudio.audioNodes.spatialNode.output.disconnect(CiderAudio.context.destination);
|
||||
CiderAudio.audioNodes.gainNode.disconnect(CiderAudio.audioNodes.spatialInput.input);} catch(e){}
|
||||
CiderAudio.audioNodes.gainNode.connect(CiderAudio.context.destination);
|
||||
CiderAudio.hierarchical_loading();
|
||||
},
|
||||
sendAudio: function (){
|
||||
var options = {
|
||||
mimeType : 'audio/webm; codecs=opus'
|
||||
};
|
||||
var destnode = CiderAudio.context.createMediaStreamDestination();
|
||||
CiderAudio.audioNodes.gainNode.connect(destnode)
|
||||
var mediaRecorder = new MediaRecorder(destnode.stream,options);
|
||||
mediaRecorder.start(1);
|
||||
mediaRecorder.ondataavailable = function(e) {
|
||||
e.data.arrayBuffer().then(buffer => {
|
||||
ipcRenderer.send('writeAudio',buffer)
|
||||
}
|
||||
);
|
||||
if (!CiderAudio.ccON) {
|
||||
CiderAudio.ccON = true
|
||||
let searchInt = setInterval(async function () {
|
||||
if (CiderAudio.context != null && CiderAudio.audioNodes.gainNode != null) {
|
||||
// var options = {
|
||||
// mimeType: 'audio/webm; codecs=opus'
|
||||
// };
|
||||
// var destnode = CiderAudio.context.createMediaStreamDestination();
|
||||
// CiderAudio.audioNodes.gainNode.connect(destnode)
|
||||
// CiderAudio.mediaRecorder = new MediaRecorder(destnode.stream, options);
|
||||
// CiderAudio.mediaRecorder.start(1);
|
||||
// CiderAudio.mediaRecorder.ondataavailable = function (e) {
|
||||
// e.data.arrayBuffer().then(buffer => {
|
||||
// ipcRenderer.send('writeAudio', buffer)
|
||||
// }
|
||||
// );
|
||||
// }
|
||||
const worklet = `class RecorderWorkletProcessor extends AudioWorkletProcessor {
|
||||
static get parameterDescriptors() {
|
||||
return [{
|
||||
name: 'isRecording',
|
||||
defaultValue: 0
|
||||
},
|
||||
{
|
||||
name: 'numberOfChannels',
|
||||
defaultValue: 2
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this._bufferSize = 1024;
|
||||
this._buffers = null;
|
||||
this._initBuffer();
|
||||
}
|
||||
_initBuffers(numberOfChannels) {
|
||||
this._buffers = [];
|
||||
for (let channel=0; channel < numberOfChannels; channel++) {
|
||||
this._buffers.push(new Float32Array(this._bufferSize));
|
||||
}
|
||||
}
|
||||
|
||||
_initBuffer() {
|
||||
this._bytesWritten = 0;
|
||||
}
|
||||
|
||||
_isBufferEmpty() {
|
||||
return this._bytesWritten === 0;
|
||||
}
|
||||
|
||||
_isBufferFull() {
|
||||
return this._bytesWritten === this._bufferSize;
|
||||
}
|
||||
_pushToBuffers(audioRawData, numberOfChannels) {
|
||||
if (this._isBufferFull()) {
|
||||
this._flush();
|
||||
}
|
||||
let dataLength = audioRawData[0].length;
|
||||
for (let idx=0; idx<dataLength; idx++) {
|
||||
for (let channel=0; channel < numberOfChannels; channel++) {
|
||||
let value = audioRawData[channel][idx];
|
||||
this._buffers[channel][this._bytesWritten] = value;
|
||||
}
|
||||
this._bytesWritten += 1;
|
||||
}
|
||||
}
|
||||
|
||||
_flush() {
|
||||
let buffers = [];
|
||||
this._buffers.forEach((buffer, channel) => {
|
||||
if (this._bytesWritten < this._bufferSize) {
|
||||
buffer = buffer.slice(0, this._bytesWritten);
|
||||
}
|
||||
buffers[channel] = buffer;
|
||||
});
|
||||
this.port.postMessage({
|
||||
eventType: 'data',
|
||||
audioBuffer: buffers,
|
||||
bufferSize: this._bufferSize
|
||||
});
|
||||
this._initBuffer();
|
||||
}
|
||||
|
||||
_recordingStopped() {
|
||||
this.port.postMessage({
|
||||
eventType: 'stop'
|
||||
});
|
||||
}
|
||||
|
||||
process(inputs, outputs, parameters) {
|
||||
const isRecordingValues = parameters.isRecording;
|
||||
const numberOfChannels = parameters.numberOfChannels[0];
|
||||
if (this._buffers === null) {
|
||||
this._initBuffers(numberOfChannels);
|
||||
}
|
||||
|
||||
for (let dataIndex = 0; dataIndex < isRecordingValues.length; dataIndex++)
|
||||
{
|
||||
const shouldRecord = isRecordingValues[dataIndex] === 1;
|
||||
if (!shouldRecord && !this._isBufferEmpty()) {
|
||||
this._flush();
|
||||
this._recordingStopped();
|
||||
}
|
||||
|
||||
if (shouldRecord) {
|
||||
let audioRawData = inputs[0];
|
||||
this._pushToBuffers(audioRawData, numberOfChannels);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
registerProcessor('recorder-worklet', RecorderWorkletProcessor);`
|
||||
let blob = new Blob([worklet], { type: 'application/javascript' });
|
||||
await CiderAudio.context.audioWorklet.addModule(URL.createObjectURL(blob))
|
||||
.then(() => {
|
||||
|
||||
const channels = 2;
|
||||
CiderAudio.audioNodes.recorderNode = new window.AudioWorkletNode(CiderAudio.context,
|
||||
'recorder-worklet',
|
||||
{ parameterData: { numberOfChannels: channels } });
|
||||
CiderAudio.audioNodes.recorderNode.port.onmessage = (e) => {
|
||||
const data = e.data;
|
||||
switch (data.eventType) {
|
||||
case "data":
|
||||
const audioData = data.audioBuffer;
|
||||
const bufferSize = data.bufferSize;
|
||||
ipcRenderer.send('writeWAV', audioData[0], audioData[1], bufferSize);
|
||||
break;
|
||||
case "stop":
|
||||
break;
|
||||
}
|
||||
}
|
||||
CiderAudio.audioNodes.recorderNode.parameters.get('isRecording').setValueAtTime(1, CiderAudio.context.currentTime);
|
||||
CiderAudio.audioNodes.gainNode.connect(CiderAudio.audioNodes.recorderNode);
|
||||
|
||||
});
|
||||
clearInterval(searchInt);
|
||||
}
|
||||
}, 1000);
|
||||
} else {if (CiderAudio.audioNodes.recorderNode != null && CiderAudio.context != null) {
|
||||
CiderAudio.audioNodes.recorderNode.parameters.get('isRecording').setValueAtTime(1, CiderAudio.context.currentTime);
|
||||
// CiderAudio.audioNodes.recorderNode = null;
|
||||
// CiderAudio.ccON = false;
|
||||
}}
|
||||
|
||||
},
|
||||
stopAudio(){
|
||||
if (CiderAudio.audioNodes.recorderNode != null && CiderAudio.context != null) {
|
||||
CiderAudio.audioNodes.recorderNode.parameters.get('isRecording').setValueAtTime(0, CiderAudio.context.currentTime);
|
||||
// CiderAudio.audioNodes.recorderNode = null;
|
||||
// CiderAudio.ccON = false;
|
||||
}
|
||||
},
|
||||
equalizer: function (){
|
||||
analogWarmth_h2_3: function (status, hierarchy){
|
||||
if (status === true) { // 23 Band Adjustment
|
||||
let WARMTH_FREQUENCIES = [10.513, 15.756, 224.01, 677.77, 1245.4, 2326.8, 2847.3, 4215.3, 11057, 12793, 16235, 16235, 17838, 18112, 18112, 19326, 19372, 19372, 20061, 20280, 20280, 20853, 22276];
|
||||
let WARMTH_GAIN = [-4.81, 0.74, 0.55, -0.84, -1.52, 0.84, 0.66, -0.29, 0.29, 0.94, 1.67, 1.62, -0.53, -0.81, -4.98, 1.43, 0.86, 1.13, -1.06, -0.95, -1.13, 1.78, -3.86];
|
||||
let WARMTH_Q = [0.442, 3.536, 2.102, 8.409, 0.625, 16.82, 5, 2.973, 3.536, 2.5, 2.5, 11.89, 0.625, 1.487, 1.153, 5, 5.453, 5, 2.973, 3.386, 3.386, 14.14, 8.409];
|
||||
CiderAudio.audioNodes.analogWarmth = []
|
||||
|
||||
|
||||
for (let i = 0; i < WARMTH_FREQUENCIES.length; i++) {
|
||||
CiderAudio.audioNodes.analogWarmth[i] = CiderAudio.context.createBiquadFilter();
|
||||
CiderAudio.audioNodes.analogWarmth[i].type = 'peaking'; // 'peaking';
|
||||
CiderAudio.audioNodes.analogWarmth[i].frequency.value = WARMTH_FREQUENCIES[i];
|
||||
CiderAudio.audioNodes.analogWarmth[i].Q.value = WARMTH_Q[i];
|
||||
CiderAudio.audioNodes.analogWarmth[i].gain.value = WARMTH_GAIN[i] * app.cfg.audio.maikiwiAudio.analogWarmth_value;
|
||||
}
|
||||
|
||||
for (let i = 1; i < WARMTH_FREQUENCIES.length; i ++) {
|
||||
CiderAudio.audioNodes.analogWarmth[i-1].connect(CiderAudio.audioNodes.analogWarmth[i]);
|
||||
}
|
||||
|
||||
switch (hierarchy) {
|
||||
case 3:
|
||||
try{
|
||||
CiderAudio.audioNodes.analogWarmth[WARMTH_FREQUENCIES.length-1].connect(CiderAudio.audioNodes.llpw[0]);} catch(e){}
|
||||
break;
|
||||
case 2:
|
||||
try{
|
||||
CiderAudio.audioNodes.analogWarmth[WARMTH_FREQUENCIES.length-1].connect(CiderAudio.audioNodes.vibrantbassNode[0]);} catch(e){}
|
||||
break;
|
||||
case 1:
|
||||
try{
|
||||
CiderAudio.audioNodes.analogWarmth[WARMTH_FREQUENCIES.length-1].connect(CiderAudio.audioNodes.audioBands[0]);} catch(e){}
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
},
|
||||
llpw_h2_2: function (status, hierarchy){
|
||||
if (status === true) {
|
||||
let c_LLPW_Q = [1.250, 0.131, 10, 2.5, 2.293, 0.110, 14.14, 1.552, 28.28, 7.071, 2.847, 5, 0.625, 7.071, 3.856, 3.856, 20, 28.28, 20, 14.14, 2.102, 6.698, 3.536, 10];
|
||||
let c_LLPW_GAIN = [-0.11, 0.27, -0.8, 0.57, 1.84, -0.38, 0.47, -1.56, 0.83, 1.58, -1.79, -0.45, 0.48, 1.22, -1.58, -1.59, -2.03, 2.56, -2.2, -2.48, 4.75, 10.5, 1.43, 3.76];
|
||||
let c_LLPW_FREQUENCIES = [400.83, 5812.8, 8360, 10413, 10658, 12079, 12899, 13205, 14848, 15591, 15778, 15783, 16716, 16891, 17255, 17496, 18555, 18622, 19219, 19448, 19664, 21341, 21353, 22595];
|
||||
let LLPW_Q = [5, 1, 3.536, 1.25, 8.409, 1.25, 14.14, 7.071, 5, 0.625, 16.82, 20, 20, 20, 28.28, 28.28, 28.28, 20, 33.64, 33.64, 10, 28.28, 7.071, 3.856];
|
||||
let LLPW_GAIN = [0.38, -1.81, -0.23, -0.51, 0.4, 0.84, 0.36, -0.34, 0.27, -1.2, -0.42, -0.67, 0.81, 1.31, -0.71, 0.68, -1.04, 0.79, -0.73, -1.33, 1.17, 0.57, 0.35, 6.33];
|
||||
let LLPW_FREQUENCIES = [16.452, 24.636, 37.134, 74.483, 159.54, 308.18, 670.21, 915.81, 1200.7, 2766.4, 2930.6, 4050.6, 4409.1, 5395.2, 5901.6, 6455.5, 7164.1, 7724.1, 8449, 10573, 12368, 14198, 17910, 18916];
|
||||
CiderAudio.audioNodes.llpw = []
|
||||
|
||||
if (app.cfg.audio.maikiwiAudio.ciderPPE_value === 0.55) {
|
||||
for (let i = 0; i < c_LLPW_FREQUENCIES.length; i++) {
|
||||
CiderAudio.audioNodes.llpw[i] = CiderAudio.context.createBiquadFilter();
|
||||
CiderAudio.audioNodes.llpw[i].type = 'peaking'; // 'peaking';
|
||||
CiderAudio.audioNodes.llpw[i].frequency.value = c_LLPW_FREQUENCIES[i];
|
||||
CiderAudio.audioNodes.llpw[i].Q.value = c_LLPW_Q[i];
|
||||
CiderAudio.audioNodes.llpw[i].gain.value = c_LLPW_GAIN[i];
|
||||
}
|
||||
|
||||
|
||||
for (let i = 1; i < c_LLPW_FREQUENCIES.length; i ++) {
|
||||
CiderAudio.audioNodes.llpw[i-1].connect(CiderAudio.audioNodes.llpw[i]);
|
||||
}
|
||||
|
||||
switch (hierarchy) {
|
||||
case 2:
|
||||
try{
|
||||
CiderAudio.audioNodes.llpw[c_LLPW_FREQUENCIES.length-1].connect(CiderAudio.audioNodes.vibrantbassNode[0]);} catch(e){}
|
||||
break;
|
||||
case 1:
|
||||
try{CiderAudio.audioNodes.llpw[c_LLPW_FREQUENCIES.length-1].connect(CiderAudio.audioNodes.audioBands[0]);} catch(e){}
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
console.debug("[Cider][Audio] CAP - Clarity Mode");
|
||||
}
|
||||
|
||||
else if (app.cfg.audio.maikiwiAudio.ciderPPE_value === 0.5) {
|
||||
for (let i = 0; i < LLPW_FREQUENCIES.length; i++) {
|
||||
CiderAudio.audioNodes.llpw[i] = CiderAudio.context.createBiquadFilter();
|
||||
CiderAudio.audioNodes.llpw[i].type = 'peaking'; // 'peaking';
|
||||
CiderAudio.audioNodes.llpw[i].frequency.value = LLPW_FREQUENCIES[i];
|
||||
CiderAudio.audioNodes.llpw[i].Q.value = LLPW_Q[i];
|
||||
CiderAudio.audioNodes.llpw[i].gain.value = LLPW_GAIN[i];
|
||||
}
|
||||
|
||||
|
||||
for (let i = 1; i < LLPW_FREQUENCIES.length; i ++) {
|
||||
CiderAudio.audioNodes.llpw[i-1].connect(CiderAudio.audioNodes.llpw[i]);
|
||||
}
|
||||
|
||||
switch (hierarchy) {
|
||||
case 2:
|
||||
try{
|
||||
CiderAudio.audioNodes.llpw[LLPW_FREQUENCIES.length-1].connect(CiderAudio.audioNodes.vibrantbassNode[0]);} catch(e){}
|
||||
break;
|
||||
case 1:
|
||||
try{CiderAudio.audioNodes.llpw[LLPW_FREQUENCIES.length-1].connect(CiderAudio.audioNodes.audioBands[0]);} catch(e){}
|
||||
break;
|
||||
|
||||
}
|
||||
console.debug("[Cider][Audio] CAP - Classic Mode");
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
vibrantbass_h2_1: function (status){
|
||||
if (status === true) {
|
||||
let VIBRANTBASSBANDS = app.cfg.audio.maikiwiAudio.vibrantBass.frequencies;
|
||||
let VIBRANTBASSGAIN = app.cfg.audio.maikiwiAudio.vibrantBass.gain;
|
||||
let VIBRANTBASSQ = app.cfg.audio.maikiwiAudio.vibrantBass.Q;
|
||||
CiderAudio.audioNodes.vibrantbassNode = []
|
||||
|
||||
for (let i = 0; i < VIBRANTBASSBANDS.length; i++) {
|
||||
CiderAudio.audioNodes.vibrantbassNode[i] = CiderAudio.context.createBiquadFilter();
|
||||
CiderAudio.audioNodes.vibrantbassNode[i].type = 'peaking'; // 'peaking';
|
||||
CiderAudio.audioNodes.vibrantbassNode[i].frequency.value = VIBRANTBASSBANDS[i];
|
||||
CiderAudio.audioNodes.vibrantbassNode[i].Q.value = VIBRANTBASSQ[i];
|
||||
CiderAudio.audioNodes.vibrantbassNode[i].gain.value = VIBRANTBASSGAIN[i] * app.cfg.audio.maikiwiAudio.vibrantBass.multiplier;
|
||||
}
|
||||
|
||||
for (let i = 1; i < VIBRANTBASSBANDS.length; i ++) {
|
||||
CiderAudio.audioNodes.vibrantbassNode[i-1].connect(CiderAudio.audioNodes.vibrantbassNode[i]);
|
||||
}
|
||||
|
||||
CiderAudio.audioNodes.vibrantbassNode[VIBRANTBASSBANDS.length-1].connect(CiderAudio.audioNodes.audioBands[0]);
|
||||
}
|
||||
|
||||
CiderAudio.audioNodes.vibrantbassNode[0].connect(CiderAudio.audioNodes.audioBands[0])
|
||||
},
|
||||
hierarchical_unloading: function (){
|
||||
try {CiderAudio.audioNodes.spatialNode.output.disconnect();} catch(e){}
|
||||
try {CiderAudio.audioNodes.spatialNode.disconnect();} catch(e){}
|
||||
try {CiderAudio.audioNodes.gainNode.disconnect();} catch(e){}
|
||||
try {for (var i of CiderAudio.audioNodes.analogWarmth){i.disconnect();} CiderAudio.audioNodes.analogWarmth = null} catch(e){}
|
||||
try {for (var i of CiderAudio.audioNodes.llpw){i.disconnect();} CiderAudio.audioNodes.llpw = null} catch(e){}
|
||||
try {for (var i of CiderAudio.audioNodes.vibrantbassNode){i.disconnect();} CiderAudio.audioNodes.vibrantbassNode = null} catch(e){}
|
||||
|
||||
console.debug("[Cider][Audio] Finished hierarchical unloading");
|
||||
|
||||
},
|
||||
hierarchical_loading: function (){
|
||||
CiderAudio.hierarchical_unloading();
|
||||
|
||||
if (app.cfg.audio.maikiwiAudio.vibrantBass.multiplier !== 0) { // Vibrant Bass
|
||||
CiderAudio.vibrantbass_h2_1(true)
|
||||
|
||||
if (app.cfg.audio.maikiwiAudio.ciderPPE === true) { // Vibrant Bass, CAP
|
||||
CiderAudio.llpw_h2_2(true, 2);
|
||||
|
||||
if (app.cfg.audio.maikiwiAudio.analogWarmth === true) { // Vibrant Bass, CAP, Analog Warmth
|
||||
CiderAudio.analogWarmth_h2_3(true, 3);
|
||||
|
||||
if (app.cfg.audio.spatial === true) {
|
||||
if (app.cfg.audio.maikiwiAudio.spatial === true) { // Vibrant Bass, CAP, Analog Warmth, Maikiwi Spatial
|
||||
app.cfg.audio.normalization = true;
|
||||
CiderAudio.audioNodes.gainNode.connect(CiderAudio.audioNodes.spatialNode);
|
||||
CiderAudio.audioNodes.spatialNode.connect(CiderAudio.audioNodes.analogWarmth[0]);
|
||||
console.debug('[Cider][Audio] Vibrant Bass, CAP, Analog Warmth, Maikiwi Spatial')
|
||||
}
|
||||
else { // Vibrant Bass, CAP, Analog Warmth, Spatial
|
||||
app.cfg.audio.normalization = true;
|
||||
CiderAudio.audioNodes.gainNode.connect(CiderAudio.audioNodes.spatialInput.input);
|
||||
CiderAudio.audioNodes.spatialNode.output.connect(CiderAudio.audioNodes.analogWarmth[0]);
|
||||
console.debug('[Cider][Audio] Vibrant Bass, CAP, Analog Warmth, Spatial')
|
||||
}
|
||||
}
|
||||
else {
|
||||
app.cfg.audio.normalization = true;
|
||||
CiderAudio.audioNodes.gainNode.connect(CiderAudio.audioNodes.analogWarmth[0]);
|
||||
console.debug('[Cider][Audio] Vibrant Bass, CAP, Analog Warmth')
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (app.cfg.audio.spatial === true) {
|
||||
if (app.cfg.audio.maikiwiAudio.spatial === true) {
|
||||
CiderAudio.audioNodes.gainNode.connect(CiderAudio.audioNodes.spatialNode);
|
||||
CiderAudio.audioNodes.spatialNode.connect(CiderAudio.audioNodes.llpw[0]);
|
||||
app.cfg.audio.normalization = true
|
||||
console.debug('[Cider][Audio] Vibrant Bass, CAP, Maikiwi Spatial')
|
||||
}
|
||||
else {
|
||||
CiderAudio.audioNodes.gainNode.connect(CiderAudio.audioNodes.spatialInput.input);
|
||||
CiderAudio.audioNodes.spatialNode.output.connect(CiderAudio.audioNodes.llpw[0]);
|
||||
console.debug('[Cider][Audio] Vibrant Bass, CAP, Spatial')
|
||||
}
|
||||
}
|
||||
else {
|
||||
app.cfg.audio.normalization = true;
|
||||
CiderAudio.audioNodes.gainNode.connect(CiderAudio.audioNodes.llpw[0]);
|
||||
console.debug('[Cider][Audio] Vibrant Bass, CAP')
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (app.cfg.audio.maikiwiAudio.analogWarmth === true) {
|
||||
CiderAudio.analogWarmth_h2_3(true, 2);
|
||||
app.cfg.audio.normalization = true;
|
||||
|
||||
if (app.cfg.audio.spatial === true) {
|
||||
if (app.cfg.audio.maikiwiAudio.spatial === true) {
|
||||
CiderAudio.audioNodes.gainNode.connect(CiderAudio.audioNodes.spatialNode);
|
||||
CiderAudio.audioNodes.spatialNode.connect(CiderAudio.audioNodes.analogWarmth[0]);
|
||||
console.debug('[Cider][Audio] Vibrant Bass, Analog Warmth, Maikiwi Spatial')
|
||||
}
|
||||
else {
|
||||
CiderAudio.audioNodes.gainNode.connect(CiderAudio.audioNodes.spatialInput.input);
|
||||
CiderAudio.audioNodes.spatialNode.output.connect(CiderAudio.audioNodes.analogWarmth[0]);
|
||||
console.debug('[Cider][Audio] Vibrant Bass, Analog Warmth, Spatial')
|
||||
}
|
||||
}
|
||||
else {
|
||||
app.cfg.audio.normalization = true;
|
||||
CiderAudio.audioNodes.gainNode.connect(CiderAudio.audioNodes.analogWarmth[0]);
|
||||
console.debug('[Cider][Audio] Vibrant Bass, Analog Warmth')
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (app.cfg.audio.spatial === true) {
|
||||
if (app.cfg.audio.maikiwiAudio.spatial === true) {
|
||||
app.cfg.audio.normalization = true;
|
||||
CiderAudio.audioNodes.gainNode.connect(CiderAudio.audioNodes.spatialNode);
|
||||
CiderAudio.audioNodes.spatialNode.connect(CiderAudio.audioNodes.vibrantbassNode[0]);
|
||||
console.debug('[Cider][Audio] Vibrant Bass, Maikiwi Spatial')
|
||||
}
|
||||
else {
|
||||
CiderAudio.audioNodes.gainNode.connect(CiderAudio.audioNodes.spatialInput.input);
|
||||
CiderAudio.audioNodes.spatialNode.output.connect(CiderAudio.audioNodes.vibrantbassNode[0]);
|
||||
console.debug('[Cider][Audio] Vibrant Bass, Spatial')
|
||||
}
|
||||
}
|
||||
else {
|
||||
app.cfg.audio.normalization = true;
|
||||
CiderAudio.audioNodes.gainNode.connect(CiderAudio.audioNodes.vibrantbassNode[0]);
|
||||
console.debug('[Cider][Audio] Vibrant Bass')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Vibrant Bass ends here
|
||||
else {
|
||||
if (app.cfg.audio.maikiwiAudio.ciderPPE === true) {
|
||||
CiderAudio.llpw_h2_2(true, 1);
|
||||
|
||||
if (app.cfg.audio.maikiwiAudio.analogWarmth === true) {
|
||||
CiderAudio.analogWarmth_h2_3(true, 3);
|
||||
|
||||
if (app.cfg.audio.spatial === true) {
|
||||
if (app.cfg.audio.maikiwiAudio.spatial === true) {
|
||||
CiderAudio.audioNodes.gainNode.connect(CiderAudio.audioNodes.spatialNode);
|
||||
CiderAudio.audioNodes.spatialNode.connect(CiderAudio.audioNodes.analogWarmth[0]);
|
||||
app.cfg.audio.normalization = true;
|
||||
console.debug('[Cider][Audio] CAP, Analog Warmth, Maikiwi Spatial')
|
||||
}
|
||||
else {
|
||||
CiderAudio.audioNodes.gainNode.connect(CiderAudio.audioNodes.spatialInput.input);
|
||||
CiderAudio.audioNodes.spatialNode.output.connect(CiderAudio.audioNodes.analogWarmth[0]);
|
||||
console.debug('[Cider][Audio] CAP, Analog Warmth, Spatial')
|
||||
}
|
||||
}
|
||||
else {
|
||||
CiderAudio.audioNodes.gainNode.connect(CiderAudio.audioNodes.analogWarmth[0]);
|
||||
console.debug('[Cider][Audio] CAP and Analog Warmth')
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (app.cfg.audio.spatial === true) {
|
||||
if (app.cfg.audio.maikiwiAudio.spatial === true) {
|
||||
CiderAudio.audioNodes.gainNode.connect(CiderAudio.audioNodes.spatialNode);
|
||||
CiderAudio.audioNodes.spatialNode.connect(CiderAudio.audioNodes.llpw[0]);
|
||||
app.cfg.audio.normalization = true;
|
||||
console.debug('[Cider][Audio] CAP, Maikiwi Spatial')
|
||||
}
|
||||
else {
|
||||
CiderAudio.audioNodes.gainNode.connect(CiderAudio.audioNodes.spatialInput.input);
|
||||
CiderAudio.audioNodes.spatialNode.output.connect(CiderAudio.audioNodes.llpw[0]);
|
||||
console.debug('[Cider][Audio] CAP, Spatial')
|
||||
}
|
||||
}
|
||||
else {
|
||||
CiderAudio.audioNodes.gainNode.connect(CiderAudio.audioNodes.llpw[0]);
|
||||
console.debug('[Cider][Audio] CAP')
|
||||
}
|
||||
}
|
||||
} // CAP ends here
|
||||
else {
|
||||
if (app.cfg.audio.maikiwiAudio.analogWarmth === true) {
|
||||
CiderAudio.analogWarmth_h2_3(true, 1);
|
||||
|
||||
if (app.cfg.audio.spatial === true) {
|
||||
if (app.cfg.audio.maikiwiAudio.spatial === true) {
|
||||
CiderAudio.audioNodes.gainNode.connect(CiderAudio.audioNodes.spatialNode);
|
||||
CiderAudio.audioNodes.spatialNode.connect(CiderAudio.audioNodes.analogWarmth[0]);
|
||||
app.cfg.audio.normalization = true;
|
||||
console.debug('[Cider][Audio] Analog Warmth, Maikiwi Spatial')
|
||||
}
|
||||
else {
|
||||
CiderAudio.audioNodes.gainNode.connect(CiderAudio.audioNodes.spatialInput.input);
|
||||
CiderAudio.audioNodes.spatialNode.output.connect(CiderAudio.audioNodes.analogWarmth[0]);
|
||||
console.debug('[Cider][Audio] Analog Warmth, Spatial')
|
||||
}
|
||||
}
|
||||
else {
|
||||
CiderAudio.audioNodes.gainNode.connect(CiderAudio.audioNodes.analogWarmth[0]);
|
||||
console.debug('[Cider][Audio] Analog Warmth')
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (app.cfg.audio.spatial === true) {
|
||||
if (app.cfg.audio.maikiwiAudio.spatial === true) {
|
||||
CiderAudio.audioNodes.gainNode.connect(CiderAudio.audioNodes.spatialNode);
|
||||
CiderAudio.audioNodes.spatialNode.connect(CiderAudio.audioNodes.audioBands[0]);
|
||||
app.cfg.audio.normalization = true;
|
||||
console.debug('[Cider][Audio] Maikiwi Spatial')
|
||||
}
|
||||
else {
|
||||
CiderAudio.audioNodes.gainNode.connect(CiderAudio.audioNodes.spatialInput.input);
|
||||
CiderAudio.audioNodes.spatialNode.output.connect(CiderAudio.audioNodes.audioBands[0]);
|
||||
console.debug('[Cider][Audio] Spatial')
|
||||
}
|
||||
}
|
||||
else {
|
||||
CiderAudio.audioNodes.gainNode.connect(CiderAudio.audioNodes.audioBands[0]);
|
||||
console.debug('[Cider][Audio] Direct Mode to Equalizer')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
console.debug("[Cider][Audio] Finished hierarchical loading");
|
||||
|
||||
},
|
||||
|
||||
equalizer: function (){ // h1_1
|
||||
let BANDS = app.cfg.audio.equalizer.frequencies;
|
||||
let GAIN = app.cfg.audio.equalizer.gain;
|
||||
let Q = app.cfg.audio.equalizer.Q;
|
||||
let VIBRANTBASSBANDS = app.cfg.audio.vibrantBass.frequencies;
|
||||
let VIBRANTBASSGAIN = app.cfg.audio.vibrantBass.gain;
|
||||
let VIBRANTBASSQ = app.cfg.audio.vibrantBass.Q;
|
||||
CiderAudio.audioNodes.audioBands = []; CiderAudio.audioNodes.vibrantbassNode = [];
|
||||
|
||||
for (i = 0; i < BANDS.length; i++) {
|
||||
CiderAudio.audioNodes.audioBands = [];
|
||||
|
||||
for (let 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];
|
||||
|
@ -119,44 +643,14 @@ var CiderAudio = {
|
|||
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;
|
||||
// Dynamic-ish loading
|
||||
CiderAudio.hierarchical_loading();
|
||||
|
||||
for (i = 0; i < VIBRANTBASSBANDS.length; i++) {
|
||||
CiderAudio.audioNodes.vibrantbassNode[i] = CiderAudio.context.createBiquadFilter();
|
||||
CiderAudio.audioNodes.vibrantbassNode[i].type = 'peaking'; // 'peaking';
|
||||
CiderAudio.audioNodes.vibrantbassNode[i].frequency.value = VIBRANTBASSBANDS[i];
|
||||
CiderAudio.audioNodes.vibrantbassNode[i].Q.value = VIBRANTBASSQ[i];
|
||||
CiderAudio.audioNodes.vibrantbassNode[i].gain.value = VIBRANTBASSGAIN[i] * app.cfg.audio.vibrantBass.multiplier;
|
||||
}
|
||||
|
||||
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.vibrantbassNode[0]);
|
||||
|
||||
for (i = 1; i < VIBRANTBASSBANDS.length; i ++) {
|
||||
CiderAudio.audioNodes.vibrantbassNode[i-1].connect(CiderAudio.audioNodes.vibrantbassNode[i]);
|
||||
}
|
||||
CiderAudio.audioNodes.vibrantbassNode[VIBRANTBASSBANDS.length-1].connect(CiderAudio.audioNodes.audioBands[0]);
|
||||
|
||||
for (i = 1; i < BANDS.length; i ++) {
|
||||
for (let 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);
|
||||
}
|
||||
|
||||
}
|
||||
if (app.cfg.advanced.AudioContext){
|
||||
CiderAudio.init()
|
||||
|
||||
}
|
||||
export {CiderAudio}
|
BIN
src/renderer/audio/impulses/CiderSpatial_Conv.wav
Normal file
BIN
src/renderer/audio/impulses/CiderSpatial_Conv.wav
Normal file
Binary file not shown.
BIN
src/renderer/audio/impulses/CiderSpatial_Conv_v2.wav
Normal file
BIN
src/renderer/audio/impulses/CiderSpatial_Conv_v2.wav
Normal file
Binary file not shown.
File diff suppressed because it is too large
Load diff
2637
src/renderer/less/bootstrap-vue.min.css
vendored
Normal file
2637
src/renderer/less/bootstrap-vue.min.css
vendored
Normal file
File diff suppressed because it is too large
Load diff
7752
src/renderer/less/bootstrap.less
vendored
7752
src/renderer/less/bootstrap.less
vendored
File diff suppressed because it is too large
Load diff
553
src/renderer/less/codicon.css
Normal file
553
src/renderer/less/codicon.css
Normal file
|
@ -0,0 +1,553 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
@font-face {
|
||||
font-family: "codicon";
|
||||
font-display: block;
|
||||
src: url("codicon.ttf") format("truetype");
|
||||
}
|
||||
|
||||
.codicon[class*='codicon-'] {
|
||||
font: normal normal normal 16px/1 codicon;
|
||||
display: inline-block;
|
||||
text-decoration: none;
|
||||
text-rendering: auto;
|
||||
text-align: center;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
user-select: none;
|
||||
-webkit-user-select: none;
|
||||
-ms-user-select: none;
|
||||
}
|
||||
|
||||
/*---------------------
|
||||
* Modifiers
|
||||
*-------------------*/
|
||||
|
||||
@keyframes codicon-spin {
|
||||
100% {
|
||||
transform:rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
.codicon-sync.codicon-modifier-spin,
|
||||
.codicon-loading.codicon-modifier-spin,
|
||||
.codicon-gear.codicon-modifier-spin {
|
||||
/* Use steps to throttle FPS to reduce CPU usage */
|
||||
animation: codicon-spin 1.5s steps(30) infinite;
|
||||
}
|
||||
|
||||
.codicon-modifier-disabled {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
/* custom speed & easing for loading icon */
|
||||
.codicon-loading {
|
||||
animation-duration: 1s !important;
|
||||
animation-timing-function: cubic-bezier(0.53, 0.21, 0.29, 0.67) !important;
|
||||
}
|
||||
|
||||
/*---------------------
|
||||
* Icons
|
||||
*-------------------*/
|
||||
|
||||
.codicon-add:before { content: "\ea60" }
|
||||
.codicon-plus:before { content: "\ea60" }
|
||||
.codicon-gist-new:before { content: "\ea60" }
|
||||
.codicon-repo-create:before { content: "\ea60" }
|
||||
.codicon-lightbulb:before { content: "\ea61" }
|
||||
.codicon-light-bulb:before { content: "\ea61" }
|
||||
.codicon-repo:before { content: "\ea62" }
|
||||
.codicon-repo-delete:before { content: "\ea62" }
|
||||
.codicon-gist-fork:before { content: "\ea63" }
|
||||
.codicon-repo-forked:before { content: "\ea63" }
|
||||
.codicon-git-pull-request:before { content: "\ea64" }
|
||||
.codicon-git-pull-request-abandoned:before { content: "\ea64" }
|
||||
.codicon-record-keys:before { content: "\ea65" }
|
||||
.codicon-keyboard:before { content: "\ea65" }
|
||||
.codicon-tag:before { content: "\ea66" }
|
||||
.codicon-tag-add:before { content: "\ea66" }
|
||||
.codicon-tag-remove:before { content: "\ea66" }
|
||||
.codicon-person:before { content: "\ea67" }
|
||||
.codicon-person-follow:before { content: "\ea67" }
|
||||
.codicon-person-outline:before { content: "\ea67" }
|
||||
.codicon-person-filled:before { content: "\ea67" }
|
||||
.codicon-git-branch:before { content: "\ea68" }
|
||||
.codicon-git-branch-create:before { content: "\ea68" }
|
||||
.codicon-git-branch-delete:before { content: "\ea68" }
|
||||
.codicon-source-control:before { content: "\ea68" }
|
||||
.codicon-mirror:before { content: "\ea69" }
|
||||
.codicon-mirror-public:before { content: "\ea69" }
|
||||
.codicon-star:before { content: "\ea6a" }
|
||||
.codicon-star-add:before { content: "\ea6a" }
|
||||
.codicon-star-delete:before { content: "\ea6a" }
|
||||
.codicon-star-empty:before { content: "\ea6a" }
|
||||
.codicon-comment:before { content: "\ea6b" }
|
||||
.codicon-comment-add:before { content: "\ea6b" }
|
||||
.codicon-alert:before { content: "\ea6c" }
|
||||
.codicon-warning:before { content: "\ea6c" }
|
||||
.codicon-search:before { content: "\ea6d" }
|
||||
.codicon-search-save:before { content: "\ea6d" }
|
||||
.codicon-log-out:before { content: "\ea6e" }
|
||||
.codicon-sign-out:before { content: "\ea6e" }
|
||||
.codicon-log-in:before { content: "\ea6f" }
|
||||
.codicon-sign-in:before { content: "\ea6f" }
|
||||
.codicon-eye:before { content: "\ea70" }
|
||||
.codicon-eye-unwatch:before { content: "\ea70" }
|
||||
.codicon-eye-watch:before { content: "\ea70" }
|
||||
.codicon-circle-filled:before { content: "\ea71" }
|
||||
.codicon-primitive-dot:before { content: "\ea71" }
|
||||
.codicon-close-dirty:before { content: "\ea71" }
|
||||
.codicon-debug-breakpoint:before { content: "\ea71" }
|
||||
.codicon-debug-breakpoint-disabled:before { content: "\ea71" }
|
||||
.codicon-debug-hint:before { content: "\ea71" }
|
||||
.codicon-primitive-square:before { content: "\ea72" }
|
||||
.codicon-edit:before { content: "\ea73" }
|
||||
.codicon-pencil:before { content: "\ea73" }
|
||||
.codicon-info:before { content: "\ea74" }
|
||||
.codicon-issue-opened:before { content: "\ea74" }
|
||||
.codicon-gist-private:before { content: "\ea75" }
|
||||
.codicon-git-fork-private:before { content: "\ea75" }
|
||||
.codicon-lock:before { content: "\ea75" }
|
||||
.codicon-mirror-private:before { content: "\ea75" }
|
||||
.codicon-close:before { content: "\ea76" }
|
||||
.codicon-remove-close:before { content: "\ea76" }
|
||||
.codicon-x:before { content: "\ea76" }
|
||||
.codicon-repo-sync:before { content: "\ea77" }
|
||||
.codicon-sync:before { content: "\ea77" }
|
||||
.codicon-clone:before { content: "\ea78" }
|
||||
.codicon-desktop-download:before { content: "\ea78" }
|
||||
.codicon-beaker:before { content: "\ea79" }
|
||||
.codicon-microscope:before { content: "\ea79" }
|
||||
.codicon-vm:before { content: "\ea7a" }
|
||||
.codicon-device-desktop:before { content: "\ea7a" }
|
||||
.codicon-file:before { content: "\ea7b" }
|
||||
.codicon-file-text:before { content: "\ea7b" }
|
||||
.codicon-more:before { content: "\ea7c" }
|
||||
.codicon-ellipsis:before { content: "\ea7c" }
|
||||
.codicon-kebab-horizontal:before { content: "\ea7c" }
|
||||
.codicon-mail-reply:before { content: "\ea7d" }
|
||||
.codicon-reply:before { content: "\ea7d" }
|
||||
.codicon-organization:before { content: "\ea7e" }
|
||||
.codicon-organization-filled:before { content: "\ea7e" }
|
||||
.codicon-organization-outline:before { content: "\ea7e" }
|
||||
.codicon-new-file:before { content: "\ea7f" }
|
||||
.codicon-file-add:before { content: "\ea7f" }
|
||||
.codicon-new-folder:before { content: "\ea80" }
|
||||
.codicon-file-directory-create:before { content: "\ea80" }
|
||||
.codicon-trash:before { content: "\ea81" }
|
||||
.codicon-trashcan:before { content: "\ea81" }
|
||||
.codicon-history:before { content: "\ea82" }
|
||||
.codicon-clock:before { content: "\ea82" }
|
||||
.codicon-folder:before { content: "\ea83" }
|
||||
.codicon-file-directory:before { content: "\ea83" }
|
||||
.codicon-symbol-folder:before { content: "\ea83" }
|
||||
.codicon-logo-github:before { content: "\ea84" }
|
||||
.codicon-mark-github:before { content: "\ea84" }
|
||||
.codicon-github:before { content: "\ea84" }
|
||||
.codicon-terminal:before { content: "\ea85" }
|
||||
.codicon-console:before { content: "\ea85" }
|
||||
.codicon-repl:before { content: "\ea85" }
|
||||
.codicon-zap:before { content: "\ea86" }
|
||||
.codicon-symbol-event:before { content: "\ea86" }
|
||||
.codicon-error:before { content: "\ea87" }
|
||||
.codicon-stop:before { content: "\ea87" }
|
||||
.codicon-variable:before { content: "\ea88" }
|
||||
.codicon-symbol-variable:before { content: "\ea88" }
|
||||
.codicon-array:before { content: "\ea8a" }
|
||||
.codicon-symbol-array:before { content: "\ea8a" }
|
||||
.codicon-symbol-module:before { content: "\ea8b" }
|
||||
.codicon-symbol-package:before { content: "\ea8b" }
|
||||
.codicon-symbol-namespace:before { content: "\ea8b" }
|
||||
.codicon-symbol-object:before { content: "\ea8b" }
|
||||
.codicon-symbol-method:before { content: "\ea8c" }
|
||||
.codicon-symbol-function:before { content: "\ea8c" }
|
||||
.codicon-symbol-constructor:before { content: "\ea8c" }
|
||||
.codicon-symbol-boolean:before { content: "\ea8f" }
|
||||
.codicon-symbol-null:before { content: "\ea8f" }
|
||||
.codicon-symbol-numeric:before { content: "\ea90" }
|
||||
.codicon-symbol-number:before { content: "\ea90" }
|
||||
.codicon-symbol-structure:before { content: "\ea91" }
|
||||
.codicon-symbol-struct:before { content: "\ea91" }
|
||||
.codicon-symbol-parameter:before { content: "\ea92" }
|
||||
.codicon-symbol-type-parameter:before { content: "\ea92" }
|
||||
.codicon-symbol-key:before { content: "\ea93" }
|
||||
.codicon-symbol-text:before { content: "\ea93" }
|
||||
.codicon-symbol-reference:before { content: "\ea94" }
|
||||
.codicon-go-to-file:before { content: "\ea94" }
|
||||
.codicon-symbol-enum:before { content: "\ea95" }
|
||||
.codicon-symbol-value:before { content: "\ea95" }
|
||||
.codicon-symbol-ruler:before { content: "\ea96" }
|
||||
.codicon-symbol-unit:before { content: "\ea96" }
|
||||
.codicon-activate-breakpoints:before { content: "\ea97" }
|
||||
.codicon-archive:before { content: "\ea98" }
|
||||
.codicon-arrow-both:before { content: "\ea99" }
|
||||
.codicon-arrow-down:before { content: "\ea9a" }
|
||||
.codicon-arrow-left:before { content: "\ea9b" }
|
||||
.codicon-arrow-right:before { content: "\ea9c" }
|
||||
.codicon-arrow-small-down:before { content: "\ea9d" }
|
||||
.codicon-arrow-small-left:before { content: "\ea9e" }
|
||||
.codicon-arrow-small-right:before { content: "\ea9f" }
|
||||
.codicon-arrow-small-up:before { content: "\eaa0" }
|
||||
.codicon-arrow-up:before { content: "\eaa1" }
|
||||
.codicon-bell:before { content: "\eaa2" }
|
||||
.codicon-bold:before { content: "\eaa3" }
|
||||
.codicon-book:before { content: "\eaa4" }
|
||||
.codicon-bookmark:before { content: "\eaa5" }
|
||||
.codicon-debug-breakpoint-conditional-unverified:before { content: "\eaa6" }
|
||||
.codicon-debug-breakpoint-conditional:before { content: "\eaa7" }
|
||||
.codicon-debug-breakpoint-conditional-disabled:before { content: "\eaa7" }
|
||||
.codicon-debug-breakpoint-data-unverified:before { content: "\eaa8" }
|
||||
.codicon-debug-breakpoint-data:before { content: "\eaa9" }
|
||||
.codicon-debug-breakpoint-data-disabled:before { content: "\eaa9" }
|
||||
.codicon-debug-breakpoint-log-unverified:before { content: "\eaaa" }
|
||||
.codicon-debug-breakpoint-log:before { content: "\eaab" }
|
||||
.codicon-debug-breakpoint-log-disabled:before { content: "\eaab" }
|
||||
.codicon-briefcase:before { content: "\eaac" }
|
||||
.codicon-broadcast:before { content: "\eaad" }
|
||||
.codicon-browser:before { content: "\eaae" }
|
||||
.codicon-bug:before { content: "\eaaf" }
|
||||
.codicon-calendar:before { content: "\eab0" }
|
||||
.codicon-case-sensitive:before { content: "\eab1" }
|
||||
.codicon-check:before { content: "\eab2" }
|
||||
.codicon-checklist:before { content: "\eab3" }
|
||||
.codicon-chevron-down:before { content: "\eab4" }
|
||||
.codicon-chevron-left:before { content: "\eab5" }
|
||||
.codicon-chevron-right:before { content: "\eab6" }
|
||||
.codicon-chevron-up:before { content: "\eab7" }
|
||||
.codicon-chrome-close:before { content: "\eab8" }
|
||||
.codicon-chrome-maximize:before { content: "\eab9" }
|
||||
.codicon-chrome-minimize:before { content: "\eaba" }
|
||||
.codicon-chrome-restore:before { content: "\eabb" }
|
||||
.codicon-circle-outline:before { content: "\eabc" }
|
||||
.codicon-debug-breakpoint-unverified:before { content: "\eabc" }
|
||||
.codicon-circle-slash:before { content: "\eabd" }
|
||||
.codicon-circuit-board:before { content: "\eabe" }
|
||||
.codicon-clear-all:before { content: "\eabf" }
|
||||
.codicon-clippy:before { content: "\eac0" }
|
||||
.codicon-close-all:before { content: "\eac1" }
|
||||
.codicon-cloud-download:before { content: "\eac2" }
|
||||
.codicon-cloud-upload:before { content: "\eac3" }
|
||||
.codicon-code:before { content: "\eac4" }
|
||||
.codicon-collapse-all:before { content: "\eac5" }
|
||||
.codicon-color-mode:before { content: "\eac6" }
|
||||
.codicon-comment-discussion:before { content: "\eac7" }
|
||||
.codicon-credit-card:before { content: "\eac9" }
|
||||
.codicon-dash:before { content: "\eacc" }
|
||||
.codicon-dashboard:before { content: "\eacd" }
|
||||
.codicon-database:before { content: "\eace" }
|
||||
.codicon-debug-continue:before { content: "\eacf" }
|
||||
.codicon-debug-disconnect:before { content: "\ead0" }
|
||||
.codicon-debug-pause:before { content: "\ead1" }
|
||||
.codicon-debug-restart:before { content: "\ead2" }
|
||||
.codicon-debug-start:before { content: "\ead3" }
|
||||
.codicon-debug-step-into:before { content: "\ead4" }
|
||||
.codicon-debug-step-out:before { content: "\ead5" }
|
||||
.codicon-debug-step-over:before { content: "\ead6" }
|
||||
.codicon-debug-stop:before { content: "\ead7" }
|
||||
.codicon-debug:before { content: "\ead8" }
|
||||
.codicon-device-camera-video:before { content: "\ead9" }
|
||||
.codicon-device-camera:before { content: "\eada" }
|
||||
.codicon-device-mobile:before { content: "\eadb" }
|
||||
.codicon-diff-added:before { content: "\eadc" }
|
||||
.codicon-diff-ignored:before { content: "\eadd" }
|
||||
.codicon-diff-modified:before { content: "\eade" }
|
||||
.codicon-diff-removed:before { content: "\eadf" }
|
||||
.codicon-diff-renamed:before { content: "\eae0" }
|
||||
.codicon-diff:before { content: "\eae1" }
|
||||
.codicon-discard:before { content: "\eae2" }
|
||||
.codicon-editor-layout:before { content: "\eae3" }
|
||||
.codicon-empty-window:before { content: "\eae4" }
|
||||
.codicon-exclude:before { content: "\eae5" }
|
||||
.codicon-extensions:before { content: "\eae6" }
|
||||
.codicon-eye-closed:before { content: "\eae7" }
|
||||
.codicon-file-binary:before { content: "\eae8" }
|
||||
.codicon-file-code:before { content: "\eae9" }
|
||||
.codicon-file-media:before { content: "\eaea" }
|
||||
.codicon-file-pdf:before { content: "\eaeb" }
|
||||
.codicon-file-submodule:before { content: "\eaec" }
|
||||
.codicon-file-symlink-directory:before { content: "\eaed" }
|
||||
.codicon-file-symlink-file:before { content: "\eaee" }
|
||||
.codicon-file-zip:before { content: "\eaef" }
|
||||
.codicon-files:before { content: "\eaf0" }
|
||||
.codicon-filter:before { content: "\eaf1" }
|
||||
.codicon-flame:before { content: "\eaf2" }
|
||||
.codicon-fold-down:before { content: "\eaf3" }
|
||||
.codicon-fold-up:before { content: "\eaf4" }
|
||||
.codicon-fold:before { content: "\eaf5" }
|
||||
.codicon-folder-active:before { content: "\eaf6" }
|
||||
.codicon-folder-opened:before { content: "\eaf7" }
|
||||
.codicon-gear:before { content: "\eaf8" }
|
||||
.codicon-gift:before { content: "\eaf9" }
|
||||
.codicon-gist-secret:before { content: "\eafa" }
|
||||
.codicon-gist:before { content: "\eafb" }
|
||||
.codicon-git-commit:before { content: "\eafc" }
|
||||
.codicon-git-compare:before { content: "\eafd" }
|
||||
.codicon-compare-changes:before { content: "\eafd" }
|
||||
.codicon-git-merge:before { content: "\eafe" }
|
||||
.codicon-github-action:before { content: "\eaff" }
|
||||
.codicon-github-alt:before { content: "\eb00" }
|
||||
.codicon-globe:before { content: "\eb01" }
|
||||
.codicon-grabber:before { content: "\eb02" }
|
||||
.codicon-graph:before { content: "\eb03" }
|
||||
.codicon-gripper:before { content: "\eb04" }
|
||||
.codicon-heart:before { content: "\eb05" }
|
||||
.codicon-home:before { content: "\eb06" }
|
||||
.codicon-horizontal-rule:before { content: "\eb07" }
|
||||
.codicon-hubot:before { content: "\eb08" }
|
||||
.codicon-inbox:before { content: "\eb09" }
|
||||
.codicon-issue-reopened:before { content: "\eb0b" }
|
||||
.codicon-issues:before { content: "\eb0c" }
|
||||
.codicon-italic:before { content: "\eb0d" }
|
||||
.codicon-jersey:before { content: "\eb0e" }
|
||||
.codicon-json:before { content: "\eb0f" }
|
||||
.codicon-kebab-vertical:before { content: "\eb10" }
|
||||
.codicon-key:before { content: "\eb11" }
|
||||
.codicon-law:before { content: "\eb12" }
|
||||
.codicon-lightbulb-autofix:before { content: "\eb13" }
|
||||
.codicon-link-external:before { content: "\eb14" }
|
||||
.codicon-link:before { content: "\eb15" }
|
||||
.codicon-list-ordered:before { content: "\eb16" }
|
||||
.codicon-list-unordered:before { content: "\eb17" }
|
||||
.codicon-live-share:before { content: "\eb18" }
|
||||
.codicon-loading:before { content: "\eb19" }
|
||||
.codicon-location:before { content: "\eb1a" }
|
||||
.codicon-mail-read:before { content: "\eb1b" }
|
||||
.codicon-mail:before { content: "\eb1c" }
|
||||
.codicon-markdown:before { content: "\eb1d" }
|
||||
.codicon-megaphone:before { content: "\eb1e" }
|
||||
.codicon-mention:before { content: "\eb1f" }
|
||||
.codicon-milestone:before { content: "\eb20" }
|
||||
.codicon-mortar-board:before { content: "\eb21" }
|
||||
.codicon-move:before { content: "\eb22" }
|
||||
.codicon-multiple-windows:before { content: "\eb23" }
|
||||
.codicon-mute:before { content: "\eb24" }
|
||||
.codicon-no-newline:before { content: "\eb25" }
|
||||
.codicon-note:before { content: "\eb26" }
|
||||
.codicon-octoface:before { content: "\eb27" }
|
||||
.codicon-open-preview:before { content: "\eb28" }
|
||||
.codicon-package:before { content: "\eb29" }
|
||||
.codicon-paintcan:before { content: "\eb2a" }
|
||||
.codicon-pin:before { content: "\eb2b" }
|
||||
.codicon-play:before { content: "\eb2c" }
|
||||
.codicon-run:before { content: "\eb2c" }
|
||||
.codicon-plug:before { content: "\eb2d" }
|
||||
.codicon-preserve-case:before { content: "\eb2e" }
|
||||
.codicon-preview:before { content: "\eb2f" }
|
||||
.codicon-project:before { content: "\eb30" }
|
||||
.codicon-pulse:before { content: "\eb31" }
|
||||
.codicon-question:before { content: "\eb32" }
|
||||
.codicon-quote:before { content: "\eb33" }
|
||||
.codicon-radio-tower:before { content: "\eb34" }
|
||||
.codicon-reactions:before { content: "\eb35" }
|
||||
.codicon-references:before { content: "\eb36" }
|
||||
.codicon-refresh:before { content: "\eb37" }
|
||||
.codicon-regex:before { content: "\eb38" }
|
||||
.codicon-remote-explorer:before { content: "\eb39" }
|
||||
.codicon-remote:before { content: "\eb3a" }
|
||||
.codicon-remove:before { content: "\eb3b" }
|
||||
.codicon-replace-all:before { content: "\eb3c" }
|
||||
.codicon-replace:before { content: "\eb3d" }
|
||||
.codicon-repo-clone:before { content: "\eb3e" }
|
||||
.codicon-repo-force-push:before { content: "\eb3f" }
|
||||
.codicon-repo-pull:before { content: "\eb40" }
|
||||
.codicon-repo-push:before { content: "\eb41" }
|
||||
.codicon-report:before { content: "\eb42" }
|
||||
.codicon-request-changes:before { content: "\eb43" }
|
||||
.codicon-rocket:before { content: "\eb44" }
|
||||
.codicon-root-folder-opened:before { content: "\eb45" }
|
||||
.codicon-root-folder:before { content: "\eb46" }
|
||||
.codicon-rss:before { content: "\eb47" }
|
||||
.codicon-ruby:before { content: "\eb48" }
|
||||
.codicon-save-all:before { content: "\eb49" }
|
||||
.codicon-save-as:before { content: "\eb4a" }
|
||||
.codicon-save:before { content: "\eb4b" }
|
||||
.codicon-screen-full:before { content: "\eb4c" }
|
||||
.codicon-screen-normal:before { content: "\eb4d" }
|
||||
.codicon-search-stop:before { content: "\eb4e" }
|
||||
.codicon-server:before { content: "\eb50" }
|
||||
.codicon-settings-gear:before { content: "\eb51" }
|
||||
.codicon-settings:before { content: "\eb52" }
|
||||
.codicon-shield:before { content: "\eb53" }
|
||||
.codicon-smiley:before { content: "\eb54" }
|
||||
.codicon-sort-precedence:before { content: "\eb55" }
|
||||
.codicon-split-horizontal:before { content: "\eb56" }
|
||||
.codicon-split-vertical:before { content: "\eb57" }
|
||||
.codicon-squirrel:before { content: "\eb58" }
|
||||
.codicon-star-full:before { content: "\eb59" }
|
||||
.codicon-star-half:before { content: "\eb5a" }
|
||||
.codicon-symbol-class:before { content: "\eb5b" }
|
||||
.codicon-symbol-color:before { content: "\eb5c" }
|
||||
.codicon-symbol-constant:before { content: "\eb5d" }
|
||||
.codicon-symbol-enum-member:before { content: "\eb5e" }
|
||||
.codicon-symbol-field:before { content: "\eb5f" }
|
||||
.codicon-symbol-file:before { content: "\eb60" }
|
||||
.codicon-symbol-interface:before { content: "\eb61" }
|
||||
.codicon-symbol-keyword:before { content: "\eb62" }
|
||||
.codicon-symbol-misc:before { content: "\eb63" }
|
||||
.codicon-symbol-operator:before { content: "\eb64" }
|
||||
.codicon-symbol-property:before { content: "\eb65" }
|
||||
.codicon-wrench:before { content: "\eb65" }
|
||||
.codicon-wrench-subaction:before { content: "\eb65" }
|
||||
.codicon-symbol-snippet:before { content: "\eb66" }
|
||||
.codicon-tasklist:before { content: "\eb67" }
|
||||
.codicon-telescope:before { content: "\eb68" }
|
||||
.codicon-text-size:before { content: "\eb69" }
|
||||
.codicon-three-bars:before { content: "\eb6a" }
|
||||
.codicon-thumbsdown:before { content: "\eb6b" }
|
||||
.codicon-thumbsup:before { content: "\eb6c" }
|
||||
.codicon-tools:before { content: "\eb6d" }
|
||||
.codicon-triangle-down:before { content: "\eb6e" }
|
||||
.codicon-triangle-left:before { content: "\eb6f" }
|
||||
.codicon-triangle-right:before { content: "\eb70" }
|
||||
.codicon-triangle-up:before { content: "\eb71" }
|
||||
.codicon-twitter:before { content: "\eb72" }
|
||||
.codicon-unfold:before { content: "\eb73" }
|
||||
.codicon-unlock:before { content: "\eb74" }
|
||||
.codicon-unmute:before { content: "\eb75" }
|
||||
.codicon-unverified:before { content: "\eb76" }
|
||||
.codicon-verified:before { content: "\eb77" }
|
||||
.codicon-versions:before { content: "\eb78" }
|
||||
.codicon-vm-active:before { content: "\eb79" }
|
||||
.codicon-vm-outline:before { content: "\eb7a" }
|
||||
.codicon-vm-running:before { content: "\eb7b" }
|
||||
.codicon-watch:before { content: "\eb7c" }
|
||||
.codicon-whitespace:before { content: "\eb7d" }
|
||||
.codicon-whole-word:before { content: "\eb7e" }
|
||||
.codicon-window:before { content: "\eb7f" }
|
||||
.codicon-word-wrap:before { content: "\eb80" }
|
||||
.codicon-zoom-in:before { content: "\eb81" }
|
||||
.codicon-zoom-out:before { content: "\eb82" }
|
||||
.codicon-list-filter:before { content: "\eb83" }
|
||||
.codicon-list-flat:before { content: "\eb84" }
|
||||
.codicon-list-selection:before { content: "\eb85" }
|
||||
.codicon-selection:before { content: "\eb85" }
|
||||
.codicon-list-tree:before { content: "\eb86" }
|
||||
.codicon-debug-breakpoint-function-unverified:before { content: "\eb87" }
|
||||
.codicon-debug-breakpoint-function:before { content: "\eb88" }
|
||||
.codicon-debug-breakpoint-function-disabled:before { content: "\eb88" }
|
||||
.codicon-debug-stackframe-active:before { content: "\eb89" }
|
||||
.codicon-debug-stackframe-dot:before { content: "\eb8a" }
|
||||
.codicon-debug-stackframe:before { content: "\eb8b" }
|
||||
.codicon-debug-stackframe-focused:before { content: "\eb8b" }
|
||||
.codicon-debug-breakpoint-unsupported:before { content: "\eb8c" }
|
||||
.codicon-symbol-string:before { content: "\eb8d" }
|
||||
.codicon-debug-reverse-continue:before { content: "\eb8e" }
|
||||
.codicon-debug-step-back:before { content: "\eb8f" }
|
||||
.codicon-debug-restart-frame:before { content: "\eb90" }
|
||||
.codicon-debug-alt:before { content: "\eb91" }
|
||||
.codicon-call-incoming:before { content: "\eb92" }
|
||||
.codicon-call-outgoing:before { content: "\eb93" }
|
||||
.codicon-menu:before { content: "\eb94" }
|
||||
.codicon-expand-all:before { content: "\eb95" }
|
||||
.codicon-feedback:before { content: "\eb96" }
|
||||
.codicon-group-by-ref-type:before { content: "\eb97" }
|
||||
.codicon-ungroup-by-ref-type:before { content: "\eb98" }
|
||||
.codicon-account:before { content: "\eb99" }
|
||||
.codicon-bell-dot:before { content: "\eb9a" }
|
||||
.codicon-debug-console:before { content: "\eb9b" }
|
||||
.codicon-library:before { content: "\eb9c" }
|
||||
.codicon-output:before { content: "\eb9d" }
|
||||
.codicon-run-all:before { content: "\eb9e" }
|
||||
.codicon-sync-ignored:before { content: "\eb9f" }
|
||||
.codicon-pinned:before { content: "\eba0" }
|
||||
.codicon-github-inverted:before { content: "\eba1" }
|
||||
.codicon-server-process:before { content: "\eba2" }
|
||||
.codicon-server-environment:before { content: "\eba3" }
|
||||
.codicon-pass:before { content: "\eba4" }
|
||||
.codicon-issue-closed:before { content: "\eba4" }
|
||||
.codicon-stop-circle:before { content: "\eba5" }
|
||||
.codicon-play-circle:before { content: "\eba6" }
|
||||
.codicon-record:before { content: "\eba7" }
|
||||
.codicon-debug-alt-small:before { content: "\eba8" }
|
||||
.codicon-vm-connect:before { content: "\eba9" }
|
||||
.codicon-cloud:before { content: "\ebaa" }
|
||||
.codicon-merge:before { content: "\ebab" }
|
||||
.codicon-export:before { content: "\ebac" }
|
||||
.codicon-graph-left:before { content: "\ebad" }
|
||||
.codicon-magnet:before { content: "\ebae" }
|
||||
.codicon-notebook:before { content: "\ebaf" }
|
||||
.codicon-redo:before { content: "\ebb0" }
|
||||
.codicon-check-all:before { content: "\ebb1" }
|
||||
.codicon-pinned-dirty:before { content: "\ebb2" }
|
||||
.codicon-pass-filled:before { content: "\ebb3" }
|
||||
.codicon-circle-large-filled:before { content: "\ebb4" }
|
||||
.codicon-circle-large-outline:before { content: "\ebb5" }
|
||||
.codicon-combine:before { content: "\ebb6" }
|
||||
.codicon-gather:before { content: "\ebb6" }
|
||||
.codicon-table:before { content: "\ebb7" }
|
||||
.codicon-variable-group:before { content: "\ebb8" }
|
||||
.codicon-type-hierarchy:before { content: "\ebb9" }
|
||||
.codicon-type-hierarchy-sub:before { content: "\ebba" }
|
||||
.codicon-type-hierarchy-super:before { content: "\ebbb" }
|
||||
.codicon-git-pull-request-create:before { content: "\ebbc" }
|
||||
.codicon-run-above:before { content: "\ebbd" }
|
||||
.codicon-run-below:before { content: "\ebbe" }
|
||||
.codicon-notebook-template:before { content: "\ebbf" }
|
||||
.codicon-debug-rerun:before { content: "\ebc0" }
|
||||
.codicon-workspace-trusted:before { content: "\ebc1" }
|
||||
.codicon-workspace-untrusted:before { content: "\ebc2" }
|
||||
.codicon-workspace-unknown:before { content: "\ebc3" }
|
||||
.codicon-terminal-cmd:before { content: "\ebc4" }
|
||||
.codicon-terminal-debian:before { content: "\ebc5" }
|
||||
.codicon-terminal-linux:before { content: "\ebc6" }
|
||||
.codicon-terminal-powershell:before { content: "\ebc7" }
|
||||
.codicon-terminal-tmux:before { content: "\ebc8" }
|
||||
.codicon-terminal-ubuntu:before { content: "\ebc9" }
|
||||
.codicon-terminal-bash:before { content: "\ebca" }
|
||||
.codicon-arrow-swap:before { content: "\ebcb" }
|
||||
.codicon-copy:before { content: "\ebcc" }
|
||||
.codicon-person-add:before { content: "\ebcd" }
|
||||
.codicon-filter-filled:before { content: "\ebce" }
|
||||
.codicon-wand:before { content: "\ebcf" }
|
||||
.codicon-debug-line-by-line:before { content: "\ebd0" }
|
||||
.codicon-inspect:before { content: "\ebd1" }
|
||||
.codicon-layers:before { content: "\ebd2" }
|
||||
.codicon-layers-dot:before { content: "\ebd3" }
|
||||
.codicon-layers-active:before { content: "\ebd4" }
|
||||
.codicon-compass:before { content: "\ebd5" }
|
||||
.codicon-compass-dot:before { content: "\ebd6" }
|
||||
.codicon-compass-active:before { content: "\ebd7" }
|
||||
.codicon-azure:before { content: "\ebd8" }
|
||||
.codicon-issue-draft:before { content: "\ebd9" }
|
||||
.codicon-git-pull-request-closed:before { content: "\ebda" }
|
||||
.codicon-git-pull-request-draft:before { content: "\ebdb" }
|
||||
.codicon-debug-all:before { content: "\ebdc" }
|
||||
.codicon-debug-coverage:before { content: "\ebdd" }
|
||||
.codicon-run-errors:before { content: "\ebde" }
|
||||
.codicon-folder-library:before { content: "\ebdf" }
|
||||
.codicon-debug-continue-small:before { content: "\ebe0" }
|
||||
.codicon-beaker-stop:before { content: "\ebe1" }
|
||||
.codicon-graph-line:before { content: "\ebe2" }
|
||||
.codicon-graph-scatter:before { content: "\ebe3" }
|
||||
.codicon-pie-chart:before { content: "\ebe4" }
|
||||
.codicon-bracket:before { content: "\eb0f" }
|
||||
.codicon-bracket-dot:before { content: "\ebe5" }
|
||||
.codicon-bracket-error:before { content: "\ebe6" }
|
||||
.codicon-lock-small:before { content: "\ebe7" }
|
||||
.codicon-azure-devops:before { content: "\ebe8" }
|
||||
.codicon-verified-filled:before { content: "\ebe9" }
|
||||
.codicon-newline:before { content: "\ebea" }
|
||||
.codicon-layout:before { content: "\ebeb" }
|
||||
.codicon-layout-activitybar-left:before { content: "\ebec" }
|
||||
.codicon-layout-activitybar-right:before { content: "\ebed" }
|
||||
.codicon-layout-panel-left:before { content: "\ebee" }
|
||||
.codicon-layout-panel-center:before { content: "\ebef" }
|
||||
.codicon-layout-panel-justify:before { content: "\ebf0" }
|
||||
.codicon-layout-panel-right:before { content: "\ebf1" }
|
||||
.codicon-layout-panel:before { content: "\ebf2" }
|
||||
.codicon-layout-sidebar-left:before { content: "\ebf3" }
|
||||
.codicon-layout-sidebar-right:before { content: "\ebf4" }
|
||||
.codicon-layout-statusbar:before { content: "\ebf5" }
|
||||
.codicon-layout-menubar:before { content: "\ebf6" }
|
||||
.codicon-layout-centered:before { content: "\ebf7" }
|
||||
.codicon-target:before { content: "\ebf8" }
|
||||
.codicon-indent:before { content: "\ebf9" }
|
||||
.codicon-record-small:before { content: "\ebfa" }
|
||||
.codicon-error-small:before { content: "\ebfb" }
|
||||
.codicon-arrow-circle-down:before { content: "\ebfc" }
|
||||
.codicon-arrow-circle-left:before { content: "\ebfd" }
|
||||
.codicon-arrow-circle-right:before { content: "\ebfe" }
|
||||
.codicon-arrow-circle-up:before { content: "\ebff" }
|
2
src/renderer/less/codicon.svg
Normal file
2
src/renderer/less/codicon.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 263 KiB |
BIN
src/renderer/less/codicon.ttf
Normal file
BIN
src/renderer/less/codicon.ttf
Normal file
Binary file not shown.
182
src/renderer/less/directives.less
Normal file
182
src/renderer/less/directives.less
Normal file
|
@ -0,0 +1,182 @@
|
|||
#app.twopanel {
|
||||
--chromeHeight1: 42px;
|
||||
--chromeHeight2: 76px;
|
||||
--chromeHeight: calc(var(--chromeHeight1) + var(--chromeHeight2));
|
||||
|
||||
.app-chrome {
|
||||
.app-mainmenu {
|
||||
margin-left: 10px;
|
||||
width: 88px;
|
||||
}
|
||||
|
||||
height: var(--chromeHeight1);
|
||||
|
||||
&.chrome-bottom {
|
||||
height: var(--chromeHeight2);
|
||||
box-shadow: 0px -1px 0px rgba(0, 0, 0, 0.25);
|
||||
}
|
||||
}
|
||||
|
||||
.app-sidebar-footer--controls {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.app-chrome.chrome-bottom {
|
||||
.app-playback-controls .actions {
|
||||
align-self: center;
|
||||
}
|
||||
|
||||
.playback-button.play,
|
||||
.playback-button.pause {
|
||||
width: 42px;
|
||||
height: 42px;
|
||||
background-color: rgb(200 200 200 / 20%);
|
||||
border-radius: 50%;
|
||||
margin: 6px;
|
||||
box-shadow: 0px 0px 0px 2px var(--keyColor);
|
||||
}
|
||||
|
||||
.app-chrome--center {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.app-chrome-playback-controls {
|
||||
display: flex;
|
||||
z-index: 1;
|
||||
// margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.app-chrome-playback-duration {
|
||||
position: relative;
|
||||
width: 80%;
|
||||
-webkit-app-region: no-drag;
|
||||
height: 16px;
|
||||
|
||||
.song-progress {
|
||||
@bgColor: transparent;
|
||||
height: 16px;
|
||||
position: absolute;
|
||||
bottom: 4px;
|
||||
left: 0px;
|
||||
right: 4px;
|
||||
background: @bgColor;
|
||||
z-index: 0;
|
||||
|
||||
|
||||
.song-duration {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.song-duration p {
|
||||
font-weight: 400;
|
||||
font-size: 10px;
|
||||
height: 1.2em;
|
||||
line-height: 1.3em;
|
||||
overflow: hidden;
|
||||
margin: 0 0 0 0.25em;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
> input[type=range] {
|
||||
&::-webkit-slider-thumb {
|
||||
opacity: 1;
|
||||
transform: scale(1);
|
||||
z-index: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
input[type=range] {
|
||||
appearance: none;
|
||||
width: 100%;
|
||||
height: 4px;
|
||||
background-color: rgb(200 200 200 / 10%);
|
||||
border-radius: 2px;
|
||||
|
||||
&::-webkit-slider-thumb {
|
||||
opacity: 0;
|
||||
transform: scale(0.5);
|
||||
-webkit-appearance: none;
|
||||
appearance: none;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
border-radius: 100%;
|
||||
background: var(--keyColor);
|
||||
cursor: default;
|
||||
transition: opacity .10s var(--appleEase), transform .10s var(--appleEase);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.app-chrome--left {
|
||||
width: 30%;
|
||||
justify-content: flex-start;
|
||||
align-items: flex-start;
|
||||
|
||||
.playback-controls {
|
||||
.artwork {
|
||||
width: var(--chromeHeight2);
|
||||
height: var(--chromeHeight2);
|
||||
margin: 0px 6px 0px 0px;
|
||||
box-shadow: unset;
|
||||
border: 0px;
|
||||
|
||||
.mediaitem-artwork,
|
||||
img {
|
||||
border-radius: 0px;
|
||||
box-shadow: unset;
|
||||
border: 0px;
|
||||
}
|
||||
}
|
||||
|
||||
.playback-info {
|
||||
align-items: flex-start;
|
||||
margin: 6px;
|
||||
|
||||
.song-name {
|
||||
text-align: left;
|
||||
font-size: 15px;
|
||||
font-weight: initial;
|
||||
width: 100%;
|
||||
-webkit-mask-image: linear-gradient(-90deg, transparent 0%, transparent 10%, black 20%);
|
||||
}
|
||||
|
||||
.song-artist-album {
|
||||
width: 100%;
|
||||
-webkit-mask-image: linear-gradient(-90deg, transparent 0%, transparent 10%, black 20%);
|
||||
}
|
||||
|
||||
.audio-type {
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
.song-artist-album-content {
|
||||
text-align: left;
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
max-width: 100%;
|
||||
border: 0px;
|
||||
}
|
||||
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
.app-chrome--right {
|
||||
width: 30%;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
}
|
||||
.collection-page {
|
||||
.top-fab {
|
||||
bottom:96px;
|
||||
}
|
||||
}
|
||||
}
|
1838
src/renderer/less/elements.less
Normal file
1838
src/renderer/less/elements.less
Normal file
File diff suppressed because it is too large
Load diff
407
src/renderer/less/helpers.less
Normal file
407
src/renderer/less/helpers.less
Normal file
|
@ -0,0 +1,407 @@
|
|||
.notyf__toast {
|
||||
-webkit-app-region: no-drag;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.notyf-info {
|
||||
background: var(--keyColor);
|
||||
}
|
||||
|
||||
|
||||
|
||||
.modal-fullscreen {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(0, 0, 0, 0.3);
|
||||
z-index: 1000;
|
||||
|
||||
.modal-window {
|
||||
background: #333;
|
||||
border-radius: 10px;
|
||||
box-shadow: var(--mediaItemShadow-Shadow);
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
max-height: 500px;
|
||||
max-width: 360px;
|
||||
background: #121212;
|
||||
width: 100%;
|
||||
position: relative;
|
||||
|
||||
&:after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
pointer-events: none;
|
||||
box-shadow: var(--mediaItemShadow);
|
||||
z-index: 1;
|
||||
border-radius: inherit;
|
||||
}
|
||||
|
||||
.modal-header {
|
||||
width: 100%;
|
||||
padding: 6px;
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
overflow-y: overlay;
|
||||
}
|
||||
|
||||
.modal-footer {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.spatialproperties-panel {
|
||||
.modal-window {
|
||||
height: 700px;
|
||||
max-height: 700px;
|
||||
width: 800px;
|
||||
max-width: 800px;
|
||||
overflow: hidden;
|
||||
|
||||
.info-header {
|
||||
padding-left: 12px;
|
||||
}
|
||||
|
||||
.visual-container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.visual {
|
||||
position: relative;
|
||||
height: 250px;
|
||||
width: 300px;
|
||||
display: inline-flex;
|
||||
align-items: flex-end;
|
||||
justify-content: center;
|
||||
filter: drop-shadow(2px 12px 6px rgb(0 0 0 / 25%));
|
||||
margin: 0 auto;
|
||||
|
||||
.face {
|
||||
position: absolute;
|
||||
width: calc(12px * 6);
|
||||
height: calc(12px * 6);
|
||||
border-radius: 6px;
|
||||
transform: rotateX(60deg) rotateZ(-45deg);
|
||||
transition: transform 0.2s linear, width 0.2s linear, height 0.2s linear;
|
||||
}
|
||||
|
||||
.listener {
|
||||
position: absolute;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border-radius: 6px;
|
||||
transform: rotateX(60deg) rotateZ(-45deg);
|
||||
transition: transform 0.2s linear, width 0.2s linear, height 0.2s linear;
|
||||
background: white;
|
||||
color: black;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.audiosource {
|
||||
position: absolute;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border-radius: 6px;
|
||||
transform: rotateX(60deg) rotateZ(-45deg);
|
||||
transition: transform 0.2s linear, width 0.2s linear, height 0.2s linear;
|
||||
background: yellow;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.face:nth-of-type(1) {
|
||||
background: linear-gradient(45deg, #28223a, #1f2038);
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.face:nth-of-type(2) {
|
||||
background: linear-gradient(45deg, #7d53ad, #5763ff);
|
||||
transform: rotateX(60deg) rotateZ(-45deg) translateZ(30px);
|
||||
opacity: 0.7;
|
||||
z-index: 3;
|
||||
}
|
||||
}
|
||||
|
||||
.modal-header {
|
||||
padding: 16px;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
|
||||
.modal-title {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.close-btn {
|
||||
width: 50px;
|
||||
height: 100%;
|
||||
background-image: var(--gfx-closeBtn);
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
-webkit-app-region: no-drag;
|
||||
appearance: none;
|
||||
border: 0;
|
||||
background-color: transparent;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
|
||||
&:hover {
|
||||
background-color: rgb(196, 43, 28)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.addtoplaylist-panel {
|
||||
.modal-window {
|
||||
max-height: 600px;
|
||||
max-width: 400px;
|
||||
background: rgb(18 18 18 / 90%);
|
||||
overflow: hidden;
|
||||
backdrop-filter: blur(16px) saturate(180%);
|
||||
|
||||
.modal-header {
|
||||
padding: 16px;
|
||||
position: relative;
|
||||
|
||||
.modal-title {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.close-btn {
|
||||
width: 50px;
|
||||
height: 100%;
|
||||
background-image: var(--gfx-closeBtn);
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
-webkit-app-region: no-drag;
|
||||
appearance: none;
|
||||
border: 0;
|
||||
background-color: transparent;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
|
||||
&:hover {
|
||||
background-color: rgb(196, 43, 28)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.modal-search {
|
||||
width: 100%;
|
||||
padding: 0px 16px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.playlist-item {
|
||||
appearance: none;
|
||||
border: 0px;
|
||||
text-align: left;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
display: flex;
|
||||
background: rgba(32, 32, 32, 0.46);
|
||||
color: #eee;
|
||||
font-family: inherit;
|
||||
font-size: 0.98em;
|
||||
padding: 6px 12px;
|
||||
align-items: center;
|
||||
flex-flow: row;
|
||||
|
||||
.icon {
|
||||
pointer-events: none;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin-right: 6px;
|
||||
}
|
||||
|
||||
.name {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: var(--selected);
|
||||
}
|
||||
|
||||
&:active {
|
||||
background: var(--selected-click);
|
||||
}
|
||||
|
||||
&.focused {
|
||||
background: var(--keyColor);
|
||||
}
|
||||
}
|
||||
|
||||
.playlist-item:last-child {
|
||||
border-bottom: 0px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.menu-panel {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 100001;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
-webkit-app-region: no-drag;
|
||||
|
||||
.menu-header-body {
|
||||
padding: 6px;
|
||||
display: flex;
|
||||
background: rgb(200 200 200 / 10%);
|
||||
|
||||
.menu-option-header {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
border-radius: var(--mediaItemRadius);
|
||||
appearance: none;
|
||||
border: 0;
|
||||
background: transparent;
|
||||
|
||||
&.active {
|
||||
.sidebar-icon > .svg-icon {
|
||||
--color: var(--keyColor);
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: var(--selected);
|
||||
}
|
||||
|
||||
&:active {
|
||||
background: var(--selected-click);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.menu-panel-body {
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
background: #262626;
|
||||
position: relative;
|
||||
min-width: 200px;
|
||||
box-shadow: var(--ciderShadow-Generic);
|
||||
border-radius: var(--mediaItemRadius);
|
||||
overflow: hidden;
|
||||
font-size: 13px;
|
||||
|
||||
.menu-option {
|
||||
text-align: left;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
padding: 9px 16px;
|
||||
appearance: none;
|
||||
border: 0px;
|
||||
font: inherit;
|
||||
background: transparent;
|
||||
color: inherit;
|
||||
|
||||
&:hover {
|
||||
background: var(--selected);
|
||||
}
|
||||
|
||||
&:active {
|
||||
background: var(--selected-click);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.menu-header-text {
|
||||
margin: 18px 6px;
|
||||
|
||||
.close-btn {
|
||||
width: 50px;
|
||||
height: 42px;
|
||||
background-image: var(--gfx-closeBtn);
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
-webkit-app-region: no-drag;
|
||||
appearance: none;
|
||||
border: 0;
|
||||
background-color: transparent;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
|
||||
&:hover {
|
||||
background-color: rgb(196, 43, 28)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.menu-body {
|
||||
overflow: overlay;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.menu-footer {
|
||||
width: 100%;
|
||||
padding: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
.queue-panel {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
|
||||
.queue-header-text {
|
||||
margin: 18px 6px;
|
||||
}
|
||||
|
||||
.queue-body {
|
||||
overflow: overlay;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.queue-footer {
|
||||
width: 100%;
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
.autoplay {
|
||||
background: rgb(200 200 200 / 15%);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
appearance: none;
|
||||
border: 0;
|
||||
border-radius: 6px;
|
||||
height: 32px;
|
||||
width: 32px;
|
||||
}
|
||||
|
||||
.infinity {
|
||||
content: url("./assets/infinity.svg");
|
||||
margin: auto;
|
||||
}
|
||||
}
|
6
src/renderer/less/linux.less
Normal file
6
src/renderer/less/linux.less
Normal file
|
@ -0,0 +1,6 @@
|
|||
// Linux
|
||||
body[platform="linux"] {
|
||||
#window-controls-container {
|
||||
display: none;
|
||||
}
|
||||
}
|
17
src/renderer/less/macos.less
Normal file
17
src/renderer/less/macos.less
Normal file
|
@ -0,0 +1,17 @@
|
|||
body[platform="darwin"] {
|
||||
html {
|
||||
background: transparent!important;
|
||||
}
|
||||
|
||||
&.notransparency::before {
|
||||
display: none;
|
||||
}
|
||||
#app {
|
||||
&.simplebg {
|
||||
background: transparent;
|
||||
}
|
||||
&::before {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
1022
src/renderer/less/pages.less
Normal file
1022
src/renderer/less/pages.less
Normal file
File diff suppressed because it is too large
Load diff
11
src/renderer/lib/bootstrap-vue.min.js
vendored
Normal file
11
src/renderer/lib/bootstrap-vue.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
src/renderer/lib/fast-plural-rules.js
Normal file
1
src/renderer/lib/fast-plural-rules.js
Normal file
|
@ -0,0 +1 @@
|
|||
!function(n,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((n="undefined"!=typeof globalThis?globalThis:n||self).fastPluralRules={})}(this,(function(n){"use strict";var e=[function(){return 0},function(n){return 1===n?0:1},function(n){return n<=1?0:1},function(n){return n%10==1&&n%100!=11?1:n%10!=0?2:0},function(n){return 1===n||11===n?0:2===n||12===n?1:n>2&&n<20?2:3},function(n){return 1===n?0:0===n||n%100>0&&n%100<20?1:2},function(n){return n%10==1&&n%100!=11?0:n%10>=2&&(n%100<10||n%100>=20)?2:1},function(n){return n%10==1&&n%100!=11?0:n%10>=2&&n%10<=4&&(n%100<10||n%100>=20)?1:2},function(n){return 1===n?0:n>=2&&n<=4?1:2},function(n){return 1===n?0:n%10>=2&&n%10<=4&&(n%100<10||n%100>=20)?1:2},function(n){return n%100==1?0:n%100==2?1:n%100==3||n%100==4?2:3},function(n){return 1===n?0:2===n?1:n>2&&n<7?2:n>6&&n<11?3:4},function(n){return 1===n?0:2===n?1:n%100>=3&&n%100<=10?2:n%100>=11?3:0!==n?4:5},function(n){return 1===n?0:0===n||n%100>0&&n%100<11?1:n%100>10&&n%100<20?2:3},function(n){return n%10==1?0:n%10==2?1:2},function(n){return n%10==1&&n%100!=11?0:1},function(n){return n%10==1&&n%100!=11&&n%100!=71&&n%100!=91?0:n%10==2&&n%100!=12&&n%100!=72&&n%100!=92?1:n%10!=3&&n%10!=4&&n%10!=9||n%100==13||n%100==73||n%100==93||n%100==14||n%100==74||n%100==94||n%100==19||n%100==79||n%100==99?0!==n&&n%1e6==0?3:4:2},function(n){return 0!==n?1:0},function(n){return 1===n?1:2===n?2:3===n?3:6===n?4:0!==n?5:0},function(n){return 1===n?0:n%10>=2&&n%10<=4&&(n%100<10||n%100>=20)?1:2},function(n){return 1===n?0:2===n?1:3===n?2:3},function(n){return n%10==1&&n%100!=11?0:n%10>=2&&n%10<=4&&(n%100<10||n%100>=20)?1:2},function(n){return 0===n?0:1===n?1:2}],r={ach:2,af:1,ak:2,am:2,an:1,anp:1,ar:12,arn:2,as:1,ast:1,ay:0,az:1,be:7,bg:1,bn:1,bo:0,br:2,brx:1,bs:7,ca:1,cgg:0,cs:8,csb:19,cy:18,da:1,de:1,doi:1,dz:0,el:1,en:1,eo:1,es:1,"es-ar":1,et:1,eu:1,fa:2,ff:1,fi:1,fil:2,fo:1,fr:2,fur:1,fy:1,ga:11,gd:4,gl:1,gu:1,gun:2,ha:1,he:1,hi:1,hne:1,hr:7,hu:1,hy:1,ia:1,id:0,is:15,it:1,ja:0,jbo:0,jv:17,ka:0,kk:1,kl:1,km:0,kn:1,ko:0,ku:1,kw:20,ky:1,lb:1,ln:2,lo:0,lt:6,lv:3,mai:1,me:21,mfe:2,mg:2,mi:2,mk:15,ml:1,mn:1,mni:1,mnk:22,mr:1,ms:0,mt:13,my:0,nah:1,nap:1,nb:1,ne:1,nl:1,nn:1,no:1,nso:1,oc:2,or:1,pa:1,pap:1,pl:9,pms:1,ps:1,pt:1,"pt-br":2,rm:1,ro:5,ru:7,rw:1,sah:0,sat:1,sco:1,sd:1,se:1,si:1,sk:8,sl:10,so:1,son:1,sq:1,sr:7,su:0,sv:1,sw:1,ta:1,te:1,tg:2,th:0,ti:2,tk:1,tr:2,tt:0,ug:0,uk:7,ur:1,uz:2,vi:0,wa:2,wo:0,yo:1,"zh-cn":0,"zh-tw":2},o=[["other"],["one","other"],["one","other"],["zero","one","other"],["one","two","few","other"],["one","few","other"],["one","few","other"],["one","few","other"],["one","few","other"],["one","few","other"],["one","two","few","other"],["one","two","few","many","other"],["one","two","few","many","other","zero"],["one","few","many","other"],["one","few","other"],["one","other"],["one","two","few","many","other"],["zero","other"],["zero","one","two","few","many","other"],["one","few","other"],["one","two","few","other"],["one","few","other"],["zero","one","other"]];function t(n){n=function(n){return n.toLowerCase().replace("_","-")}(n);var e=r[n];if(void 0===e){var o=function(n){var e=n.indexOf("-");return e>0?n.substr(0,e):n}(n);e=r[o]}if(void 0===e)throw new Error('Unrecognized locale: "'+n+'".');return e}function u(n,e){var r=o[e];return function(e){return r[n(e)]}}function a(n){var r=t(n);return e[r]}function i(n){var r=e[n];if(void 0===r)throw new Error('Invalid index: "'+n+'".');return r}function f(n){var r=t(n);return u(e[r],r)}function l(n){if(void 0===e[n])throw new Error('Invalid index: "'+n+'".');return u(e[n],n)}n.getPluralFormForCardinalByIndex=function(n,e){return i(n)(e)},n.getPluralFormForCardinalByLocale=function(n,e){return a(n)(e)},n.getPluralFormNameForCardinalByIndex=function(n,e){return l(n)(e)},n.getPluralFormNameForCardinalByLocale=function(n,e){return f(n)(e)},n.getPluralRuleForCardinalsByIndex=i,n.getPluralRuleForCardinalsByLocale=a,n.getPluralRuleForNamedFormsForCardinalsByIndex=l,n.getPluralRuleForNamedFormsForCardinalsByLocale=f,Object.defineProperty(n,"__esModule",{value:!0})}));
|
181
src/renderer/lib/resonance-audio.min.js
vendored
Normal file
181
src/renderer/lib/resonance-audio.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
5531
src/renderer/lib/showdown.min.js
vendored
Normal file
5531
src/renderer/lib/showdown.min.js
vendored
Normal file
File diff suppressed because it is too large
Load diff
434
src/renderer/lib/smoothscroll.js
Normal file
434
src/renderer/lib/smoothscroll.js
Normal file
|
@ -0,0 +1,434 @@
|
|||
/* smoothscroll v0.4.4 - 2019 - Dustan Kasten, Jeremias Menichelli - MIT License */
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
// polyfill
|
||||
function polyfill() {
|
||||
// aliases
|
||||
var w = window;
|
||||
var d = document;
|
||||
|
||||
// return if scroll behavior is supported and polyfill is not forced
|
||||
if (
|
||||
'scrollBehavior' in d.documentElement.style &&
|
||||
w.__forceSmoothScrollPolyfill__ !== true
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
// globals
|
||||
var Element = w.HTMLElement || w.Element;
|
||||
var SCROLL_TIME = 468;
|
||||
|
||||
// object gathering original scroll methods
|
||||
var original = {
|
||||
scroll: w.scroll || w.scrollTo,
|
||||
scrollBy: w.scrollBy,
|
||||
elementScroll: Element.prototype.scroll || scrollElement,
|
||||
scrollIntoView: Element.prototype.scrollIntoView
|
||||
};
|
||||
|
||||
// define timing method
|
||||
var now =
|
||||
w.performance && w.performance.now
|
||||
? w.performance.now.bind(w.performance)
|
||||
: Date.now;
|
||||
|
||||
/**
|
||||
* indicates if a the current browser is made by Microsoft
|
||||
* @method isMicrosoftBrowser
|
||||
* @param {String} userAgent
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
function isMicrosoftBrowser(userAgent) {
|
||||
var userAgentPatterns = ['MSIE ', 'Trident/', 'Edge/'];
|
||||
|
||||
return new RegExp(userAgentPatterns.join('|')).test(userAgent);
|
||||
}
|
||||
|
||||
/*
|
||||
* IE has rounding bug rounding down clientHeight and clientWidth and
|
||||
* rounding up scrollHeight and scrollWidth causing false positives
|
||||
* on hasScrollableSpace
|
||||
*/
|
||||
var ROUNDING_TOLERANCE = isMicrosoftBrowser(w.navigator.userAgent) ? 1 : 0;
|
||||
|
||||
/**
|
||||
* changes scroll position inside an element
|
||||
* @method scrollElement
|
||||
* @param {Number} x
|
||||
* @param {Number} y
|
||||
* @returns {undefined}
|
||||
*/
|
||||
function scrollElement(x, y) {
|
||||
this.scrollLeft = x;
|
||||
this.scrollTop = y;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns result of applying ease math function to a number
|
||||
* @method ease
|
||||
* @param {Number} k
|
||||
* @returns {Number}
|
||||
*/
|
||||
function ease(k) {
|
||||
return 0.5 * (1 - Math.cos(Math.PI * k));
|
||||
}
|
||||
|
||||
/**
|
||||
* indicates if a smooth behavior should be applied
|
||||
* @method shouldBailOut
|
||||
* @param {Number|Object} firstArg
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
function shouldBailOut(firstArg) {
|
||||
if (
|
||||
firstArg === null ||
|
||||
typeof firstArg !== 'object' ||
|
||||
firstArg.behavior === undefined ||
|
||||
firstArg.behavior === 'auto' ||
|
||||
firstArg.behavior === 'instant'
|
||||
) {
|
||||
// first argument is not an object/null
|
||||
// or behavior is auto, instant or undefined
|
||||
return true;
|
||||
}
|
||||
|
||||
if (typeof firstArg === 'object' && firstArg.behavior === 'smooth') {
|
||||
// first argument is an object and behavior is smooth
|
||||
return false;
|
||||
}
|
||||
|
||||
// throw error when behavior is not supported
|
||||
throw new TypeError(
|
||||
'behavior member of ScrollOptions ' +
|
||||
firstArg.behavior +
|
||||
' is not a valid value for enumeration ScrollBehavior.'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* indicates if an element has scrollable space in the provided axis
|
||||
* @method hasScrollableSpace
|
||||
* @param {Node} el
|
||||
* @param {String} axis
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
function hasScrollableSpace(el, axis) {
|
||||
if (axis === 'Y') {
|
||||
return el.clientHeight + ROUNDING_TOLERANCE < el.scrollHeight;
|
||||
}
|
||||
|
||||
if (axis === 'X') {
|
||||
return el.clientWidth + ROUNDING_TOLERANCE < el.scrollWidth;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* indicates if an element has a scrollable overflow property in the axis
|
||||
* @method canOverflow
|
||||
* @param {Node} el
|
||||
* @param {String} axis
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
function canOverflow(el, axis) {
|
||||
var overflowValue = w.getComputedStyle(el, null)['overflow' + axis];
|
||||
|
||||
return overflowValue === 'auto' || overflowValue === 'scroll';
|
||||
}
|
||||
|
||||
/**
|
||||
* indicates if an element can be scrolled in either axis
|
||||
* @method isScrollable
|
||||
* @param {Node} el
|
||||
* @param {String} axis
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
function isScrollable(el) {
|
||||
var isScrollableY = hasScrollableSpace(el, 'Y') && canOverflow(el, 'Y');
|
||||
var isScrollableX = hasScrollableSpace(el, 'X') && canOverflow(el, 'X');
|
||||
|
||||
return isScrollableY || isScrollableX;
|
||||
}
|
||||
|
||||
/**
|
||||
* finds scrollable parent of an element
|
||||
* @method findScrollableParent
|
||||
* @param {Node} el
|
||||
* @returns {Node} el
|
||||
*/
|
||||
function findScrollableParent(el) {
|
||||
while (el !== d.body && isScrollable(el) === false) {
|
||||
el = el.parentNode || el.host;
|
||||
}
|
||||
|
||||
return el;
|
||||
}
|
||||
|
||||
/**
|
||||
* self invoked function that, given a context, steps through scrolling
|
||||
* @method step
|
||||
* @param {Object} context
|
||||
* @returns {undefined}
|
||||
*/
|
||||
function step(context) {
|
||||
var time = now();
|
||||
var value;
|
||||
var currentX;
|
||||
var currentY;
|
||||
var elapsed = (time - context.startTime) / SCROLL_TIME;
|
||||
|
||||
// avoid elapsed times higher than one
|
||||
elapsed = elapsed > 1 ? 1 : elapsed;
|
||||
|
||||
// apply easing to elapsed time
|
||||
value = ease(elapsed);
|
||||
|
||||
currentX = context.startX + (context.x - context.startX) * value;
|
||||
currentY = context.startY + (context.y - context.startY) * value;
|
||||
|
||||
context.method.call(context.scrollable, currentX, currentY);
|
||||
|
||||
// scroll more if we have not reached our destination
|
||||
if (currentX !== context.x || currentY !== context.y) {
|
||||
w.requestAnimationFrame(step.bind(w, context));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* scrolls window or element with a smooth behavior
|
||||
* @method smoothScroll
|
||||
* @param {Object|Node} el
|
||||
* @param {Number} x
|
||||
* @param {Number} y
|
||||
* @returns {undefined}
|
||||
*/
|
||||
function smoothScroll(el, x, y) {
|
||||
var scrollable;
|
||||
var startX;
|
||||
var startY;
|
||||
var method;
|
||||
var startTime = now();
|
||||
|
||||
// define scroll context
|
||||
if (el === d.body) {
|
||||
scrollable = w;
|
||||
startX = w.scrollX || w.pageXOffset;
|
||||
startY = w.scrollY || w.pageYOffset;
|
||||
method = original.scroll;
|
||||
} else {
|
||||
scrollable = el;
|
||||
startX = el.scrollLeft;
|
||||
startY = el.scrollTop;
|
||||
method = scrollElement;
|
||||
}
|
||||
|
||||
// scroll looping over a frame
|
||||
step({
|
||||
scrollable: scrollable,
|
||||
method: method,
|
||||
startTime: startTime,
|
||||
startX: startX,
|
||||
startY: startY,
|
||||
x: x,
|
||||
y: y
|
||||
});
|
||||
}
|
||||
|
||||
// ORIGINAL METHODS OVERRIDES
|
||||
// w.scroll and w.scrollTo
|
||||
w.scroll = w.scrollTo = function() {
|
||||
// avoid action when no arguments are passed
|
||||
if (arguments[0] === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
// avoid smooth behavior if not required
|
||||
if (shouldBailOut(arguments[0]) === true) {
|
||||
original.scroll.call(
|
||||
w,
|
||||
arguments[0].left !== undefined
|
||||
? arguments[0].left
|
||||
: typeof arguments[0] !== 'object'
|
||||
? arguments[0]
|
||||
: w.scrollX || w.pageXOffset,
|
||||
// use top prop, second argument if present or fallback to scrollY
|
||||
arguments[0].top !== undefined
|
||||
? arguments[0].top
|
||||
: arguments[1] !== undefined
|
||||
? arguments[1]
|
||||
: w.scrollY || w.pageYOffset
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// LET THE SMOOTHNESS BEGIN!
|
||||
smoothScroll.call(
|
||||
w,
|
||||
d.body,
|
||||
arguments[0].left !== undefined
|
||||
? ~~arguments[0].left
|
||||
: w.scrollX || w.pageXOffset,
|
||||
arguments[0].top !== undefined
|
||||
? ~~arguments[0].top
|
||||
: w.scrollY || w.pageYOffset
|
||||
);
|
||||
};
|
||||
|
||||
// w.scrollBy
|
||||
w.scrollBy = function() {
|
||||
// avoid action when no arguments are passed
|
||||
if (arguments[0] === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
// avoid smooth behavior if not required
|
||||
if (shouldBailOut(arguments[0])) {
|
||||
original.scrollBy.call(
|
||||
w,
|
||||
arguments[0].left !== undefined
|
||||
? arguments[0].left
|
||||
: typeof arguments[0] !== 'object' ? arguments[0] : 0,
|
||||
arguments[0].top !== undefined
|
||||
? arguments[0].top
|
||||
: arguments[1] !== undefined ? arguments[1] : 0
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// LET THE SMOOTHNESS BEGIN!
|
||||
smoothScroll.call(
|
||||
w,
|
||||
d.body,
|
||||
~~arguments[0].left + (w.scrollX || w.pageXOffset),
|
||||
~~arguments[0].top + (w.scrollY || w.pageYOffset)
|
||||
);
|
||||
};
|
||||
|
||||
// Element.prototype.scroll and Element.prototype.scrollTo
|
||||
Element.prototype.scroll = Element.prototype.scrollTo = function() {
|
||||
// avoid action when no arguments are passed
|
||||
if (arguments[0] === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
// avoid smooth behavior if not required
|
||||
if (shouldBailOut(arguments[0]) === true) {
|
||||
// if one number is passed, throw error to match Firefox implementation
|
||||
if (typeof arguments[0] === 'number' && arguments[1] === undefined) {
|
||||
throw new SyntaxError('Value could not be converted');
|
||||
}
|
||||
|
||||
original.elementScroll.call(
|
||||
this,
|
||||
// use left prop, first number argument or fallback to scrollLeft
|
||||
arguments[0].left !== undefined
|
||||
? ~~arguments[0].left
|
||||
: typeof arguments[0] !== 'object' ? ~~arguments[0] : this.scrollLeft,
|
||||
// use top prop, second argument or fallback to scrollTop
|
||||
arguments[0].top !== undefined
|
||||
? ~~arguments[0].top
|
||||
: arguments[1] !== undefined ? ~~arguments[1] : this.scrollTop
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var left = arguments[0].left;
|
||||
var top = arguments[0].top;
|
||||
|
||||
// LET THE SMOOTHNESS BEGIN!
|
||||
smoothScroll.call(
|
||||
this,
|
||||
this,
|
||||
typeof left === 'undefined' ? this.scrollLeft : ~~left,
|
||||
typeof top === 'undefined' ? this.scrollTop : ~~top
|
||||
);
|
||||
};
|
||||
|
||||
// Element.prototype.scrollBy
|
||||
Element.prototype.scrollBy = function() {
|
||||
// avoid action when no arguments are passed
|
||||
if (arguments[0] === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
// avoid smooth behavior if not required
|
||||
if (shouldBailOut(arguments[0]) === true) {
|
||||
original.elementScroll.call(
|
||||
this,
|
||||
arguments[0].left !== undefined
|
||||
? ~~arguments[0].left + this.scrollLeft
|
||||
: ~~arguments[0] + this.scrollLeft,
|
||||
arguments[0].top !== undefined
|
||||
? ~~arguments[0].top + this.scrollTop
|
||||
: ~~arguments[1] + this.scrollTop
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this.scroll({
|
||||
left: ~~arguments[0].left + this.scrollLeft,
|
||||
top: ~~arguments[0].top + this.scrollTop,
|
||||
behavior: arguments[0].behavior
|
||||
});
|
||||
};
|
||||
|
||||
// Element.prototype.scrollIntoView
|
||||
Element.prototype.scrollIntoView = function() {
|
||||
// avoid smooth behavior if not required
|
||||
if (shouldBailOut(arguments[0]) === true) {
|
||||
original.scrollIntoView.call(
|
||||
this,
|
||||
arguments[0] === undefined ? true : arguments[0]
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// LET THE SMOOTHNESS BEGIN!
|
||||
var scrollableParent = findScrollableParent(this);
|
||||
var parentRects = scrollableParent.getBoundingClientRect();
|
||||
var clientRects = this.getBoundingClientRect();
|
||||
|
||||
if (scrollableParent !== d.body) {
|
||||
// reveal element inside parent
|
||||
smoothScroll.call(
|
||||
this,
|
||||
scrollableParent,
|
||||
scrollableParent.scrollLeft + clientRects.left - parentRects.left,
|
||||
scrollableParent.scrollTop + clientRects.top - parentRects.top
|
||||
);
|
||||
|
||||
// reveal parent in viewport unless is fixed
|
||||
if (w.getComputedStyle(scrollableParent).position !== 'fixed') {
|
||||
w.scrollBy({
|
||||
left: parentRects.left,
|
||||
top: parentRects.top,
|
||||
behavior: 'smooth'
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// reveal element in viewport
|
||||
w.scrollBy({
|
||||
left: clientRects.left,
|
||||
top: clientRects.top,
|
||||
behavior: 'smooth'
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
if (typeof exports === 'object' && typeof module !== 'undefined') {
|
||||
// commonjs
|
||||
module.exports = { polyfill: polyfill };
|
||||
} else {
|
||||
// global
|
||||
polyfill();
|
||||
}
|
||||
|
||||
}());
|
||||
|
6
src/renderer/lib/velocity.min.js
vendored
Normal file
6
src/renderer/lib/velocity.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
src/renderer/lib/vue-horizontal.js
Normal file
1
src/renderer/lib/vue-horizontal.js
Normal file
File diff suppressed because one or more lines are too long
30
src/renderer/main/app.js
Normal file
30
src/renderer/main/app.js
Normal file
|
@ -0,0 +1,30 @@
|
|||
import { app } from "./vueapp.js"
|
||||
import {CiderCache} from './cidercache.js'
|
||||
import {CiderFrontAPI} from './ciderfrontapi.js'
|
||||
import {simulateGamepad} from './gamepad.js'
|
||||
import {CiderAudio} from '../audio/audio.js'
|
||||
import {Events} from './events.js'
|
||||
import { wsapi } from "./wsapi_interop.js"
|
||||
import { MusicKitTools } from "./musickittools.js"
|
||||
|
||||
|
||||
// Define window objects
|
||||
window.app = app
|
||||
window.MusicKitTools = MusicKitTools
|
||||
window.CiderAudio = CiderAudio
|
||||
window.CiderCache = CiderCache
|
||||
window.CiderFrontAPI = CiderFrontAPI
|
||||
window.wsapi = wsapi
|
||||
|
||||
// Mount Vue to #app
|
||||
app.$mount("#app")
|
||||
|
||||
// Init CiderAudio
|
||||
if (app.cfg.advanced.AudioContext){
|
||||
CiderAudio.init()
|
||||
}
|
||||
|
||||
// Import gamepad support
|
||||
app.simulateGamepad = simulateGamepad
|
||||
|
||||
Events.InitEvents()
|
24
src/renderer/main/cidercache.js
Normal file
24
src/renderer/main/cidercache.js
Normal file
|
@ -0,0 +1,24 @@
|
|||
const CiderCache = {
|
||||
async getCache(file) {
|
||||
let cache = await ipcRenderer.sendSync("get-cache", file)
|
||||
if (isJson(cache)) {
|
||||
cache = JSON.parse(cache)
|
||||
if (Object.keys(cache).length === 0) {
|
||||
cache = false
|
||||
}
|
||||
} else {
|
||||
cache = false
|
||||
}
|
||||
return cache
|
||||
},
|
||||
async putCache(file, data) {
|
||||
console.log(`Caching ${file}`)
|
||||
ipcRenderer.invoke("put-cache", {
|
||||
file: file,
|
||||
data: JSON.stringify(data)
|
||||
})
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
export {CiderCache}
|
32
src/renderer/main/ciderfrontapi.js
Normal file
32
src/renderer/main/ciderfrontapi.js
Normal file
|
@ -0,0 +1,32 @@
|
|||
const CiderFrontAPI = {
|
||||
Objects: {
|
||||
MenuEntry: function () {
|
||||
this.id = ""
|
||||
this.name = ""
|
||||
this.onClick = () => {
|
||||
}
|
||||
}
|
||||
},
|
||||
AddMenuEntry(entry) {
|
||||
app.pluginMenuEntries.push(entry)
|
||||
app.pluginInstalled = true
|
||||
},
|
||||
StyleSheets: {
|
||||
Add(href) {
|
||||
console.log("Adding stylesheet: " + href)
|
||||
let id = uuidv4()
|
||||
let link = document.createElement("link")
|
||||
link.rel = "stylesheet/less"
|
||||
link.type = "text/css"
|
||||
link.href = href
|
||||
link.setAttribute("css-id", id)
|
||||
// insert the link before document.querySelector("#userTheme") in head
|
||||
document.querySelector("head").insertBefore(link, document.querySelector("#userTheme"))
|
||||
less.registerStylesheetsImmediately()
|
||||
less.refresh(true, true, true)
|
||||
return link
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export {CiderFrontAPI}
|
74
src/renderer/main/events.js
Normal file
74
src/renderer/main/events.js
Normal file
|
@ -0,0 +1,74 @@
|
|||
const Events = {
|
||||
InitEvents() {
|
||||
const app = window.app
|
||||
// Key binds
|
||||
document.addEventListener('keydown', function (e) {
|
||||
if (e.keyCode === 70 && e.ctrlKey) {
|
||||
app.$refs.searchInput.focus()
|
||||
app.$refs.searchInput.select()
|
||||
}
|
||||
});
|
||||
|
||||
// add event listener for when window.location.hash changes
|
||||
window.addEventListener("hashchange", function () {
|
||||
app.appRoute(window.location.hash)
|
||||
});
|
||||
|
||||
// Key bind to unjam MusicKit in case it fails: CTRL+F10
|
||||
|
||||
document.addEventListener('keydown', function (event) {
|
||||
if (event.ctrlKey && event.keyCode == 121) {
|
||||
try {
|
||||
app.mk._services.mediaItemPlayback._currentPlayer.stop()
|
||||
} catch (e) {
|
||||
}
|
||||
try {
|
||||
app.mk._services.mediaItemPlayback._currentPlayer.destroy()
|
||||
} catch (e) {
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
window.addEventListener("mouseup", (e) => {
|
||||
if (e.button === 3) {
|
||||
e.preventDefault()
|
||||
app.navigateBack()
|
||||
} else if (e.button === 4) {
|
||||
e.preventDefault()
|
||||
app.navigateForward()
|
||||
}
|
||||
});
|
||||
|
||||
document.addEventListener('keydown', function (event) {
|
||||
if (event.ctrlKey && event.keyCode == 122) {
|
||||
try {
|
||||
ipcRenderer.send('detachDT', '')
|
||||
} catch (e) {
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Hang Timer
|
||||
app.hangtimer = setTimeout(() => {
|
||||
if (confirm("Cider is not responding. Reload the app?")) {
|
||||
window.location.reload()
|
||||
}
|
||||
}, 10000)
|
||||
|
||||
// Refresh Focus
|
||||
function refreshFocus() {
|
||||
if (document.hasFocus() == false) {
|
||||
app.windowFocus(false)
|
||||
} else {
|
||||
app.windowFocus(true)
|
||||
}
|
||||
setTimeout(refreshFocus, 200);
|
||||
}
|
||||
|
||||
app.getHTMLStyle()
|
||||
|
||||
refreshFocus();
|
||||
}
|
||||
}
|
||||
|
||||
export {Events}
|
327
src/renderer/main/gamepad.js
Normal file
327
src/renderer/main/gamepad.js
Normal file
|
@ -0,0 +1,327 @@
|
|||
function simulateGamepad () {
|
||||
const app = window.app
|
||||
app.chrome.showCursor = true
|
||||
let cursorPos = [0, 0];
|
||||
let intTabIndex = 0
|
||||
const cursorSpeedPvt = 8
|
||||
const cursorSize = 16
|
||||
let scrollSpeed = 8
|
||||
let buttonPressDelay = 500
|
||||
let stickDeadZone = 0.2
|
||||
let scrollGroup = null
|
||||
let scrollGroupY = null
|
||||
let elementFocusEnabled = true
|
||||
let start;
|
||||
|
||||
let cursorSpeed = cursorSpeedPvt
|
||||
|
||||
let lastButtonPress = {
|
||||
|
||||
}
|
||||
|
||||
var sounds = {
|
||||
Confirm: new Audio("./sounds/confirm.ogg"),
|
||||
Menu: new Audio("./sounds/btn1.ogg"),
|
||||
Hover: new Audio("./sounds/hover.ogg")
|
||||
}
|
||||
|
||||
let element = document.elementFromPoint(0, 0)
|
||||
let elementType = 0
|
||||
|
||||
function appLoop() {
|
||||
var gamepads = navigator.getGamepads ? navigator.getGamepads() : (navigator.webkitGetGamepads ? navigator.webkitGetGamepads() : []);
|
||||
if (!gamepads) {
|
||||
return;
|
||||
}
|
||||
|
||||
var gp = gamepads[0];
|
||||
|
||||
// LEFT STICK
|
||||
if (gp.axes[0] > stickDeadZone) {
|
||||
cursorPos[0] += (gp.axes[0] * cursorSpeed)
|
||||
} else if (gp.axes[0] < -stickDeadZone) {
|
||||
cursorPos[0] += (gp.axes[0] * cursorSpeed)
|
||||
}
|
||||
|
||||
if (gp.axes[1] > stickDeadZone) {
|
||||
cursorPos[1] += (gp.axes[1] * cursorSpeed)
|
||||
} else if (gp.axes[1] < -stickDeadZone) {
|
||||
cursorPos[1] += (gp.axes[1] * cursorSpeed)
|
||||
}
|
||||
|
||||
if (cursorPos[0] < cursorSize) {
|
||||
cursorPos[0] = cursorSize
|
||||
}
|
||||
if (cursorPos[1] < cursorSize) {
|
||||
cursorPos[1] = cursorSize
|
||||
}
|
||||
if (cursorPos[0] > window.innerWidth - cursorSize) {
|
||||
cursorPos[0] = window.innerWidth - cursorSize
|
||||
}
|
||||
if (cursorPos[1] > window.innerHeight - cursorSize) {
|
||||
cursorPos[1] = window.innerHeight - cursorSize
|
||||
}
|
||||
|
||||
|
||||
// RIGHT STICK.
|
||||
if (scrollGroupY) {
|
||||
if (gp.axes[3] > stickDeadZone) {
|
||||
$(scrollGroupY).scrollTop($(scrollGroupY).scrollTop() + (gp.axes[3] * scrollSpeed))
|
||||
elementFocusEnabled = false
|
||||
} else if (gp.axes[3] < -stickDeadZone) {
|
||||
$(scrollGroupY).scrollTop($(scrollGroupY).scrollTop() + (gp.axes[3] * scrollSpeed))
|
||||
elementFocusEnabled = false
|
||||
} else {
|
||||
elementFocusEnabled = true
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (scrollGroup) {
|
||||
if (gp.axes[2] > stickDeadZone) {
|
||||
$(scrollGroup).scrollLeft($(scrollGroup).scrollLeft() + (gp.axes[2] * scrollSpeed))
|
||||
elementFocusEnabled = false
|
||||
} else if (gp.axes[2] < -stickDeadZone) {
|
||||
$(scrollGroup).scrollLeft($(scrollGroup).scrollLeft() + (gp.axes[2] * scrollSpeed))
|
||||
elementFocusEnabled = false
|
||||
} else {
|
||||
elementFocusEnabled = true
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$(".cursor").css({
|
||||
top: cursorPos[1] + "px",
|
||||
left: cursorPos[0] + "px",
|
||||
display: "block"
|
||||
})
|
||||
|
||||
// A BUTTON
|
||||
if (gp.buttons[0].pressed) {
|
||||
if (!lastButtonPress["A"]) {
|
||||
lastButtonPress["A"] = 0
|
||||
}
|
||||
if (Date.now() - lastButtonPress["A"] > buttonPressDelay) {
|
||||
lastButtonPress["A"] = Date.now()
|
||||
sounds.Confirm.play()
|
||||
if (elementType == 0) {
|
||||
document.activeElement.dispatchEvent(new Event("click"))
|
||||
document.activeElement.dispatchEvent(new Event("controller-click"))
|
||||
} else {
|
||||
element.dispatchEvent(new Event("click"))
|
||||
element.dispatchEvent(new Event("controller-click"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// B BUTTON
|
||||
if (gp.buttons[1].pressed) {
|
||||
|
||||
if (!lastButtonPress["B"]) {
|
||||
lastButtonPress["B"] = 0
|
||||
}
|
||||
if (Date.now() - lastButtonPress["B"] > buttonPressDelay) {
|
||||
lastButtonPress["B"] = Date.now()
|
||||
if (elementType == 0) {
|
||||
document.activeElement.dispatchEvent(new Event("contextmenu"))
|
||||
setTimeout(() => {
|
||||
if ($(".menu-option").length > 0) {
|
||||
let bounds = $(".menu-option")[0].getBoundingClientRect()
|
||||
cursorPos[0] = bounds.left + (bounds.width / 2)
|
||||
cursorPos[1] = bounds.top + (bounds.height / 2)
|
||||
}
|
||||
}, 100)
|
||||
} else {
|
||||
element.dispatchEvent(new Event("contextmenu"))
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// right bumper
|
||||
if (gp.buttons[5].pressed) {
|
||||
if (!lastButtonPress["RB"]) {
|
||||
lastButtonPress["RB"] = 0
|
||||
}
|
||||
if (Date.now() - lastButtonPress["RB"] > buttonPressDelay) {
|
||||
lastButtonPress["RB"] = Date.now()
|
||||
app.navigateForward()
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// left bumper
|
||||
if (gp.buttons[4].pressed) {
|
||||
if (!lastButtonPress["LB"]) {
|
||||
lastButtonPress["LB"] = 0
|
||||
}
|
||||
if (Date.now() - lastButtonPress["LB"] > buttonPressDelay) {
|
||||
lastButtonPress["LB"] = Date.now()
|
||||
app.navigateBack()
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// cursor hover
|
||||
if (elementFocusEnabled) {
|
||||
element = document.elementFromPoint(cursorPos[0], cursorPos[1])
|
||||
}
|
||||
|
||||
if (element) {
|
||||
|
||||
let closest = element.closest("[tabindex], input, button, a")
|
||||
|
||||
// VERT SCROLL
|
||||
let scrollGroupCloY = element.closest(`[scrollaxis="y"]`)
|
||||
if (scrollGroupCloY) {
|
||||
scrollGroupY = scrollGroupCloY
|
||||
}
|
||||
|
||||
|
||||
// HOZ SCROLL
|
||||
let scrollGroupClo = element.closest(".v-hl-container")
|
||||
|
||||
if (scrollGroupClo) {
|
||||
if (scrollGroupClo.classList.contains("v-hl-container")) {
|
||||
scrollGroup = scrollGroupClo
|
||||
scrollGroup.style["scroll-snap-type"] = "unset"
|
||||
} else {
|
||||
scrollGroup.style["scroll-snap-type"] = ""
|
||||
scrollGroup = null
|
||||
}
|
||||
}
|
||||
|
||||
if (closest) {
|
||||
elementType = 0
|
||||
closest.focus()
|
||||
} else {
|
||||
if (closest) {
|
||||
closest.blur()
|
||||
}
|
||||
elementType = 1
|
||||
element.focus()
|
||||
}
|
||||
cursorSpeed = cursorSpeedPvt
|
||||
if (!element.classList.contains("app-chrome")
|
||||
&& !element.classList.contains("app-content")) {
|
||||
cursorSpeed = cursorSpeedPvt
|
||||
}
|
||||
// console.log($._data($(element), "events"))
|
||||
} else {
|
||||
cursorSpeed = 12
|
||||
}
|
||||
// console.log(gp.axes[0], gp.axes[1])
|
||||
start = requestAnimationFrame(appLoop);
|
||||
}
|
||||
|
||||
// controller pairing
|
||||
notyf.error("Press the button on your controller to pair it to Cider.")
|
||||
window.addEventListener("gamepadconnected", function (e) {
|
||||
console.log("Gamepad connected at index %d: %s. %d buttons, %d axes.",
|
||||
e.gamepad.index, e.gamepad.id,
|
||||
e.gamepad.buttons.length, e.gamepad.axes.length);
|
||||
notyf.success("Pairing successful!")
|
||||
appLoop()
|
||||
}, { once: true });
|
||||
|
||||
document.addEventListener("keydown", (e) => {
|
||||
sounds.Confirm.currentTime = 0
|
||||
sounds.Menu.currentTime = 0
|
||||
sounds.Hover.currentTime = 0
|
||||
let tabbable = $("[tabindex]")
|
||||
console.log(e.key)
|
||||
switch (e.key) {
|
||||
default:
|
||||
break;
|
||||
case "ArrowLeft":
|
||||
e.preventDefault()
|
||||
|
||||
cursorPos[0] -= cursorSpeed
|
||||
break;
|
||||
case "ArrowRight":
|
||||
e.preventDefault()
|
||||
|
||||
cursorPos[0] += cursorSpeed
|
||||
break;
|
||||
case "ArrowUp":
|
||||
e.preventDefault()
|
||||
|
||||
cursorPos[1] -= cursorSpeed
|
||||
// sounds.Hover.play()
|
||||
// if(intTabIndex <= 0) {
|
||||
// intTabIndex = 0
|
||||
// }else{
|
||||
// intTabIndex--
|
||||
// }
|
||||
// $(tabbable[intTabIndex]).focus()
|
||||
// $("#app-content").scrollTop($(document.activeElement).offset().top)
|
||||
break;
|
||||
case "ArrowDown":
|
||||
e.preventDefault()
|
||||
|
||||
cursorPos[1] += cursorSpeed
|
||||
// if(intTabIndex < tabbable.length) {
|
||||
// intTabIndex++
|
||||
// }else{
|
||||
// intTabIndex = tabbable.length
|
||||
// }
|
||||
// $(tabbable[intTabIndex]).focus()
|
||||
// $("#app-content").scrollTop($(document.activeElement).offset().top)
|
||||
break;
|
||||
case "c":
|
||||
app.resetState()
|
||||
break;
|
||||
case "x":
|
||||
// set cursorPos to the top right of the screen
|
||||
// sounds.Menu.play()
|
||||
if (elementType == 0) {
|
||||
document.activeElement.dispatchEvent(new Event("contextmenu"))
|
||||
} else {
|
||||
element.dispatchEvent(new Event("contextmenu"))
|
||||
}
|
||||
|
||||
e.preventDefault()
|
||||
break;
|
||||
case "z":
|
||||
sounds.Confirm.play()
|
||||
if (elementType == 0) {
|
||||
document.activeElement.dispatchEvent(new Event("click"))
|
||||
document.activeElement.dispatchEvent(new Event("controller-click"))
|
||||
} else {
|
||||
element.dispatchEvent(new Event("click"))
|
||||
element.dispatchEvent(new Event("controller-click"))
|
||||
}
|
||||
|
||||
e.preventDefault()
|
||||
break;
|
||||
}
|
||||
|
||||
$(".cursor").css({
|
||||
top: cursorPos[1] + "px",
|
||||
left: cursorPos[0] + "px"
|
||||
})
|
||||
function lerp(a, b, n) {
|
||||
return (1 - n) * a + n * b
|
||||
}
|
||||
|
||||
|
||||
element = document.elementFromPoint(cursorPos[0], cursorPos[1])
|
||||
|
||||
if (element) {
|
||||
let closest = element.closest("[tabindex], input, button, a")
|
||||
if (closest) {
|
||||
elementType = 0
|
||||
closest.focus()
|
||||
} else {
|
||||
elementType = 1
|
||||
element.focus()
|
||||
}
|
||||
}
|
||||
console.log(element)
|
||||
});
|
||||
}
|
||||
|
||||
export {simulateGamepad}
|
42
src/renderer/main/musickittools.js
Normal file
42
src/renderer/main/musickittools.js
Normal file
|
@ -0,0 +1,42 @@
|
|||
const MusicKitTools = {
|
||||
async v3Continuous ({
|
||||
href,
|
||||
options = {},
|
||||
reqOptions = {},
|
||||
onProgress = () => {},
|
||||
onError = () => {},
|
||||
onSuccess = () => {}
|
||||
} = {}) {
|
||||
let returnData = []
|
||||
async function sendReq(href, options) {
|
||||
const response = await app.mk.api.v3.music(href, options).catch(error => onError)
|
||||
|
||||
returnData = returnData.concat(response.data.data)
|
||||
if(response.data.next) {
|
||||
onProgress({
|
||||
response: response,
|
||||
total: returnData.length
|
||||
})
|
||||
try {
|
||||
await sendReq(response.data.next, options)
|
||||
}catch(e){
|
||||
await sendReq(response.data.next, options)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await sendReq(href, options)
|
||||
onSuccess(returnData)
|
||||
return returnData
|
||||
},
|
||||
getHeader() {
|
||||
return new Headers({
|
||||
Authorization: 'Bearer ' + MusicKit.getInstance().developerToken,
|
||||
Accept: 'application/json',
|
||||
'Content-Type': 'application/json',
|
||||
'Music-User-Token': '' + MusicKit.getInstance().musicUserToken
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export { MusicKitTools }
|
4006
src/renderer/main/vueapp.js
Normal file
4006
src/renderer/main/vueapp.js
Normal file
File diff suppressed because it is too large
Load diff
20
src/renderer/main/vuex-store.js
Normal file
20
src/renderer/main/vuex-store.js
Normal file
|
@ -0,0 +1,20 @@
|
|||
const store = new Vuex.Store({
|
||||
state: {
|
||||
library: {
|
||||
// songs: ipcRenderer.sendSync("get-library-songs"),
|
||||
// albums: ipcRenderer.sendSync("get-library-albums"),
|
||||
// recentlyAdded: ipcRenderer.sendSync("get-library-recentlyAdded"),
|
||||
// playlists: ipcRenderer.sendSync("get-library-playlists")
|
||||
},
|
||||
artwork: {
|
||||
playerLCD: ""
|
||||
}
|
||||
},
|
||||
mutations: {
|
||||
setLCDArtwork(state, artwork) {
|
||||
state.artwork.playerLCD = artwork
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
export {store}
|
|
@ -49,13 +49,13 @@ const wsapi = {
|
|||
},
|
||||
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)
|
||||
})
|
||||
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)
|
||||
})
|
||||
MusicKit.getInstance().api[method](id, params).then((results)=>{
|
||||
ipcRenderer.send('wsapi-returnMusicKitApi', JSON.stringify(results), method)
|
||||
})
|
||||
}
|
||||
},
|
||||
getPlaybackState () {
|
||||
|
@ -81,14 +81,14 @@ const wsapi = {
|
|||
|
||||
},
|
||||
playTrackById(id, kind = "song") {
|
||||
MusicKit.getInstance().setQueue({ [kind]: id }).then(function (queue) {
|
||||
MusicKit.getInstance().setQueue({ [kind]: id , parameters : {l : app.mklang}}).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().setQueue({ song: data["songs"][0]["id"],parameters : {l : app.mklang} }).then(function (queue) {
|
||||
MusicKit.getInstance().play()
|
||||
})
|
||||
})
|
||||
|
@ -104,5 +104,10 @@ const wsapi = {
|
|||
}else{
|
||||
MusicKit.getInstance().repeatMode = 0
|
||||
}
|
||||
},
|
||||
getmaxVolume() {
|
||||
ipcRenderer.send('wsapi-returnvolumeMax',JSON.stringify(app.cfg.audio.maxVolume));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export {wsapi}
|
BIN
src/renderer/sounds/btn1.ogg
Normal file
BIN
src/renderer/sounds/btn1.ogg
Normal file
Binary file not shown.
BIN
src/renderer/sounds/confirm.ogg
Normal file
BIN
src/renderer/sounds/confirm.ogg
Normal file
Binary file not shown.
BIN
src/renderer/sounds/hover.ogg
Normal file
BIN
src/renderer/sounds/hover.ogg
Normal file
Binary file not shown.
13152
src/renderer/style.css
Normal file
13152
src/renderer/style.css
Normal file
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
1
src/renderer/themes/groovy/index.less
Normal file
1
src/renderer/themes/groovy/index.less
Normal file
|
@ -0,0 +1 @@
|
|||
//
|
15
src/renderer/themes/groovy/theme.json
Normal file
15
src/renderer/themes/groovy/theme.json
Normal file
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"name": "Groovy",
|
||||
"description": "Inspired by Groove Music and Media Player found on Windows",
|
||||
"version": "1.0.0",
|
||||
"author": "ciderapp",
|
||||
"github_repo": "ciderapp/Groovy",
|
||||
"directives": {
|
||||
"windowLayout": {
|
||||
"value": "twopanel"
|
||||
},
|
||||
"lcdArtworkSize": {
|
||||
"value": 70
|
||||
}
|
||||
}
|
||||
}
|
40
src/renderer/themes/sweetener.css
Normal file
40
src/renderer/themes/sweetener.css
Normal file
|
@ -0,0 +1,40 @@
|
|||
.menu-panel .menu-panel-body {
|
||||
background-color: rgba(30, 30, 30, 0.45);
|
||||
backdrop-filter: blur(32px) saturate(180%);
|
||||
animation: menuIn 0.1s var(--appleEase);
|
||||
}
|
||||
@keyframes menuIn {
|
||||
0% {
|
||||
opacity: 0;
|
||||
transform: translateY(-10px) translate3d(0, 0, 0);
|
||||
background: #1e1e1e;
|
||||
}
|
||||
100% {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
background: rgba(30, 30, 30, 0.45);
|
||||
}
|
||||
}
|
||||
.cd-mediaitem-square:not(.mediaitem-card) {
|
||||
transition: transform 0.2s var(--appleEase);
|
||||
transition-delay: 0.1s;
|
||||
padding: 12px;
|
||||
height: 250px;
|
||||
}
|
||||
.cd-mediaitem-square:not(.mediaitem-card) .artwork-container,
|
||||
.cd-mediaitem-square:not(.mediaitem-card) .info-rect {
|
||||
transition: transform 0.22s var(--appleEase);
|
||||
transition-delay: 0.05s;
|
||||
}
|
||||
.cd-mediaitem-square:not(.mediaitem-card):hover .artwork-container {
|
||||
transform: scale(1.1);
|
||||
transition: transform 0.1s var(--appleEase);
|
||||
transition-delay: 0s;
|
||||
transform-origin: center;
|
||||
}
|
||||
.cd-mediaitem-square:not(.mediaitem-card):hover .info-rect {
|
||||
z-index: 1;
|
||||
transition: transform 0.1s var(--appleEase);
|
||||
transition-delay: 0s;
|
||||
transform: translateY(8px) translate3d(0, 0, 0);
|
||||
}
|
68
src/renderer/themes/sweetener.less
Normal file
68
src/renderer/themes/sweetener.less
Normal file
|
@ -0,0 +1,68 @@
|
|||
@panelColorsFallback: rgb(30 30 30);
|
||||
@panelColors : rgb(30 30 30 / 45%);
|
||||
|
||||
.menu-panel {
|
||||
.menu-panel-body {
|
||||
background-color: @panelColors;
|
||||
backdrop-filter : blur(32px) saturate(180%);
|
||||
animation: menuIn .10s var(--appleEase);
|
||||
}
|
||||
|
||||
|
||||
@keyframes menuIn {
|
||||
0% {
|
||||
opacity : 0;
|
||||
transform : translateY(-10px) translate3d(0,0,0);
|
||||
background: @panelColorsFallback;
|
||||
}
|
||||
|
||||
100% {
|
||||
opacity : 1;
|
||||
transform : translateY(0);
|
||||
background: @panelColors;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
.cd-mediaitem-square:not(.mediaitem-card) {
|
||||
transition : transform .2s var(--appleEase);
|
||||
transition-delay: .1s;
|
||||
padding : 12px;
|
||||
|
||||
// background-color: red;
|
||||
height: 250px;
|
||||
|
||||
|
||||
.artwork-container {}
|
||||
|
||||
.info-rect {}
|
||||
|
||||
.artwork-container,
|
||||
.info-rect {
|
||||
transition : transform .22s var(--appleEase);
|
||||
transition-delay: .05s;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
.artwork-container {
|
||||
transform : scale(1.1);
|
||||
transition : transform .1s var(--appleEase);
|
||||
transition-delay: 0s;
|
||||
transform-origin: center;
|
||||
}
|
||||
|
||||
|
||||
.info-rect {
|
||||
z-index : 1;
|
||||
transition : transform .1s var(--appleEase);
|
||||
transition-delay: 0s;
|
||||
transform : translateY(8px) translate3d(0,0,0);
|
||||
}
|
||||
}
|
||||
|
||||
&:active {
|
||||
|
||||
}
|
||||
}
|
56
src/renderer/views/app/app-content.ejs
Normal file
56
src/renderer/views/app/app-content.ejs
Normal file
|
@ -0,0 +1,56 @@
|
|||
<div id="app-content" scrollaxis="y" :style="{'overflow': (chrome.contentAreaScrolling ? '' : 'hidden')}">
|
||||
<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>
|
||||
</div>
|
||||
|
||||
<!-- Include App Routes -->
|
||||
<% for(var i=0; i < Object.keys(env.appRoutes).length ; i++) {%>
|
||||
<transition
|
||||
<% if(env.appRoutes[i].onEnter) {
|
||||
%>
|
||||
v-on:enter="<%- env.appRoutes[i].onEnter %>"
|
||||
<%
|
||||
}
|
||||
%>
|
||||
:name="chrome.desiredPageTransition">
|
||||
<template
|
||||
v-if="<%- env.appRoutes[i].condition %>">
|
||||
<%- env.appRoutes[i].component %>
|
||||
</template>
|
||||
</transition>
|
||||
<% } %>
|
||||
|
||||
<transition v-on:enter="getRadioStations()" :name="chrome.desiredPageTransition">
|
||||
<template v-if="page == 'radio'" @created="console.log('radio')">
|
||||
<div class="content-inner">
|
||||
<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>
|
||||
</transition>
|
||||
<!-- Library - Recently Added -->
|
||||
<transition :name="chrome.desiredPageTransition" v-on:enter="getLibraryAlbumsFull(null, 0); searchLibraryAlbums(0);">
|
||||
<%- include('../pages/library-recentlyadded') %>');
|
||||
</transition>
|
||||
<!-- Library - Made For You -->
|
||||
<transition :name="chrome.desiredPageTransition" v-on:enter="getMadeForYou()">
|
||||
<template v-if="page == 'library-madeforyou'">
|
||||
<%- include('../pages/madeforyou') %>');
|
||||
%>
|
||||
</template>
|
||||
</transition>
|
||||
<!-- Library - Artists-->
|
||||
<transition :name="chrome.desiredPageTransition" v-on:enter="getLibraryArtistsFull(null, 0);">
|
||||
<template v-if="page == 'library-artists'">
|
||||
<%- include('../pages/library-artists') %>');
|
||||
%>
|
||||
</template>
|
||||
</transition>
|
||||
|
||||
</div>
|
28
src/renderer/views/app/app-navigation.ejs
Normal file
28
src/renderer/views/app/app-navigation.ejs
Normal file
|
@ -0,0 +1,28 @@
|
|||
<div class="app-navigation" v-cloak>
|
||||
<%- include("sidebar") %>
|
||||
<%- include("app-content") %>
|
||||
<transition name="drawertransition">
|
||||
<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 v-if="(cfg.visual.bg_artwork_rotation && animateBackground)" class="bg-artwork a" :src="$store.state.artwork.playerLCD">
|
||||
<img v-if="(cfg.visual.bg_artwork_rotation && animateBackground)" class="bg-artwork b" :src="$store.state.artwork.playerLCD">
|
||||
<img v-if="!(cfg.visual.bg_artwork_rotation && animateBackground)" class="bg-artwork no-animation" :src="$store.state.artwork.playerLCD">
|
||||
</div>
|
||||
</div>
|
||||
<lyrics-view v-if="drawer.panel == 'lyrics'" :time="lyriccurrenttime" :lyrics="lyrics"
|
||||
:richlyrics="richlyrics"></lyrics-view>
|
||||
<div v-if="drawer.panel == 'lyrics'" class="lyric-footer">
|
||||
<button class="md-btn" @click="modularUITest(!fullscreenLyrics)">{{fullscreenLyrics ?
|
||||
$root.getLz('term.defaultView'): $root.getLz('term.fullscreenView')}}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
<transition name="drawertransition">
|
||||
<div class="app-drawer" v-if="drawer.open && drawer.panel == 'queue'">
|
||||
<cider-queue ref="queue" v-if="drawer.panel == 'queue'"></cider-queue>
|
||||
</div>
|
||||
</transition>
|
||||
</div>
|
124
src/renderer/views/app/chrome-bottom.ejs
Normal file
124
src/renderer/views/app/chrome-bottom.ejs
Normal file
|
@ -0,0 +1,124 @@
|
|||
<div class="app-chrome chrome-bottom" v-if="getThemeDirective('windowLayout') == 'twopanel'" :style="{'display': chrome.topChromeVisible ? '' : 'none'}">
|
||||
<div class="app-chrome--left">
|
||||
<div class="app-chrome-item playback-controls">
|
||||
<template v-if="mkReady()">
|
||||
<div class="app-playback-controls" @mouseover="chrome.progresshover = true"
|
||||
@mouseleave="chrome.progresshover = false" @contextmenu="nowPlayingContextMenu">
|
||||
<div class="artwork" @click="drawer.open = false; fullscreen(true)">
|
||||
<mediaitem-artwork :url="currentArtUrl"></mediaitem-artwork>
|
||||
</div>
|
||||
<div class="playback-info">
|
||||
<div class="song-name"
|
||||
:class="[isElementOverflowing('#app-main > div.app-chrome > div.app-chrome--center > div > div > div.playback-info > div.song-name') ? 'marquee' : '']">
|
||||
{{ mk.nowPlayingItem["attributes"]["name"] }}
|
||||
<div class="explicit-icon"
|
||||
v-if="mk.nowPlayingItem['attributes']['contentRating'] == 'explicit'"
|
||||
style="display: inline-block"></div>
|
||||
</div>
|
||||
<div class="audio-type ppe-icon" v-if="cfg.audio.maikiwiAudio.ciderPPE === true"></div>
|
||||
<div class="song-artist-album">
|
||||
<div class="song-artist-album-content"
|
||||
:class="[isElementOverflowing('#app-main > .app-chrome .app-chrome-item > .app-playback-controls > div >.song-artist-album > .song-artist-album-content') ? 'marquee' : '']"
|
||||
style="display: inline-block; -webkit-box-orient: horizontal; white-space: nowrap;">
|
||||
<div class="item-navigate song-artist" style="display: inline-block"
|
||||
@click="getNowPlayingItemDetailed(`artist`)">
|
||||
{{ mk.nowPlayingItem["attributes"]["artistName"] }}
|
||||
</div>
|
||||
<div class="song-artist item-navigate" style="display: inline-block"
|
||||
@click="getNowPlayingItemDetailed('album')"
|
||||
v-if="mk.nowPlayingItem['attributes']['albumName'] != ''">
|
||||
<div class="separator" style="display: inline-block;">{{"—"}}</div>
|
||||
{{(mk.nowPlayingItem["attributes"]["albumName"]) ?
|
||||
(mk.nowPlayingItem["attributes"]["albumName"]) : "" }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<template v-if="mk.nowPlayingItem['attributes']['playParams']">
|
||||
<div class="actions">
|
||||
<button class="lcdMenu" @click="nowPlayingContextMenu">
|
||||
<div class="svg-icon"></div>
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="app-chrome--center">
|
||||
<div class="app-chrome-playback-controls">
|
||||
<div class="app-chrome-item">
|
||||
<button class="playback-button--small shuffle" v-if="mk.shuffleMode == 0"
|
||||
@click="mk.shuffleMode = 1"></button>
|
||||
<button class="playback-button--small shuffle active" v-else
|
||||
@click="mk.shuffleMode = 0"></button>
|
||||
</div>
|
||||
<div class="app-chrome-item">
|
||||
<button class="playback-button previous" @click="prevButton()"></button>
|
||||
</div>
|
||||
<div class="app-chrome-item">
|
||||
<button class="playback-button pause" @click="mk.pause()" v-if="mk.isPlaying"></button>
|
||||
<button class="playback-button play" @click="mk.play()" v-else></button>
|
||||
</div>
|
||||
<div class="app-chrome-item">
|
||||
<button class="playback-button next" @click="skipToNextItem()"></button>
|
||||
</div>
|
||||
<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 repeatOne" @click="mk.repeatMode = 2"
|
||||
v-else-if="mk.repeatMode == 1"></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-playback-duration">
|
||||
<div class="song-progress">
|
||||
<div class="song-duration"
|
||||
style="justify-content: space-between; height: 1px;">
|
||||
<p style="width: auto">{{ convertTime(getSongProgress()) }}</p>
|
||||
<p style="width: auto">{{ convertTime(mk.currentPlaybackDuration) }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<input type="range" step="0.01" min="0" :style="progressBarStyle()"
|
||||
@input="playerLCD.desiredDuration = $event.target.value;playerLCD.userInteraction = true"
|
||||
@mouseup="mk.seekToTime($event.target.value);playerLCD.desiredDuration = 0;playerLCD.userInteraction = false"
|
||||
:max="mk.currentPlaybackDuration" :value="getSongProgress()">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="app-chrome--right">
|
||||
<div class="app-chrome-item volume">
|
||||
<button class="volume-button--small volume" @click="muteButtonPressed()"
|
||||
:class="{'active': this.cfg.audio.volume == 0}"></button>
|
||||
<input type="range" @wheel="volumeWheel" :step="cfg.audio.volumeStep" min="0" :max="cfg.audio.maxVolume"
|
||||
v-model="mk.volume" v-if="typeof mk.volume != 'undefined'" @change="checkMuteChange()"
|
||||
v-b-tooltip.hover :title="`${(Math.log10(mk.volume) * 20).toFixed(2)} dB`">
|
||||
</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>
|
||||
<template v-else>
|
||||
<button class="playback-button--small lyrics"
|
||||
:style="{'opacity': 0.3, 'pointer-events': 'none'}"
|
||||
@click="invokeDrawer('lyrics')"></button>
|
||||
</template>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
150
src/renderer/views/app/chrome-top.ejs
Normal file
150
src/renderer/views/app/chrome-top.ejs
Normal file
|
@ -0,0 +1,150 @@
|
|||
<div class="app-chrome" :style="{'display': chrome.topChromeVisible ? '' : 'none'}">
|
||||
<div class="app-chrome--left">
|
||||
<div class="app-chrome-item full-height" v-if="chrome.windowControlPosition == 'left'">
|
||||
<div class="window-controls">
|
||||
<div class="close" @click="ipcRenderer.send('close')"></div>
|
||||
<div class="minimize" @click="ipcRenderer.send('minimize')"></div>
|
||||
<div class="minmax restore" v-if="chrome.maximized"
|
||||
@click="ipcRenderer.send('maximize')">
|
||||
</div>
|
||||
<div class="minmax" v-else @click="ipcRenderer.send('maximize')"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="app-chrome-item full-height" v-else>
|
||||
<button class="app-mainmenu"
|
||||
@blur="mainMenuVisibility(false)"
|
||||
@click="mainMenuVisibility(true)"
|
||||
:class="{active: chrome.menuOpened}"></button>
|
||||
</div>
|
||||
<template v-if="getThemeDirective('windowLayout') != 'twopanel'">
|
||||
<div class="app-chrome-item display--large">
|
||||
<button class="playback-button--small shuffle" v-if="mk.shuffleMode == 0"
|
||||
@click="mk.shuffleMode = 1"></button>
|
||||
<button class="playback-button--small shuffle active" v-else
|
||||
@click="mk.shuffleMode = 0"></button>
|
||||
</div>
|
||||
<div class="app-chrome-item display--large">
|
||||
<button class="playback-button previous" @click="prevButton()"></button>
|
||||
</div>
|
||||
<div class="app-chrome-item display--large">
|
||||
<button class="playback-button pause" @click="mk.pause()" v-if="mk.isPlaying"></button>
|
||||
<button class="playback-button play" @click="mk.play()" v-else></button>
|
||||
</div>
|
||||
<div class="app-chrome-item display--large">
|
||||
<button class="playback-button next" @click="skipToNextItem()"></button>
|
||||
</div>
|
||||
<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 repeatOne" @click="mk.repeatMode = 2"
|
||||
v-else-if="mk.repeatMode == 1"></button>
|
||||
<button class="playback-button--small repeat active" @click="mk.repeatMode = 0"
|
||||
v-else-if="mk.repeatMode == 2"></button>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
<div class="app-chrome--center">
|
||||
<div class="app-chrome-item playback-controls" v-if="getThemeDirective('windowLayout') != 'twopanel'">
|
||||
<template v-if="mkReady()">
|
||||
<div class="app-playback-controls" @mouseover="chrome.progresshover = true"
|
||||
@mouseleave="chrome.progresshover = false" @contextmenu="nowPlayingContextMenu">
|
||||
<div class="artwork" @click="drawer.open = false; fullscreen(true)">
|
||||
<mediaitem-artwork :url="currentArtUrl"></mediaitem-artwork>
|
||||
</div>
|
||||
<div class="playback-info">
|
||||
<div class="song-name"
|
||||
:class="[isElementOverflowing('#app-main > div.app-chrome > div.app-chrome--center > div > div > div.playback-info > div.song-name') ? 'marquee' : '']">
|
||||
{{ mk.nowPlayingItem["attributes"]["name"] }}
|
||||
<div class="explicit-icon"
|
||||
v-if="mk.nowPlayingItem['attributes']['contentRating'] == 'explicit'"
|
||||
style="display: inline-block"></div>
|
||||
</div>
|
||||
<div class="audio-type ppe-icon" v-if="cfg.audio.maikiwiAudio.ciderPPE === true"></div>
|
||||
<div class="song-artist-album">
|
||||
<div class="song-artist-album-content"
|
||||
:class="[isElementOverflowing('#app-main > .app-chrome .app-chrome-item > .app-playback-controls > div >.song-artist-album > .song-artist-album-content') ? 'marquee' : '']"
|
||||
style="display: inline-block; -webkit-box-orient: horizontal; white-space: nowrap;">
|
||||
<div class="item-navigate song-artist" style="display: inline-block"
|
||||
@click="getNowPlayingItemDetailed(`artist`)">
|
||||
{{ mk.nowPlayingItem["attributes"]["artistName"] }}
|
||||
</div>
|
||||
<div class="song-artist item-navigate" style="display: inline-block"
|
||||
@click="getNowPlayingItemDetailed('album')"
|
||||
v-if="mk.nowPlayingItem['attributes']['albumName'] != ''">
|
||||
<div class="separator" style="display: inline-block;">{{"—"}}</div>
|
||||
{{(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;"
|
||||
:style="[chrome.progresshover ? {'display': 'flex'} : {'display' : 'none'} ]">
|
||||
<p style="width: auto">{{ convertTime(getSongProgress()) }}</p>
|
||||
<p style="width: auto">{{ convertTime(mk.currentPlaybackDuration) }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<input type="range" step="0.01" min="0" :style="progressBarStyle()"
|
||||
@input="playerLCD.desiredDuration = $event.target.value;playerLCD.userInteraction = true"
|
||||
@mouseup="mk.seekToTime($event.target.value);playerLCD.desiredDuration = 0;playerLCD.userInteraction = false"
|
||||
:max="mk.currentPlaybackDuration" :value="getSongProgress()">
|
||||
</div>
|
||||
</div>
|
||||
<template v-if="mk.nowPlayingItem['attributes']['playParams']">
|
||||
<div class="actions">
|
||||
<button class="lcdMenu" @click="nowPlayingContextMenu">
|
||||
<div class="svg-icon"></div>
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="app-chrome--right">
|
||||
<template v-if="getThemeDirective('windowLayout') != 'twopanel'">
|
||||
<div class="app-chrome-item volume display--large">
|
||||
<button class="volume-button--small volume" @click="muteButtonPressed()"
|
||||
:class="{'active': this.cfg.audio.volume == 0}"></button>
|
||||
<input type="range" @wheel="volumeWheel" :step="cfg.audio.volumeStep" min="0" :max="cfg.audio.maxVolume"
|
||||
v-model="mk.volume" v-if="typeof mk.volume != 'undefined'" @change="checkMuteChange()"
|
||||
v-b-tooltip.hover :title="`${(Math.log10(mk.volume) * 20).toFixed(2)} dB`">
|
||||
</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>
|
||||
<template v-else>
|
||||
<button class="playback-button--small lyrics"
|
||||
:style="{'opacity': 0.3, 'pointer-events': 'none'}"
|
||||
@click="invokeDrawer('lyrics')"></button>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
<div class="app-chrome-item full-height" id="window-controls-container" 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>
|
||||
<div class="minmax" v-else @click="ipcRenderer.send('maximize')"></div>
|
||||
<div class="close" @click="ipcRenderer.send('close')"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
68
src/renderer/views/app/panels.ejs
Normal file
68
src/renderer/views/app/panels.ejs
Normal file
|
@ -0,0 +1,68 @@
|
|||
<cider-menu-panel v-if="menuPanel.visible">
|
||||
</cider-menu-panel>
|
||||
<transition name="wpfade">
|
||||
<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">
|
||||
</div>
|
||||
</transition>
|
||||
<transition name="wpfade">
|
||||
<div class="bg-artwork--placeholder"></div>
|
||||
</transition>
|
||||
<transition name="modal">
|
||||
<add-to-playlist :playlists="playlists.listing" v-if="modals.addToPlaylist"></add-to-playlist>
|
||||
</transition>
|
||||
<transition name="modal">
|
||||
<spatial-properties v-if="modals.spatialProperties"></spatial-properties>
|
||||
</transition>
|
||||
<transition name="modal">
|
||||
<audio-controls v-if="modals.audioControls"></audio-controls>
|
||||
</transition>
|
||||
<transition name="modal">
|
||||
<audio-settings v-if="modals.audioSettings"></audio-settings>
|
||||
</transition>
|
||||
<transition name="modal">
|
||||
<castmenu v-if="modals.castMenu"></castmenu>
|
||||
</transition>
|
||||
<transition name="modal">
|
||||
<plugin-menu v-if="modals.pluginMenu"></plugin-menu>
|
||||
</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()">
|
||||
<svg fill="white" 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 id="captions">{{((lyricon) ? ((lyrics.length > 0 && lyrics[currentLyricsLine] &&
|
||||
lyrics[currentLyricsLine].line ) ?
|
||||
lyrics[currentLyricsLine].line.replace('lrcInstrumental','') : "") : '') + ((lyricon) ?
|
||||
((lyrics.length
|
||||
> 0 && lyrics[currentLyricsLine] && lyrics[currentLyricsLine].line ) ?
|
||||
(lyrics[currentLyricsLine].translation ? ('\n\r' + lyrics[currentLyricsLine].translation) : ""): "")
|
||||
:
|
||||
'')}}
|
||||
</div>
|
||||
<div id="player-pip"
|
||||
@click="document.querySelector('video#apple-music-video-player').requestPictureInPicture()"
|
||||
title="Picture-in-Picture">
|
||||
<%- include("../svg/pip.svg") %>
|
||||
</div>
|
||||
<div id="player-fullscreen"
|
||||
@click="document.querySelector('video#apple-music-video-player').requestFullscreen()"
|
||||
title="Fullscreen">
|
||||
<%- include("../svg/fullscreen.svg") %>
|
||||
</div>
|
||||
</div>
|
||||
<div id="apple-music-video-player"></div>
|
||||
</div>
|
186
src/renderer/views/app/sidebar.ejs
Normal file
186
src/renderer/views/app/sidebar.ejs
Normal file
|
@ -0,0 +1,186 @@
|
|||
<div id="app-sidebar">
|
||||
<div class="app-sidebar-header">
|
||||
<div class="search-input-container">
|
||||
<div class="search-input--icon"></div>
|
||||
<input type="search" spellcheck="false" @click="showSearch()"
|
||||
@focus="search.showHints = true"
|
||||
@blur="setTimeout(()=>{search.showHints = false}, 300)"
|
||||
v-on:keyup.enter="searchQuery();search.showHints = false" @change="showSearch();"
|
||||
@input="getSearchHints()" :placeholder="$root.getLz('term.search') + '...'"
|
||||
v-model="search.term"
|
||||
ref="searchInput" class="search-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="search-hints-container" v-if="search.showHints && search.hints.length != 0">
|
||||
<div class="search-hints">
|
||||
<button class="search-hint" v-for="hint in search.hints"
|
||||
@click="search.term = hint;search.showHints = false;searchQuery(hint)">
|
||||
{{ hint }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="app-sidebar-content" scrollaxis="y">
|
||||
<div class="app-sidebar-header-text">
|
||||
{{$root.getLz('app.name')}}
|
||||
</div>
|
||||
<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">
|
||||
{{$root.getLz('term.appleMusic')}}
|
||||
</div>
|
||||
<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="$root.getLz('term.songs')" svg-icon="./assets/feather/music.svg"
|
||||
page="library-songs"></sidebar-library-item>
|
||||
<sidebar-library-item :name="$root.getLz('term.albums')" svg-icon="./assets/feather/disc.svg"
|
||||
page="library-albums"></sidebar-library-item>
|
||||
<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>
|
||||
<template v-if="getPlaylistFolderChildren('p.applemusic').length != 0">
|
||||
<div class="app-sidebar-header-text" @contextmenu="playlistHeaderContextMenu">
|
||||
{{ $root.getLz('term.appleMusic') }} {{ $root.getLz('term.playlists') }}
|
||||
</div>
|
||||
<sidebar-playlist v-for="item in getPlaylistFolderChildren('p.applemusic')" :item="item">
|
||||
</sidebar-playlist>
|
||||
</template>
|
||||
<div class="app-sidebar-header-text" @contextmenu="playlistHeaderContextMenu">
|
||||
{{ $root.getLz('term.playlists') }}
|
||||
</div>
|
||||
<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="app-sidebar-button" style="width:100%">
|
||||
|
||||
<img class="sidebar-user-icon" loading="lazy"
|
||||
:src="getMediaItemArtwork(chrome.hideUserInfo ? 'http://localhost:9000/assets/logocut.png' : (chrome.userinfo.attributes['artwork'] ? chrome.userinfo.attributes['artwork']['url'] : ''), 26)"/>
|
||||
|
||||
<div class="sidebar-user-text" v-if="!chrome.hideUserInfo">
|
||||
<template v-if="chrome.userinfo.id || mk.isAuthorized">
|
||||
<div class="fullname text-overflow-elipsis">{{ (chrome.userinfo != null &&
|
||||
chrome.userinfo.attributes != null) ? (chrome.userinfo.attributes.name ?? "") :
|
||||
""
|
||||
}}
|
||||
</div>
|
||||
<div class="handle-text text-overflow-elipsis">{{
|
||||
(chrome.userinfo != null && chrome.userinfo.attributes != null) ?
|
||||
(chrome.userinfo.attributes.handle ?? "") : ""
|
||||
}}
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div @click="mk.authorize()">
|
||||
{{$root.getLz('term.login')}}
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
<div class="sidebar-user-text" v-else>
|
||||
{{$root.getLz('app.name')}}
|
||||
</div>
|
||||
</button>
|
||||
<button class="usermenu-item" @click="appRoute('remote-pair')">
|
||||
<span class="usermenu-item-icon"><%- include("../svg/smartphone.svg") %></span>
|
||||
<span class="usermenu-item-name">{{$root.getLz('action.showWebRemoteQR')}}</span>
|
||||
</button>
|
||||
<button class="usermenu-item" v-if="cfg.advanced.AudioContext" @click="modals.castMenu = true">
|
||||
<span class="usermenu-item-icon"><%- include("../svg/cast.svg") %></span>
|
||||
<span class="usermenu-item-name">Cast</span>
|
||||
</button>
|
||||
<button class="usermenu-item" v-if="cfg.advanced.AudioContext"
|
||||
@click="modals.audioSettings = true">
|
||||
<span class="usermenu-item-icon"><%- include("../svg/headphones.svg") %></span>
|
||||
<span class="usermenu-item-name">{{$root.getLz('term.audioSettings')}}</span>
|
||||
</button>
|
||||
<button class="usermenu-item" v-if="pluginInstalled"
|
||||
@click="modals.pluginMenu = true">
|
||||
<span class="usermenu-item-icon"><%- include("../svg/grid.svg") %></span>
|
||||
<span class="usermenu-item-name">{{$root.getLz('term.plugin')}}</span>
|
||||
</button>
|
||||
<button class="usermenu-item" @click="appRoute('about')">
|
||||
<span class="usermenu-item-icon"><%- include("../svg/info.svg") %></span>
|
||||
<span class="usermenu-item-name">{{$root.getLz('term.about')}}</span>
|
||||
</button>
|
||||
<button class="usermenu-item" @click="appRoute('settings')">
|
||||
<span class="usermenu-item-icon"><%- include("../svg/settings.svg") %></span>
|
||||
<span class="usermenu-item-name">{{$root.getLz('term.settings')}}</span>
|
||||
</button>
|
||||
<button class="usermenu-item" @click="unauthorize()">
|
||||
<span class="usermenu-item-icon"
|
||||
style="right:2.5px;"><%- include("../svg/log-out.svg") %></span>
|
||||
<span class="usermenu-item-name">{{$root.getLz('term.logout')}}</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
<div class="app-sidebar-footer display--small app-sidebar-footer--controls">
|
||||
|
||||
<div class="app-playback-controls " v-if="mkReady()"
|
||||
@contextmenu="nowPlayingContextMenu">
|
||||
<div class="control-buttons">
|
||||
<div class="app-chrome-item">
|
||||
<button class="playback-button--small shuffle" v-if="mk.shuffleMode == 0"
|
||||
@click="mk.shuffleMode = 1"></button>
|
||||
<button class="playback-button--small shuffle active" v-else
|
||||
@click="mk.shuffleMode = 0"></button>
|
||||
</div>
|
||||
<div class="app-chrome-item">
|
||||
<button class="playback-button previous" @click="prevButton()"></button>
|
||||
</div>
|
||||
<div class="app-chrome-item">
|
||||
<button class="playback-button pause" @click="mk.pause()"
|
||||
v-if="mk.isPlaying"></button>
|
||||
<button class="playback-button play" @click="mk.play()" v-else></button>
|
||||
</div>
|
||||
<div class="app-chrome-item">
|
||||
<button class="playback-button next" @click="skipToNextItem()"></button>
|
||||
</div>
|
||||
<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 repeatOne" @click="mk.repeatMode = 2"
|
||||
v-else-if="mk.repeatMode == 1"></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">
|
||||
<button class="volume-button--small volume" @click="muteButtonPressed()"
|
||||
:class="{'active': this.cfg.audio.volume == 0}"></button>
|
||||
<input type="range" class="" @wheel="volumeWheel" :step="cfg.audio.volumeStep" min="0"
|
||||
:max="cfg.audio.maxVolume"
|
||||
v-model="mk.volume" v-if="typeof mk.volume != 'undefined'"
|
||||
@change="checkMuteChange()"
|
||||
v-b-tooltip.hover :title="`${(Math.log10(mk.volume) * 20).toFixed(2)} dB`">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<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>
|
|
@ -12,7 +12,7 @@
|
|||
<div class="icon"><%- include("../svg/plus.svg") %></div>
|
||||
<div class="name">{{app.getLz('action.createPlaylist')}}</div>
|
||||
</button>
|
||||
<sidebar-playlist :playlist-select="playlistSelect" v-for="item in $root.getPlaylistFolderChildren('p.playlistsroot')" :item="item">
|
||||
<sidebar-playlist :playlist-select="playlistSelect" :relate-media-items="relateItems" v-for="item in $root.getPlaylistFolderChildren('p.playlistsroot')" :item="item">
|
||||
</sidebar-playlist>
|
||||
</div>
|
||||
<div class="modal-search">
|
||||
|
@ -42,6 +42,7 @@
|
|||
searchQuery: "",
|
||||
focused: "",
|
||||
app: this.$root,
|
||||
relateItems: []
|
||||
}
|
||||
},
|
||||
props: {
|
||||
|
@ -51,6 +52,7 @@
|
|||
}
|
||||
},
|
||||
mounted() {
|
||||
this.relateItems = [this.$root.selectedMediaItems[0].id]
|
||||
this.search()
|
||||
this.$refs.searchInput.focus()
|
||||
this.$refs.searchInput.addEventListener('keydown', (e) => {
|
||||
|
|
|
@ -57,9 +57,32 @@
|
|||
platformInfo: {requiresCDMAttachOnStart: !0, maxSecurityLevel: d, keySystemConfig: h},
|
||||
appData: {serviceName: "Apple Music"}
|
||||
}
|
||||
|
||||
this.hls.attachMedia(this.$refs.video);
|
||||
this.hls.loadSource(this.video);
|
||||
this.hls.loadLevel = parseInt(app.cfg.visual.animated_artwork_qualityLevel || 1);
|
||||
let u = this.hls;
|
||||
var quality = app.cfg.visual.animated_artwork_qualityLevel;
|
||||
setTimeout(() => {
|
||||
let levelsnum = u.levels.map((level)=>{return level.width})
|
||||
if (levelsnum.length > 0) {
|
||||
let qualities = []
|
||||
let qualities2 = []
|
||||
for (let i = 0; i < levelsnum.length; i++) {
|
||||
if (qualities2.indexOf(levelsnum[i]) == -1) {
|
||||
qualities.push({level: i, quality: levelsnum[i]})
|
||||
qualities2.push(levelsnum[i])
|
||||
}
|
||||
}
|
||||
let actualnum = Math.floor(qualities[qualities.length -1 ].level * (quality / 4))
|
||||
if (quality != 0 ){
|
||||
quality = qualities[Math.min(actualnum,qualities.length -1 )].level
|
||||
}
|
||||
if (quality == 4 ){
|
||||
quality = qualities[qualities.length - 1].level
|
||||
}
|
||||
}
|
||||
try{
|
||||
this.hls.loadLevel = parseInt( quality || 1);} catch(e){}},200)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
45
src/renderer/views/components/artist-chip.ejs
Normal file
45
src/renderer/views/components/artist-chip.ejs
Normal file
|
@ -0,0 +1,45 @@
|
|||
<script type="text/x-template" id="artist-chip">
|
||||
<div class="artist-chip" @click.self="route" tabindex="0">
|
||||
<div class="artist-chip__image">
|
||||
<mediaitem-artwork v-if="artist.id != null" :url="artist.attributes.artwork.url" :size="32"></mediaitem-artwork>
|
||||
</div>
|
||||
<div class="artist-chip__name">
|
||||
<span>{{ item.attributes.name }}</span>
|
||||
</div>
|
||||
<button @click="$root.followArtistById(artist.id, true)" title="Follow" v-if="!$root.followingArtist(artist.id)" class="artist-chip__follow codicon codicon-add"></button>
|
||||
<button @click="$root.followArtistById(artist.id, false)" title="Following" v-else class="artist-chip__follow codicon codicon-check"></button>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script>
|
||||
Vue.component('artist-chip', {
|
||||
props: {
|
||||
item: {
|
||||
type: Object,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data: function() {
|
||||
return {
|
||||
artist: {
|
||||
id: null
|
||||
}
|
||||
}
|
||||
},
|
||||
template: '#artist-chip',
|
||||
async mounted() {
|
||||
let artistId = this.item.id
|
||||
if(typeof this.item.relationships.catalog == "object") {
|
||||
artistId = this.item.relationships.catalog.data[0].id
|
||||
}
|
||||
app.mk.api.v3.music(`/v1/catalog/${app.mk.storefrontId}/artists/${artistId}`).then(response => {
|
||||
this.artist = response.data.data[0];
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
route() {
|
||||
app.appRoute(`artist/${this.artist.id}`);
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
87
src/renderer/views/components/audio-controls.ejs
Normal file
87
src/renderer/views/components/audio-controls.ejs
Normal file
|
@ -0,0 +1,87 @@
|
|||
<script type="text/x-template" id="audio-controls">
|
||||
<div class="modal-fullscreen addtoplaylist-panel" @click.self="app.resetState()"
|
||||
@contextmenu.self="app.resetState()">
|
||||
<div class="modal-window">
|
||||
<div class="modal-header">
|
||||
<div class="modal-title">{{app.getLz('term.audioControls')}}</div>
|
||||
<button class="close-btn" @click="app.resetState()"></button>
|
||||
</div>
|
||||
<div class="modal-content">
|
||||
<div class="md-option-line">
|
||||
<div class="md-option-segment">
|
||||
{{app.getLz('term.volume')}}
|
||||
</div>
|
||||
<div class="md-option-segment md-option-segment_auto percent">
|
||||
<input type="number"
|
||||
style="width: 100%; text-align: center; margin-right: 5px;" min="0"
|
||||
step="5" v-model="volume"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="md-option-line">
|
||||
<div class="md-option-segment">
|
||||
{{app.getLz('settings.option.audio.volumeStep')}}
|
||||
</div>
|
||||
<div class="md-option-segment md-option-segment_auto percent">
|
||||
<input type="number" style="width: 100%; text-align: center; margin-right: 5px;" min="0"
|
||||
v-model="volumeStep"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="md-option-line">
|
||||
<div class="md-option-segment">
|
||||
{{app.getLz('settings.option.audio.maxVolume')}}
|
||||
</div>
|
||||
<div class="md-option-segment md-option-segment_auto percent">
|
||||
<input type="number" style="width: 100%; text-align: center; margin-right: 5px;" min="0"
|
||||
v-model="maxVolume"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script>
|
||||
Vue.component('audio-controls', {
|
||||
template: '#audio-controls',
|
||||
data: function () {
|
||||
return {
|
||||
app: this.$root,
|
||||
maxVolume: this.$root.cfg.audio.maxVolume * 100,
|
||||
volumeStep: this.$root.cfg.audio.volumeStep * 100,
|
||||
volume: this.$root.cfg.audio.volume * 100
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
maxVolume: function (newValue, _oldValue) {
|
||||
if (newValue > 100) {
|
||||
newValue = 100
|
||||
} else {
|
||||
newValue = Math.round(newValue)
|
||||
}
|
||||
this.$root.cfg.audio.maxVolume = newValue / 100
|
||||
this.maxVolume = newValue
|
||||
console.log(newValue, _oldValue)
|
||||
},
|
||||
volume: function (newValue, _oldValue) {
|
||||
if (newValue > this.maxVolume) {
|
||||
newValue = 100
|
||||
} else {
|
||||
newValue = Math.round(newValue)
|
||||
}
|
||||
this.$root.mk.volume = newValue / 100
|
||||
this.volume = newValue
|
||||
console.log(newValue, _oldValue)
|
||||
},
|
||||
volumeStep: function (newValue, _oldValue) {
|
||||
if (newValue > this.maxVolume) {
|
||||
newValue = 100
|
||||
} else {
|
||||
newValue = Math.round(newValue)
|
||||
}
|
||||
this.$root.cfg.audio.volumeStep = newValue / 100
|
||||
this.volumeStep = newValue
|
||||
console.log(newValue, _oldValue)
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
|
@ -13,10 +13,20 @@
|
|||
<div class="name">{{app.getLz('term.equalizer')}}</div>
|
||||
</button>
|
||||
<button class="playlist-item"
|
||||
@click="openSpacialAudio()" style="width:100%;">
|
||||
@click="openSpatialAudio()" style="width:100%;">
|
||||
<div class="icon"><%- include("../svg/speaker.svg") %></div>
|
||||
<div class="name">{{app.getLz('settings.option.audio.enableAdvancedFunctionality.audioSpatialization')}}</div>
|
||||
</button>
|
||||
<button class="playlist-item"
|
||||
@click="openAudioControls" style="width:100%;">
|
||||
<div class="icon"><%- include("../svg/speaker.svg") %></div>
|
||||
<div class="name">{{app.getLz('term.audioControls')}}</div>
|
||||
</button>
|
||||
<button class="playlist-item"
|
||||
@click="$root.appRoute('audiolabs')" style="width:100%;">
|
||||
<div class="icon"><%- include("../svg/speaker.svg") %></div>
|
||||
<div class="name">{{app.getLz('settings.option.audio.audioLab')}}</div>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -38,14 +48,19 @@
|
|||
app.modals.equalizer = true
|
||||
app.modals.audioSettings = false
|
||||
},
|
||||
openSpacialAudio() {
|
||||
if(app.cfg.audio.spatial) {
|
||||
openSpatialAudio() {
|
||||
if(app.cfg.audio.spatial === true && app.cfg.audio.maikiwiAudio.spatial === false) {
|
||||
app.modals.spatialProperties = true
|
||||
app.modals.audioSettings = false
|
||||
} else {
|
||||
notyf.error(app.getLz('spatial.notTurnedOn'))
|
||||
}
|
||||
},
|
||||
openAudioControls() {
|
||||
app.modals.audioControls = true
|
||||
app.modals.audioSettings = false
|
||||
},
|
||||
},
|
||||
}
|
||||
});
|
||||
);
|
||||
</script>
|
107
src/renderer/views/components/castmenu.ejs
Normal file
107
src/renderer/views/components/castmenu.ejs
Normal file
|
@ -0,0 +1,107 @@
|
|||
<script type="text/x-template" id="castmenu">
|
||||
<div class="spatialproperties-panel castmenu modal-fullscreen" >
|
||||
<div class="modal-window">
|
||||
<div class="modal-header">
|
||||
<div class="modal-title">Cast To Devices</div>
|
||||
<button class="close-btn" @click="close()"></button>
|
||||
</div>
|
||||
<div class="modal-content" style="overflow-y: overlay; padding: 3%">
|
||||
<div class="md-labeltext">Chromecast</div>
|
||||
<div class="md-option-container" style="margin-top: 12px;margin-bottom: 12px;">
|
||||
<template v-if="!scanning">
|
||||
<template v-for="(device) in devices.cast">
|
||||
<div class="md-option-line" style="cursor: pointer" @click="setCast(device)">
|
||||
<div class="md-option-segment">
|
||||
{{ device.name }}
|
||||
<br>
|
||||
<small>{{ device.host }}</small>
|
||||
</div>
|
||||
<div class="md-option-segment_auto" style="display: flex;justify-content: center;align-items: center" v-if="activeCasts.includes(device)">
|
||||
Connected
|
||||
</div>
|
||||
<div class="md-option-segment_auto" v-else style="display: flex;justify-content: center;align-items: center">
|
||||
<svg width="20" height="20" viewBox="0 0 34 34" fill="#fff" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" class="castPlayIndicator"><path d="M28.228,18.327l-16.023,8.983c-0.99,0.555 -2.205,-0.17 -2.205,-1.318l0,-17.984c0,-1.146 1.215,-1.873 2.205,-1.317l16.023,8.982c1.029,0.577 1.029,2.077 0,2.654Z" style="fill-rule:nonzero"></path></svg>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div class="md-option-line" style="cursor: pointer">
|
||||
<div class="md-option-segment">
|
||||
Scanning...
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
<div class="md-labeltext" style="opacity:0.5;">AirPlay</div>
|
||||
<div class="md-option-container" style="margin-top: 12px;margin-bottom: 12px;opacity:0.5;">
|
||||
<div class="md-option-line">
|
||||
<div class="md-option-segment">
|
||||
AirPlay is still under development
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="md-footer">
|
||||
<div class="row">
|
||||
<div class="col" v-if="activeCasts.length != 0">
|
||||
<button style="width:100%" @click="stopCasting()" class="md-btn md-btn-block md-btn-primary">Stop casting to all devices</button>
|
||||
</div>
|
||||
<div class="col">
|
||||
<button style="width:100%" class="md-btn md-btn-block" @click="scan()">Scan</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
<script>
|
||||
Vue.component('castmenu', {
|
||||
template: '#castmenu',
|
||||
data: function () {
|
||||
return {
|
||||
devices: {
|
||||
cast: [],
|
||||
airplay: []
|
||||
},
|
||||
scanning: false,
|
||||
activeCasts: this.$root.activeCasts,
|
||||
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.scan();
|
||||
},
|
||||
watch:{
|
||||
activeCasts: function (newVal, oldVal) {
|
||||
this.$root.activeCasts = this.activeCasts;
|
||||
}},
|
||||
methods: {
|
||||
close() {
|
||||
this.$root.modals.castMenu = false
|
||||
},
|
||||
scan() {
|
||||
let self = this;
|
||||
this.scanning = true;
|
||||
ipcRenderer.send('getChromeCastDevices', '');
|
||||
setTimeout(() => {
|
||||
self.devices.cast = ipcRenderer.sendSync("getKnownCastDevices");
|
||||
self.scanning = false;
|
||||
}, 2000);
|
||||
console.log(this.devices);
|
||||
// vm.$forceUpdate();
|
||||
},
|
||||
setCast(device) {
|
||||
CiderAudio.sendAudio();
|
||||
this.activeCasts.push(device);
|
||||
ipcRenderer.send('performGCCast', device, "Cider", "Playing ...", "Test build", '');
|
||||
},
|
||||
stopCasting() {
|
||||
CiderAudio.stopAudio();
|
||||
ipcRenderer.send('stopGCast', '');
|
||||
this.activeCasts = [];
|
||||
// vm.$forceUpdate();
|
||||
},
|
||||
}
|
||||
});
|
||||
</script>
|
|
@ -5,11 +5,11 @@
|
|||
<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:19.75em" v-model="$root.cfg.audio.equalizer.preset" v-on:change="changePreset($root.cfg.audio.equalizer.preset)">
|
||||
<optgroup label="User Presets">
|
||||
<select class="md-select" style="width:220px;text-align:center;margin-right:245px" v-model="$root.cfg.audio.equalizer.preset" v-on:change="changePreset($root.cfg.audio.equalizer.preset)">
|
||||
<optgroup :label="$root.getLz('term.userPresets')">
|
||||
<option v-for="preset in $root.cfg.audio.equalizer.presets" :value="preset.preset">{{preset.name}}</option>
|
||||
</optgroup>
|
||||
<optgroup label="Default Presets">
|
||||
<optgroup :label="$root.getLz('term.defaultPresets')">
|
||||
<option v-for="preset in defaultPresets" :value="preset.preset">{{preset.name}}</option>
|
||||
</optgroup>
|
||||
</select>
|
||||
|
@ -23,11 +23,6 @@
|
|||
<input tabindex="0" type="range" class="eq-slider mini" orient="vertical" min="-15" max="15" step="1" v-model="$root.cfg.audio.equalizer.vibrantBass" @change="changeVibrantBass()">
|
||||
Vibrant Bass
|
||||
</div>
|
||||
<div class="input-container mini">
|
||||
<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()">
|
||||
|
@ -128,7 +123,6 @@
|
|||
this.frequencies = []
|
||||
this.gain = []
|
||||
this.Q = []
|
||||
this.preamp = 0
|
||||
this.mix = 1
|
||||
this.vibrantBass = 0
|
||||
this.userGenerated = true
|
||||
|
@ -140,27 +134,15 @@
|
|||
'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,
|
||||
'vibrantBass': 0,
|
||||
'userGenerated': false
|
||||
},{
|
||||
'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,
|
||||
'vibrantBass': 0,
|
||||
'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,
|
||||
'preset': 'boostAiriness',
|
||||
'name': 'Boost Airiness',
|
||||
'frequencies': [1169, 1733, 5962, 8688, 14125, 18628, 18628, 19000, 19500, 20000],
|
||||
'gain': [-1.41, 0.25, 3.33, 0.22, -0.53, 0.2, 3.64, 0, 0, 0],
|
||||
'Q': [0.405, 2.102, 0.025, 2.5, 7.071, 1.768, 1.146, 1, 1, 1],
|
||||
'mix': 1,
|
||||
'vibrantBass': 0,
|
||||
'userGenerated': false
|
||||
|
@ -170,7 +152,6 @@
|
|||
'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,
|
||||
'vibrantBass': 0,
|
||||
'userGenerated': false
|
||||
|
@ -180,7 +161,6 @@
|
|||
'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,
|
||||
'vibrantBass': 0,
|
||||
'userGenerated': false
|
||||
|
@ -190,7 +170,6 @@
|
|||
'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,
|
||||
'vibrantBass': 0,
|
||||
'userGenerated': false
|
||||
|
@ -200,7 +179,6 @@
|
|||
'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,
|
||||
'vibrantBass': 0,
|
||||
'userGenerated': false
|
||||
|
@ -210,29 +188,16 @@
|
|||
'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,
|
||||
'vibrantBass': 0,
|
||||
'userGenerated': false
|
||||
},
|
||||
{
|
||||
'preset': 'bassBoostGentle',
|
||||
'name': 'Gentle 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,
|
||||
'vibrantBass': 0,
|
||||
'userGenerated': false
|
||||
},
|
||||
{
|
||||
'preset': 'bassBoostSurgical',
|
||||
'name': 'Surgical Bass Boost',
|
||||
'frequencies': [32, 63, 125, 250, 500, 1000, 2000, 4000, 8000, 16000],
|
||||
'gain': [2.7, 2.2, 1.6, 1.4, 0.6, 0, 0, 0, 0, 0],
|
||||
'Q': [1.4, 1.4, 1.4, 1.4, 1.4, 1, 1, 1, 1, 1],
|
||||
'preamp': 0,
|
||||
'mix': 1,
|
||||
'vibrantBass': 0,
|
||||
'userGenerated': false
|
||||
|
@ -242,7 +207,6 @@
|
|||
'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,
|
||||
'vibrantBass': 0,
|
||||
'userGenerated': false
|
||||
|
@ -273,15 +237,15 @@
|
|||
"import": {
|
||||
"icon": "./assets/feather/share.svg",
|
||||
"name": app.getLz('action.import'),
|
||||
"action": function () {
|
||||
this.importPreset()
|
||||
action: () => {
|
||||
notyf.error("Not implemented yet")
|
||||
}
|
||||
},
|
||||
"export": {
|
||||
"icon": "./assets/feather/share.svg",
|
||||
"name": app.getLz('action.export'),
|
||||
"action": function () {
|
||||
this.exportPreset()
|
||||
action: () => {
|
||||
notyf.error("Not implemented yet")
|
||||
}
|
||||
},
|
||||
}
|
||||
|
@ -330,13 +294,20 @@
|
|||
app.resetState()
|
||||
},
|
||||
changeVibrantBass() {
|
||||
app.cfg.audio.vibrantBass.multiplier = app.cfg.audio.equalizer.vibrantBass / 10
|
||||
for (var i = 0; i < 21; i++) {
|
||||
CiderAudio.audioNodes.vibrantbassNode[i].gain.value = app.cfg.audio.vibrantBass.gain[i] * (app.cfg.audio.equalizer.vibrantBass / 10);
|
||||
}
|
||||
},
|
||||
changePreamp() {
|
||||
CiderAudio.audioNodes.preampNode.gain.value = app.cfg.audio.equalizer.preamp;
|
||||
app.cfg.audio.maikiwiAudio.vibrantBass.multiplier = app.cfg.audio.equalizer.vibrantBass / 10
|
||||
if (app.cfg.audio.equalizer.vibrantBass !== '0') {
|
||||
try {
|
||||
for (var i = 0; i < 21; i++) {
|
||||
CiderAudio.audioNodes.vibrantbassNode[i].gain.value = app.cfg.audio.maikiwiAudio.vibrantBass.gain[i] * (app.cfg.audio.equalizer.vibrantBass / 10);
|
||||
}}
|
||||
catch(e) {
|
||||
CiderAudio.hierarchical_loading();
|
||||
}
|
||||
}
|
||||
|
||||
else {
|
||||
CiderAudio.hierarchical_loading();
|
||||
}
|
||||
},
|
||||
changeMix() {
|
||||
for (var i = 0; i < 10; i++) {
|
||||
|
@ -357,7 +328,6 @@
|
|||
'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,
|
||||
'vibrantBass': 0,
|
||||
})
|
||||
|
@ -375,7 +345,6 @@
|
|||
newPreset.frequencies = eqSettings.frequencies
|
||||
newPreset.gain = eqSettings.gain
|
||||
newPreset.Q = eqSettings.Q
|
||||
newPreset.preamp = eqSettings.preamp
|
||||
newPreset.mix = eqSettings.mix
|
||||
newPreset.vibrantBass = eqSettings.vibrantBass
|
||||
app.cfg.audio.equalizer.presets.push(newPreset)
|
||||
|
@ -393,14 +362,13 @@
|
|||
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
|
||||
preset.vibrantBass = app.cfg.audio.equalizer.vibrantBass
|
||||
notyf.success("Saved Preset")
|
||||
},
|
||||
exportPreset() {
|
||||
const preset = app.cfg.audio.equalizer.presets.find(p => p.preset == app.cfg.audio.equalizer.preset)
|
||||
const jsonObj = {"name": preset.name, "author": app.chrome.userinfo.attributes.name, "frequency": preset.frequencies, "gain": preset.gain, "q": preset.Q, "preamp": preset.preamp, "mix": preset.mix, "vibrantBass": preset.vibrantBass};
|
||||
const jsonObj = {"name": preset.name, "author": app.chrome.userinfo.attributes.name, "frequency": preset.frequencies, "gain": preset.gain, "q": preset.Q, "mix": preset.mix, "vibrantBass": preset.vibrantBass};
|
||||
ipcRenderer.send("export-eq", jsonObj)
|
||||
},
|
||||
importPreset() {
|
||||
|
@ -411,7 +379,6 @@
|
|||
newPreset.frequencies = result.frequency
|
||||
newPreset.gain = result.gain
|
||||
newPreset.Q = result.q
|
||||
newPreset.preamp = result.preamp
|
||||
newPreset.mix = result.mix
|
||||
newPreset.vibrantBass = result.vibrantBass
|
||||
app.cfg.audio.equalizer.presets.push(newPreset)
|
||||
|
@ -423,7 +390,6 @@
|
|||
},
|
||||
applyPreset(preset) {
|
||||
Object.assign(this.$root.cfg.audio.equalizer, preset)
|
||||
this.changePreamp()
|
||||
this.changeVibrantBass()
|
||||
for (var i = 0; i < 10; i++) {
|
||||
this.changeGain(i)
|
||||
|
|
|
@ -3,9 +3,9 @@
|
|||
<div class="background">
|
||||
<div class="bgArtworkMaterial">
|
||||
<div class="bg-artwork-container">
|
||||
<img v-if="(app.cfg.visual.bg_artwork_rotation || app.animateBackground)" class="bg-artwork a" :src="image.replace('600x600','30x30') ?? ''">
|
||||
<img v-if="(app.cfg.visual.bg_artwork_rotation || app.animateBackground)" class="bg-artwork b" :src="image.replace('600x600','30x30') ?? ''">
|
||||
<img v-if="!(app.cfg.visual.bg_artwork_rotation || app.animateBackground)" class="bg-artwork no-animation" :src="image.replace('600x600','30x30') ?? ''">
|
||||
<img v-if="(app.cfg.visual.bg_artwork_rotation && app.animateBackground)" class="bg-artwork a" :src="(image ?? '').replace('{w}','30').replace('{h}','30')">
|
||||
<img v-if="(app.cfg.visual.bg_artwork_rotation && app.animateBackground)" class="bg-artwork b" :src="(image ?? '').replace('{w}','30').replace('{h}','30')">
|
||||
<img v-if="!(app.cfg.visual.bg_artwork_rotation && app.animateBackground)" class="bg-artwork no-animation" :src="(image ?? '').replace('{w}','30').replace('{h}','30')">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -14,7 +14,7 @@
|
|||
<div class="artwork" @click="app.fullscreen(false)">
|
||||
<mediaitem-artwork
|
||||
:size="600"
|
||||
:url="image ?? ''"
|
||||
:url="(image ?? '').replace('{w}','600').replace('{h}','600') "
|
||||
></mediaitem-artwork>
|
||||
</div>
|
||||
<div class="controls-parents">
|
||||
|
@ -41,8 +41,8 @@
|
|||
<div class="song-progress">
|
||||
<div class="song-duration" style="justify-content: space-between; height: 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>
|
||||
<p style="width: auto">{{ app.convertTime(app.getSongProgress()) }}</p>
|
||||
<p style="width: auto">{{ app.convertTime(app.mk.currentPlaybackDuration) }}</p>
|
||||
</div>
|
||||
|
||||
<input type="range" step="0.01" min="0" :style="app.progressBarStyle()"
|
||||
|
@ -66,7 +66,7 @@
|
|||
<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>
|
||||
<button class="playback-button next" @click="app.skipToNextItem()"></button>
|
||||
</div>
|
||||
<div class="app-chrome-item">
|
||||
<button class="playback-button--small repeat" v-if="app.mk.repeatMode == 0"
|
||||
|
@ -80,8 +80,9 @@
|
|||
<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="$root.cfg.audio.maxVolume" v-model="app.mk.volume"
|
||||
v-if="typeof app.mk.volume != 'undefined'" @change="app.checkMuteChange()">
|
||||
<input type="range" class="slider" @wheel="app.volumeWheel" :step="app.cfg.audio.volumeStep" min="0" :max="app.cfg.audio.maxVolume" v-model="app.mk.volume"
|
||||
v-if="typeof app.mk.volume != 'undefined'" @change="app.checkMuteChange()"
|
||||
v-b-tooltip.hover :title="`${(Math.log10(app.mk.volume) * 20).toFixed(2)} dB`">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
</script>
|
||||
|
||||
<script>
|
||||
Vue.component('hello-world', {
|
||||
var hw = Vue.component('hello-world', {
|
||||
template: '#hello-world',
|
||||
methods: {
|
||||
sayHello: function () {
|
||||
|
|
69
src/renderer/views/components/listitem-horizontal.ejs
Normal file
69
src/renderer/views/components/listitem-horizontal.ejs
Normal file
|
@ -0,0 +1,69 @@
|
|||
<script type="text/x-template" id="listitem-horizontal">
|
||||
<div class="listitem-horizontal">
|
||||
<vue-horizontal>
|
||||
<div v-for="items in itemPages">
|
||||
<mediaitem-list-item
|
||||
v-for="(song, index) in items" :show-library-status="showLibraryStatus" :parent="'listitem-hr' + simplifiedParent"
|
||||
:index="song.index"
|
||||
:item="song"></mediaitem-list-item>
|
||||
</div>
|
||||
</vue-horizontal>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script>
|
||||
Vue.component('listitem-horizontal', {
|
||||
template: '#listitem-horizontal',
|
||||
name: "listitem-horizontal",
|
||||
props: {
|
||||
items: {
|
||||
type: Array,
|
||||
required: true
|
||||
},
|
||||
showLibraryStatus: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
},
|
||||
data: function () {
|
||||
return {
|
||||
itemPages: [],
|
||||
simplifiedParent : []
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
// give every item an id
|
||||
this.items.forEach(function (item, index) {
|
||||
item.id = index;
|
||||
});
|
||||
// split items into pages
|
||||
this.itemPages = app.arrayToChunk(this.items, 4);
|
||||
try{
|
||||
this.simplifiedParent = JSON.stringify(this.items.map ( function(x){return x.attributes.playParams}));
|
||||
console.log("simplifiedParent: " + this.simplifiedParent);
|
||||
}
|
||||
catch (e){}
|
||||
|
||||
},
|
||||
watch: {
|
||||
items: function (items) {
|
||||
// give every item an id
|
||||
this.items.forEach(function (item, index) {
|
||||
item.id = index;
|
||||
});
|
||||
// split items into pages
|
||||
this.itemPages = app.arrayToChunk(this.items, 4);
|
||||
try{
|
||||
this.simplifiedParent = JSON.stringify(this.items.map ( function(x){return x.attributes.playParams}));
|
||||
console.log("simplifiedParent: " + this.simplifiedParent);
|
||||
}
|
||||
catch (e){}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
sayHello: function () {
|
||||
alert('Hello world!');
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
|
@ -1,5 +1,5 @@
|
|||
<script type="text/x-template" id="mediaitem-artwork">
|
||||
<div class="mediaitem-artwork" :class="[{'rounded': (type == 'artists')}, classes]" :key="url">
|
||||
<div class="mediaitem-artwork" @contextmenu="contextMenu" :class="[{'rounded': (type == 'artists')}, classes]" :key="url">
|
||||
<img :src="app.getMediaItemArtwork(url, size, width)"
|
||||
decoding="async"
|
||||
:style="{background: bgcolor}"
|
||||
|
@ -61,6 +61,19 @@
|
|||
this.getClasses()
|
||||
},
|
||||
methods: {
|
||||
contextMenu(event) {
|
||||
let self = this
|
||||
app.showMenuPanel({
|
||||
items: {
|
||||
"save": {
|
||||
name: "Open artwork in browser",
|
||||
action: () => {
|
||||
window.open(app.getMediaItemArtwork(self.url, 1024, 1024))
|
||||
}
|
||||
}
|
||||
}
|
||||
}, event)
|
||||
},
|
||||
getVideoPriority() {
|
||||
if(app.cfg.visual.animated_artwork == "always") {
|
||||
return true;
|
||||
|
|
|
@ -12,24 +12,30 @@
|
|||
@mouseenter="checkLibrary"
|
||||
@mouseover="showInLibrary = true"
|
||||
@mouseleave="showInLibrary = false"
|
||||
@dblclick="route()"
|
||||
@controller-click="route()"
|
||||
tabindex="0"
|
||||
:class="[{'mediaitem-selected': app.select_hasMediaItem(guid)}, addClasses]">
|
||||
<template v-if="isVisible">
|
||||
<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">
|
||||
<button @click="addToLibrary()" v-if="!addedToLibrary && (showIndex == false ||(showIndex == true && showIndexPlaylist != false))">
|
||||
<div class="svg-icon" :style="{'--color': 'var(--keyColor)', '--url': 'url(./assets/feather/plus.svg)'}"></div>
|
||||
</button>
|
||||
<button v-else-if='!(showArtwork == true && (showIndex == false ||(showIndex == true && showIndexPlaylist != false)))' @click="playTrack()" style="width: 44px;margin-left: -11px;">
|
||||
<%- include("../svg/play.svg") %>
|
||||
</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 v-if="!(app.mk.isPlaying && (((app.mk.nowPlayingItem._songId ?? (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 v-if="app.mk.isPlaying && (((app.mk.nowPlayingItem._songId ?? (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">
|
||||
<div class="artwork" v-if="showArtwork == true && (showIndex == false ||(showIndex == true && showIndexPlaylist != false)) ">
|
||||
<mediaitem-artwork
|
||||
:url="item.attributes.artwork ? item.attributes.artwork.url : ''"
|
||||
:size="48"
|
||||
|
@ -37,9 +43,9 @@
|
|||
:type="item.type"></mediaitem-artwork>
|
||||
<button class="overlay-play" @click="playTrack()"><%- include("../svg/play.svg") %></button>
|
||||
</div>
|
||||
<div class="info-rect text-overflow-elipsis" :style="{'padding-left': (showArtwork ? '' : '16px')}"
|
||||
<div class="info-rect" :style="{'padding-left': (showArtwork ? '' : '16px')}"
|
||||
@dblclick="route()">
|
||||
<div class="title">
|
||||
<div class="title text-overflow-elipsis">
|
||||
{{ item.attributes.name }}
|
||||
</div>
|
||||
<div class="subtitle text-overflow-elipsis" style="-webkit-box-orient: horizontal;">
|
||||
|
@ -71,6 +77,9 @@
|
|||
<div class="duration" v-if="displayDuration" @dblclick="route()">
|
||||
{{ msToMinSec(item.attributes.durationInMillis ?? 0) }}
|
||||
</div>
|
||||
<div class="duration" v-if="item.attributes.playCount" @dblclick="route()">
|
||||
{{ item.attributes.playCount }}
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</script>
|
||||
|
@ -90,17 +99,17 @@
|
|||
}
|
||||
},
|
||||
props: {
|
||||
'item': {type: Object, required: true},
|
||||
'parent': {type: String, required: false},
|
||||
'index': {type: Number, required: false, default: -1},
|
||||
'show-artwork': {type: Boolean, default: true},
|
||||
'show-library-status': {type: Boolean, default: true},
|
||||
'show-meta-data': {type: Boolean, default: false},
|
||||
'show-duration': {type: Boolean, default: true},
|
||||
'showIndex': {type: Boolean, required: false},
|
||||
'showIndexPlaylist': {type: Boolean, required: false},
|
||||
'contextExt': {type: Object, required: false},
|
||||
'class-list': {type: String, required: false, default: ""},
|
||||
'item': { type: Object, required: true },
|
||||
'parent': { type: String, required: false },
|
||||
'index': { type: Number, required: false, default: -1 },
|
||||
'show-artwork': { type: Boolean, default: true },
|
||||
'show-library-status': { type: Boolean, default: true },
|
||||
'show-meta-data': { type: Boolean, default: false },
|
||||
'show-duration': { type: Boolean, default: true },
|
||||
'showIndex': { type: Boolean, required: false },
|
||||
'showIndexPlaylist': { type: Boolean, required: false },
|
||||
'contextExt': { type: Object, required: false },
|
||||
'class-list': { type: String, required: false, default: "" },
|
||||
},
|
||||
mounted() {
|
||||
let duration = this.item.attributes.durationInMillis ?? 0
|
||||
|
@ -115,21 +124,21 @@
|
|||
return color
|
||||
},
|
||||
async checkLibrary() {
|
||||
if(this.addedToLibrary) {return this.addedToLibrary}
|
||||
if(this.item.type.includes("library-playlists") || this.item.type.includes("station")) {
|
||||
if (this.addedToLibrary) { return this.addedToLibrary }
|
||||
if (this.item.type.includes("library-playlists") || this.item.type.includes("station")) {
|
||||
this.addedToLibrary = true
|
||||
return
|
||||
}
|
||||
this.$root.inLibrary([this.item]).then(res => {
|
||||
this.addedToLibrary = res[0].attributes.inLibrary
|
||||
this.addedToLibrary = res[0]?.attributes?.inLibrary ?? false
|
||||
})
|
||||
return this.addedToLibrary
|
||||
},
|
||||
getClasses() {
|
||||
if(this.classList) {
|
||||
if (this.classList) {
|
||||
this.addClasses = {}
|
||||
let classList = this.classList.split(' ')
|
||||
for(let i = 0; i < classList.length; i++) {
|
||||
for (let i = 0; i < classList.length; i++) {
|
||||
this.addClasses[classList[i]] = true
|
||||
}
|
||||
}
|
||||
|
@ -259,7 +268,7 @@
|
|||
for (let kind in itemsToPlay) {
|
||||
let ids = itemsToPlay[kind]
|
||||
if (ids.length > 0) {
|
||||
app.mk.playNext({[kind + "s"]: itemsToPlay[kind]})
|
||||
app.mk.playNext({ [kind + "s"]: itemsToPlay[kind] })
|
||||
}
|
||||
}
|
||||
console.log(itemsToPlay)
|
||||
|
@ -281,7 +290,7 @@
|
|||
for (let kind in itemsToPlay) {
|
||||
let ids = itemsToPlay[kind]
|
||||
if (ids.length > 0) {
|
||||
app.mk.playLater({[kind + "s"]: itemsToPlay[kind]})
|
||||
app.mk.playLater({ [kind + "s"]: itemsToPlay[kind] })
|
||||
}
|
||||
}
|
||||
app.selectedMediaItems = []
|
||||
|
@ -363,7 +372,7 @@
|
|||
"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})
|
||||
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 = []
|
||||
}
|
||||
|
@ -372,7 +381,7 @@
|
|||
"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})
|
||||
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 = []
|
||||
}
|
||||
|
@ -381,7 +390,7 @@
|
|||
"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.setStationQueue({ song: self.item.attributes.playParams.id ?? self.item.id }).then(() => {
|
||||
app.mk.play()
|
||||
app.selectedMediaItems = []
|
||||
})
|
||||
|
@ -405,12 +414,26 @@
|
|||
"icon": "./assets/feather/share.svg",
|
||||
"name": app.getLz('action.share'),
|
||||
"action": function () {
|
||||
if (!self.item.attributes.url && self.item.relationships){
|
||||
if (self.item.relationships.catalog){
|
||||
app.mkapi(self.item.attributes.playParams.kind, false, self.item.relationships.catalog.data[0].id).then(u => {self.app.copyToClipboard((u.data.data.length && u.data.data.length > 0)? u.data.data[0].attributes.url : u.data.data.attributes.url)})
|
||||
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)}
|
||||
} else {
|
||||
self.app.copyToClipboard(self.item.attributes.url)
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"icon": "./assets/feather/share.svg",
|
||||
"name": `${app.getLz('action.share')} (song.link)`,
|
||||
"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.songLinkShare((u.data.data.length && u.data.data.length > 0) ? u.data.data[0].attributes.url : u.data.data.attributes.url) })
|
||||
}
|
||||
} else {
|
||||
self.app.songLinkShare(self.item.attributes.url)
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
|
@ -430,31 +453,31 @@
|
|||
try {
|
||||
await this.checkLibrary().then(res => {
|
||||
console.log(res)
|
||||
if(res) {
|
||||
if (res) {
|
||||
menus.normal.items.find(x => x.id == 'addToLibrary').hidden = true
|
||||
menus.normal.items.find(x => x.id == 'removeFromLibrary').hidden = false
|
||||
}else{
|
||||
} else {
|
||||
menus.normal.items.find(x => x.id == 'addToLibrary').disabled = false
|
||||
}
|
||||
})
|
||||
|
||||
}catch(e) {
|
||||
} catch (e) {
|
||||
|
||||
}
|
||||
try{
|
||||
let rating = await app.getRating(self.item)
|
||||
if (rating == 0) {
|
||||
menus.normal.headerItems.find(x => x.id == 'love').disabled = false
|
||||
menus.normal.headerItems.find(x => x.id == 'dislike').disabled = false
|
||||
} else if (rating == 1) {
|
||||
menus.normal.headerItems.find(x => x.id == 'unlove').hidden = false
|
||||
menus.normal.headerItems.find(x => x.id == 'love').hidden = true
|
||||
} else if (rating == -1) {
|
||||
menus.normal.headerItems.find(x => x.id == 'undo_dislike').hidden = false
|
||||
menus.normal.headerItems.find(x => x.id == 'dislike').hidden = true
|
||||
}
|
||||
} catch(err) {
|
||||
|
||||
try {
|
||||
let rating = await app.getRating(self.item)
|
||||
if (rating == 0) {
|
||||
menus.normal.headerItems.find(x => x.id == 'love').disabled = false
|
||||
menus.normal.headerItems.find(x => x.id == 'dislike').disabled = false
|
||||
} else if (rating == 1) {
|
||||
menus.normal.headerItems.find(x => x.id == 'unlove').hidden = false
|
||||
menus.normal.headerItems.find(x => x.id == 'love').hidden = true
|
||||
} else if (rating == -1) {
|
||||
menus.normal.headerItems.find(x => x.id == 'undo_dislike').hidden = false
|
||||
menus.normal.headerItems.find(x => x.id == 'dislike').hidden = true
|
||||
}
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
}
|
||||
},
|
||||
visibilityChanged: function (isVisible, entry) {
|
||||
|
@ -474,7 +497,7 @@
|
|||
},
|
||||
async removeFromLibrary() {
|
||||
let item = this.item
|
||||
let params = {"fields[songs]": "inLibrary", "fields[albums]": "inLibrary", "relate": "library"}
|
||||
let params = { "fields[songs]": "inLibrary", "fields[albums]": "inLibrary", "relate": "library" }
|
||||
let id = item.id ?? item.attributes.playParams.id
|
||||
let res = await app.mkapi(item.attributes.playParams.kind ?? item.type, item.attributes.playParams.isLibrary ?? false, item.attributes.playParams.id ?? item.id, params);
|
||||
if (res && res.relationships && res.relationships.library && res.relationships.library.data && res.relationships.library.data.length > 0) {
|
||||
|
@ -502,10 +525,10 @@
|
|||
let truekind = (!kind.endsWith("s")) ? (kind + "s") : kind;
|
||||
console.log(item, parent, childIndex, kind, id, isLibrary, kind == "playlists", id.startsWith("p.") || id.startsWith("pl.u"))
|
||||
app.mk.stop().then(() => {
|
||||
if (parent != null && childIndex != null) {
|
||||
app.queueParentandplayChild(parent, childIndex, item);
|
||||
}
|
||||
else if (kind.includes("playlist") && (id.startsWith("p.") || id.startsWith("pl."))){
|
||||
if (parent != null && childIndex != null) {
|
||||
app.queueParentandplayChild(parent, childIndex, item);
|
||||
}
|
||||
else if (kind.includes("playlist") && (id.startsWith("p.") || id.startsWith("pl."))) {
|
||||
function shuffleArray(array) {
|
||||
for (var i = array.length - 1; i > 0; i--) {
|
||||
var j = Math.floor(Math.random() * (i + 1));
|
||||
|
@ -514,58 +537,59 @@
|
|||
array[j] = temp;
|
||||
}
|
||||
}
|
||||
app.mk.setQueue({[truekind]: [item.attributes.playParams.id ?? item.id]}).then(function () {
|
||||
app.mk.play().then(function (){
|
||||
var playlistId = id
|
||||
function getPlaylist(id, isLibrary){
|
||||
if (isLibrary){
|
||||
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}`)}
|
||||
app.mk.setQueue({ [truekind]: [item.attributes.playParams.id ?? item.id] , parameters : {l : this.app.mklang} }).then(function () {
|
||||
app.mk.play().then(function () {
|
||||
var playlistId = id
|
||||
function getPlaylist(id, isLibrary) {
|
||||
if (isLibrary) {
|
||||
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, 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.data.relationships.tracks.next) {
|
||||
return
|
||||
} else {
|
||||
getPlaylistTracks(res.data.relationships.tracks.next)
|
||||
}
|
||||
try {
|
||||
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.data.relationships.tracks.next) {
|
||||
return
|
||||
} else {
|
||||
getPlaylistTracks(res.data.relationships.tracks.next)
|
||||
}
|
||||
|
||||
function getPlaylistTracks(next) {
|
||||
app.apiCall(app.musicBaseUrl + next, res => {
|
||||
// if (res.id != playlistId || next.includes(playlistId)) {
|
||||
// return
|
||||
// }
|
||||
console.log('nextres', res)
|
||||
let query = res.data.map(item => new MusicKit.MediaItem(item))
|
||||
if (app.mk.shuffleMode == 1){shuffleArray(query); console.log('shf')}
|
||||
app.mk.queue.append(query)
|
||||
function getPlaylistTracks(next) {
|
||||
app.apiCall(app.musicBaseUrl + next, res => {
|
||||
// if (res.id != playlistId || next.includes(playlistId)) {
|
||||
// return
|
||||
// }
|
||||
console.log('nextres', res)
|
||||
let query = res.data.map(item => new MusicKit.MediaItem(item))
|
||||
if (app.mk.shuffleMode == 1) { shuffleArray(query); console.log('shf') }
|
||||
app.mk.queue.append(query)
|
||||
|
||||
if (res.next) {
|
||||
getPlaylistTracks(res.next)
|
||||
}
|
||||
})
|
||||
if (res.next) {
|
||||
getPlaylistTracks(res.next)
|
||||
}
|
||||
})
|
||||
} catch (e) {}
|
||||
}
|
||||
})
|
||||
} catch (e) { }
|
||||
|
||||
|
||||
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
}
|
||||
else {
|
||||
app.playMediaItemById(item.attributes.playParams.id ?? item.id, item.attributes.playParams.kind ?? item.type, item.attributes.playParams.isLibrary ?? false, item.attributes.url)
|
||||
}})
|
||||
}
|
||||
else {
|
||||
app.playMediaItemById(item.attributes.playParams.id ?? item.id, item.attributes.playParams.kind ?? item.type, item.attributes.playParams.isLibrary ?? false, item.attributes.url)
|
||||
}
|
||||
})
|
||||
},
|
||||
route(){
|
||||
route() {
|
||||
let kind = (this.item.attributes.playParams ? (this.item.attributes.playParams.kind ?? (this.item.type ?? '')) : (this.item.type ?? ''));
|
||||
if (kind.toLowerCase().includes('album') || kind.toLowerCase().includes('playlist')){
|
||||
if (kind.toLowerCase().includes('album') || kind.toLowerCase().includes('playlist')) {
|
||||
app.routeView(this.item)
|
||||
} else {
|
||||
this.playTrack()
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
<script type="text/x-template" id="mediaitem-scroller-horizontal-large">
|
||||
<div class="cd-hmedia-scroller">
|
||||
<template >
|
||||
<mediaitem-square :item="item"
|
||||
v-for="item in items"></mediaitem-square>
|
||||
</template>
|
||||
</div>
|
||||
<vue-horizontal>
|
||||
<mediaitem-square :item="item"
|
||||
v-for="item in items"></mediaitem-square>
|
||||
</vue-horizontal>
|
||||
</script>
|
||||
|
||||
|
||||
|
|
|
@ -1,18 +1,18 @@
|
|||
<script type="text/x-template" id="mediaitem-scroller-horizontal-mvview">
|
||||
<div class="cd-hmedia-scroller">
|
||||
<vue-horizontal>
|
||||
<template v-if="browsesp">
|
||||
<mediaitem-mvview-sp
|
||||
:item="item ? (item.attributes.kind ? item : ((item.relationships && item.relationships.contents ) ? item.relationships.contents.data[0] : item)) : []"
|
||||
:item="item ? ((item.attributes?.kind != null || item.attributes?.type == 'editorial-elements') ? item : ((item.relationships && item.relationships.contents ) ? item.relationships.contents.data[0] : item)) : []"
|
||||
:imagesize="imagesize"
|
||||
:badge="item.attributes" v-for="item in items"></mediaitem-mvview-sp>
|
||||
</template>
|
||||
<template v-else>
|
||||
<mediaitem-square :kind="kind" size="600"
|
||||
:item="item ? (item.attributes.kind ? item : ((item.relationships && item.relationships.contents ) ? item.relationships.contents.data[0] : item)) : []"
|
||||
:item="item ? ((item.attributes?.kind != null || item.type == 'editorial-elements') ? item : ((item.relationships && item.relationships.contents ) ? item.relationships.contents.data[0] : item)) : []"
|
||||
:imagesize="imagesize"
|
||||
v-for="item in items"></mediaitem-square>
|
||||
</template>
|
||||
</div>
|
||||
</vue-horizontal>
|
||||
</script>
|
||||
|
||||
|
||||
|
@ -43,6 +43,8 @@
|
|||
app: this.$root,
|
||||
}
|
||||
},
|
||||
methods: {}
|
||||
// mounted(){
|
||||
// console.log('hes',this.items)
|
||||
// }
|
||||
});
|
||||
</script>
|
|
@ -1,9 +1,11 @@
|
|||
<script type="text/x-template" id="mediaitem-scroller-horizontal-sp">
|
||||
<div class="cd-hmedia-scroller hmedia-scroller-card">
|
||||
<template>
|
||||
<mediaitem-square kind="card" :item="item" size="300"
|
||||
v-for="item in items"></mediaitem-square>
|
||||
</template>
|
||||
<vue-horizontal>
|
||||
<template>
|
||||
<mediaitem-square kind="card" :item="item" size="300"
|
||||
v-for="item in items"></mediaitem-square>
|
||||
</template>
|
||||
</vue-horizontal>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
|
|
|
@ -1,11 +1,8 @@
|
|||
<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>
|
||||
</template>
|
||||
<vue-horizontal>
|
||||
<slot></slot>
|
||||
<mediaitem-square :kind="kind" :item="item" v-for="item in items"></mediaitem-square>
|
||||
</vue-horizontal>
|
||||
</script>
|
||||
|
||||
<script>
|
||||
|
@ -22,7 +19,7 @@
|
|||
defualt: ""
|
||||
}
|
||||
},
|
||||
data: function () {
|
||||
data: function() {
|
||||
return {
|
||||
app: this.$root,
|
||||
}
|
||||
|
|
|
@ -1,244 +0,0 @@
|
|||
<script type="text/x-template" id="mediaitem-square-large">
|
||||
<div ref="main" style="position: relative; display: inline-flex;" @contextmenu="contextMenu">
|
||||
<div @click.self='app.routeView(item)'
|
||||
class="cd-mediaitem-square-large" ref="main2">
|
||||
<div class="artwork">
|
||||
<mediaitem-artwork
|
||||
:url="item.attributes.artwork ? item.attributes.artwork.url : ''"
|
||||
: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="300"
|
||||
:type="item.type"></mediaitem-artwork>
|
||||
</div>
|
||||
<div class="cd-mediaitem-square-large-overlay" @click.self='app.routeView(item)'>
|
||||
<div class="button" style="
|
||||
border-radius: 50%;
|
||||
background: rgba(50,50,50,0.7);"
|
||||
:style="[(!(item.attributes.playParams ? (item.attributes.playParams.kind ?? (item.type ?? '')): (item.type ?? '')).includes('radioStation') && !(item.attributes.playParams ? (item.attributes.playParams.kind ?? (item.type ?? '')): (item.type ?? '')).includes('song')) ? {'margin': '140px','position': 'absolute',
|
||||
width: '40px',
|
||||
height: '40px',} :
|
||||
{margin: '35px', 'position': 'absolute',
|
||||
width: '120px',
|
||||
height: '120px',}]" @click="app.playMediaItem(item)">
|
||||
<%- include("../svg/play.svg") %>
|
||||
</div>
|
||||
<div class="button" style="
|
||||
border-radius: 50%;
|
||||
background: rgba(50,50,50,0.7);"
|
||||
:style="[(!(item.attributes.playParams ? (item.attributes.playParams.kind ?? (item.type ?? '')): (item.type ?? '')).includes('radioStation') && !(item.attributes.playParams ? (item.attributes.playParams.kind ?? (item.type ?? '')): (item.type ?? '')).includes('song')) ? {'position': 'absolute','margin': '140px',
|
||||
width: '40px', 'margin-left': '10px',
|
||||
height: '40px',} :
|
||||
{display: 'none',margin: '35px','position': 'absolute',
|
||||
width: '120px',
|
||||
height: '120px',}]" @click="clickContext() ">
|
||||
<%- include("../svg/more.svg") %>
|
||||
</div>
|
||||
</div>
|
||||
<div class="title text-overflow-elipsis" @click='app.routeView(item)'>
|
||||
{{ item.attributes.name ?? '' }}
|
||||
</div>
|
||||
<div class="subtitle text-overflow-elipsis item-navigate" v-if="item.attributes.artistName" :style = "{'z-index': ((item.attributes.editorialNotes == null) && item.attributes.artistName) ? '4' : ''}" @click="if(item.attributes.artistName)app.searchAndNavigate(item,'artist')">
|
||||
{{ item.attributes.artistName ?? '' }}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="cd-mediaitem-square-large-overlay" @click.self='app.routeView(item)' tabindex="0">
|
||||
<div class="button" style="
|
||||
border-radius: 50%;
|
||||
background: rgba(50,50,50,0.7);"
|
||||
:style="[(!(item.attributes.playParams ? (item.attributes.playParams.kind ?? (item.type ?? '')): (item.type ?? '')).includes('radioStation') && !(item.attributes.playParams ? (item.attributes.playParams.kind ?? (item.type ?? '')): (item.type ?? '')).includes('song')) ? {'margin': '140px','position': 'absolute',
|
||||
width: '40px',
|
||||
height: '40px',} :
|
||||
{margin: '35px','position': 'absolute',
|
||||
width: '120px',
|
||||
height: '120px',}]" @click="app.playMediaItem(item)">
|
||||
<%- include("../svg/play.svg") %>
|
||||
</div>
|
||||
<div class="button" style="
|
||||
border-radius: 50%;
|
||||
background: rgba(50,50,50,0.7);"
|
||||
:style="[(!(item.attributes.playParams ? (item.attributes.playParams.kind ?? (item.type ?? '')): (item.type ?? '')).includes('radioStation') && !(item.attributes.playParams ? (item.attributes.playParams.kind ?? (item.type ?? '')): (item.type ?? '')).includes('song')) ? {'position': 'absolute','margin': '140px',
|
||||
width: '40px', 'margin-left': '10px',
|
||||
height: '40px',} :
|
||||
{display: 'none',margin: '35px','position': 'absolute',
|
||||
width: '120px',
|
||||
height: '120px',}]" @click="console.log('as');contextMenu()">
|
||||
<%- include("../svg/more.svg") %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script>
|
||||
Vue.component('mediaitem-square-large', {
|
||||
template: '#mediaitem-square-large',
|
||||
props: ['item'],
|
||||
data: function () {
|
||||
return {
|
||||
isVisible: false,
|
||||
addedToLibrary: false,
|
||||
app: this.$root,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
clickContext() {
|
||||
var evt = document.createEvent('MouseEvent');
|
||||
var rect = this.$refs.main2.getBoundingClientRect();
|
||||
evt.initMouseEvent(
|
||||
"contextmenu",
|
||||
true /* bubble */, true /* cancelable */,
|
||||
window, null,
|
||||
0, 0, rect.x + 100, rect.y + 100, /* coordinates */
|
||||
false, false, false, false, /* modifier keys */
|
||||
0 /*left*/, null
|
||||
);
|
||||
this.$refs.main.dispatchEvent(evt);
|
||||
},
|
||||
async isInLibrary() {
|
||||
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);
|
||||
this.addedToLibrary = (res && res.attributes && res.attributes.inLibrary) ? res.attributes.inLibrary : false
|
||||
} else {
|
||||
this.addedToLibrary = true
|
||||
}
|
||||
},
|
||||
async removeFromLibrary(id) {
|
||||
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);
|
||||
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.v3.music(`v1/me/library/${truekind}/${id.toString()}`,{},
|
||||
{
|
||||
fetchOptions: {
|
||||
method: "DELETE"
|
||||
}})
|
||||
this.addedToLibrary = true
|
||||
},
|
||||
async contextMenu(event) {
|
||||
if (!event) { event = this.$refs.main } else { console.log(event) }
|
||||
let self = this
|
||||
let useMenu = "normal"
|
||||
await this.isInLibrary()
|
||||
if (app.selectedMediaItems.length <= 1) {
|
||||
app.selectedMediaItems = []
|
||||
app.select_selectMediaItem(this.item.attributes.playParams.id ?? this.item.id, this.item.attributes.playParams.kind ?? this.item.type, this.index, this.guid, this.item.attributes.playParams.isLibrary ?? false)
|
||||
} else {
|
||||
useMenu = "multiple"
|
||||
}
|
||||
let menus = {
|
||||
multiple: {
|
||||
items: [
|
||||
{
|
||||
name: this.$root.getLz('action.playTracksNext').replace("${app.selectedMediaItems.length}", app.selectedMediaItems.length),
|
||||
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: app.getLz('action.playTracksLater').replace("${app.selectedMediaItems.length}", app.selectedMediaItems.length),
|
||||
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 = []
|
||||
}
|
||||
},
|
||||
]
|
||||
},
|
||||
normal: {
|
||||
items: [
|
||||
{
|
||||
"name": "Play Next",
|
||||
"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 = []
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "addToPlaylist",
|
||||
"name": "Add to Playlist...",
|
||||
"action": function () {
|
||||
app.promptAddToPlaylist()
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": (this.addedToLibrary) ? "Remove from Library..." : "Add to Library...",
|
||||
"action": async function () {
|
||||
let item_id = self.item.attributes.playParams.id ?? self.item.id;
|
||||
let data_type = self.item.attributes.playParams.kind ?? self.item.type;
|
||||
if (self.addedToLibrary != true) {
|
||||
console.log("add");
|
||||
app.addToLibrary(item_id);
|
||||
self.addedToLibrary = true
|
||||
} else {
|
||||
console.log("remove");
|
||||
await self.removeFromLibrary(item_id);
|
||||
self.addedToLibrary = false
|
||||
}
|
||||
;
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": this.$root.getLz('term.share'),
|
||||
"action": function () {
|
||||
self.app.copyToClipboard(self.item.attributes.url)
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
CiderContextMenu.Create(event, menus[useMenu])
|
||||
},
|
||||
}
|
||||
});
|
||||
</script>
|
|
@ -1,293 +0,0 @@
|
|||
<script type="text/x-template" id="mediaitem-square-sp">
|
||||
<div ref="main" style="position: relative; display: inline-flex;" @contextmenu="contextMenu" v-observe-visibility="{callback: visibilityChanged}" width="250px">
|
||||
<div @click.self='app.routeView(item)' v-if="isVisible"
|
||||
class="cd-mediaitem-square-sp" ref="main2"
|
||||
:style="{'--spcolor' : (item.attributes.artwork.bgColor != null) ? ('#'+item.attributes.artwork.bgColor) : `black`}">
|
||||
<div class="artwork">
|
||||
<mediaitem-artwork
|
||||
:url="item.attributes.artwork ? item.attributes.artwork.url : ''"
|
||||
size="300"
|
||||
: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 : '')) : '' "
|
||||
:type="item.type"></mediaitem-artwork>
|
||||
</div>
|
||||
<div class="cd-mediaitem-square-large-overlay" @click.self='app.routeView(item)'>
|
||||
<div class="button" style="
|
||||
border-radius: 50%;
|
||||
background: rgba(50,50,50,0.7);"
|
||||
:style="[(!(item.attributes.playParams ? (item.attributes.playParams.kind ?? (item.type ?? '')): (item.type ?? '')).includes('radioStation') && !(item.attributes.playParams ? (item.attributes.playParams.kind ?? (item.type ?? '')): (item.type ?? '')).includes('song')) ? {'margin': '153px','position': 'absolute','margin-left': '153px',
|
||||
width: '30px',
|
||||
height: '30px',} :
|
||||
{margin: '35px',display:'none',
|
||||
width: '120px',
|
||||
height: '120px',}]" @click="clickContext()">
|
||||
<%- include("../svg/more.svg") %>
|
||||
</div>
|
||||
<div class="button" style="
|
||||
border-radius: 50%;
|
||||
background: rgba(50,50,50,0.7);"
|
||||
:style="[(!(item.attributes.playParams ? (item.attributes.playParams.kind ?? (item.type ?? '')): (item.type ?? '')).includes('radioStation') && !(item.attributes.playParams ? (item.attributes.playParams.kind ?? (item.type ?? '')): (item.type ?? '')).includes('song')) ? {'position': 'absolute','margin': '153px',
|
||||
width: '30px', 'margin-left': '8px',
|
||||
height: '30px',} :
|
||||
{margin: '35px','position': 'absolute',
|
||||
width: '120px',
|
||||
height: '120px',}]" @click="app.playMediaItem(item)">
|
||||
<%- include("../svg/play.svg") %>
|
||||
</div>
|
||||
</div>
|
||||
<div class="title text-overflow-elipsis"
|
||||
:style="{'color' : (item.attributes.artwork.textColor1 != null) ? ('#'+item.attributes.artwork.textColor1) : `#eee`}"
|
||||
style="font-weight: 600">
|
||||
{{ item.attributes.name }}
|
||||
</div>
|
||||
<div class="subtitle text-overflow-elipsis "
|
||||
:class="{'item-navigate': ((item.attributes.editorialNotes == null) && item.attributes.artistName)}"
|
||||
:style="{ 'z-index': ((item.attributes.editorialNotes == null) && item.attributes.artistName) ? '4' : '' ,'color' : (item.attributes.artwork.textColor1 != null) ? ('#'+item.attributes.artwork.textColor1) : `#eee`}"
|
||||
style="padding-left: 4px;padding-right: 4px; display: -webkit-box;-webkit-box-orient: vertical; -webkit-line-clamp: 2;white-space: normal;"
|
||||
@click="subtitleSearchNavigate(item)"
|
||||
>
|
||||
{{ (item.attributes.editorialNotes != null) ? item.attributes.editorialNotes.short
|
||||
:(item.attributes.artistName ?? '') }}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="cd-mediaitem-square-large-overlay" @click.self='app.routeView(item)' tabindex="0" v-if="isVisible">
|
||||
<div class="button" style="
|
||||
border-radius: 50%;
|
||||
background: rgba(50,50,50,0.7);"
|
||||
:style="[(!(item.attributes.playParams ? (item.attributes.playParams.kind ?? (item.type ?? '')): (item.type ?? '')).includes('radioStation') && !(item.attributes.playParams ? (item.attributes.playParams.kind ?? (item.type ?? '')): (item.type ?? '')).includes('song')) ? {'margin': '153px','position': 'absolute','margin-left': '153px',
|
||||
width: '30px',
|
||||
height: '30px',} :
|
||||
{margin: '35px','position': 'absolute', display: 'none',
|
||||
width: '120px',
|
||||
height: '120px',}]" @click="clickContext()">
|
||||
<%- include("../svg/more.svg") %>
|
||||
</div>
|
||||
<div class="button" style="
|
||||
border-radius: 50%;
|
||||
background: rgba(50,50,50,0.7);"
|
||||
:style="[(!(item.attributes.playParams ? (item.attributes.playParams.kind ?? (item.type ?? '')): (item.type ?? '')).includes('radioStation') && !(item.attributes.playParams ? (item.attributes.playParams.kind ?? (item.type ?? '')): (item.type ?? '')).includes('song')) ? {'position': 'absolute','margin': '153px',
|
||||
width: '30px', 'margin-left': '8px',
|
||||
height: '30px',} :
|
||||
{margin: '35px','position': 'absolute',
|
||||
width: '120px',
|
||||
height: '120px',}]" @click="app.playMediaItem(item)">
|
||||
<%- include("../svg/play.svg") %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script>
|
||||
Vue.component('mediaitem-square-sp', {
|
||||
template: '#mediaitem-square-sp',
|
||||
props: ['item'],
|
||||
data: function () {
|
||||
return {
|
||||
app: this.$root,
|
||||
isVisible: true,
|
||||
addedToLibrary : false,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
revisedRandId() {
|
||||
return Math.random().toString(36).replace(/[^a-z]+/g, '').substr(2, 10);
|
||||
},
|
||||
async isInLibrary() {
|
||||
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
|
||||
}
|
||||
},
|
||||
async removeFromLibrary(id) {
|
||||
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.v3.music(`v1/me/library/${truekind}/${id.toString()}`,{},
|
||||
{
|
||||
fetchOptions: {
|
||||
method: "DELETE"
|
||||
}})
|
||||
this.addedToLibrary = true
|
||||
},
|
||||
subtitleSearchNavigate(item) {
|
||||
if((item.attributes.editorialNotes == null) && item.attributes.artistName)app.searchAndNavigate(item,'artist')
|
||||
},
|
||||
clickContext() {
|
||||
var evt = document.createEvent('MouseEvent');
|
||||
var rect = this.$refs.main2.getBoundingClientRect();
|
||||
evt.initMouseEvent(
|
||||
"contextmenu",
|
||||
true /* bubble */, true /* cancelable */,
|
||||
window, null,
|
||||
0, 0, rect.x + 100, rect.y + 100, /* coordinates */
|
||||
false, false, false, false, /* modifier keys */
|
||||
0 /*left*/, null
|
||||
);
|
||||
this.$refs.main.dispatchEvent(evt);
|
||||
}
|
||||
,
|
||||
visibilityChanged: function (isVisible, entry) {
|
||||
this.isVisible = isVisible
|
||||
},
|
||||
async contextMenu(event) {
|
||||
if (!event) {
|
||||
event = this.$refs.main
|
||||
} else {
|
||||
console.log(event)
|
||||
}
|
||||
let self = this
|
||||
let useMenu = "normal"
|
||||
await this.isInLibrary()
|
||||
if (app.selectedMediaItems.length <= 1) {
|
||||
app.selectedMediaItems = []
|
||||
app.select_selectMediaItem(this.item.attributes.playParams.id ?? this.item.id, this.item.attributes.playParams.kind ?? this.item.type, this.index, this.guid, this.item.attributes.playParams.isLibrary ?? false)
|
||||
} else {
|
||||
useMenu = "multiple"
|
||||
}
|
||||
let menus = {
|
||||
multiple: {
|
||||
items: [
|
||||
{
|
||||
name: app.getLz('action.playTracksNext').replace("${app.selectedMediaItems.length}", app.selectedMediaItems.length),
|
||||
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: app.getLz('action.playTracksLater').replace("${app.selectedMediaItems.length}", app.selectedMediaItems.length),
|
||||
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 = []
|
||||
}
|
||||
},
|
||||
]
|
||||
},
|
||||
normal: {
|
||||
items: [
|
||||
|
||||
{
|
||||
"name": "Play Next",
|
||||
"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 = []
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "addToPlaylist",
|
||||
"name": "Add to Playlist...",
|
||||
"action": function () {
|
||||
app.promptAddToPlaylist()
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "love",
|
||||
"name": "Love",
|
||||
"disabled": true,
|
||||
"action": function () {
|
||||
app.love(self.item)
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "unlove",
|
||||
"name": "Unlove",
|
||||
"disabled": true,
|
||||
"action": function () {
|
||||
app.unlove(self.item)
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "dislike",
|
||||
"name": "Dislike",
|
||||
"disabled": true,
|
||||
"action": function () {
|
||||
app.dislike(self.item)
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "undo_dislike",
|
||||
"name": "Undo dislike",
|
||||
"disabled": true,
|
||||
"action": function () {
|
||||
app.unlove(self.item)
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": (this.addedToLibrary) ? "Remove from Library..." : "Add to Library...",
|
||||
"action": async function () {
|
||||
let item_id = self.item.attributes.playParams.id ?? self.item.id;
|
||||
let data_type = self.item.attributes.playParams.kind ?? self.item.type;
|
||||
if (self.addedToLibrary != true) { console.log("add"); app.addToLibrary(item_id); self.addedToLibrary = true}
|
||||
else { console.log("remove"); await self.removeFromLibrary(item_id); self.addedToLibrary = false};
|
||||
}
|
||||
},
|
||||
|
||||
]
|
||||
}
|
||||
}
|
||||
let rating = await app.getRating(self.item)
|
||||
if(rating == 0) {
|
||||
menus.normal.items.find(x => x.id == 'love').disabled = false
|
||||
menus.normal.items.find(x => x.id == 'dislike').disabled = false
|
||||
}else if(rating == 1) {
|
||||
menus.normal.items.find(x => x.id == 'unlove').disabled = false
|
||||
}else if(rating == -1) {
|
||||
menus.normal.items.find(x => x.id == 'undo_dislike').disabled = false
|
||||
}
|
||||
if ((self.item.attributes.playParams.kind ?? self.item.type).includes("playlist")) {
|
||||
// remove the add to playlist option by id "addToPlaylist" using the .filter() method
|
||||
menus.normal.items = menus.normal.items.filter(function (item) {
|
||||
return item.id != "addToPlaylist"
|
||||
})
|
||||
}
|
||||
CiderContextMenu.Create(event, menus[useMenu])
|
||||
},
|
||||
}
|
||||
});
|
||||
</script>
|
|
@ -1,10 +1,17 @@
|
|||
<script type="text/x-template" id="mediaitem-square">
|
||||
<div tabindex="0"
|
||||
<div
|
||||
tabindex="0"
|
||||
@click.self="app.routeView(item)"
|
||||
@controller-click="app.routeView(item)"
|
||||
@contextmenu.self="contextMenu"
|
||||
class="cd-mediaitem-square" :class="getClasses()" @contextmenu="contextMenu"
|
||||
v-observe-visibility="{callback: visibilityChanged}"
|
||||
:style="{'--spcolor': getBgColor()}">
|
||||
<template v-if="isVisible">
|
||||
<div class="artwork-container">
|
||||
<div class="unavailable-overlay" v-if="unavailable">
|
||||
<div class="codicon codicon-circle-slash"></div>
|
||||
</div>
|
||||
<div class="artwork" @click='app.routeView(item)'>
|
||||
<mediaitem-artwork
|
||||
:url="getArtworkUrl()"
|
||||
|
@ -12,6 +19,7 @@
|
|||
:size="size"
|
||||
shadow="subtle"
|
||||
:bgcolor="getBgColor()"
|
||||
:video-priority="forceVideo"
|
||||
:type="item.type"></mediaitem-artwork>
|
||||
</div>
|
||||
<button class="menu-btn" v-if="!nomenu.includes(item.type)"
|
||||
|
@ -28,7 +36,7 @@
|
|||
</div>
|
||||
<div class="info-rect" :class="{'info-rect-card': kind == 'card'}" :style="{'--bgartwork': getArtworkUrl(size, true)}">
|
||||
<div class="title" v-if="item.attributes.artistNames == null || kind!= 'card'" @click='app.routeView(item)'>
|
||||
<div class="item-navigate text-overflow-elipsis">{{ item.attributes.name }}</div>
|
||||
<div class="item-navigate text-overflow-elipsis">{{ item.attributes?.name ?? (item.relationships?.contents?.data[0]?.attributes?.name ?? '') }}</div>
|
||||
<div class="explicit-icon" v-if="item.attributes && item.attributes.contentRating == 'explicit'" style= "background-image: url(./assets/explicit.svg);height: 12px;width: 12px;filter: contrast(0);background-repeat: no-repeat;margin-top: 2.63px;margin-left: 4px;"></div>
|
||||
</div>
|
||||
<div class="subtitle item-navigate text-overflow-elipsis" @click="getSubtitleNavigation()"
|
||||
|
@ -57,6 +65,10 @@
|
|||
type: String,
|
||||
default: '190'
|
||||
},
|
||||
forceVideo: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
'contextExt': {type: Object, required: false},
|
||||
},
|
||||
data: function () {
|
||||
|
@ -64,15 +76,25 @@
|
|||
isVisible: false,
|
||||
addedToLibrary: false,
|
||||
guid: this.uuidv4(),
|
||||
noplay: ["apple-curators"],
|
||||
nomenu: ["artists", "stations", "apple-curators"],
|
||||
noplay: ["apple-curators", "editorial-elements"],
|
||||
nomenu: ["artists", "stations", "apple-curators", "editorial-elements"],
|
||||
app: this.$root,
|
||||
badges: this.$root.socialBadges.badgeMap,
|
||||
itemBadges: []
|
||||
itemBadges: [],
|
||||
unavailable: false
|
||||
}
|
||||
},
|
||||
async mounted() {
|
||||
await this.getBadges()
|
||||
if(typeof this.item.attributes.playParams == "object") {
|
||||
if(this.item.attributes.playParams.kind.includes("radioStation") && (this.item.attributes.playParams.streamingKind == 1 || this.item.attributes.playParams.streamingKind == 2)) {
|
||||
this.unavailable = true
|
||||
}
|
||||
}else{
|
||||
if(this.item.type == "music-movies" || this.item.type == "tv-episodes") {
|
||||
this.unavailable = true
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getBgColor() {
|
||||
|
@ -127,7 +149,7 @@
|
|||
},
|
||||
async getBadges() {
|
||||
const self = this
|
||||
const id = (this.item.attributes.playParams ? this.item.attributes.playParams.id : null) || this.item.id
|
||||
const id = ((this.item.attributes?.playParams ?? false) ? this.item.attributes?.playParams.id : null) || this.item.id
|
||||
if (id && this.badges[id]) {
|
||||
let friends = this.badges[id]
|
||||
if (friends) {
|
||||
|
@ -140,17 +162,19 @@
|
|||
}
|
||||
},
|
||||
revisedRandId() {
|
||||
return Math.random().toString(36).replace(/[^a-z]+/g, '').substr(2, 10);
|
||||
return Math.random().toString(36).replace(/[^a-z]+/g, '').slice(2, 10);
|
||||
},
|
||||
async isInLibrary() {
|
||||
if (this.item.type && !this.item.type.includes("library")) {
|
||||
var params = {
|
||||
"fields[playlists]": "inLibrary",
|
||||
"fields[albums]": "inLibrary",
|
||||
"relate": "library",
|
||||
let params = {
|
||||
relate:"library",
|
||||
"fields":"inLibrary",
|
||||
"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);
|
||||
let kind = this.item.type ?? this.item.attributes.playParams.kind
|
||||
let truekind = (!kind.endsWith("s")) ? (kind + "s") : kind;
|
||||
if (truekind == "musicVideos") {truekind = "music-videos"}
|
||||
let res = await app.mk.api.v3.music(`/v1/catalog/${app.mk.storefrontId}/?ids[${truekind}]=${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 {
|
||||
|
@ -158,21 +182,20 @@
|
|||
}
|
||||
},
|
||||
async removeFromLibrary(id) {
|
||||
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);
|
||||
let params = {
|
||||
relate:"library",
|
||||
"fields":"inLibrary",
|
||||
"extend": this.revisedRandId()
|
||||
}
|
||||
let kind = this.item.type ?? this.item.attributes.playParams.kind
|
||||
let truekind = (!kind.endsWith("s")) ? (kind + "s") : kind;
|
||||
if (truekind == "musicVideos") {truekind = "music-videos"}
|
||||
let res = await app.mk.api.v3.music(`/v1/catalog/${app.mk.storefrontId}/?ids[${truekind}]=${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.v3.music(`v1/me/library/${truekind}/${id.toString()}`,{},
|
||||
{
|
||||
fetchOptions: {
|
||||
|
@ -192,7 +215,7 @@
|
|||
}
|
||||
switch (this.kind) {
|
||||
case "385":
|
||||
artwork = this.item.attributes.editorialArtwork.subscriptionHero.url
|
||||
artwork = this.item.attributes.editorialArtwork?.subscriptionHero?.url ?? (this.item.attributes.artwork?.url ?? (this.item.relationships?.contents?.data[0]?.attributes?.editorialArtwork?.subscriptionHero?.url ?? ''))
|
||||
break;
|
||||
}
|
||||
if(!includeUrl) {
|
||||
|
@ -202,7 +225,12 @@
|
|||
}
|
||||
},
|
||||
getClasses() {
|
||||
let type = this.item.type
|
||||
let type = []
|
||||
try{
|
||||
type = this.item.type
|
||||
|
||||
}catch(e) {console.log('sd',this.item)}
|
||||
|
||||
if (this.kind != "") {
|
||||
type = this.kind
|
||||
}
|
||||
|
@ -210,6 +238,7 @@
|
|||
default:
|
||||
return []
|
||||
break;
|
||||
case "editorial-elements":
|
||||
case "card":
|
||||
return ["mediaitem-card"]
|
||||
break;
|
||||
|
@ -402,6 +431,18 @@
|
|||
}else {
|
||||
self.app.copyToClipboard(self.item.attributes.url)}
|
||||
}
|
||||
},
|
||||
{
|
||||
"icon": "./assets/feather/share.svg",
|
||||
"name": `${app.getLz('action.share')} (song.link)`,
|
||||
"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.songLinkShare((u.data.data.length && u.data.data.length > 0)? u.data.data[0].attributes.url : u.data.data.attributes.url)})
|
||||
}
|
||||
}else {
|
||||
self.app.songLinkShare(self.item.attributes.url)}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
</div>
|
||||
<div class="menu-header-body" v-if="Object.keys(content.headerItems).length != 0">
|
||||
<template v-for="item in content.headerItems">
|
||||
<button class="menu-option-header" :class="getClasses(item)" :title="item.name"
|
||||
<button class="menu-option-header" :class="getClasses(item)" v-b-tooltip.hover :title="item.name"
|
||||
v-if="canDisplay(item)" :style="getItemStyle(item)" @click="action(item)">
|
||||
<div class="sidebar-icon" style="margin: 0;" v-if="item.icon">
|
||||
<div class="svg-icon" :style="{'--url': 'url(' + item.icon + ')'}"></div>
|
||||
|
|
|
@ -6,11 +6,15 @@
|
|||
<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 fill="#323232e3" width="21" height="21" viewBox="0 0 21 21" aria-role="presentation" focusable="false" xmlns="http://www.w3.org/2000/svg">
|
||||
<defs>
|
||||
<radialGradient gradientUnits="userSpaceOnUse" cx="10.5" cy="10.5" r="10.5" id="gradient-0">
|
||||
<stop offset="0" style="stop-color: rgba(168, 163, 163, 1)"/>
|
||||
<stop offset="1" style="stop-color: rgba(118, 111, 111, 1)"/>
|
||||
</radialGradient>
|
||||
</defs>
|
||||
<path d="M10.5 21C4.724 21 0 16.275 0 10.5S4.724 0 10.5 0 21 4.725 21 10.5 16.276 21 10.5 21zm-3.543-5.967a.96.96 0 00.693-.295l2.837-2.842 2.85 2.842c.167.167.41.295.693.295.552 0 1.001-.461 1.001-1.012 0-.281-.115-.512-.295-.704L11.899 10.5l2.85-2.855a.875.875 0 00.295-.68c0-.55-.45-.998-1.001-.998a.871.871 0 00-.668.295l-2.888 2.855-2.862-2.843a.891.891 0 00-.668-.281.99.99 0 00-1.001.986c0 .269.116.512.295.678L9.088 10.5l-2.837 2.843a.926.926 0 00-.295.678c0 .551.45 1.012 1.001 1.012z"
|
||||
fill-rule="nonzero" style="stroke-miterlimit: 11; vector-effect: non-scaling-stroke; stroke-width: 31px; fill: url(#gradient-0);"/>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="col artwork-col">
|
||||
|
@ -44,8 +48,8 @@
|
|||
<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>
|
||||
<p style="width: auto">{{ app.convertTime(app.getSongProgress()) }}</p>
|
||||
<p style="width: auto">{{ app.convertTime(app.mk.currentPlaybackDuration) }}</p>
|
||||
</div>
|
||||
|
||||
<input type="range" step="0.01" min="0" :style="app.progressBarStyle()"
|
||||
|
@ -69,7 +73,7 @@
|
|||
<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>
|
||||
<button class="playback-button next" @click="app.skipToNextItem()"></button>
|
||||
</div>
|
||||
<div class="app-chrome-item">
|
||||
<button class="playback-button--small repeat" v-if="app.mk.repeatMode == 0"
|
||||
|
@ -83,7 +87,7 @@
|
|||
<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"
|
||||
<input type="range" class="slider" @wheel="app.volumeWheel" :step="app.cfg.audio.volumeStep" min="0" :max="app.cfg.audio.maxVolume" v-model="app.mk.volume"
|
||||
v-if="typeof app.mk.volume != 'undefined'" @change="app.checkMuteChange()">
|
||||
</div>
|
||||
</div>
|
||||
|
@ -151,6 +155,9 @@
|
|||
beforeDestroy() {
|
||||
window.removeEventListener('keyup', this.onEscapeKeyUp)
|
||||
},
|
||||
mounted() {
|
||||
app.pinMiniPlayer(true)
|
||||
},
|
||||
methods: {
|
||||
onEscapeKeyUp(event) {
|
||||
if (event.which === 27) {
|
||||
|
|
39
src/renderer/views/components/plugin-menu.ejs
Normal file
39
src/renderer/views/components/plugin-menu.ejs
Normal file
|
@ -0,0 +1,39 @@
|
|||
<script type="text/x-template" id="plugin-menu">
|
||||
<div class="modal-fullscreen addtoplaylist-panel" @click.self="app.resetState()" @contextmenu.self="app.resetState()">
|
||||
<div class="modal-window">
|
||||
<div class="modal-header">
|
||||
<div class="modal-title">{{$root.getLz('term.pluginMenu')}}</div>
|
||||
<button class="close-btn" @click="app.resetState()"></button>
|
||||
</div>
|
||||
<div class="modal-content">
|
||||
<span class="playlist-item" v-if="!app.pluginInstalled">
|
||||
<span class="icon"><%- include("../svg/x.svg") %></span>
|
||||
<span class="name" style="top: 0.5px;">{{$root.getLz('term.pluginMenu.none')}}</span>
|
||||
</span>
|
||||
<button class="playlist-item" @click="entry.onClick(); closeMenu();" v-for="entry in app.pluginMenuEntries">
|
||||
<span class="icon"><%- include("../svg/grid.svg") %></span>
|
||||
<span class="name" style="top: 0.5px;">{{ entry.name }}</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script>
|
||||
Vue.component('plugin-menu', {
|
||||
template: '#plugin-menu',
|
||||
data: function () {
|
||||
return {
|
||||
app: this.$root,
|
||||
}
|
||||
},
|
||||
props: {},
|
||||
mounted() {},
|
||||
methods: {
|
||||
closeMenu() {
|
||||
app.modals.pluginMenu = false
|
||||
},
|
||||
},
|
||||
}
|
||||
);
|
||||
</script>
|
|
@ -1,65 +0,0 @@
|
|||
<script type="text/x-template" id="queue-item">
|
||||
<template>
|
||||
<div v-observe-visibility="{callback: visibilityChanged}"
|
||||
@contextmenu="contextMenu"
|
||||
class="cd-mediaitem-list-item">
|
||||
<template v-if="isVisible">
|
||||
<div class="artwork">
|
||||
<mediaitem-artwork
|
||||
:url="item.attributes.artwork ? item.attributes.artwork.url : ''"
|
||||
size="34"
|
||||
:type="item.type"></mediaitem-artwork>
|
||||
</div>
|
||||
<div class="info-rect" :style="{'padding-left': '16px'}">
|
||||
<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.artistName" >
|
||||
<div class="artist item-navigate text-overflow-elipsis" @click="app.searchAndNavigate(item,'artist')">
|
||||
{{ item.attributes.artistName }}
|
||||
</div>
|
||||
<template v-if="item.attributes.albumName"> — </template>
|
||||
<template v-if="item.attributes.albumName">
|
||||
<div class="artist item-navigate text-overflow-elipsis" @click="app.searchAndNavigate(item,'album')">
|
||||
{{ item.attributes.albumName }}
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
<div class="duration">
|
||||
{{ msToMinSec(item.attributes.durationInMillis ?? 0) }}
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
</script>
|
||||
|
||||
<script>
|
||||
Vue.component('queue-item', {
|
||||
template: '#queue-item',
|
||||
props: ['item'],
|
||||
data: function () {
|
||||
return {}
|
||||
},
|
||||
methods: {
|
||||
contextMenu(event) {
|
||||
let self = this
|
||||
CiderContextMenu.Create(event, {
|
||||
items: [{
|
||||
"name": $root.getLz('action.removeFromQueue'),
|
||||
"action": function () {
|
||||
|
||||
}
|
||||
}]
|
||||
});
|
||||
},
|
||||
msToMinSec(ms) {
|
||||
var minutes = Math.floor(ms / 60000);
|
||||
var seconds = ((ms % 60000) / 1000).toFixed(0);
|
||||
return minutes + ":" + (seconds < 10 ? '0' : '') + seconds;
|
||||
},
|
||||
}
|
||||
});
|
||||
</script>
|
|
@ -8,7 +8,10 @@
|
|||
<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">
|
||||
<div class="queue-body" v-if="page == 'history'">
|
||||
<mediaitem-list-item :show-library-status="false" v-for="item in history" :item="item"></mediaitem-list-item>
|
||||
</div>
|
||||
<div class="queue-body" v-if="page == 'queue'">
|
||||
<draggable v-model="queueItems" @start="drag=true" @end="drag=false;move()">
|
||||
<template v-for="(queueItem, position) in queueItems">
|
||||
<div v-if="position <= queuePosition" style="display: none;">{{ position }}</div>
|
||||
|
@ -33,7 +36,11 @@
|
|||
</draggable>
|
||||
</div>
|
||||
<div class="queue-footer">
|
||||
<button class="md-btn" style="width:100%;" v-if="queueItems.length > 1" @click="app.mk.clearQueue();updateQueue()">{{app.getLz('term.clearAll')}}</button>
|
||||
<div class="btn-group" style="width:100%;">
|
||||
<button class="md-btn md-btn-small" :class="{'md-btn-primary': (page == 'queue')}" @click="page = 'queue'">{{app.getLz('term.queue')}}</button>
|
||||
<button class="md-btn md-btn-small" :class="{'md-btn-primary': (page == 'history')}" @click="getHistory();page = 'history'">{{app.getLz('term.history')}}</button>
|
||||
</div>
|
||||
<button class="md-btn md-btn-small" style="width:100%;margin-top:6px;" v-if="queueItems.length > 1" @click="app.mk.clearQueue();updateQueue()">{{app.getLz('term.clearAll')}}</button>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
|
@ -49,6 +56,8 @@
|
|||
queueItems: [],
|
||||
selected: -1,
|
||||
selectedItems: [],
|
||||
history: [],
|
||||
page: "queue",
|
||||
app: this.$root
|
||||
}
|
||||
},
|
||||
|
@ -56,6 +65,10 @@
|
|||
this.updateQueue()
|
||||
},
|
||||
methods: {
|
||||
async getHistory() {
|
||||
let history = await app.mk.api.v3.music(`/v1/me/recent/played/tracks`, { l : this.$root.mklang})
|
||||
this.history = history.data.data
|
||||
},
|
||||
select(e, position) {
|
||||
if(e.ctrlKey || e.shiftKey) {
|
||||
if(this.selectedItems.indexOf(position) == -1) {
|
||||
|
@ -81,8 +94,8 @@
|
|||
self.queueItems.splice(position, 1)
|
||||
app.mk.queue._queueItems = self.queueItems;
|
||||
app.mk.queue._reindex()
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": app.getLz('action.startRadio'),
|
||||
"action": function () {
|
||||
|
@ -93,6 +106,18 @@
|
|||
})
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": app.getLz('action.goToArtist'),
|
||||
"action": function () {
|
||||
app.searchAndNavigate(item,'artist')
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": app.getLz('action.goToAlbum'),
|
||||
"action": function () {
|
||||
app.searchAndNavigate(item,'album')
|
||||
}
|
||||
},
|
||||
]
|
||||
},
|
||||
multiple: {
|
||||
|
|
88
src/renderer/views/components/share-sheet.ejs
Normal file
88
src/renderer/views/components/share-sheet.ejs
Normal file
|
@ -0,0 +1,88 @@
|
|||
<script type="text/x-template" id="add-to-playlist">
|
||||
<template>
|
||||
<div class="modal-fullscreen addtoplaylist-panel" @click.self="app.resetState()" @contextmenu.self="app.resetState()">
|
||||
<div class="modal-window">
|
||||
<div class="modal-header">
|
||||
<div class="modal-title">{{app.getLz('action.addToPlaylist')}}</div>
|
||||
<button class="close-btn" @click="app.resetState()"></button>
|
||||
</div>
|
||||
<div class="modal-content">
|
||||
<button class="playlist-item"
|
||||
@click="app.addSelectedToNewPlaylist()" style="width:100%;">
|
||||
<div class="icon"><%- include("../svg/plus.svg") %></div>
|
||||
<div class="name">{{app.getLz('action.createPlaylist')}}</div>
|
||||
</button>
|
||||
<sidebar-playlist :playlist-select="playlistSelect" v-for="item in $root.getPlaylistFolderChildren('p.playlistsroot')" :item="item">
|
||||
</sidebar-playlist>
|
||||
</div>
|
||||
<div class="modal-search">
|
||||
<div class="search-input-container" style="width:100%;margin: 16px 0;">
|
||||
<div class="search-input--icon"></div>
|
||||
<input type="search"
|
||||
ref="searchInput"
|
||||
style="width:100%;"
|
||||
spellcheck="false"
|
||||
:placeholder="app.getLz('term.search') + '...'"
|
||||
v-model="searchQuery"
|
||||
@input="search()"
|
||||
class="search-input">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</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: {
|
||||
playlistSelect(playlist) {
|
||||
if(playlist.type != "library-playlist-folders") {
|
||||
this.addToPlaylist(playlist.id)
|
||||
}
|
||||
},
|
||||
addToPlaylist(id) {
|
||||
app.addSelectedToPlaylist(id)
|
||||
},
|
||||
search() {
|
||||
this.focused = ""
|
||||
if (this.searchQuery == "") {
|
||||
this.playlistSorted = this.playlists
|
||||
} else {
|
||||
this.playlistSorted = this.playlists.filter(playlist => {
|
||||
return playlist.attributes.name.toLowerCase().indexOf(this.searchQuery.toLowerCase()) > -1
|
||||
})
|
||||
if (this.playlistSorted.length == 1) {
|
||||
this.focused = this.playlistSorted[0].id
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
});
|
||||
</script>
|
|
@ -9,13 +9,14 @@
|
|||
:href="item.href"
|
||||
@click='clickEvent()'>
|
||||
<template v-if="!renaming">
|
||||
<div class="sidebar-icon" v-html="icon"></div> {{ item.attributes.name }}
|
||||
<div class="sidebar-icon" :key="item.id" v-html="icon"></div> {{ item.attributes.name }}
|
||||
<small class="presentNotice" v-if="hasRelatedMediaItems">(Track present)</small>
|
||||
</template>
|
||||
<input type="text" v-model="item.attributes.name" class="pl-rename-field" @blur="rename()" @keydown.enter="rename()" v-else>
|
||||
</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" :playlist-select="playlistSelect" :item="item" :key="item.id"></sidebar-playlist>
|
||||
<sidebar-playlist v-for="item in children" :relate-media-items="relateMediaItems" :playlist-select="playlistSelect" :item="item" :key="item.id"></sidebar-playlist>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div class="spinner"></div>
|
||||
|
@ -35,6 +36,13 @@
|
|||
playlistSelect: {
|
||||
type: Function,
|
||||
required: false
|
||||
},
|
||||
relateMediaItems: {
|
||||
type: Array,
|
||||
required: false,
|
||||
default () {
|
||||
return []
|
||||
}
|
||||
}
|
||||
},
|
||||
data: function () {
|
||||
|
@ -43,7 +51,8 @@
|
|||
children: [],
|
||||
playlistRoot: "p.playlistsroot",
|
||||
renaming: false,
|
||||
icon: ""
|
||||
icon: "",
|
||||
hasRelatedMediaItems: false
|
||||
}
|
||||
},
|
||||
async mounted() {
|
||||
|
@ -52,6 +61,12 @@
|
|||
} else {
|
||||
this.icon = await this.$root.getSvgIcon("./assets/feather/folder.svg")
|
||||
}
|
||||
let playlistMap = this.$root.playlists.trackMapping
|
||||
if(this.relateMediaItems.length != 0) {
|
||||
if(playlistMap[this.relateMediaItems[0]].includes(this.item.id)) {
|
||||
this.hasRelatedMediaItems = true
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
clickEvent() {
|
||||
|
@ -189,7 +204,7 @@
|
|||
openPlaylist(item) {
|
||||
this.$root.appRoute(`playlist_` + item.id);
|
||||
this.$root.showingPlaylist = [];
|
||||
this.$root.getPlaylistFromID(this.$root.page.substring(9))
|
||||
this.$root.getPlaylistFromID(this.$root.page.substring(9), true)
|
||||
},
|
||||
getPlaylistChildren(item) {
|
||||
let self = this
|
||||
|
|
|
@ -2,710 +2,106 @@
|
|||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<link rel="preconnect" href="https://amp-api.music.apple.com/" crossorigin/>
|
||||
<link rel="preconnect" href="https://api.music.apple.com/" crossorigin/>
|
||||
<link rel="preconnect" href="https://is1-ssl.mzstatic.com/" crossorigin/>
|
||||
<link rel="preconnect" href="https://is2-ssl.mzstatic.com/" crossorigin/>
|
||||
<link rel="preconnect" href="https://is3-ssl.mzstatic.com/" crossorigin/>
|
||||
<link rel="preconnect" href="https://is4-ssl.mzstatic.com/" crossorigin/>
|
||||
<link rel="preconnect" href="https://is5-ssl.mzstatic.com/" crossorigin/>
|
||||
<link rel="preconnect" href="https://play.itunes.apple.com/" crossorigin/>
|
||||
<link rel="preconnect" href="https://aod-ssl.itunes.apple.com/" crossorigin/>
|
||||
<link rel="preconnect" href="https://amp-api.music.apple.com/" crossorigin />
|
||||
<link rel="preconnect" href="https://api.music.apple.com/" crossorigin />
|
||||
<link rel="preconnect" href="https://is1-ssl.mzstatic.com/" crossorigin />
|
||||
<link rel="preconnect" href="https://is2-ssl.mzstatic.com/" crossorigin />
|
||||
<link rel="preconnect" href="https://is3-ssl.mzstatic.com/" crossorigin />
|
||||
<link rel="preconnect" href="https://is4-ssl.mzstatic.com/" crossorigin />
|
||||
<link rel="preconnect" href="https://is5-ssl.mzstatic.com/" crossorigin />
|
||||
<link rel="preconnect" href="https://play.itunes.apple.com/" crossorigin />
|
||||
<link rel="preconnect" href="https://aod-ssl.itunes.apple.com/" crossorigin />
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no, viewport-fit=cover">
|
||||
<title>Cider</title>
|
||||
<link rel="stylesheet/less" type="text/css" href="style.less"/>
|
||||
<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="stylesheet/less" type="text/css" href="style.less" />
|
||||
<link rel="stylesheet/less" type="text/css" id="userTheme" href="themes/default.less" />
|
||||
<script src="./lib/less.js"></script>
|
||||
<script src="<%- (env.dev ? " ./lib/vue.js" : "./lib/vue.dev.js" ) %>"></script>
|
||||
<script src="./lib/vue-horizontal.js"></script>
|
||||
<script src="./lib/smoothscroll.js"></script>
|
||||
<script src="./lib/vuex.min.js"></script>
|
||||
<script src="./lib/sortable.min.js"></script>
|
||||
<script src="./lib/vue-observe-visibility.min.js"></script>
|
||||
<script src="./lib/vuedraggable.umd.min.js"></script>
|
||||
<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>
|
||||
<script src="./lib/jquery-3.2.1.slim.min.js"></script>
|
||||
<script src="./lib/popper.min.js"></script>
|
||||
<script src="./lib/bootstrap-vue.min.js"></script>
|
||||
<script src="./lib/bootstrap.min.js"></script>
|
||||
<script src="./lib/bootbox.min.js"></script>
|
||||
<script src="./lib/notyf.min.js"></script>
|
||||
<script src="./lib/showdown.min.js"></script>
|
||||
<script src="./lib/velocity.min.js"></script>
|
||||
<script src="./lib/fast-plural-rules.js"></script>
|
||||
<script src="./lib/resonance-audio.min.js"></script>
|
||||
<script type="module" src="./main/app.js"></script>
|
||||
|
||||
<style>
|
||||
#LOADER {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: #1E1E1E;
|
||||
z-index: 99999;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
#LOADER>svg {
|
||||
width: 128px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body oncontextmenu="return false;" loading="1" platform="<%= env.platform %>">
|
||||
<div id="app" :class="getAppClasses()">
|
||||
<transition name="fsModeSwitch">
|
||||
<div id="app-main" v-show="appMode == 'player'">
|
||||
<div class="mv-chrome" v-if="chrome.topChromeVisible == false"></div>
|
||||
<div class="app-chrome" :style="{'display': chrome.topChromeVisible ? '' : 'none'}">
|
||||
<div class="app-chrome--left">
|
||||
<div class="app-chrome-item full-height" v-if="chrome.windowControlPosition == 'left'">
|
||||
<div class="window-controls">
|
||||
<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>
|
||||
<div class="minmax" v-else @click="ipcRenderer.send('maximize')"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="app-chrome-item full-height" v-else>
|
||||
<div class="app-title"></div>
|
||||
</div>
|
||||
<div class="app-chrome-item display--large">
|
||||
<button class="playback-button--small shuffle" v-if="mk.shuffleMode == 0"
|
||||
@click="mk.shuffleMode = 1"></button>
|
||||
<button class="playback-button--small shuffle active" v-else
|
||||
@click="mk.shuffleMode = 0"></button>
|
||||
</div>
|
||||
<div class="app-chrome-item display--large">
|
||||
<button class="playback-button previous" @click="prevButton()"></button>
|
||||
</div>
|
||||
<div class="app-chrome-item display--large">
|
||||
<button class="playback-button pause" @click="mk.pause()" v-if="mk.isPlaying"></button>
|
||||
<button class="playback-button play" @click="mk.play()" v-else></button>
|
||||
</div>
|
||||
<div class="app-chrome-item display--large">
|
||||
<button class="playback-button next" @click="mk.skipToNextItem()"></button>
|
||||
</div>
|
||||
<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 repeatOne" @click="mk.repeatMode = 2"
|
||||
v-else-if="mk.repeatMode == 1"></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--center">
|
||||
<div class="app-chrome-item playback-controls">
|
||||
<template v-if="mkReady()">
|
||||
<div class="app-playback-controls" @mouseover="chrome.progresshover = true"
|
||||
@mouseleave="chrome.progresshover = false" @contextmenu="nowPlayingContextMenu">
|
||||
<div class="artwork" @click="drawer.open = false; fullscreen(true)">
|
||||
<mediaitem-artwork :url="currentArtUrl"></mediaitem-artwork>
|
||||
</div>
|
||||
<div class="playback-info">
|
||||
<div class="song-name" style="-webkit-box-orient: horizontal;"
|
||||
: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>
|
||||
<div class="song-artist-album">
|
||||
<div class="song-artist-album-content"
|
||||
:class="[isElementOverflowing('#app-main > .app-chrome .app-chrome-item > .app-playback-controls > div >.song-artist-album > .song-artist-album-content') ? 'marquee' : '']"
|
||||
style="display: inline-block; -webkit-box-orient: horizontal; white-space: nowrap;">
|
||||
<div class="item-navigate song-artist" style="display: inline-block"
|
||||
@click="getNowPlayingItemDetailed(`artist`)">
|
||||
{{ mk.nowPlayingItem["attributes"]["artistName"] }}
|
||||
</div>
|
||||
<div class="song-artist item-navigate" style="display: inline-block"
|
||||
@click="getNowPlayingItemDetailed('album')"
|
||||
v-if="mk.nowPlayingItem['attributes']['albumName'] != ''">
|
||||
<div class="separator" style="display: inline-block;">{{"—"}}</div>
|
||||
{{(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;"
|
||||
:style="[chrome.progresshover ? {'display': 'flex'} : {'display' : 'none'} ]">
|
||||
<p style="width: auto">{{ convertToMins(getSongProgress()) }}</p>
|
||||
<p style="width: auto">{{ convertToMins(mk.currentPlaybackDuration) }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<input type="range" step="0.01" min="0" :style="progressBarStyle()"
|
||||
@input="playerLCD.desiredDuration = $event.target.value;playerLCD.userInteraction = true"
|
||||
@mouseup="mk.seekToTime($event.target.value);playerLCD.desiredDuration = 0;playerLCD.userInteraction = false"
|
||||
:max="mk.currentPlaybackDuration" :value="getSongProgress()">
|
||||
</div>
|
||||
</div>
|
||||
<template v-if="mk.nowPlayingItem['attributes']['playParams']">
|
||||
<div class="actions">
|
||||
<button class="lcdMenu" @click="nowPlayingContextMenu">
|
||||
<div class="svg-icon"></div>
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="app-chrome--right">
|
||||
<div class="app-chrome-item volume display--large">
|
||||
<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>
|
||||
|
||||
</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>
|
||||
<div class="minmax" v-else @click="ipcRenderer.send('maximize')"></div>
|
||||
<div class="close" @click="closeWindow()"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="app-navigation" v-cloak>
|
||||
<div id="app-sidebar">
|
||||
<div class="app-sidebar-header">
|
||||
<div class="search-input-container">
|
||||
<div class="search-input--icon"></div>
|
||||
<input type="search" spellcheck="false" @click="showSearch()"
|
||||
@focus="search.showHints = true"
|
||||
@blur="setTimeout(()=>{search.showHints = false}, 300)"
|
||||
v-on:keyup.enter="searchQuery();search.showHints = false" @change="showSearch();"
|
||||
@input="getSearchHints()" :placeholder="$root.getLz('term.search') + '...'" v-model="search.term"
|
||||
ref="searchInput" class="search-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="search-hints-container" v-if="search.showHints && search.hints.length != 0">
|
||||
<div class="search-hints">
|
||||
<button class="search-hint" v-for="hint in search.hints"
|
||||
@click="search.term = hint;search.showHints = false;searchQuery(hint)">
|
||||
{{ hint }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="app-sidebar-content">
|
||||
<div class="app-sidebar-header-text">
|
||||
Cider
|
||||
</div>
|
||||
<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">
|
||||
{{$root.getLz('term.appleMusic')}}
|
||||
</div>
|
||||
<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="$root.getLz('term.songs')" svg-icon="./assets/feather/music.svg"
|
||||
page="library-songs"></sidebar-library-item>
|
||||
<sidebar-library-item :name="$root.getLz('term.albums')" svg-icon="./assets/feather/disc.svg"
|
||||
page="library-albums"></sidebar-library-item>
|
||||
<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">
|
||||
{{ $root.getLz('term.playlists') }}
|
||||
</div>
|
||||
<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="showWebRemoteQR()">
|
||||
<div class="row nopadding">
|
||||
<div class="col nopadding">
|
||||
<span class="usermenu-item-icon"><%- include("./svg/smartphone.svg") %></span>
|
||||
<span class="usermenu-item-name">{{$root.getLz('action.showWebRemoteQR')}}</span>
|
||||
</div>
|
||||
</div>
|
||||
</button>
|
||||
<button class="usermenu-item" v-if="cfg.advanced.AudioContext"
|
||||
@click="modals.audioSettings = true">
|
||||
<span class="usermenu-item-icon"><%- include("./svg/headphones.svg") %></span>
|
||||
<span class="usermenu-item-name">{{$root.getLz('term.audioSettings')}}</span>
|
||||
</button>
|
||||
<button class="usermenu-item" @click="appRoute('about')">
|
||||
<span class="usermenu-item-icon"><%- include("./svg/info.svg") %></span>
|
||||
<span class="usermenu-item-name">{{$root.getLz('term.about')}}</span>
|
||||
</button>
|
||||
<button class="usermenu-item" @click="appRoute('settings')">
|
||||
<span class="usermenu-item-icon"><%- include("./svg/settings.svg") %></span>
|
||||
<span class="usermenu-item-name">{{$root.getLz('term.settings')}}</span>
|
||||
</button>
|
||||
<button class="usermenu-item" @click="unauthorize()">
|
||||
<span class="usermenu-item-icon" style="right:2.5px;"><%- include("./svg/log-out.svg") %></span>
|
||||
<span class="usermenu-item-name">{{$root.getLz('term.logout')}}</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
<div class="app-sidebar-footer">
|
||||
|
||||
<div class="app-playback-controls display--small" v-if="mkReady()"
|
||||
@contextmenu="nowPlayingContextMenu">
|
||||
<div class="control-buttons">
|
||||
<div class="app-chrome-item">
|
||||
<button class="playback-button--small shuffle" v-if="mk.shuffleMode == 0"
|
||||
@click="mk.shuffleMode = 1"></button>
|
||||
<button class="playback-button--small shuffle active" v-else
|
||||
@click="mk.shuffleMode = 0"></button>
|
||||
</div>
|
||||
<div class="app-chrome-item">
|
||||
<button class="playback-button previous" @click="prevButton()"></button>
|
||||
</div>
|
||||
<div class="app-chrome-item">
|
||||
<button class="playback-button pause" @click="mk.pause()"
|
||||
v-if="mk.isPlaying"></button>
|
||||
<button class="playback-button play" @click="mk.play()" v-else></button>
|
||||
</div>
|
||||
<div class="app-chrome-item">
|
||||
<button class="playback-button next" @click="mk.skipToNextItem()"></button>
|
||||
</div>
|
||||
<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 repeatOne" @click="mk.repeatMode = 2"
|
||||
v-else-if="mk.repeatMode == 1"></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">
|
||||
<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}"
|
||||
@blur="setTimeout(()=>{chrome.menuOpened = false}, 100)"
|
||||
@click="(chrome.userinfo.id) ? chrome.menuOpened = !chrome.menuOpened : false">
|
||||
|
||||
<img class="sidebar-user-icon" loading="lazy"
|
||||
:src="getMediaItemArtwork(chrome.hideUserInfo ? 'http://localhost:9000/assets/logocut.png' : (chrome.userinfo.attributes['artwork'] ? chrome.userinfo.attributes['artwork']['url'] : ''), 26)"/>
|
||||
|
||||
<div class="sidebar-user-text" v-if="!chrome.hideUserInfo">
|
||||
<template v-if="chrome.userinfo.id || mk.isAuthorized">
|
||||
<div class="fullname text-overflow-elipsis">{{ (chrome.userinfo != null && chrome.userinfo.attributes != null) ? (chrome.userinfo.attributes.name ?? "") : ""
|
||||
}}
|
||||
</div>
|
||||
<div class="handle-text text-overflow-elipsis">{{
|
||||
(chrome.userinfo != null && chrome.userinfo.attributes != null) ? (chrome.userinfo.attributes.handle ?? "") : ""
|
||||
}}
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div @click="mk.authorize()">
|
||||
Sign In
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
<div class="sidebar-user-text" v-else>
|
||||
Cider
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
<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>
|
||||
</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'">
|
||||
<apple-account-settings></apple-account-settings>
|
||||
</template>
|
||||
</transition>
|
||||
<!-- About -->
|
||||
<transition name="wpfade">
|
||||
<template v-if="page == 'about'">
|
||||
<about-page></about-page>
|
||||
</template>
|
||||
</transition>
|
||||
<!-- Artist Page -->
|
||||
<transition name="wpfade">
|
||||
<template v-if="page == 'artist-page' && artistPage.data.attributes">
|
||||
<cider-artist :data="artistPage.data"></cider-artist>
|
||||
</template>
|
||||
</transition>
|
||||
<transition name="wpfade">
|
||||
<%- include('pages/zoo') %>
|
||||
</transition>
|
||||
<transition name="wpfade">
|
||||
<%- include('pages/webview') %>
|
||||
</transition>
|
||||
<!-- Collection List -->
|
||||
<transition name="wpfade">
|
||||
<template v-if="page == 'collection-list'">
|
||||
<cider-collection-list :data="collectionList.response" :type="collectionList.type"
|
||||
:title="collectionList.title"></cider-collection-list>
|
||||
</template>
|
||||
</transition>
|
||||
<!-- Home -->
|
||||
<transition name="wpfade">
|
||||
<template v-if="page == 'home'">
|
||||
<cider-home></cider-home>
|
||||
</template>
|
||||
</transition>
|
||||
<!-- Home -->
|
||||
<transition name="wpfade">
|
||||
<template v-if="page == 'artist-feed'">
|
||||
<cider-artist-feed></cider-artist-feed>
|
||||
</template>
|
||||
</transition>
|
||||
<!-- Playlist / Album page-->
|
||||
<transition name="wpfade">
|
||||
<template v-if="page.includes('playlist_')">
|
||||
<cider-playlist :data="showingPlaylist"></cider-playlist>
|
||||
</template>
|
||||
</transition>
|
||||
<transition name="wpfade">
|
||||
<template v-if="page.includes('album_')">
|
||||
<cider-playlist :data="showingPlaylist"></cider-playlist>
|
||||
</template>
|
||||
</transition>
|
||||
<transition name="wpfade">
|
||||
<template v-if="page.includes('recordLabel_')">
|
||||
<cider-recordlabel :data="showingPlaylist"></cider-recordlabel>
|
||||
</template>
|
||||
</transition>
|
||||
|
||||
<transition name="wpfade">
|
||||
<template v-if="page.includes('curator_')">
|
||||
<cider-recordlabel :data="showingPlaylist"></cider-recordlabel>
|
||||
</template>
|
||||
</transition>
|
||||
<!-- Browse -->
|
||||
<transition v-on:enter="getBrowsePage(); console.log('browse')" name="wpfade">
|
||||
<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>
|
||||
<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">{{$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">{{$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>
|
||||
<!-- Listen Now -->
|
||||
<transition v-on:enter="getListenNow()" name="wpfade">
|
||||
<template v-if="page == 'listen_now'" @created="console.log('listennow')">
|
||||
<cider-listen-now :data="listennow"></cider-listen-now>
|
||||
</template>
|
||||
</transition>
|
||||
<!-- Radio -->
|
||||
<transition v-on:enter="getRadioStations()" name="wpfade">
|
||||
<template v-if="page == 'radio'" @created="console.log('radio')">
|
||||
<div class="content-inner">
|
||||
<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>
|
||||
</transition>
|
||||
<!-- Settings -->
|
||||
<transition name="wpfade">
|
||||
<template v-if="page == 'settings'">
|
||||
<cider-settings></cider-settings>
|
||||
</template>
|
||||
</transition>
|
||||
<!-- Search -->
|
||||
<transition name="wpfade">
|
||||
<template v-if="page == 'search'">
|
||||
<cider-search :search="search"></cider-search>
|
||||
</template>
|
||||
</transition>
|
||||
<!-- Library - Recently Added -->
|
||||
<transition name="wpfade" v-on:enter="getLibraryAlbumsFull(null, 0); searchLibraryAlbums(0);">
|
||||
<%- include('pages/library-recentlyadded') %>');
|
||||
</transition>
|
||||
<!-- Library - Songs -->
|
||||
<transition name="wpfade" v-on:enter="getLibrarySongsFull()">
|
||||
<template v-if="page == 'library-songs'">
|
||||
<cider-library-songs :data="library.songs"></cider-library-songs>
|
||||
</template>
|
||||
</transition>
|
||||
<!-- Library - Albums -->
|
||||
<transition name="wpfade" v-on:enter="getLibraryAlbumsFull(null, 1); searchLibraryAlbums(1);">
|
||||
<%- include('pages/library-albums') %>');
|
||||
%>
|
||||
</transition>
|
||||
<!-- Library - Made For You -->
|
||||
<transition name="wpfade" v-on:enter="getMadeForYou()">
|
||||
<template v-if="page == 'library-madeforyou'">
|
||||
<%- include('pages/madeforyou') %>');
|
||||
%>
|
||||
</template>
|
||||
</transition>
|
||||
<!-- Library - Artists-->
|
||||
<transition name="wpfade" v-on:enter="getLibraryArtistsFull(null, 0);">
|
||||
<template v-if="page == 'library-artists'">
|
||||
<%- include('pages/library-artists') %>');
|
||||
%>
|
||||
</template>
|
||||
</transition>
|
||||
<transition name="wpfade">
|
||||
<template v-if="page.includes('appleCurator')">
|
||||
<cider-applecurator :data="appleCurator"></cider-applecurator>
|
||||
</template>
|
||||
</transition>
|
||||
|
||||
</div>
|
||||
<transition name="drawertransition">
|
||||
<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">
|
||||
<img class="bg-artwork b" :src="$store.state.artwork.playerLCD">
|
||||
</div>
|
||||
</div>
|
||||
<lyrics-view v-if="drawer.panel == 'lyrics'" :time="lyriccurrenttime" :lyrics="lyrics"
|
||||
:richlyrics="richlyrics"></lyrics-view>
|
||||
<div v-if="drawer.panel == 'lyrics'" class="lyric-footer">
|
||||
<button class="md-btn" @click="modularUITest(!fullscreenLyrics)">{{fullscreenLyrics ?
|
||||
$root.getLz('term.defaultView'): $root.getLz('term.fullscreenView')}}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
<transition name="drawertransition">
|
||||
<div class="app-drawer" v-if="drawer.open && drawer.panel == 'queue'">
|
||||
<cider-queue ref="queue" v-if="drawer.panel == 'queue'"></cider-queue>
|
||||
</div>
|
||||
</transition>
|
||||
</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" 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">
|
||||
</div>
|
||||
</transition>
|
||||
<transition name="wpfade">
|
||||
<div class="bg-artwork--placeholder"></div>
|
||||
</transition>
|
||||
<transition name="modal">
|
||||
<add-to-playlist :playlists="playlists.listing" v-if="modals.addToPlaylist"></add-to-playlist>
|
||||
</transition>
|
||||
<transition name="modal">
|
||||
<spatial-properties v-if="modals.spatialProperties"></spatial-properties>
|
||||
</transition>
|
||||
<transition name="modal">
|
||||
<audio-settings v-if="modals.audioSettings"></audio-settings>
|
||||
</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()">
|
||||
<svg fill="white" 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 id="captions">{{((lyricon) ? ((lyrics.length > 0 && lyrics[currentLyricsLine] &&
|
||||
lyrics[currentLyricsLine].line ) ?
|
||||
lyrics[currentLyricsLine].line.replace('lrcInstrumental','') : "") : '') + ((lyricon) ?
|
||||
((lyrics.length
|
||||
> 0 && lyrics[currentLyricsLine] && lyrics[currentLyricsLine].line ) ?
|
||||
(lyrics[currentLyricsLine].translation ? ('\n\r' + lyrics[currentLyricsLine].translation) : ""): "")
|
||||
:
|
||||
'')}}
|
||||
</div>
|
||||
<div id="player-pip"
|
||||
@click="document.querySelector('video#apple-music-video-player').requestPictureInPicture()"
|
||||
title="Picture-in-Picture">
|
||||
<%- include("svg/pip.svg") %>
|
||||
</div>
|
||||
<div id="player-fullscreen"
|
||||
@click="document.querySelector('video#apple-music-video-player').requestFullscreen()"
|
||||
title="Fullscreen">
|
||||
<%- include("svg/fullscreen.svg") %>
|
||||
</div>
|
||||
</div>
|
||||
<div id="apple-music-video-player"></div>
|
||||
<div id="LOADER">
|
||||
<%- include("../assets/cider-round.svg") %>
|
||||
</div>
|
||||
</div>
|
||||
<div id="app" :class="getAppClasses()">
|
||||
<transition name="fsModeSwitch">
|
||||
<div id="app-main" v-show="appMode == 'player'">
|
||||
<%- include('app/chrome-top'); %>
|
||||
<%- include('app/app-navigation'); %>
|
||||
<%- include('app/chrome-bottom'); %>
|
||||
</div>
|
||||
</transition>
|
||||
<transition name="fsModeSwitch">
|
||||
<div class="fullscreen-view-container" v-if="appMode == 'fullscreen'">
|
||||
<fullscreen-view :image="currentArtUrlRaw" :time="lyriccurrenttime" :lyrics="lyrics"
|
||||
:richlyrics="richlyrics"></fullscreen-view>
|
||||
</div>
|
||||
</transition>
|
||||
<transition name="fsModeSwitch">
|
||||
<div class="fullscreen-view-container" v-if="appMode == 'mini'">
|
||||
<mini-view :image="currentArtUrlRaw" :time="lyriccurrenttime" :lyrics="lyrics" :richlyrics="richlyrics">
|
||||
</mini-view>
|
||||
</div>
|
||||
</transition>
|
||||
<%- include('app/panels'); %>
|
||||
<div class="cursor" v-if="chrome.showCursor"></div>
|
||||
</div>
|
||||
|
||||
<% for(var i=0; i < Object.keys(env.components).length ; i++) {%>
|
||||
<%- include(env.components[i]); %>
|
||||
<% } %>
|
||||
|
||||
|
||||
<!-- Apple Settings Page -->
|
||||
<%- include('pages/podcasts') %>
|
||||
<!-- Apple Settings Page -->
|
||||
<%- include('pages/apple-account-settings') %>
|
||||
<!-- Library - Songs -->
|
||||
<%- include('pages/library-songs') %>
|
||||
<script async src="https://js-cdn.music.apple.com/musickit/v2/amp/musickit.js"></script>
|
||||
<script src="index.js?v=1"></script>
|
||||
|
||||
<!-- Media Item Artwork-->
|
||||
<%- include("components/mediaitem-artwork"); %>
|
||||
<!-- Browse -->
|
||||
<%- include('pages/browse') %>
|
||||
|
||||
<!-- Settings -->
|
||||
<%- include('pages/settings') %>
|
||||
|
||||
<!-- Listen Now -->
|
||||
<%- include('pages/listen_now') %>
|
||||
|
||||
<!-- Home -->
|
||||
<%- include('pages/home') %>
|
||||
|
||||
<!-- Artist Feed -->
|
||||
<%- include('pages/artist-feed') %>
|
||||
|
||||
<!-- Playlists / Albums -->
|
||||
<%- include('pages/cider-playlist') %>
|
||||
|
||||
<!-- Record Label -->
|
||||
<%- include('pages/recordLabel') %>
|
||||
|
||||
<!-- Collection List -->
|
||||
<%- include('pages/collection-list') %>
|
||||
|
||||
<!-- Apple Curator -->
|
||||
<%- include('pages/apple-curator') %>
|
||||
|
||||
<!-- Artist Page -->
|
||||
<%- include('pages/artist') %>
|
||||
|
||||
<!-- Search -->
|
||||
<%- include('pages/search') %>
|
||||
|
||||
<!-- About -->
|
||||
<%- include('pages/about') %>
|
||||
|
||||
|
||||
<%- include('pages/library-videos') %>
|
||||
|
||||
<script type="text/x-template"
|
||||
id="am-musiccovershelf">
|
||||
<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">
|
||||
<!-- Sidebar 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>
|
||||
|
@ -713,98 +109,6 @@
|
|||
</button>
|
||||
</script>
|
||||
|
||||
<!-- Artwork Material -->
|
||||
<%- include('components/artwork-material') %>
|
||||
<!-- Menu Panel -->
|
||||
<%- include('components/menu-panel') %>
|
||||
<!-- Playlist Listing -->
|
||||
<%- include('components/sidebar-playlist')
|
||||
%>
|
||||
<!-- Spatial Properties -->
|
||||
<%- include('components/spatial-properties')
|
||||
%>
|
||||
<!-- Audio Settings -->
|
||||
<%- include('components/audio-settings')
|
||||
%>
|
||||
<!-- QRCode Modal -->
|
||||
<%- include('components/qrcode-modal')
|
||||
%>
|
||||
<!-- Equalizer -->
|
||||
<%- include('components/equalizer')
|
||||
%>
|
||||
<!-- Add to playlist -->
|
||||
<%- include('components/add-to-playlist')
|
||||
%>
|
||||
<!-- Queue -->
|
||||
<%- include('components/queue')
|
||||
%>
|
||||
<!-- Queue Item -->
|
||||
<%- include('components/queue-item')
|
||||
%>
|
||||
<!-- Horizontal MediaItem Scroller -->
|
||||
<%- include('components/mediaitem-scroller-horizontal')
|
||||
%>
|
||||
<!-- Horizontal MediaItem Scroller (Large) -->
|
||||
<%- include('components/mediaitem-scroller-horizontal-large')
|
||||
%>
|
||||
<!-- Horizontal MediaItem Scroller (SP : Special) -->
|
||||
<%- include('components/mediaitem-scroller-horizontal-sp')
|
||||
%>
|
||||
<!-- Horizontal MediaItem Scroller (MV) -->
|
||||
<%- include('components/mediaitem-scroller-horizontal-mvview')
|
||||
%>
|
||||
<!-- MediaItem List Item -->
|
||||
<%- include('components/mediaitem-list-item')
|
||||
%>
|
||||
<!-- MediaItem Horizontal Rectangle -->
|
||||
<%- include('components/mediaitem-hrect')
|
||||
%>
|
||||
<!-- MediaItem Square -->
|
||||
<%- include('components/mediaitem-square')
|
||||
%>
|
||||
<!-- MediaItem Square SP -->
|
||||
<%- include('components/mediaitem-square-sp')
|
||||
%>
|
||||
<!-- MediaItem MusicVideo -->
|
||||
<%- include('components/mediaitem-mvview')
|
||||
%>
|
||||
<!-- MediaItem MusicVideo -->
|
||||
<%- include('components/libraryartist-item')
|
||||
%>
|
||||
<%- include('components/listennow-child')
|
||||
%>
|
||||
<!-- MediaItem MusicVideo SP -->
|
||||
<%- include('components/mediaitem-mvview-sp')
|
||||
%>
|
||||
<!-- Animated Artwork View -->
|
||||
<%- include('components/animatedartwork-view')
|
||||
%>
|
||||
<!-- Lyrics View -->
|
||||
<%- include('components/lyrics-view')
|
||||
%>
|
||||
<!-- Fullscreen View -->
|
||||
<%- include('components/fullscreen')
|
||||
%>
|
||||
|
||||
<!-- 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="./js/WSAPI_Interop.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
</html>
|
|
@ -3,6 +3,7 @@
|
|||
<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" id="version">{{ $root.getLz("term.version") }} {{ $root.version }}</p>
|
||||
<p style="text-align: center"> {{$root.getLz('about.thanks')}} </p>
|
||||
|
||||
<p style="text-align: center">"{{$root.getLz('term.appleMusic')}}" - {{$root.getLz('term.copyright')}} © 2022 <a href="https://www.apple.com/" class="dt-footer__link"
|
||||
|
@ -11,9 +12,11 @@
|
|||
{{$root.getLz('term.rightsReserved')}}</p>
|
||||
<hr>
|
||||
<h3>{{$root.getLz('term.sponsor')}}</h3>
|
||||
<button onclick="window.open('https://github.com/sponsors/ciderapp')" class="md-btn sponsorBtn"><img src="./assets/github.svg"/>GitHub Sponsors</button>
|
||||
<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>
|
||||
<h3>{{$root.getLz('term.socials')}}</h3>
|
||||
<button onclick="window.open('https://github.com/ciderapp/Cider')" class="md-btn sponsorBtn"><img style="width: 20.5px;" src="./assets/github.svg"/>{{$root.getLz('term.github')}}</button>
|
||||
<button onclick="window.open('https://discord.gg/applemusic')" class="md-btn sponsorBtn"><img src="./assets/discord.svg"/>{{$root.getLz('term.discord')}}</button>
|
||||
|
||||
</div>
|
||||
|
@ -55,6 +58,7 @@
|
|||
data: function () {
|
||||
return {
|
||||
window: window,
|
||||
version: app.version,
|
||||
team: [
|
||||
{
|
||||
name: 'cryptofyre',
|
||||
|
@ -85,6 +89,18 @@
|
|||
link: 'https://github.com/vapormusic',
|
||||
role: app.getLz('term.developer'),
|
||||
avatar: 'https://avatars.githubusercontent.com/u/27716185?v=4'
|
||||
},
|
||||
{
|
||||
name: 'crypticplank',
|
||||
link: 'https://github.com/crypticplank',
|
||||
role: app.getLz('term.developer'),
|
||||
avatar: 'https://avatars.githubusercontent.com/u/52553007?v=4'
|
||||
},
|
||||
{
|
||||
name: 'Maikiwi',
|
||||
link: 'https://github.com/maikirakiwi',
|
||||
role: app.getLz('term.developer'),
|
||||
avatar: 'https://avatars.githubusercontent.com/u/74925636?v=4'
|
||||
},
|
||||
{
|
||||
name: 'Void',
|
||||
|
|
|
@ -8,18 +8,16 @@
|
|||
<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>
|
||||
<vue-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>
|
||||
</vue-horizontal>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -80,21 +78,30 @@
|
|||
let self = this
|
||||
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])
|
||||
}
|
||||
})
|
||||
|
||||
// Apple limits the number of IDs we can provide in a single API call to 50.
|
||||
// Divide it into groups of 50 and send parallel requests
|
||||
let chunks = []
|
||||
for (let artistIdx = 0; artistIdx < artists.length; artistIdx += 50) {
|
||||
chunks.push(artists.slice(artistIdx, artistIdx + 50))
|
||||
}
|
||||
try {
|
||||
const chunkArtistData = await Promise.all(chunks.map(chunk =>
|
||||
this.app.mk.api.v3.music(`/v1/catalog/${app.mk.storefrontId}/artists?ids=${chunk.toString()}&views=latest-release&include[songs]=albums&fields[albums]=artistName,artistUrl,artwork,contentRating,editorialArtwork,editorialVideo,name,playParams,releaseDate,url,trackCount&limit[artists:top-songs]=2&art[url]=f`)))
|
||||
chunkArtistData.forEach(chunkResult =>
|
||||
chunkResult.data.data.forEach(item => {
|
||||
self.artists.push(item)
|
||||
if (item.views["latest-release"].data.length != 0) {
|
||||
self.artistFeed.push(item.views["latest-release"].data[0])
|
||||
}
|
||||
}))
|
||||
// sort artistFeed by attributes.releaseDate descending, date is formatted as "YYYY-MM-DD"
|
||||
this.artistFeed.sort((a, b) => {
|
||||
let dateA = new Date(a.attributes.releaseDate)
|
||||
let dateB = new Date(b.attributes.releaseDate)
|
||||
return dateB - dateA
|
||||
})
|
||||
})
|
||||
|
||||
} catch (err) { }
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -57,35 +57,32 @@
|
|||
</div>
|
||||
<div class="artist-body">
|
||||
<div class="row well">
|
||||
<div class="col">
|
||||
<div class="col-sm-3" v-if="data.views['latest-release'].data.length != 0">
|
||||
<h3>{{app.getLz('term.latestReleases')}}</h3>
|
||||
<div style="width: auto;margin: 0 auto;">
|
||||
<mediaitem-square kind="card" v-for="song in data.views['latest-release'].data"
|
||||
:item="song">
|
||||
</mediaitem-square>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-12" v-if="data.views['top-songs']">
|
||||
<div class="row">
|
||||
<div class="col-auto" v-if="data.views['latest-release'].data.length != 0">
|
||||
<h3>{{app.getLz('term.latestReleases')}}</h3>
|
||||
<div style="width: auto;margin: 0 auto;">
|
||||
<mediaitem-square kind="card" v-for="song in data.views['latest-release'].data"
|
||||
:item="song">
|
||||
</mediaitem-square>
|
||||
</div>
|
||||
<div class="col" style="padding:0;">
|
||||
<h3>{{app.getLz('term.topSongs')}}</h3>
|
||||
</div>
|
||||
<div class="col" v-if="data.views['top-songs']">
|
||||
<div class="row">
|
||||
<div class="col" style="padding:0;">
|
||||
<h3>{{app.getLz('term.topSongs')}}</h3>
|
||||
</div>
|
||||
<div class="col-auto flex-center" v-if="data.views['top-songs'].data.length >= 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>
|
||||
<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>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-auto flex-center" v-if="data.views['top-songs'].data.length >= 20" style="padding:0;">
|
||||
<button class="cd-btn-seeall" @click="app.showArtistView(data.id, data.attributes.name + ' - Top Songs', 'top-songs')">{{app.getLz('term.seeAll')}}</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col flex-center" style="padding:0;">
|
||||
<div class="mediaitem-list-item__grid">
|
||||
<listitem-horizontal :items="data.views['top-songs'].data.limit(20)">
|
||||
</listitem-horizontal>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="row well">
|
||||
|
|
222
src/renderer/views/pages/audiolabs.ejs
Normal file
222
src/renderer/views/pages/audiolabs.ejs
Normal file
|
@ -0,0 +1,222 @@
|
|||
<script type="text/x-template" id="audiolabs-page">
|
||||
<div class="content-inner settings-page">
|
||||
<div class="md-option-container">
|
||||
<div class="md-option-header">
|
||||
<span>{{$root.getLz('settings.option.audio.audioLab')}}</span>
|
||||
</div>
|
||||
<div class="settings-option-body">
|
||||
<div class="md-option-line" v-show="!app.cfg.advanced.AudioContext">
|
||||
<div class="md-option-segment">
|
||||
{{$root.getLz('settings.warn.audioLab.withoutAF')}}
|
||||
</div>
|
||||
<button class="md-btn" style="margin-top: 5px;" onclick="app.appRoute('settings')">
|
||||
{{$root.getLz('term.settings')}}
|
||||
</button>
|
||||
</div>
|
||||
<div class="md-option-line" v-show="app.cfg.advanced.AudioContext">
|
||||
<div class="md-option-segment">
|
||||
{{$root.getLz('settings.option.audio.enableAdvancedFunctionality.ciderPPE')}}
|
||||
<br>
|
||||
<small>{{$root.getLz('settings.option.audio.enableAdvancedFunctionality.ciderPPE.description')}}</small>
|
||||
</div>
|
||||
<div class="md-option-segment md-option-segment_auto">
|
||||
<input type="checkbox" v-model="app.cfg.audio.maikiwiAudio.ciderPPE" v-on:change="CiderAudio.hierarchical_loading();" switch/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="md-option-line" v-show="app.cfg.advanced.AudioContext && app.cfg.audio.maikiwiAudio.ciderPPE === true">
|
||||
<div class="md-option-segment">
|
||||
{{$root.getLz('settings.option.audio.enableAdvancedFunctionality.ciderPPEStrength')}}
|
||||
<br>
|
||||
<small>{{$root.getLz('settings.option.audio.enableAdvancedFunctionality.ciderPPEStrength.description')}}</small>
|
||||
</div>
|
||||
<div class="md-option-segment md-option-segment_auto">
|
||||
<button class="md-btn" :disabled="app.cfg.audio.maikiwiAudio.ciderPPE_value === 0.5" v-model="app.cfg.audio.maikiwiAudio.ciderPPE_value" v-on:click="ciderPPEStandard">
|
||||
{{$root.getLz('settings.option.audio.enableAdvancedFunctionality.ciderPPEStrength.standard')}}
|
||||
</button>
|
||||
<button class="md-btn" style="margin-top: 5px;" :disabled="app.cfg.audio.maikiwiAudio.ciderPPE_value === 0.55" v-model="app.cfg.audio.maikiwiAudio.ciderPPE_value" v-on:click="ciderPPEClarity">
|
||||
{{$root.getLz('settings.option.audio.enableAdvancedFunctionality.ciderPPEStrength.aggressive')}}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="md-option-line" v-show="app.cfg.advanced.AudioContext">
|
||||
<div class="md-option-segment">
|
||||
{{$root.getLz('settings.option.audio.enableAdvancedFunctionality.analogWarmth')}}
|
||||
<br>
|
||||
<small>{{$root.getLz('settings.option.audio.enableAdvancedFunctionality.analogWarmth.description')}}</small>
|
||||
</div>
|
||||
<div class="md-option-segment md-option-segment_auto">
|
||||
<input type="checkbox" v-model="app.cfg.audio.maikiwiAudio.analogWarmth" v-on:change="CiderAudio.hierarchical_loading();" switch/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="md-option-line" v-show="app.cfg.advanced.AudioContext === true && app.cfg.audio.maikiwiAudio.analogWarmth === true">
|
||||
<div class="md-option-segment">
|
||||
{{$root.getLz('settings.option.audio.enableAdvancedFunctionality.analogWarmthIntensity')}}
|
||||
<br>
|
||||
<small>{{$root.getLz('settings.option.audio.enableAdvancedFunctionality.analogWarmthIntensity.description')}}</small>
|
||||
</div>
|
||||
<div class="md-option-segment md-option-segment_auto">
|
||||
<button class="md-btn" :disabled="app.cfg.audio.maikiwiAudio.analogWarmth_value === 1.25" v-model="app.cfg.audio.maikiwiAudio.analogWarmth_value" v-on:click="analogWarmthSmooth">
|
||||
{{$root.getLz('settings.option.audio.enableAdvancedFunctionality.analogWarmthIntensity.smooth')}}
|
||||
</button>
|
||||
<button class="md-btn" :disabled="app.cfg.audio.maikiwiAudio.analogWarmth_value === 1.75" v-model="app.cfg.audio.maikiwiAudio.analogWarmth_value" v-on:click="analogWarmthWarm">
|
||||
{{$root.getLz('settings.option.audio.enableAdvancedFunctionality.analogWarmthIntensity.warm')}}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="md-option-line" v-show="app.cfg.advanced.AudioContext === true">
|
||||
<div class="md-option-segment">
|
||||
{{$root.getLz('settings.option.audio.enableAdvancedFunctionality.audioSpatialization')}}
|
||||
<br>
|
||||
<small>{{$root.getLz('settings.option.audio.enableAdvancedFunctionality.audioSpatialization.description')}}</small>
|
||||
</div>
|
||||
<div class="md-option-segment md-option-segment_auto">
|
||||
<input type="checkbox" v-model="app.cfg.audio.spatial" v-on:change="toggleSpatial" switch/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="md-option-line" v-show="app.cfg.advanced.AudioContext === true">
|
||||
<div class="md-option-segment">
|
||||
{{$root.getLz('settings.option.audio.enableAdvancedFunctionality.tunedAudioSpatialization')}}
|
||||
<br>
|
||||
<small>{{$root.getLz('settings.option.audio.enableAdvancedFunctionality.tunedAudioSpatialization.description')}}</small>
|
||||
</div>
|
||||
<div class="md-option-segment md-option-segment_auto">
|
||||
<input type="checkbox" v-model="app.cfg.audio.maikiwiAudio.spatial" :disabled="app.cfg.audio.spatial === false" v-on:change="toggleSpatial" switch/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="md-option-line" v-show="app.cfg.audio.maikiwiAudio.spatial === true && app.cfg.audio.spatial === true">
|
||||
<div class="md-option-segment">
|
||||
{{$root.getLz('settings.option.audio.enableAdvancedFunctionality.tunedAudioSpatialization.profile')}}
|
||||
<br>
|
||||
<small>{{$root.getLz('settings.option.audio.enableAdvancedFunctionality.tunedAudioSpatialization.profile.description')}}</small>
|
||||
</div>
|
||||
<div class="md-option-segment md-option-segment_auto">
|
||||
<button class="md-btn" :disabled="app.cfg.audio.maikiwiAudio.spatialType === 0" v-model="app.cfg.audio.maikiwiAudio.spatialType" onclick="app.cfg.audio.maikiwiAudio.spatialType = 0; CiderAudio.hierarchical_loading();">
|
||||
{{$root.getLz('settings.option.audio.enableAdvancedFunctionality.tunedAudioSpatialization.profile.standard')}}
|
||||
</button>
|
||||
<button class="md-btn" :disabled="app.cfg.audio.maikiwiAudio.spatialType === 1" v-model="app.cfg.audio.maikiwiAudio.spatialType" onclick="app.cfg.audio.maikiwiAudio.spatialType = 1; CiderAudio.hierarchical_loading();">
|
||||
{{$root.getLz('settings.option.audio.enableAdvancedFunctionality.tunedAudioSpatialization.profile.audiophile')}}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div style="opacity: 0.5; pointer-events: none">
|
||||
<div class="md-option-header">
|
||||
<span>{{$root.getLz('settings.header.unfinished')}}</span>
|
||||
</div>
|
||||
<div class="md-option-line" v-show="app.cfg.advanced.AudioContext === true">
|
||||
<div class="md-option-segment">
|
||||
Cider Atmosphere Realizer™️
|
||||
<br>
|
||||
<small>Realizes an entirely different musical atmosphere only to be found on state of the art audio setups.</small>
|
||||
</div>
|
||||
<div class="md-option-segment md-option-segment_auto">
|
||||
<button class="md-btn">
|
||||
Signature
|
||||
</button>
|
||||
<button class="md-btn">
|
||||
Signature+
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="md-option-line" v-show="app.cfg.advanced.AudioContext === true">
|
||||
<div class="md-option-segment">
|
||||
Cider Origami™️ Vocal Enhancer/Remasterer
|
||||
<br>
|
||||
<small>Re-textures the vocals by carving out the frequencies and adjusts them to the selected profile.<br>
|
||||
<b>Modern:</b>
|
||||
Embracing 21st Century Equipment, this revives old recordings while preserving the Master's original intent.<br>
|
||||
<b>Intimate:</b>
|
||||
Bringing the vocals closer to your heart, communicating only the most personal connection between you and the artist.<br>
|
||||
<b>Breathy:</b>
|
||||
Giving the perfectionists a new voice, this adds naturality to the vocals by making them more breathy and more natural. <br>
|
||||
<b>Articulate:</b>
|
||||
Wrapping every detail of the vocal to your ear, resulting in a more expressive voice.
|
||||
</small>
|
||||
</div>
|
||||
<div class="md-option-segment md-option-segment_auto">
|
||||
<select class="md-select">
|
||||
<option value="none">{{$root.getLz('settings.header.visual.windowBackgroundStyle.none')}}
|
||||
</option>
|
||||
<option value="modern">
|
||||
Modern
|
||||
</option>
|
||||
<option value="intimate">
|
||||
Intimate
|
||||
</option>
|
||||
<option value="breathy">
|
||||
Breathy
|
||||
</option>
|
||||
<option value="articulate">
|
||||
Articulate
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script>
|
||||
Vue.component('audiolabs-page', {
|
||||
template: "#audiolabs-page",
|
||||
props: [],
|
||||
data: function () {
|
||||
return {
|
||||
app: this.$root,
|
||||
}
|
||||
},
|
||||
mounted: function () {
|
||||
},
|
||||
methods: {
|
||||
toggleSpatial: function () {
|
||||
if (app.cfg.audio.spatial) {
|
||||
if (app.cfg.audio.maikiwiAudio.spatial === false) {
|
||||
if (app.mk.volume - 0.2512 > 0) {app.mk.volume -= 0.2512}
|
||||
else {app.mk.volume = 0.0001}
|
||||
}
|
||||
CiderAudio.spatialOn()
|
||||
CiderAudio.hierarchical_loading();
|
||||
if (app.cfg.audio.maikiwiAudio.spatial === true) {
|
||||
if (app.mk.volume + 0.2512 < 1) {app.mk.volume += 0.2512}
|
||||
else {app.mk.volume = 1}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (app.cfg.audio.maikiwiAudio.spatial === true) {
|
||||
if (app.mk.volume - 0.2512 > 0) {app.mk.volume -= 0.2512}
|
||||
else {app.mk.volume = 0.0001}
|
||||
}
|
||||
app.cfg.audio.maikiwiAudio.spatial = false;
|
||||
CiderAudio.spatialOff()
|
||||
}
|
||||
|
||||
},
|
||||
ciderPPEStandard: function () {
|
||||
app.cfg.audio.maikiwiAudio.ciderPPE_value = 0.5;
|
||||
let LLPW_GAIN = [0.38, -1.81, -0.23, -0.51, 0.4, 0.84, 0.36, -0.34, 0.27, -1.2, -0.42, -0.67, 0.81, 1.31, -0.71, 0.68, -1.04, 0.79, -0.73, -1.33, 1.17, 0.57, 0.35, 6.33];
|
||||
for (let i = 0; i < 24; i++) {
|
||||
CiderAudio.audioNodes.llpw[i].gain.value = LLPW_GAIN[i];
|
||||
}
|
||||
},
|
||||
ciderPPEClarity: function () {
|
||||
app.cfg.audio.maikiwiAudio.ciderPPE_value = 0.55;
|
||||
let c_LLPW_GAIN = [-0.11, 0.27, -0.8, 0.57, 1.84, -0.38, 0.47, -1.56, 0.83, 1.58, -1.79, -0.45, 0.48, 1.22, -1.58, -1.59, -2.03, 2.56, -2.2, -2.48, 4.75, 10.5, 1.43, 3.76];
|
||||
for (let i = 0; i < 24; i++) {
|
||||
CiderAudio.audioNodes.llpw[i].gain.value = LLPW_GAIN[i];
|
||||
}
|
||||
},
|
||||
analogWarmthSmooth: function () {
|
||||
app.cfg.audio.maikiwiAudio.analogWarmth_value = 1.25
|
||||
let WARMTH_GAIN = [-4.81, 0.74, 0.55, -0.84, -1.52, 0.84, 0.66, -0.29, 0.29, 0.94, 1.67, 1.62, -0.53, -0.81, -4.98, 1.43, 0.86, 1.13, -1.06, -0.95, -1.13, 1.78, -3.86];
|
||||
for (let i = 0; i < 23; i++) {
|
||||
CiderAudio.audioNodes.analogWarmth[i].gain.value = WARMTH_GAIN[i] * 1.25;
|
||||
}
|
||||
},
|
||||
analogWarmthWarm: function () {
|
||||
app.cfg.audio.maikiwiAudio.analogWarmth_value = 1.75
|
||||
let WARMTH_GAIN = [-4.81, 0.74, 0.55, -0.84, -1.52, 0.84, 0.66, -0.29, 0.29, 0.94, 1.67, 1.62, -0.53, -0.81, -4.98, 1.43, 0.86, 1.13, -1.06, -0.95, -1.13, 1.78, -3.86];
|
||||
for (let i = 0; i < 23; i++) {
|
||||
CiderAudio.audioNodes.analogWarmth[i].gain.value = WARMTH_GAIN[i] * 1.75;
|
||||
}
|
||||
}
|
||||
}})
|
||||
</script>
|
|
@ -21,7 +21,7 @@
|
|||
: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"
|
||||
size="500"
|
||||
></mediaitem-artwork>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -32,23 +32,32 @@
|
|||
{{data.attributes ? (data.attributes.name ??
|
||||
(data.attributes.title ?? '') ?? '') : ''}}
|
||||
</div>
|
||||
<div class="playlist-name" v-show="nameEditing"><input type="text" spellcheck="false"
|
||||
<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>
|
||||
@keydown.enter="editPlaylist"/>
|
||||
</div>
|
||||
<div class="playlist-artist item-navigate"
|
||||
v-if="getArtistName(data) != ''"
|
||||
v-if="getArtistName(data) != '' && !useArtistChip"
|
||||
@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>
|
||||
<template v-if="useArtistChip">
|
||||
<artist-chip v-for="artist in data.relationships.artists.data"
|
||||
:item="artist"></artist-chip>
|
||||
</template>
|
||||
<div class="playlist-desc"
|
||||
v-if="data.attributes.description && (data.attributes.description.standard || data.attributes.description.short)">
|
||||
<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')}}
|
||||
{{app.getLz('term.showMore')}}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -57,26 +66,31 @@
|
|||
<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 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')}}
|
||||
@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')}}
|
||||
@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 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')}}
|
||||
@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>
|
||||
|
@ -90,7 +104,8 @@
|
|||
</div>
|
||||
|
||||
</div>
|
||||
<div class="floating-header" :style="{opacity: (headerVisible ? 0 : 1),'pointer-events': (headerVisible ? 'none' : '')}">
|
||||
<div class="floating-header"
|
||||
:style="{opacity: (headerVisible ? 0 : 1),'pointer-events': (headerVisible ? 'none' : '')}">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<h3>{{data.attributes ? (data.attributes.name ??
|
||||
|
@ -99,20 +114,24 @@
|
|||
<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')}}
|
||||
@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')}}
|
||||
@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 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')}}
|
||||
@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>
|
||||
</div>
|
||||
|
@ -128,7 +147,9 @@
|
|||
<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" :showIndex="true" :showIndexPlaylist="(data.attributes.playParams.kind ?? data.type ?? '').includes('playlist')"
|
||||
<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>
|
||||
|
@ -156,21 +177,26 @@
|
|||
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])">
|
||||
<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("action.showAlbum")}}
|
||||
</div>
|
||||
</template>
|
||||
</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="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 class="row">
|
||||
<div class="col">
|
||||
<mediaitem-scroller-horizontal
|
||||
:items="data.views[view].data"></mediaitem-scroller-horizontal>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -196,7 +222,8 @@
|
|||
app: this.$root,
|
||||
itemBadges: [],
|
||||
badgesRequested: false,
|
||||
headerVisible: true
|
||||
headerVisible: true,
|
||||
useArtistChip: false,
|
||||
}
|
||||
},
|
||||
mounted: function () {
|
||||
|
@ -246,10 +273,11 @@
|
|||
setTimeout(() => this.confirm = false, 3000);
|
||||
},
|
||||
getArtistName(data) {
|
||||
console.log(data.attributes)
|
||||
if (data.attributes.artistName) {
|
||||
this.useArtistChip = true
|
||||
return data.attributes.artistName
|
||||
} else if (data.attributes.artist) {
|
||||
this.useArtistChip = true
|
||||
return data.attributes.artist.attributes.name
|
||||
} else if (data.attributes.curatorName) {
|
||||
return data.attributes.curatorName
|
||||
|
@ -287,7 +315,7 @@
|
|||
this.confirm = false
|
||||
},
|
||||
async removeFromLibrary(id) {
|
||||
const params = {"fields[somgs]": "inLibrary", "fields[albums]": "inLibrary", "relate": "library"};
|
||||
const params = {"fields[songs]": "inLibrary", "fields[albums]": "inLibrary", "relate": "library"};
|
||||
var id = this.data.id ?? this.data.attributes.playParams.id
|
||||
const res = await app.mkapi(this.data.attributes.playParams.kind ?? this.data.type, this.data.attributes.playParams.isLibrary ?? false, this.data.attributes.playParams.id ?? this.data.id, params);
|
||||
if (res.data.data[0] && res.data.data[0].relationships && res.data.data[0].relationships.library && res.data.data[0].relationships.library.data && res.data.data[0].relationships.library.data.length > 0) {
|
||||
|
@ -295,11 +323,12 @@
|
|||
}
|
||||
let kind = this.data.attributes.playParams.kind ?? this.data.type ?? '';
|
||||
const truekind = (!kind.endsWith("s")) ? (kind + "s") : kind;
|
||||
app.mk.api.v3.music(`v1/me/library/${truekind}/${id.toString()}`,{},
|
||||
app.mk.api.v3.music(`v1/me/library/${truekind}/${id.toString()}`, {},
|
||||
{
|
||||
fetchOptions: {
|
||||
method: "DELETE"
|
||||
}})
|
||||
fetchOptions: {
|
||||
method: "DELETE"
|
||||
}
|
||||
})
|
||||
this.inLibrary = false
|
||||
this.confirm = false
|
||||
},
|
||||
|
@ -339,18 +368,18 @@
|
|||
if (!this.data.attributes.canEdit) {
|
||||
return
|
||||
}
|
||||
console.log('sds',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()
|
||||
})
|
||||
`/v1/me/library/playlists/${this.data.attributes.playParams.id}/tracks`,
|
||||
{},
|
||||
{
|
||||
fetchOptions: {
|
||||
method: "PUT",
|
||||
body: JSON.stringify({
|
||||
data: this.convert()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
},
|
||||
async remove() {
|
||||
|
@ -386,7 +415,17 @@
|
|||
})
|
||||
},
|
||||
menu(event) {
|
||||
app.showMenuPanel({
|
||||
let self = this
|
||||
let artistId = null
|
||||
|
||||
if(typeof this.data.relationships.artists != "undefined") {
|
||||
artistId = this.data.relationships.artists.data[0].id
|
||||
if(this.data.relationships.artists.data[0].type == "library-artists") {
|
||||
artistId = this.data.relationships.artists.data[0].relationships.catalog.data[0].id
|
||||
}
|
||||
}
|
||||
|
||||
let menuItems = {
|
||||
items: {
|
||||
"share": {
|
||||
name: app.getLz('term.share'),
|
||||
|
@ -415,9 +454,42 @@
|
|||
app.copyToClipboard(res.data.data[0].attributes.url)
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
"follow": {
|
||||
name: app.getLz('action.follow'),
|
||||
icon: "./assets/feather/plus-circle.svg",
|
||||
hidden: false,
|
||||
action: () => {
|
||||
app.followArtistById(artistId, true)
|
||||
}
|
||||
},
|
||||
"unfollow": {
|
||||
name: app.getLz('action.unfollow'),
|
||||
icon: "./assets/feather/x-circle.svg",
|
||||
hidden: true,
|
||||
action: () => {
|
||||
app.followArtistById(artistId, false)
|
||||
}
|
||||
},
|
||||
}
|
||||
}, event)
|
||||
}
|
||||
|
||||
if(artistId != null) {
|
||||
if(app.followingArtist(artistId)){
|
||||
menuItems.items.follow.hidden = true
|
||||
menuItems.items.unfollow.hidden = false
|
||||
} else {
|
||||
menuItems.items.follow.hidden = false
|
||||
menuItems.items.unfollow.hidden = true
|
||||
}
|
||||
}else{
|
||||
menuItems.items.follow.hidden = true
|
||||
menuItems.items.unfollow.hidden = true
|
||||
}
|
||||
|
||||
|
||||
app.showMenuPanel(menuItems, event)
|
||||
|
||||
},
|
||||
getItemParent: function (data) {
|
||||
kind = data.attributes.playParams.kind;
|
||||
|
@ -430,13 +502,13 @@
|
|||
if (date == null || date === "") return "";
|
||||
switch (date) {
|
||||
case this.data.attributes.releaseDate:
|
||||
prefix = this.app.getLz('term.time.released')+ ' '
|
||||
prefix = this.app.getLz('term.time.released') + ' '
|
||||
break;
|
||||
case this.data.attributes.lastModifiedDate:
|
||||
prefix = this.app.getLz('term.time.updated')+ ' '
|
||||
prefix = this.app.getLz('term.time.updated') + ' '
|
||||
break;
|
||||
case this.data.attributes.dateAdded:
|
||||
prefix = this.app.getLz('term.time.added')+ ' '
|
||||
prefix = this.app.getLz('term.time.added') + ' '
|
||||
break;
|
||||
}
|
||||
let month, year;
|
||||
|
@ -446,13 +518,22 @@
|
|||
// 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){
|
||||
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){
|
||||
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);
|
||||
formatted = new Intl.DateTimeFormat('en-US', {
|
||||
day: 'numeric',
|
||||
month: 'long',
|
||||
year: 'numeric'
|
||||
}).format(releaseDate);
|
||||
}
|
||||
}
|
||||
return prefix + formatted
|
||||
|
@ -478,7 +559,7 @@
|
|||
|
||||
let query = (this.data ?? app.showingPlaylist).relationships.tracks.data.map(item => new MusicKit.MediaItem(item));
|
||||
app.mk.stop().then(function () {
|
||||
app.mk.setQueue({[truekind]: [id]}).then(function () {
|
||||
app.mk.setQueue({[truekind]: [id], parameters: {l: app.mklang}}).then(function () {
|
||||
app.mk.play().then(function () {
|
||||
if (query.length > 100) {
|
||||
let u = query.slice(100);
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
<script type="text/x-template" id="cider-collection-list">
|
||||
<div class="content-inner collection-page">
|
||||
<h3 class="header-text" v-observe-visibility="{callback: headerVisibility}">{{ title }}</h3>
|
||||
<div v-if="data['data'] != 'null'" class="well">
|
||||
<div v-if="data['data'] != 'null'" class="well itemContainer">
|
||||
<template v-for="(item, key) in data.data">
|
||||
<template v-if="item.type == 'artists'">
|
||||
<mediaitem-square :item="item"></mediaitem-square>
|
||||
</template>
|
||||
<template v-else>
|
||||
<template v-else>
|
||||
<mediaitem-list-item
|
||||
v-if="getKind(item) == 'song'"
|
||||
:index="key"
|
||||
|
@ -14,8 +14,7 @@
|
|||
<mediaitem-square v-else :item="item" :type="getKind(item)"></mediaitem-square>
|
||||
</template>
|
||||
</template>
|
||||
<button v-if="triggerEnabled" style="opacity:0;height: 32px;"
|
||||
v-observe-visibility="{callback: visibilityChanged}">{{this.app.getLz('term.showMore')}}
|
||||
<button v-if="triggerEnabled" style="opacity:0;height: 32px;" v-observe-visibility="{callback: visibilityChanged}">{{this.app.getLz('term.showMore')}}
|
||||
</button>
|
||||
</div>
|
||||
<transition name="fabfade">
|
||||
|
@ -23,7 +22,9 @@
|
|||
<%- include("../svg/arrow-up.svg") %>
|
||||
</button>
|
||||
</transition>
|
||||
<div class="well" v-show="loading"><div class="spinner"></div></div>
|
||||
<div class="well itemContainer" v-show="loading">
|
||||
<div class="spinner"></div>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
<script>
|
||||
|
@ -44,7 +45,7 @@
|
|||
default: "artists"
|
||||
}
|
||||
},
|
||||
data: function () {
|
||||
data: function() {
|
||||
return {
|
||||
triggerEnabled: true,
|
||||
canSeeTrigger: false,
|
||||
|
@ -92,8 +93,8 @@
|
|||
this.triggerEnabled = true;
|
||||
}
|
||||
this.loading = false
|
||||
}else{
|
||||
if(!response.data.results[app.collectionList.response.groups]) {
|
||||
} else {
|
||||
if (!response.data.results[app.collectionList.response.groups]) {
|
||||
this.loading = false
|
||||
return
|
||||
}
|
||||
|
@ -106,14 +107,14 @@
|
|||
}
|
||||
})
|
||||
},
|
||||
headerVisibility: function (isVisible, entry) {
|
||||
headerVisibility: function(isVisible, entry) {
|
||||
if (isVisible) {
|
||||
this.showFab = false;
|
||||
} else {
|
||||
this.showFab = true;
|
||||
}
|
||||
},
|
||||
visibilityChanged: function (isVisible, entry) {
|
||||
visibilityChanged: function(isVisible, entry) {
|
||||
if (isVisible) {
|
||||
this.canSeeTrigger = true;
|
||||
this.getNext();
|
||||
|
|
|
@ -3,7 +3,14 @@
|
|||
<div v-if="page == 'main'">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<h3>{{app.getLz('home.recentlyPlayed')}}</h3>
|
||||
<div class="row">
|
||||
<div class="col nopadding">
|
||||
<h3>{{app.getLz('home.recentlyPlayed')}}</h3>
|
||||
</div>
|
||||
<div class="col-auto nopadding flex-center">
|
||||
<button class="cd-btn-seeall" @click="seeAllHistory()">{{app.getLz('term.history')}}</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="well artistfeed-well">
|
||||
<template v-if="isSectionReady('recentlyPlayed')">
|
||||
<mediaitem-list-item v-for="item in recentlyPlayed.limit(6)"
|
||||
|
@ -13,7 +20,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="row nopadding">
|
||||
<div class="row">
|
||||
<div class="col nopadding">
|
||||
<h3>{{app.getLz('home.artistsFeed')}}</h3>
|
||||
</div>
|
||||
|
@ -42,13 +49,24 @@
|
|||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<div class="row" v-if="!seenReplay">
|
||||
<div class="col">
|
||||
<button class="md-btn md-btn-block md-btn-replay--hero" @click="$root.appRoute('replay')">{{$root.getLz('term.replay')}} {{ year }}</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<h3>{{app.getLz('home.madeForYou')}}</h3>
|
||||
<div class="row">
|
||||
<div class="col nopadding">
|
||||
<h3>{{app.getLz('home.madeForYou')}}</h3>
|
||||
</div>
|
||||
<div class="col-auto nopadding flex-center">
|
||||
<button class="md-btn md-btn-replay" v-if="seenReplay" @click="$root.appRoute('replay')">{{$root.getLz('term.replay')}} {{ year }}</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="well">
|
||||
<template v-if="isSectionReady('madeForYou')">
|
||||
<mediaitem-square kind="small" v-for="item in madeForYou" :item="item"></mediaitem-square>
|
||||
</template>
|
||||
<mediaitem-scroller-horizontal :items="madeForYou" v-if="isSectionReady('madeForYou')">
|
||||
</mediaitem-scroller-horizontal>
|
||||
<div class="spinner" v-else></div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -64,10 +82,8 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="well">
|
||||
<template v-if="isSectionReady('friendsListeningTo')">
|
||||
<mediaitem-square kind="small" v-for="item in friendsListeningTo"
|
||||
:item="item"></mediaitem-square>
|
||||
</template>
|
||||
<mediaitem-scroller-horizontal :items="friendsListeningTo" v-if="isSectionReady('friendsListeningTo')">
|
||||
</mediaitem-scroller-horizontal>
|
||||
<div class="spinner" v-else></div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -94,7 +110,9 @@
|
|||
artistFeed: [],
|
||||
showingArtistFeed: false,
|
||||
page: "main",
|
||||
sectionsReady: []
|
||||
sectionsReady: [],
|
||||
year: new Date().getFullYear(),
|
||||
seenReplay: localStorage.getItem('seenReplay')
|
||||
}
|
||||
},
|
||||
async mounted() {
|
||||
|
@ -102,8 +120,18 @@
|
|||
this.getListenNowData()
|
||||
await this.getArtistFeed()
|
||||
await this.getFavorites()
|
||||
if (new Date().getMonth() == 11) {
|
||||
this.seenReplay = false
|
||||
localStorage.setItem('seenReplay', false)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async seeAllHistory() {
|
||||
let hist = await app.mk.api.v3.music(`/v1/me/recent/played/tracks`, {
|
||||
l: this.$root.mklang
|
||||
})
|
||||
app.showCollection(hist.data, app.getLz('term.history'))
|
||||
},
|
||||
isSectionReady(section) {
|
||||
return this.sectionsReady.includes(section)
|
||||
},
|
||||
|
@ -131,13 +159,17 @@
|
|||
playlists.push(item.id)
|
||||
}
|
||||
}
|
||||
if (playlists.length != 0) {
|
||||
this.app.mk.api.v3.music(`/v1/catalog/${app.mk.storefrontId}/playlists/${playlists.toString()}`).then(playlistsData => {
|
||||
if (playlists.length != 0) {
|
||||
this.app.mk.api.v3.music(`/v1/catalog/${app.mk.storefrontId}/playlists/${playlists.toString()}`, {
|
||||
l: this.$root.mklang
|
||||
}).then(playlistsData => {
|
||||
self.favorites.push(...playlistsData.data)
|
||||
})
|
||||
}
|
||||
if (libraryPlaylists.length != 0) {
|
||||
this.app.mk.api.v3.music(`v1/me/library/playlists/${playlists.toString()}`).then(playlistsData => {
|
||||
if (libraryPlaylists.length != 0) {
|
||||
this.app.mk.api.v3.music(`v1/me/library/playlists/${playlists.toString()}`, {
|
||||
l: this.$root.mklang
|
||||
}).then(playlistsData => {
|
||||
self.favorites.push(...playlistsData.data)
|
||||
})
|
||||
}
|
||||
|
@ -145,28 +177,34 @@
|
|||
async getArtistFeed() {
|
||||
let artists = this.followedArtists
|
||||
let self = this
|
||||
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 => {
|
||||
|
||||
let chunks = []
|
||||
for (let artistIdx = 0; artistIdx < artists.length; artistIdx += 50) {
|
||||
chunks.push(artists.slice(artistIdx, artistIdx + 50));
|
||||
}
|
||||
try {
|
||||
const chunkArtistData = await Promise.all(chunks.map(chunk =>
|
||||
this.app.mk.api.v3.music(`/v1/catalog/${app.mk.storefrontId}/artists?ids=${chunk.toString()}&views=latest-release&include[songs]=albums&fields[albums]=artistName,artistUrl,artwork,contentRating,editorialArtwork,editorialVideo,name,playParams,releaseDate,url,trackCount&limit[artists:top-songs]=2&art[url]=f`)))
|
||||
chunkArtistData.forEach(chunkResult =>
|
||||
chunkResult.data.data.forEach(item => {
|
||||
if (item.views["latest-release"].data.length != 0) {
|
||||
self.artistFeed.push(item.views["latest-release"].data[0])
|
||||
}
|
||||
})
|
||||
// sort artistFeed by attributes.releaseDate descending, date is formatted as "YYYY-MM-DD"
|
||||
}))
|
||||
// sort artistFeed by attributes.releaseDate descending, date is formatted as "YYYY-MM-DD"
|
||||
this.artistFeed.sort((a, b) => {
|
||||
let dateA = new Date(a.attributes.releaseDate)
|
||||
let dateB = new Date(b.attributes.releaseDate)
|
||||
return dateB - dateA
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
} catch (error) { }
|
||||
},
|
||||
getRecentlyPlayed() {
|
||||
|
||||
},
|
||||
async getListenNowData() {
|
||||
let self = this
|
||||
this.app.mk.api.v3.music(`/v1/me/recommendations?timezone=${encodeURIComponent(app.formatTimezoneOffset())}&name=listen-now&with=friendsMix,library,social&art[social-profiles:url]=c&art[url]=c,f&omit[resource]=autos&relate[editorial-items]=contents&extend=editorialCard,editorialVideo&extend[albums]=artistUrl&extend[library-albums]=artistUrl,editorialVideo&extend[playlists]=artistNames,editorialArtwork,editorialVideo&extend[library-playlists]=artistNames,editorialArtwork,editorialVideo&extend[social-profiles]=topGenreNames&include[albums]=artists&include[songs]=artists&include[music-videos]=artists&fields[albums]=artistName,artistUrl,artwork,contentRating,editorialArtwork,editorialVideo,name,playParams,releaseDate,url&fields[artists]=name,url&extend[stations]=airDate,supportsAirTimeUpdates&meta[stations]=inflectionPoints&types=artists,albums,editorial-items,library-albums,library-playlists,music-movies,music-videos,playlists,stations,uploaded-audios,uploaded-videos,activities,apple-curators,curators,tv-shows,social-upsells&platform=web`).then((data) => {
|
||||
this.app.mk.api.v3.music(`/v1/me/recommendations?timezone=${encodeURIComponent(app.formatTimezoneOffset())}&name=listen-now&with=friendsMix,library,social&art[social-profiles:url]=c&art[url]=c,f&omit[resource]=autos&relate[editorial-items]=contents&extend=editorialCard,editorialVideo&extend[albums]=artistUrl&extend[library-albums]=artistUrl,editorialVideo&extend[playlists]=artistNames,editorialArtwork,editorialVideo&extend[library-playlists]=artistNames,editorialArtwork,editorialVideo&extend[social-profiles]=topGenreNames&include[albums]=artists&include[songs]=artists&include[music-videos]=artists&fields[albums]=artistName,artistUrl,artwork,contentRating,editorialArtwork,editorialVideo,name,playParams,releaseDate,url&fields[artists]=name,url&extend[stations]=airDate,supportsAirTimeUpdates&meta[stations]=inflectionPoints&types=artists,albums,editorial-items,library-albums,library-playlists,music-movies,music-videos,playlists,stations,uploaded-audios,uploaded-videos,activities,apple-curators,curators,tv-shows,social-upsells&platform=web&l=${this.$root.mklang}`).then((data) => {
|
||||
console.log(data.data.data[1])
|
||||
try {
|
||||
self.madeForYou = data.data.data.filter(section => {
|
||||
|
@ -193,7 +231,7 @@
|
|||
self.profile = response.data.data[0]
|
||||
})
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
|
@ -1,11 +1,11 @@
|
|||
<template v-if="page == 'library-albums'">
|
||||
<script type="text/x-template" id="cider-library-albums">
|
||||
<div class="content-inner">
|
||||
<div class="row">
|
||||
<div class="col" style="padding:0;">
|
||||
<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>
|
||||
<button v-if="library.albums.downloadState == 2" @click="$root.getLibraryAlbumsFull(true, 1)" class="reload-btn"><%- include('../svg/redo.svg') %></button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
|
@ -16,21 +16,21 @@
|
|||
style="width:100%;"
|
||||
spellcheck="false"
|
||||
:placeholder="$root.getLz('term.search') + '...'"
|
||||
@input="searchLibraryAlbums"
|
||||
@input="$root.searchLibraryAlbums"
|
||||
v-model="library.albums.search" class="search-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-auto flex-center">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<select class="md-select" v-model="library.albums.sorting[1]" @change="searchLibraryAlbums(1)">
|
||||
<select class="md-select" v-model="prefs.sort" @change="library.albums.sorting[1] = prefs.sort; $root.searchLibraryAlbums(1)">
|
||||
<optgroup :label="$root.getLz('term.sortBy')">
|
||||
<option v-for="(sort, index) in library.albums.sortingOptions" :value="index">{{ sort }}</option>
|
||||
</optgroup>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col">
|
||||
<select class="md-select" v-model="library.albums.sortOrder[1]" @change="searchLibraryAlbums(1)">
|
||||
<select class="md-select" v-model="prefs.sortOrder" @change="library.albums.sortOrder[1] = prefs.sortOrder; $root.searchLibraryAlbums(1)">
|
||||
<optgroup :label="$root.getLz('term.sortOrder')">
|
||||
<option value="asc">{{$root.getLz('term.sortOrder.ascending')}}</option>
|
||||
<option value="desc">{{$root.getLz('term.sortOrder.descending')}}</option>
|
||||
|
@ -38,7 +38,7 @@
|
|||
</select>
|
||||
</div>
|
||||
<div class="col">
|
||||
<select class="md-select" v-model="library.albums.viewAs">
|
||||
<select class="md-select" v-model="prefs.viewAs">
|
||||
<optgroup :label="$root.getLz('term.viewAs')">
|
||||
<option value="covers">{{$root.getLz('term.viewAs.coverArt')}}</option>
|
||||
<option value="list">{{$root.getLz('term.viewAs.list')}}</option>
|
||||
|
@ -51,12 +51,27 @@
|
|||
<div class="well">
|
||||
<div class="albums-square-container">
|
||||
<div>
|
||||
<mediaitem-square v-if="library.albums.viewAs == 'covers'" :size="'300'" :item="item" v-for="item in library.albums.displayListing">
|
||||
<mediaitem-square v-if="prefs.viewAs == 'covers'" :size="'300'" :item="item" v-for="item in library.albums.displayListing">
|
||||
</mediaitem-square>
|
||||
</div>
|
||||
</div>
|
||||
<mediaitem-list-item v-if="library.albums.viewAs == 'list'" :show-duration="false" :show-meta-data="true" :show-library-status="false" :item="item" v-for="item in library.albums.displayListing">
|
||||
<mediaitem-list-item v-if="prefs.viewAs == 'list'" :show-duration="false" :show-meta-data="true" :show-library-status="false" :item="item" v-for="item in library.albums.displayListing">
|
||||
</mediaitem-list-item>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</script>
|
||||
<script>
|
||||
Vue.component('cider-library-albums', {
|
||||
template: '#cider-library-albums',
|
||||
data: function () {
|
||||
return {
|
||||
library: this.$root.library,
|
||||
mediaItemSize: "compact",
|
||||
prefs: this.$root.cfg.libraryPrefs.albums,
|
||||
app : this.$root
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
}
|
||||
});
|
||||
</script>
|
|
@ -1,40 +1,35 @@
|
|||
<div class="content-inner">
|
||||
<div class="row">
|
||||
<div class="col" style="padding:0;">
|
||||
<h1 class="header-text">{{$root.getLz('term.artists')}}</h1>
|
||||
</div>
|
||||
|
||||
<div class="content-inner">
|
||||
<div class="row">
|
||||
<div class="col" style="padding:0;">
|
||||
<h1 class="header-text">{{$root.getLz('term.artists')}}</h1>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col" style="padding:0;">
|
||||
<div class="search-input-container" style="width:100%;margin: 16px 0;">
|
||||
<div class="search-input--icon"></div>
|
||||
<input type="search"
|
||||
style="width:100%;"
|
||||
spellcheck="false"
|
||||
:placeholder="$root.getLz('term.search') + '...'"
|
||||
@input="searchLibraryArtists"
|
||||
v-model="library.artists.search" class="search-input">
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col" style="padding:0;">
|
||||
<div class="search-input-container" style="width:100%;margin: 16px 0;">
|
||||
<div class="search-input--icon"></div>
|
||||
<input type="search" style="width:100%;" spellcheck="false" :placeholder="$root.getLz('term.search') + '...'" @input="searchLibraryArtists" v-model="library.artists.search" class="search-input">
|
||||
</div>
|
||||
<div class="col-auto flex-center">
|
||||
<div class="row">
|
||||
<!-- <div class="col">
|
||||
</div>
|
||||
<div class="col-auto flex-center">
|
||||
<div class="row">
|
||||
<!-- <div class="col">
|
||||
<select class="md-select" v-model="library.artists.sorting[1]" @change="searchLibraryArtists(1)">
|
||||
<optgroup label="Sort By">
|
||||
<option v-for="(sort, index) in library.artists.sortingOptions" :value="index">{{ sort }}</option>
|
||||
</optgroup>
|
||||
</select>
|
||||
</div> -->
|
||||
<div class="col">
|
||||
<select class="md-select" v-model="library.artists.sortOrder[1]" @change="searchLibraryArtists(1)">
|
||||
<div class="col">
|
||||
<select class="md-select" v-model="library.artists.sortOrder[1]" @change="searchLibraryArtists(1)">
|
||||
<optgroup :label="$root.getLz('term.sortOrder')">
|
||||
<option value="asc">{{$root.getLz('term.sortOrder.ascending')}}</option>
|
||||
<option value="desc">{{$root.getLz('term.sortOrder.descending')}}</option>
|
||||
</optgroup>
|
||||
</select>
|
||||
</div>
|
||||
<!-- <div class="col">
|
||||
</div>
|
||||
<!-- <div class="col">
|
||||
<select class="md-select" v-model="library.artists.viewAs">
|
||||
<optgroup label="View As">
|
||||
<option value="covers">Cover Art</option>
|
||||
|
@ -42,13 +37,13 @@
|
|||
</optgroup>
|
||||
</select>
|
||||
</div> -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="well">
|
||||
<!-- <mediaitem-square v-if="library.artists.viewAs == 'covers'" :item="item" v-for="item in library.artists.displayListing">
|
||||
</div>
|
||||
<div class="well">
|
||||
<!-- <mediaitem-square v-if="library.artists.viewAs == 'covers'" :item="item" v-for="item in library.artists.displayListing">
|
||||
</mediaitem-square> -->
|
||||
<libraryartist-item :show-duration="false" :show-meta-data="true" :show-library-status="false" :item="item" v-for="item in library.artists.displayListing">
|
||||
</libraryartist-item>
|
||||
</div>
|
||||
</div>
|
||||
<libraryartist-item :show-duration="false" :show-meta-data="true" :show-library-status="false" :item="item" v-for="item in library.artists.displayListing">
|
||||
</libraryartist-item>
|
||||
</div>
|
||||
</div>
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue