CHONKY BOY
This commit is contained in:
parent
31ed921a1a
commit
c15f55d0ee
213 changed files with 64188 additions and 55736 deletions
|
@ -1,5 +0,0 @@
|
|||
{
|
||||
"js": {
|
||||
"beautify.ignore": "src/renderer/index.js"
|
||||
}
|
||||
}
|
|
@ -1,154 +1,136 @@
|
|||
@font-face {
|
||||
font-family: 'Inter';
|
||||
font-style: normal;
|
||||
font-family: "Inter";
|
||||
font-style: normal;
|
||||
font-weight: 100;
|
||||
font-display: swap;
|
||||
src: url("Inter-Thin.woff2?v=3.19") format("woff2"),
|
||||
url("Inter-Thin.woff?v=3.19") format("woff");
|
||||
src: url("Inter-Thin.woff2?v=3.19") format("woff2"), url("Inter-Thin.woff?v=3.19") format("woff");
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
font-style: italic;
|
||||
font-family: "Inter";
|
||||
font-style: italic;
|
||||
font-weight: 100;
|
||||
font-display: swap;
|
||||
src: url("Inter-ThinItalic.woff2?v=3.19") format("woff2"),
|
||||
url("Inter-ThinItalic.woff?v=3.19") format("woff");
|
||||
src: url("Inter-ThinItalic.woff2?v=3.19") format("woff2"), url("Inter-ThinItalic.woff?v=3.19") format("woff");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
font-style: normal;
|
||||
font-family: "Inter";
|
||||
font-style: normal;
|
||||
font-weight: 200;
|
||||
font-display: swap;
|
||||
src: url("Inter-ExtraLight.woff2?v=3.19") format("woff2"),
|
||||
url("Inter-ExtraLight.woff?v=3.19") format("woff");
|
||||
src: url("Inter-ExtraLight.woff2?v=3.19") format("woff2"), url("Inter-ExtraLight.woff?v=3.19") format("woff");
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
font-style: italic;
|
||||
font-family: "Inter";
|
||||
font-style: italic;
|
||||
font-weight: 200;
|
||||
font-display: swap;
|
||||
src: url("Inter-ExtraLightItalic.woff2?v=3.19") format("woff2"),
|
||||
url("Inter-ExtraLightItalic.woff?v=3.19") format("woff");
|
||||
src: url("Inter-ExtraLightItalic.woff2?v=3.19") format("woff2"), url("Inter-ExtraLightItalic.woff?v=3.19") format("woff");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
font-style: normal;
|
||||
font-family: "Inter";
|
||||
font-style: normal;
|
||||
font-weight: 300;
|
||||
font-display: swap;
|
||||
src: url("Inter-Light.woff2?v=3.19") format("woff2"),
|
||||
url("Inter-Light.woff?v=3.19") format("woff");
|
||||
src: url("Inter-Light.woff2?v=3.19") format("woff2"), url("Inter-Light.woff?v=3.19") format("woff");
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
font-style: italic;
|
||||
font-family: "Inter";
|
||||
font-style: italic;
|
||||
font-weight: 300;
|
||||
font-display: swap;
|
||||
src: url("Inter-LightItalic.woff2?v=3.19") format("woff2"),
|
||||
url("Inter-LightItalic.woff?v=3.19") format("woff");
|
||||
src: url("Inter-LightItalic.woff2?v=3.19") format("woff2"), url("Inter-LightItalic.woff?v=3.19") format("woff");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
font-style: normal;
|
||||
font-family: "Inter";
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
src: url("Inter-Regular.woff2?v=3.19") format("woff2"),
|
||||
url("Inter-Regular.woff?v=3.19") format("woff");
|
||||
src: url("Inter-Regular.woff2?v=3.19") format("woff2"), url("Inter-Regular.woff?v=3.19") format("woff");
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
font-style: italic;
|
||||
font-family: "Inter";
|
||||
font-style: italic;
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
src: url("Inter-Italic.woff2?v=3.19") format("woff2"),
|
||||
url("Inter-Italic.woff?v=3.19") format("woff");
|
||||
src: url("Inter-Italic.woff2?v=3.19") format("woff2"), url("Inter-Italic.woff?v=3.19") format("woff");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
font-style: normal;
|
||||
font-family: "Inter";
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
font-display: swap;
|
||||
src: url("Inter-Medium.woff2?v=3.19") format("woff2"),
|
||||
url("Inter-Medium.woff?v=3.19") format("woff");
|
||||
src: url("Inter-Medium.woff2?v=3.19") format("woff2"), url("Inter-Medium.woff?v=3.19") format("woff");
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
font-style: italic;
|
||||
font-family: "Inter";
|
||||
font-style: italic;
|
||||
font-weight: 500;
|
||||
font-display: swap;
|
||||
src: url("Inter-MediumItalic.woff2?v=3.19") format("woff2"),
|
||||
url("Inter-MediumItalic.woff?v=3.19") format("woff");
|
||||
src: url("Inter-MediumItalic.woff2?v=3.19") format("woff2"), url("Inter-MediumItalic.woff?v=3.19") format("woff");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
font-style: normal;
|
||||
font-family: "Inter";
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
font-display: swap;
|
||||
src: url("Inter-SemiBold.woff2?v=3.19") format("woff2"),
|
||||
url("Inter-SemiBold.woff?v=3.19") format("woff");
|
||||
src: url("Inter-SemiBold.woff2?v=3.19") format("woff2"), url("Inter-SemiBold.woff?v=3.19") format("woff");
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
font-style: italic;
|
||||
font-family: "Inter";
|
||||
font-style: italic;
|
||||
font-weight: 600;
|
||||
font-display: swap;
|
||||
src: url("Inter-SemiBoldItalic.woff2?v=3.19") format("woff2"),
|
||||
url("Inter-SemiBoldItalic.woff?v=3.19") format("woff");
|
||||
src: url("Inter-SemiBoldItalic.woff2?v=3.19") format("woff2"), url("Inter-SemiBoldItalic.woff?v=3.19") format("woff");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
font-style: normal;
|
||||
font-family: "Inter";
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
font-display: swap;
|
||||
src: url("Inter-Bold.woff2?v=3.19") format("woff2"),
|
||||
url("Inter-Bold.woff?v=3.19") format("woff");
|
||||
src: url("Inter-Bold.woff2?v=3.19") format("woff2"), url("Inter-Bold.woff?v=3.19") format("woff");
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
font-style: italic;
|
||||
font-family: "Inter";
|
||||
font-style: italic;
|
||||
font-weight: 700;
|
||||
font-display: swap;
|
||||
src: url("Inter-BoldItalic.woff2?v=3.19") format("woff2"),
|
||||
url("Inter-BoldItalic.woff?v=3.19") format("woff");
|
||||
src: url("Inter-BoldItalic.woff2?v=3.19") format("woff2"), url("Inter-BoldItalic.woff?v=3.19") format("woff");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
font-style: normal;
|
||||
font-family: "Inter";
|
||||
font-style: normal;
|
||||
font-weight: 800;
|
||||
font-display: swap;
|
||||
src: url("Inter-ExtraBold.woff2?v=3.19") format("woff2"),
|
||||
url("Inter-ExtraBold.woff?v=3.19") format("woff");
|
||||
src: url("Inter-ExtraBold.woff2?v=3.19") format("woff2"), url("Inter-ExtraBold.woff?v=3.19") format("woff");
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
font-style: italic;
|
||||
font-family: "Inter";
|
||||
font-style: italic;
|
||||
font-weight: 800;
|
||||
font-display: swap;
|
||||
src: url("Inter-ExtraBoldItalic.woff2?v=3.19") format("woff2"),
|
||||
url("Inter-ExtraBoldItalic.woff?v=3.19") format("woff");
|
||||
src: url("Inter-ExtraBoldItalic.woff2?v=3.19") format("woff2"), url("Inter-ExtraBoldItalic.woff?v=3.19") format("woff");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
font-style: normal;
|
||||
font-family: "Inter";
|
||||
font-style: normal;
|
||||
font-weight: 900;
|
||||
font-display: swap;
|
||||
src: url("Inter-Black.woff2?v=3.19") format("woff2"),
|
||||
url("Inter-Black.woff?v=3.19") format("woff");
|
||||
src: url("Inter-Black.woff2?v=3.19") format("woff2"), url("Inter-Black.woff?v=3.19") format("woff");
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
font-style: italic;
|
||||
font-family: "Inter";
|
||||
font-style: italic;
|
||||
font-weight: 900;
|
||||
font-display: swap;
|
||||
src: url("Inter-BlackItalic.woff2?v=3.19") format("woff2"),
|
||||
url("Inter-BlackItalic.woff?v=3.19") format("woff");
|
||||
src: url("Inter-BlackItalic.woff2?v=3.19") format("woff2"), url("Inter-BlackItalic.woff?v=3.19") format("woff");
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------
|
||||
|
@ -161,23 +143,22 @@ Usage:
|
|||
}
|
||||
*/
|
||||
@font-face {
|
||||
font-family: 'Inter var';
|
||||
font-family: "Inter var";
|
||||
font-weight: 100 900;
|
||||
font-display: swap;
|
||||
font-style: normal;
|
||||
font-named-instance: 'Regular';
|
||||
font-named-instance: "Regular";
|
||||
src: url("Inter-roman.var.woff2?v=3.19") format("woff2");
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Inter var';
|
||||
font-family: "Inter var";
|
||||
font-weight: 100 900;
|
||||
font-display: swap;
|
||||
font-style: italic;
|
||||
font-named-instance: 'Italic';
|
||||
font-named-instance: "Italic";
|
||||
src: url("Inter-italic.var.woff2?v=3.19") format("woff2");
|
||||
}
|
||||
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
[EXPERIMENTAL] Multi-axis, single variable font.
|
||||
|
||||
|
@ -192,7 +173,7 @@ explicitly, e.g.
|
|||
|
||||
*/
|
||||
@font-face {
|
||||
font-family: 'Inter var experimental';
|
||||
font-family: "Inter var experimental";
|
||||
font-weight: 100 900;
|
||||
font-display: swap;
|
||||
font-style: oblique 0deg 10deg;
|
||||
|
|
|
@ -8,9 +8,9 @@ http://scripts.sil.org/OFL
|
|||
*/
|
||||
|
||||
@font-face {
|
||||
font-family: 'Pretendard Variable';
|
||||
font-weight: 45 920;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
src: local('Pretendard Variable'), url('./woff2/PretendardVariable.woff2') format('woff2-variations');
|
||||
font-family: "Pretendard Variable";
|
||||
font-weight: 45 920;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
src: local("Pretendard Variable"), url("./woff2/PretendardVariable.woff2") format("woff2-variations");
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
52902
src/renderer/hlscider.js
52902
src/renderer/hlscider.js
File diff suppressed because it is too large
Load diff
|
@ -57,11 +57,11 @@ Vue.component("animated-number", {
|
|||
});
|
||||
|
||||
function initMusicKit() {
|
||||
if(!this.responseText) {
|
||||
console.log("Using stored token")
|
||||
if (!this.responseText) {
|
||||
console.log("Using stored token");
|
||||
this.responseText = JSON.stringify({
|
||||
token: localStorage.getItem("lastToken")
|
||||
})
|
||||
token: localStorage.getItem("lastToken"),
|
||||
});
|
||||
}
|
||||
let parsedJson = JSON.parse(this.responseText);
|
||||
localStorage.setItem("lastToken", parsedJson.token);
|
||||
|
@ -95,10 +95,10 @@ function capiInit() {
|
|||
request.addEventListener("load", initMusicKit);
|
||||
request.onreadystatechange = function (aEvt) {
|
||||
if (request.readyState == 4 && request.status != 200) {
|
||||
if(localStorage.getItem("lastToken") != null) {
|
||||
initMusicKit()
|
||||
if (localStorage.getItem("lastToken") != null) {
|
||||
initMusicKit();
|
||||
} else {
|
||||
console.error(`Failed to load capi, cannot get token [${request.status}]`)
|
||||
console.error(`Failed to load capi, cannot get token [${request.status}]`);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -110,7 +110,7 @@ document.addEventListener("musickitloaded", function () {
|
|||
if (showOobe()) return;
|
||||
console.log("MusicKit loaded");
|
||||
// MusicKit global is now defined
|
||||
capiInit()
|
||||
capiInit();
|
||||
});
|
||||
window.addEventListener("drmUnsupported", function () {
|
||||
initMusicKit();
|
||||
|
@ -140,12 +140,7 @@ function Clone(obj) {
|
|||
}
|
||||
|
||||
function uuidv4() {
|
||||
return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, (c) =>
|
||||
(
|
||||
c ^
|
||||
(crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (c / 4)))
|
||||
).toString(16)
|
||||
);
|
||||
return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, (c) => (c ^ (crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (c / 4)))).toString(16));
|
||||
}
|
||||
|
||||
function xmlToJson(xml) {
|
||||
|
@ -196,26 +191,19 @@ async function asyncForEach(array, callback) {
|
|||
|
||||
var checkIfScrollIsStatic = setInterval(() => {
|
||||
try {
|
||||
if (
|
||||
position === document.getElementsByClassName("lyric-body")[0].scrollTop
|
||||
) {
|
||||
if (position === document.getElementsByClassName("lyric-body")[0].scrollTop) {
|
||||
clearInterval(checkIfScrollIsStatic);
|
||||
// do something
|
||||
}
|
||||
position = document.getElementsByClassName("lyric-body")[0].scrollTop;
|
||||
} catch (e) { }
|
||||
} catch (e) {}
|
||||
}, 50);
|
||||
|
||||
// WebGPU Console Notification
|
||||
async function webGPU() {
|
||||
try {
|
||||
const currentGPU = await navigator.gpu.requestAdapter();
|
||||
console.log(
|
||||
"WebGPU enabled on",
|
||||
currentGPU.name,
|
||||
"with feature ID",
|
||||
currentGPU.features.size
|
||||
);
|
||||
console.log("WebGPU enabled on", currentGPU.name, "with feature ID", currentGPU.features.size);
|
||||
} catch (e) {
|
||||
console.log("WebGPU disabled / WebGPU initialization failed");
|
||||
}
|
||||
|
@ -240,9 +228,9 @@ function isJson(item) {
|
|||
webGPU().then();
|
||||
|
||||
function showOobe() {
|
||||
return false
|
||||
return false;
|
||||
if (localStorage.getItem("music.ampwebplay.media-user-token") && localStorage.getItem("seenOOBE")) {
|
||||
return false
|
||||
return false;
|
||||
} else {
|
||||
function waitForApp() {
|
||||
if (typeof app.init !== "undefined") {
|
||||
|
@ -252,7 +240,7 @@ function showOobe() {
|
|||
}
|
||||
}
|
||||
waitForApp();
|
||||
return true
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -266,13 +254,7 @@ document.addEventListener("DOMContentLoaded", async function () {
|
|||
document.addEventListener(
|
||||
"contextmenu",
|
||||
function (e) {
|
||||
if (
|
||||
e.target.tagName.toLowerCase() == "textarea" ||
|
||||
(e.target.tagName.toLowerCase() == "input" &&
|
||||
e.target.type != "checkbox" &&
|
||||
e.target.type != "radio" &&
|
||||
e.target.disabled == false)
|
||||
) {
|
||||
if (e.target.tagName.toLowerCase() == "textarea" || (e.target.tagName.toLowerCase() == "input" && e.target.type != "checkbox" && e.target.type != "radio" && e.target.disabled == false)) {
|
||||
e.preventDefault();
|
||||
const menuPanel = {
|
||||
items: {
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,7 +1,7 @@
|
|||
@colorMixRate: 1%;
|
||||
@transparencyRate: 50%;
|
||||
|
||||
@keyColor : #fc3c44;
|
||||
@keyColor: #fc3c44;
|
||||
@ciderColor: #ff2654;
|
||||
@baseColor: #1e1e1e;
|
||||
@baseColorMix: mix(@baseColor, transparent, @transparencyRate);
|
||||
|
@ -10,12 +10,12 @@
|
|||
@appOpacity: 0.15;
|
||||
|
||||
:root {
|
||||
--baseColor: @baseColor;
|
||||
--baseColorMix: @baseColorMix;
|
||||
--sidebarColor: @sidebarColor;
|
||||
--sidebarColorMix: @sidebarColorMix;
|
||||
--ciderColor: @ciderColor;
|
||||
--appOpacity: @appOpacity;
|
||||
--transparencyRate: @transparencyRate;
|
||||
--macOSChromeColor: rgb(14 14 14 / 32%);
|
||||
}
|
||||
--baseColor: @baseColor;
|
||||
--baseColorMix: @baseColorMix;
|
||||
--sidebarColor: @sidebarColor;
|
||||
--sidebarColorMix: @sidebarColorMix;
|
||||
--ciderColor: @ciderColor;
|
||||
--appOpacity: @appOpacity;
|
||||
--transparencyRate: @transparencyRate;
|
||||
--macOSChromeColor: rgb(14 14 14 / 32%);
|
||||
}
|
||||
|
|
1994
src/renderer/less/bootstrap.less
vendored
1994
src/renderer/less/bootstrap.less
vendored
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -3,7 +3,7 @@
|
|||
zoom: 0.95;
|
||||
}
|
||||
.app-sidebar-content {
|
||||
padding:0px;
|
||||
padding: 0px;
|
||||
|
||||
.app-sidebar-header-text {
|
||||
padding: 6px 10px;
|
||||
|
@ -56,4 +56,4 @@
|
|||
#app-content {
|
||||
// zoom: 0.8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,36 +5,35 @@
|
|||
#app.twopanel {
|
||||
--chromeHeight1: 46px;
|
||||
--chromeHeight2: 90px;
|
||||
--chromeHeight : calc(var(--chromeHeight1) + var(--chromeHeight2));
|
||||
--chromeHeight: calc(var(--chromeHeight1) + var(--chromeHeight2));
|
||||
|
||||
.modular-fs .app-drawer .lyric-footer {
|
||||
bottom: var(--chromeHeight2);
|
||||
}
|
||||
|
||||
.app-chrome {
|
||||
|
||||
&:not(.chrome-bottom) {
|
||||
.app-chrome--center {
|
||||
flex: 1;
|
||||
|
||||
.top-nav-group {
|
||||
background : #1e1e1e99;
|
||||
border : 1px solid lighten(@baseColor, 8);
|
||||
background: #1e1e1e99;
|
||||
border: 1px solid lighten(@baseColor, 8);
|
||||
border-radius: 12px;
|
||||
display : flex;
|
||||
height : 32px;
|
||||
display: flex;
|
||||
height: 32px;
|
||||
|
||||
.app-sidebar-item {
|
||||
background-color: #1e1e1e00;
|
||||
border-radius : 10px !important;
|
||||
border : 0px;
|
||||
min-width : 120px;
|
||||
padding : 6px;
|
||||
justify-content : center;
|
||||
align-items : center;
|
||||
margin : 0px;
|
||||
height : 100%;
|
||||
position : relative;
|
||||
border-radius: 10px !important;
|
||||
border: 0px;
|
||||
min-width: 120px;
|
||||
padding: 6px;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin: 0px;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
white-space: nowrap;
|
||||
|
||||
._svg-icon {
|
||||
|
@ -42,18 +41,18 @@
|
|||
}
|
||||
|
||||
&:before {
|
||||
--dist : 1px;
|
||||
content : '';
|
||||
position : absolute;
|
||||
top : var(--dist);
|
||||
left : var(--dist);
|
||||
right : var(--dist);
|
||||
bottom : var(--dist);
|
||||
--dist: 1px;
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: var(--dist);
|
||||
left: var(--dist);
|
||||
right: var(--dist);
|
||||
bottom: var(--dist);
|
||||
background-color: #fff;
|
||||
opacity : 0;
|
||||
border-radius : 10px;
|
||||
transform : scale(0.5);
|
||||
transition : transform 0.2s ease-in-out, opacity 0.2s ease-in-out;
|
||||
opacity: 0;
|
||||
border-radius: 10px;
|
||||
transform: scale(0.5);
|
||||
transition: transform 0.2s ease-in-out, opacity 0.2s ease-in-out;
|
||||
}
|
||||
|
||||
&:after {
|
||||
|
@ -65,8 +64,8 @@
|
|||
|
||||
&:before {
|
||||
transition: transform 0.1s ease-in-out, opacity 0.1s ease-in-out;
|
||||
opacity : .1;
|
||||
transform : scale(1);
|
||||
opacity: 0.1;
|
||||
transform: scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -74,15 +73,15 @@
|
|||
background-color: transparent;
|
||||
|
||||
&:before {
|
||||
opacity : .2;
|
||||
opacity: 0.2;
|
||||
transform: scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
&.md-btn-primary {
|
||||
box-shadow : 0px 0px 0px 1px lighten(@baseColor, @colorMixRate * 8);
|
||||
box-shadow: 0px 0px 0px 1px lighten(@baseColor, @colorMixRate * 8);
|
||||
background-color: lighten(@baseColor, @colorMixRate * 5);
|
||||
z-index : 1;
|
||||
z-index: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -90,7 +89,7 @@
|
|||
}
|
||||
|
||||
.app-mainmenu {
|
||||
width : 30px;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
}
|
||||
|
||||
|
@ -101,11 +100,10 @@
|
|||
height: var(--chromeHeight1);
|
||||
|
||||
&.chrome-bottom {
|
||||
background : var(--color2);
|
||||
background: var(--color2);
|
||||
-webkit-app-region: no-drag;
|
||||
height : var(--chromeHeight2);
|
||||
box-shadow : 0px -2px 6px rgb(20 20 20 / 12%),
|
||||
0px -1px 0px 0px rgb(200 200 200 / 12%);
|
||||
height: var(--chromeHeight2);
|
||||
box-shadow: 0px -2px 6px rgb(20 20 20 / 12%), 0px -1px 0px 0px rgb(200 200 200 / 12%);
|
||||
z-index: 4;
|
||||
|
||||
.app-chrome-playback-duration-bottom {
|
||||
|
@ -116,33 +114,33 @@
|
|||
}
|
||||
|
||||
.col-sm-auto {
|
||||
width : 4em;
|
||||
display : flex;
|
||||
width: 4em;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items : center;
|
||||
font-size : 0.8em;
|
||||
align-items: center;
|
||||
font-size: 0.8em;
|
||||
}
|
||||
|
||||
input[type=range] {
|
||||
appearance : none;
|
||||
width : 100%;
|
||||
height : 5px;
|
||||
input[type="range"] {
|
||||
appearance: none;
|
||||
width: 100%;
|
||||
height: 5px;
|
||||
background-color: rgb(200 200 200 / 10%);
|
||||
border-radius : 6px;
|
||||
box-shadow : 0px 0px 0px 1px rgba(0 0 0 / 10%);
|
||||
align-self : center;
|
||||
border-radius: 6px;
|
||||
box-shadow: 0px 0px 0px 1px rgba(0 0 0 / 10%);
|
||||
align-self: center;
|
||||
|
||||
&::-webkit-slider-thumb {
|
||||
opacity : 0;
|
||||
transform : scale(1);
|
||||
opacity: 0;
|
||||
transform: scale(1);
|
||||
-webkit-appearance: none;
|
||||
appearance : none;
|
||||
width : 16px;
|
||||
height : 16px;
|
||||
border-radius : 100%;
|
||||
background : var(--keyColor);
|
||||
cursor : default;
|
||||
transition : opacity .10s var(--appleEase), transform .10s var(--appleEase);
|
||||
appearance: none;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
border-radius: 100%;
|
||||
background: var(--keyColor);
|
||||
cursor: default;
|
||||
transition: opacity 0.1s var(--appleEase), transform 0.1s var(--appleEase);
|
||||
}
|
||||
|
||||
&:hover {
|
||||
|
@ -169,38 +167,37 @@
|
|||
.playback-button.play,
|
||||
.playback-button.pause,
|
||||
.playback-button.stop {
|
||||
width : 42px;
|
||||
height : 42px;
|
||||
width: 42px;
|
||||
height: 42px;
|
||||
border-radius: 50%;
|
||||
margin : 6px;
|
||||
margin: 6px;
|
||||
}
|
||||
|
||||
.app-chrome--center {
|
||||
display : flex;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.app-chrome-playback-controls {
|
||||
display : flex;
|
||||
z-index : 1;
|
||||
display: flex;
|
||||
z-index: 1;
|
||||
// margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.app-chrome-playback-duration {
|
||||
position : relative;
|
||||
width : 80%;
|
||||
position: relative;
|
||||
width: 80%;
|
||||
-webkit-app-region: no-drag;
|
||||
height : 16px;
|
||||
height: 16px;
|
||||
|
||||
.song-progress {
|
||||
@bgColor : transparent;
|
||||
height : 16px;
|
||||
position : absolute;
|
||||
bottom : 4px;
|
||||
left : 0px;
|
||||
right : 4px;
|
||||
@bgColor: transparent;
|
||||
height: 16px;
|
||||
position: absolute;
|
||||
bottom: 4px;
|
||||
left: 0px;
|
||||
right: 4px;
|
||||
background: @bgColor;
|
||||
z-index : 0;
|
||||
|
||||
z-index: 0;
|
||||
|
||||
.song-duration {
|
||||
display: flex;
|
||||
|
@ -208,64 +205,63 @@
|
|||
|
||||
.song-duration p {
|
||||
font-weight: 400;
|
||||
font-size : 10px;
|
||||
height : 1.2em;
|
||||
font-size: 10px;
|
||||
height: 1.2em;
|
||||
line-height: 1.3em;
|
||||
overflow : hidden;
|
||||
margin : 0 0 0 0.25em;
|
||||
overflow: hidden;
|
||||
margin: 0 0 0 0.25em;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
>input[type=range] {
|
||||
> input[type="range"] {
|
||||
&::-webkit-slider-thumb {
|
||||
opacity : 1;
|
||||
opacity: 1;
|
||||
transform: scale(1);
|
||||
z-index : 1;
|
||||
z-index: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
input[type=range] {
|
||||
appearance : none;
|
||||
width : 100%;
|
||||
height : 4px;
|
||||
input[type="range"] {
|
||||
appearance: none;
|
||||
width: 100%;
|
||||
height: 4px;
|
||||
background-color: rgb(200 200 200 / 10%);
|
||||
border-radius : 2px;
|
||||
border-radius: 2px;
|
||||
|
||||
&::-webkit-slider-thumb {
|
||||
opacity : 0;
|
||||
transform : scale(0.5);
|
||||
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);
|
||||
appearance: none;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
border-radius: 100%;
|
||||
background: var(--keyColor);
|
||||
cursor: default;
|
||||
transition: opacity 0.1s var(--appleEase), transform 0.1s var(--appleEase);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.app-chrome--left {
|
||||
width : 30%;
|
||||
justify-content : flex-start;
|
||||
align-items : flex-start;
|
||||
width: 30%;
|
||||
justify-content: flex-start;
|
||||
align-items: flex-start;
|
||||
-webkit-app-region: no-drag !important;
|
||||
|
||||
.playback-controls {
|
||||
-webkit-app-region: no-drag !important;
|
||||
|
||||
.artwork {
|
||||
--offset : 20px;
|
||||
--offset: 20px;
|
||||
--marginOffset: 2;
|
||||
--size : calc(var(--chromeHeight2) - var(--offset));
|
||||
width : var(--size);
|
||||
height : var(--size);
|
||||
margin : 0 calc(var(--offset) / var(--marginOffset)) 0 calc(var(--offset) / var(--marginOffset));
|
||||
--size: calc(var(--chromeHeight2) - var(--offset));
|
||||
width: var(--size);
|
||||
height: var(--size);
|
||||
margin: 0 calc(var(--offset) / var(--marginOffset)) 0 calc(var(--offset) / var(--marginOffset));
|
||||
|
||||
.mediaitem-artwork,
|
||||
img {
|
||||
|
@ -275,13 +271,13 @@
|
|||
|
||||
.playback-info {
|
||||
align-items: flex-start;
|
||||
margin : 6px;
|
||||
margin: 6px;
|
||||
|
||||
.song-name {
|
||||
text-align : left;
|
||||
font-size : 0.8em;
|
||||
font-weight : 500;
|
||||
width : 100%;
|
||||
text-align: left;
|
||||
font-size: 0.8em;
|
||||
font-weight: 500;
|
||||
width: 100%;
|
||||
-webkit-mask-image: linear-gradient(-90deg, transparent 0%, transparent 10%, black 20%);
|
||||
}
|
||||
|
||||
|
@ -306,23 +302,22 @@
|
|||
|
||||
.song-artist-album-content {
|
||||
text-align: left;
|
||||
font-size : 12px;
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
width : 100%;
|
||||
height : 100%;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
max-width: 100%;
|
||||
border : 0px;
|
||||
border: 0px;
|
||||
}
|
||||
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
.app-chrome--right {
|
||||
width : 30%;
|
||||
flex : 0 0 auto;
|
||||
width: 30%;
|
||||
flex: 0 0 auto;
|
||||
padding-right: 8px;
|
||||
}
|
||||
}
|
||||
|
@ -334,7 +329,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
// screen width is less than 768px
|
||||
@media (max-width: 1100px) {
|
||||
#app.twopanel .app-chrome:not(.chrome-bottom) .app-chrome--center {
|
||||
|
|
|
@ -26,7 +26,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
// Buttons
|
||||
.md-btn {
|
||||
font-family: inherit;
|
||||
|
@ -115,7 +114,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
.md-close-btn {
|
||||
-webkit-mask-image: url("ameres://icons/webui/close.svg");
|
||||
-webkit-mask-repeat: no-repeat;
|
||||
|
@ -165,7 +163,7 @@
|
|||
.page-btn {
|
||||
align-self: center;
|
||||
height: 32px;
|
||||
width:max-content;
|
||||
width: max-content;
|
||||
}
|
||||
|
||||
.page-btn img {
|
||||
|
@ -174,19 +172,19 @@
|
|||
}
|
||||
|
||||
.md-ico-first {
|
||||
content: url('./assets/angles-left.svg');
|
||||
content: url("./assets/angles-left.svg");
|
||||
}
|
||||
|
||||
.md-ico-prev {
|
||||
content: url('./assets/chevron-left.svg');
|
||||
content: url("./assets/chevron-left.svg");
|
||||
}
|
||||
|
||||
.md-ico-next {
|
||||
content: url('./assets/chevron-right.svg');
|
||||
content: url("./assets/chevron-right.svg");
|
||||
}
|
||||
|
||||
.md-ico-last {
|
||||
content: url('./assets/angles-right.svg');
|
||||
content: url("./assets/angles-right.svg");
|
||||
}
|
||||
|
||||
.reload-btn {
|
||||
|
@ -234,7 +232,7 @@
|
|||
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
background: rgb(200 200 200 / 10%)
|
||||
background: rgb(200 200 200 / 10%);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -315,7 +313,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
#artworkLCD img {
|
||||
image-rendering: auto;
|
||||
}
|
||||
|
@ -514,7 +511,7 @@
|
|||
|
||||
.subtitle {
|
||||
width: 90%;
|
||||
font-size: .8em;
|
||||
font-size: 0.8em;
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
|
@ -570,39 +567,39 @@
|
|||
*/
|
||||
@keyframes load-bar {
|
||||
10% {
|
||||
box-shadow: inset 0 -4px 0
|
||||
box-shadow: inset 0 -4px 0;
|
||||
}
|
||||
|
||||
20% {
|
||||
box-shadow: inset 0 -10px 0
|
||||
box-shadow: inset 0 -10px 0;
|
||||
}
|
||||
|
||||
30% {
|
||||
box-shadow: inset 0 -12px 0
|
||||
box-shadow: inset 0 -12px 0;
|
||||
}
|
||||
|
||||
40% {
|
||||
box-shadow: inset 0 -8px 0
|
||||
box-shadow: inset 0 -8px 0;
|
||||
}
|
||||
|
||||
50% {
|
||||
box-shadow: inset 0 -4px 0
|
||||
box-shadow: inset 0 -4px 0;
|
||||
}
|
||||
|
||||
60% {
|
||||
box-shadow: inset 0 -6px 0
|
||||
box-shadow: inset 0 -6px 0;
|
||||
}
|
||||
|
||||
80% {
|
||||
box-shadow: inset 0 -12px 0
|
||||
box-shadow: inset 0 -12px 0;
|
||||
}
|
||||
|
||||
90% {
|
||||
box-shadow: inset 0 -6px 0
|
||||
box-shadow: inset 0 -6px 0;
|
||||
}
|
||||
|
||||
to {
|
||||
box-shadow: inset 0 -2px 0
|
||||
box-shadow: inset 0 -2px 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -629,17 +626,17 @@
|
|||
.loadbar-sound::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
bottom: 0
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.loadbar-sound::before {
|
||||
left: -4.5px;
|
||||
animation-delay: -2.4s
|
||||
animation-delay: -2.4s;
|
||||
}
|
||||
|
||||
.loadbar-sound::after {
|
||||
right: -4.2px;
|
||||
animation-delay: -3.7s
|
||||
animation-delay: -3.7s;
|
||||
}
|
||||
|
||||
.isLibrary {
|
||||
|
@ -670,7 +667,6 @@
|
|||
box-shadow: var(--mediaItemShadow);
|
||||
}
|
||||
|
||||
|
||||
&:active {
|
||||
background: var(--selected-click);
|
||||
box-shadow: var(--mediaItemShadow);
|
||||
|
@ -805,7 +801,6 @@
|
|||
|
||||
&:hover + .cd-mediaitem-square-large-overlay {
|
||||
opacity: 1;
|
||||
|
||||
}
|
||||
|
||||
&:hover {
|
||||
|
@ -813,7 +808,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/* mediaitem-square-large */
|
||||
.cd-mediaitem-square-large {
|
||||
width: 190px;
|
||||
|
@ -855,12 +849,10 @@
|
|||
margin: 10px;
|
||||
margin-top: 0px;
|
||||
opacity: 0;
|
||||
|
||||
}
|
||||
|
||||
.cd-mediaitem-square-large-overlay > * {
|
||||
pointer-events: auto;
|
||||
|
||||
}
|
||||
|
||||
.cd-mediaitem-square-large > .cd-mediaitem-square-large-overlay {
|
||||
|
@ -873,15 +865,12 @@
|
|||
|
||||
.cd-mediaitem-square-large + .cd-mediaitem-square-large-overlay {
|
||||
pointer-events: none;
|
||||
|
||||
}
|
||||
|
||||
.cd-mediaitem-square-large:hover + .cd-mediaitem-square-large-overlay {
|
||||
opacity: 1;
|
||||
|
||||
}
|
||||
|
||||
|
||||
.cd-mediaitem-square-large .artwork.round {
|
||||
border-radius: var(--mediaItemRadiusRound);
|
||||
}
|
||||
|
@ -940,12 +929,10 @@
|
|||
margin: 10px;
|
||||
margin-top: 0px;
|
||||
opacity: 0;
|
||||
|
||||
}
|
||||
|
||||
.cd-mediaitem-mvview-overlay > * {
|
||||
pointer-events: auto;
|
||||
|
||||
}
|
||||
|
||||
.cd-mediaitem-mvview > .cd-mediaitem-mvview-overlay {
|
||||
|
@ -958,15 +945,12 @@
|
|||
|
||||
.cd-mediaitem-mvview + .cd-mediaitem-mvview-overlay {
|
||||
pointer-events: none;
|
||||
|
||||
}
|
||||
|
||||
.cd-mediaitem-mvview:hover + .cd-mediaitem-mvview-overlay {
|
||||
opacity: 1;
|
||||
|
||||
}
|
||||
|
||||
|
||||
.cd-mediaitem-mvview .artwork.round {
|
||||
border-radius: var(--mediaItemRadiusRound);
|
||||
}
|
||||
|
@ -982,10 +966,9 @@
|
|||
font-size: 12px;
|
||||
}
|
||||
|
||||
|
||||
/* mediaitem-square */
|
||||
.cd-mediaitem-square {
|
||||
--transitionDuration: .5s;
|
||||
--transitionDuration: 0.5s;
|
||||
--scaleRate: 1.25;
|
||||
--scaleRateArtwork: 1;
|
||||
width: calc(160px * var(--windowRelativeScale));
|
||||
|
@ -1062,7 +1045,6 @@
|
|||
bottom: 14px;
|
||||
left: 14px;
|
||||
z-index: 2;
|
||||
|
||||
}
|
||||
|
||||
> .menu-btn {
|
||||
|
@ -1110,7 +1092,6 @@
|
|||
// }
|
||||
// }
|
||||
|
||||
|
||||
.info-rect {
|
||||
width: 90%;
|
||||
height: 100%;
|
||||
|
@ -1119,7 +1100,6 @@
|
|||
align-items: center;
|
||||
}
|
||||
|
||||
|
||||
.title {
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
|
@ -1174,19 +1154,19 @@
|
|||
--scaleRateArtwork: 1.1;
|
||||
width: calc(240px * var(--scaleRate));
|
||||
height: calc(200px * var(--scaleRate));
|
||||
|
||||
|
||||
.artwork-container > .artwork {
|
||||
width: calc(220px * var(--scaleRateArtwork));
|
||||
height: calc(123px * var(--scaleRateArtwork));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@media (min-width: 1550px) {
|
||||
--scaleRate: 1.25;
|
||||
--scaleRateArtwork: 1.25;
|
||||
width: calc(240px * var(--scaleRate));
|
||||
height: calc(200px * var(--scaleRate));
|
||||
|
||||
|
||||
.artwork-container > .artwork {
|
||||
width: calc(220px * var(--scaleRateArtwork));
|
||||
height: calc(123px * var(--scaleRateArtwork));
|
||||
|
@ -1212,19 +1192,19 @@
|
|||
--scaleRateArtwork: 1.1;
|
||||
width: calc(240px * var(--scaleRate));
|
||||
height: calc(200px * var(--scaleRate));
|
||||
|
||||
|
||||
.artwork-container > .artwork {
|
||||
width: calc(220px * var(--scaleRateArtwork));
|
||||
height: calc(123px * var(--scaleRateArtwork));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@media (min-width: 1550px) {
|
||||
--scaleRate: 1.25;
|
||||
--scaleRateArtwork: 1.25;
|
||||
width: calc(240px * var(--scaleRate));
|
||||
height: calc(200px * var(--scaleRate));
|
||||
|
||||
|
||||
.artwork-container > .artwork {
|
||||
width: calc(220px * var(--scaleRateArtwork));
|
||||
height: calc(123px * var(--scaleRateArtwork));
|
||||
|
@ -1338,7 +1318,7 @@
|
|||
}
|
||||
|
||||
&:hover {
|
||||
.artwork{
|
||||
.artwork {
|
||||
filter: brightness(0.8);
|
||||
}
|
||||
.info-rect-card::before {
|
||||
|
@ -1430,7 +1410,6 @@
|
|||
}
|
||||
|
||||
&:hover {
|
||||
|
||||
> .play-btn,
|
||||
> .menu-btn {
|
||||
opacity: 1;
|
||||
|
@ -1438,7 +1417,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
.title {
|
||||
width: 90%;
|
||||
text-align: center;
|
||||
|
@ -1471,7 +1449,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
.listitem-horizontal {
|
||||
.cd-mediaitem-list-item {
|
||||
width: 350px;
|
||||
|
@ -1497,7 +1474,6 @@
|
|||
|
||||
&:hover::-webkit-scrollbar {
|
||||
display: initial;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1536,9 +1512,8 @@
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/* Switch Checkbox */
|
||||
input[type=checkbox][switch] {
|
||||
input[type="checkbox"][switch] {
|
||||
width: 38px;
|
||||
appearance: none;
|
||||
border-radius: 32px;
|
||||
|
@ -1554,12 +1529,12 @@ input[type=checkbox][switch] {
|
|||
margin: 0;
|
||||
}
|
||||
|
||||
input[type=checkbox][switch]:focus,
|
||||
input[type=checkbox][switch]:active {
|
||||
input[type="checkbox"][switch]:focus,
|
||||
input[type="checkbox"][switch]:active {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
input[type=checkbox][switch]:checked {
|
||||
input[type="checkbox"][switch]:checked {
|
||||
background: var(--keyColor);
|
||||
border: 0 solid var(--keyColor);
|
||||
mix-blend-mode: unset;
|
||||
|
@ -1573,43 +1548,41 @@ input[type=checkbox][switch]:checked {
|
|||
}
|
||||
}
|
||||
|
||||
input[type=checkbox][switch]::before {
|
||||
input[type="checkbox"][switch]::before {
|
||||
background: white;
|
||||
width: 26px;
|
||||
height: 26px;
|
||||
top: -1px;
|
||||
left: -1px;
|
||||
position: absolute;
|
||||
content: ' ';
|
||||
content: " ";
|
||||
border-radius: 32px;
|
||||
transition: .10s left var(--appleEase);
|
||||
transform: scale(.75);
|
||||
transition: 0.1s left var(--appleEase);
|
||||
transform: scale(0.75);
|
||||
}
|
||||
|
||||
|
||||
input[type=checkbox][switch]:checked::before {
|
||||
input[type="checkbox"][switch]:checked::before {
|
||||
background: white;
|
||||
top: -1px;
|
||||
left: 13px;
|
||||
transition: .10s left var(--appleEase);
|
||||
transform: scale(.75);
|
||||
transition: 0.1s left var(--appleEase);
|
||||
transform: scale(0.75);
|
||||
}
|
||||
|
||||
input[type=checkbox][switch]:disabled::before {
|
||||
opacity: .5;
|
||||
input[type="checkbox"][switch]:disabled::before {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
input[type=checkbox][switch]:active::before {
|
||||
input[type="checkbox"][switch]:active::before {
|
||||
left: 13px;
|
||||
}
|
||||
|
||||
input[type=checkbox][switch]:checked:active::before {
|
||||
input[type="checkbox"][switch]:checked:active::before {
|
||||
left: -1px;
|
||||
}
|
||||
|
||||
/* End Switch Checkbox */
|
||||
|
||||
|
||||
.header-text {
|
||||
margin: 0px;
|
||||
}
|
||||
|
@ -1649,7 +1622,7 @@ input[type=checkbox][switch]:checked:active::before {
|
|||
|
||||
.media-item--small .text {
|
||||
font-weight: 600;
|
||||
font-size: 0.90em;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
.media-item--small .subtext {
|
||||
|
@ -1684,11 +1657,11 @@ input[type=checkbox][switch]:checked:active::before {
|
|||
background-repeat: no-repeat;
|
||||
border-radius: 8px;
|
||||
box-shadow: inset 0px 0px 0px 1px rgb(200 200 200 / 16%), 0 8px 40px rgb(0 0 0 / 0.55);
|
||||
transition: transform .10s var(--appleEase);
|
||||
transition: transform 0.1s var(--appleEase);
|
||||
}
|
||||
|
||||
.media-artwork.paused {
|
||||
transition: transform .35s var(--appleEase);
|
||||
transition: transform 0.35s var(--appleEase);
|
||||
transform: scale(0.85);
|
||||
}
|
||||
|
||||
|
@ -1727,7 +1700,7 @@ input[type=checkbox][switch]:checked:active::before {
|
|||
background-size: 12px;
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
opacity: 0.70;
|
||||
opacity: 0.7;
|
||||
border-radius: 6px;
|
||||
position: relative;
|
||||
|
||||
|
@ -1745,7 +1718,7 @@ input[type=checkbox][switch]:checked:active::before {
|
|||
z-index: -1;
|
||||
transform: scale(0.5);
|
||||
pointer-events: none;
|
||||
transition: opacity .10s var(--appleEase), transform .10s var(--appleEase);
|
||||
transition: opacity 0.1s var(--appleEase), transform 0.1s var(--appleEase);
|
||||
}
|
||||
|
||||
&:hover {
|
||||
|
@ -1768,7 +1741,7 @@ input[type=checkbox][switch]:checked:active::before {
|
|||
height: 32px;
|
||||
border: 0px;
|
||||
box-shadow: unset;
|
||||
opacity: 0.70;
|
||||
opacity: 0.7;
|
||||
position: relative;
|
||||
|
||||
&:before {
|
||||
|
@ -1785,7 +1758,7 @@ input[type=checkbox][switch]:checked:active::before {
|
|||
z-index: -1;
|
||||
transform: scale(0.5);
|
||||
pointer-events: none;
|
||||
transition: opacity .10s var(--appleEase), transform .10s var(--appleEase);
|
||||
transition: opacity 0.1s var(--appleEase), transform 0.1s var(--appleEase);
|
||||
}
|
||||
|
||||
&:hover {
|
||||
|
@ -1845,7 +1818,7 @@ input[type=checkbox][switch]:checked:active::before {
|
|||
}
|
||||
|
||||
.playback-button.stop {
|
||||
background-image: url('./assets/cider-icons/stop.svg');
|
||||
background-image: url("./assets/cider-icons/stop.svg");
|
||||
background-size: 38px;
|
||||
background-position: center;
|
||||
}
|
||||
|
@ -1863,25 +1836,25 @@ input[type=checkbox][switch]:checked:active::before {
|
|||
}
|
||||
|
||||
.playback-button.pause {
|
||||
background-image: url('./assets/cider-icons/pause.svg');
|
||||
background-image: url("./assets/cider-icons/pause.svg");
|
||||
background-size: 38px;
|
||||
background-position: center;
|
||||
}
|
||||
|
||||
.playback-button.play {
|
||||
background-image: url('./assets/cider-icons/play.svg');
|
||||
background-image: url("./assets/cider-icons/play.svg");
|
||||
background-size: 38px;
|
||||
background-position: center;
|
||||
}
|
||||
|
||||
.playback-button.next {
|
||||
background-image: url('./assets/cider-icons/forward.svg');
|
||||
background-image: url("./assets/cider-icons/forward.svg");
|
||||
background-size: 60%;
|
||||
background-position: center;
|
||||
}
|
||||
|
||||
.playback-button.previous {
|
||||
background-image: url('./assets/cider-icons/backward.svg');
|
||||
background-image: url("./assets/cider-icons/backward.svg");
|
||||
background-size: 60%;
|
||||
background-position: center;
|
||||
}
|
||||
|
@ -1950,7 +1923,7 @@ input[type=checkbox][switch]:checked:active::before {
|
|||
}
|
||||
|
||||
.player-song-artist {
|
||||
font-size: 1.0em;
|
||||
font-size: 1em;
|
||||
text-align: left;
|
||||
margin: 0 auto;
|
||||
color: var(--keyColor);
|
||||
|
@ -1999,10 +1972,8 @@ input[type=checkbox][switch]:checked:active::before {
|
|||
height: 40px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
}
|
||||
|
||||
|
||||
.list-entry-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
@ -2204,9 +2175,9 @@ input[type=checkbox][switch]:checked:active::before {
|
|||
.fancy-pills {
|
||||
.nav-pills {
|
||||
position: relative;
|
||||
|
||||
|
||||
.nav-link {
|
||||
transition: transform .3s var(--appleEase);
|
||||
transition: transform 0.3s var(--appleEase);
|
||||
position: relative;
|
||||
background-color: transparent;
|
||||
border: 0;
|
||||
|
@ -2215,8 +2186,7 @@ input[type=checkbox][switch]:checked:active::before {
|
|||
-webkit-user-drag: none;
|
||||
font-weight: 500;
|
||||
margin: 0px 4px;
|
||||
|
||||
|
||||
|
||||
&:after {
|
||||
--dist: 1px;
|
||||
content: "";
|
||||
|
@ -2231,27 +2201,23 @@ input[type=checkbox][switch]:checked:active::before {
|
|||
border-radius: 50px;
|
||||
z-index: -1;
|
||||
opacity: 0;
|
||||
transition: background-color .5s var(--appleEase), opacity 0.25s var(--appleEase), border-radius .32s var(--appleEase);
|
||||
transition: background-color 0.5s var(--appleEase), opacity 0.25s var(--appleEase), border-radius 0.32s var(--appleEase);
|
||||
}
|
||||
|
||||
|
||||
|
||||
&:hover {
|
||||
outline: none;
|
||||
transform: scale(1.1);
|
||||
// background: #eee;
|
||||
background: transparent;
|
||||
color: #333;
|
||||
|
||||
|
||||
&:after {
|
||||
opacity: 1;
|
||||
background-color: #eee;
|
||||
transition: background-color .25s var(--appleEase),
|
||||
border-radius .25s var(--appleEase),
|
||||
color .0s var(--appleEase),
|
||||
opacity 0.0s var(--appleEase);
|
||||
transition: background-color 0.25s var(--appleEase), border-radius 0.25s var(--appleEase), color 0s var(--appleEase), opacity 0s var(--appleEase);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
&.active {
|
||||
outline: none;
|
||||
transform: scale(1.1);
|
||||
|
@ -2259,24 +2225,22 @@ input[type=checkbox][switch]:checked:active::before {
|
|||
background: transparent;
|
||||
color: #333;
|
||||
font-weight: 600;
|
||||
|
||||
|
||||
&:after {
|
||||
opacity: 1;
|
||||
background-color: #eee;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
&:hover {
|
||||
.nav-link.active {
|
||||
outline: none;
|
||||
transform: scale(1.0);
|
||||
transform: scale(1);
|
||||
background: transparent;
|
||||
color: #eee;
|
||||
transform: scale(1.0);
|
||||
|
||||
transform: scale(1);
|
||||
|
||||
&:after {
|
||||
background: rgb(200 200 200 / 15%);
|
||||
opacity: 1;
|
||||
|
@ -2284,12 +2248,12 @@ input[type=checkbox][switch]:checked:active::before {
|
|||
// border-radius: 5px;
|
||||
--dist: 4px;
|
||||
}
|
||||
|
||||
|
||||
&:hover {
|
||||
transform: scale(1.1);
|
||||
z-index: 1;
|
||||
color: #333;
|
||||
|
||||
|
||||
&:after {
|
||||
background: #eee;
|
||||
border-radius: inherit;
|
||||
|
@ -2298,9 +2262,9 @@ input[type=checkbox][switch]:checked:active::before {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
&:after {
|
||||
content: '';
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
|
@ -2387,7 +2351,7 @@ input[type=checkbox][switch]:checked:active::before {
|
|||
border-radius: 50%;
|
||||
div {
|
||||
border-radius: 50%;
|
||||
}
|
||||
}
|
||||
img {
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
@ -2399,8 +2363,7 @@ input[type=checkbox][switch]:checked:active::before {
|
|||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
margin-bottom: 16px;
|
||||
.md-input-number{
|
||||
.md-input-number {
|
||||
min-width: 12em;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,14 +22,13 @@
|
|||
--chromeHeight1: 70px;
|
||||
|
||||
.app-content-container {
|
||||
width:100%;
|
||||
height:100%;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
#app-content {
|
||||
width:100%;
|
||||
height:100%;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
.fs-search {
|
||||
|
||||
.search-input--icon {
|
||||
width: 4em;
|
||||
background-size: 40%;
|
||||
|
@ -38,7 +37,7 @@
|
|||
input {
|
||||
padding-left: 2em;
|
||||
font-size: 2em;
|
||||
border-radius: var(--mediaItemRadius)
|
||||
border-radius: var(--mediaItemRadius);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -56,42 +55,41 @@
|
|||
z-index: 9999;
|
||||
|
||||
.top-nav-group {
|
||||
background : #1e1e1e99;
|
||||
border : 1px solid lighten(@baseColor, 8);
|
||||
background: #1e1e1e99;
|
||||
border: 1px solid lighten(@baseColor, 8);
|
||||
border-radius: 12px;
|
||||
display : flex;
|
||||
height : 55px;
|
||||
display: flex;
|
||||
height: 55px;
|
||||
width: 90%;
|
||||
backdrop-filter: var(--glassFilter);
|
||||
|
||||
|
||||
.app-sidebar-item {
|
||||
background-color: #1e1e1e00;
|
||||
border-radius : 10px !important;
|
||||
border : 0px;
|
||||
min-width : 120px;
|
||||
padding : 6px;
|
||||
justify-content : center;
|
||||
align-items : center;
|
||||
margin : 0px;
|
||||
height : 100%;
|
||||
position : relative;
|
||||
border-radius: 10px !important;
|
||||
border: 0px;
|
||||
min-width: 120px;
|
||||
padding: 6px;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin: 0px;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
font-size: 1.1em;
|
||||
font-weight: 500;
|
||||
|
||||
&:before {
|
||||
--dist : 1px;
|
||||
content : '';
|
||||
position : absolute;
|
||||
top : var(--dist);
|
||||
left : var(--dist);
|
||||
right : var(--dist);
|
||||
bottom : var(--dist);
|
||||
--dist: 1px;
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: var(--dist);
|
||||
left: var(--dist);
|
||||
right: var(--dist);
|
||||
bottom: var(--dist);
|
||||
background-color: #fff;
|
||||
opacity : 0;
|
||||
border-radius : 10px;
|
||||
transform : scale(0.5);
|
||||
transition : transform 0.2s ease-in-out, opacity 0.2s ease-in-out;
|
||||
opacity: 0;
|
||||
border-radius: 10px;
|
||||
transform: scale(0.5);
|
||||
transition: transform 0.2s ease-in-out, opacity 0.2s ease-in-out;
|
||||
}
|
||||
|
||||
&:after {
|
||||
|
@ -103,8 +101,8 @@
|
|||
|
||||
&:before {
|
||||
transition: transform 0.1s ease-in-out, opacity 0.1s ease-in-out;
|
||||
opacity : .1;
|
||||
transform : scale(1);
|
||||
opacity: 0.1;
|
||||
transform: scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -112,15 +110,15 @@
|
|||
background-color: transparent;
|
||||
|
||||
&:before {
|
||||
opacity : .2;
|
||||
opacity: 0.2;
|
||||
transform: scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
&.md-btn-primary {
|
||||
box-shadow : 0px 0px 0px 1px lighten(@baseColor, @colorMixRate * 8);
|
||||
box-shadow: 0px 0px 0px 1px lighten(@baseColor, @colorMixRate * 8);
|
||||
background-color: lighten(@baseColor, @colorMixRate * 5);
|
||||
z-index : 1;
|
||||
z-index: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -164,7 +162,7 @@
|
|||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 100%
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.volume-button--small {
|
||||
|
@ -178,7 +176,7 @@
|
|||
width: 30px;
|
||||
border: 0px;
|
||||
box-shadow: unset;
|
||||
opacity: 0.70;
|
||||
opacity: 0.7;
|
||||
background-image: url("./assets/feather/volume-2.svg");
|
||||
}
|
||||
|
||||
|
@ -190,7 +188,7 @@
|
|||
background-image: url("./assets/feather/volume.svg");
|
||||
}
|
||||
|
||||
input[type=range] {
|
||||
input[type="range"] {
|
||||
-webkit-appearance: none;
|
||||
height: 4px;
|
||||
background: rgba(255, 255, 255, 0.4);
|
||||
|
@ -228,7 +226,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
.background {
|
||||
position: absolute;
|
||||
background-size: cover;
|
||||
|
@ -247,13 +244,10 @@
|
|||
.bg-artwork-container .bg-artwork {
|
||||
filter: brightness(85%) saturate(95%) blur(180px) contrast(0.9) opacity(0.9);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
.lyrics-col {
|
||||
|
||||
height: 62vh;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
|
@ -278,11 +272,9 @@
|
|||
.lyric-line {
|
||||
font-size: 35px;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.queue-col {
|
||||
|
||||
width: 60vh;
|
||||
height: 62vh;
|
||||
|
||||
|
@ -361,7 +353,8 @@
|
|||
}
|
||||
|
||||
.app-playback-controls {
|
||||
.song-artist, .song-name {
|
||||
.song-artist,
|
||||
.song-name {
|
||||
font-weight: 600;
|
||||
text-align: center;
|
||||
font-size: 0.9em;
|
||||
|
@ -414,8 +407,6 @@
|
|||
width: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
.app-playback-controls .song-progress {
|
||||
|
@ -436,7 +427,7 @@
|
|||
}
|
||||
|
||||
&:hover {
|
||||
> input[type=range] {
|
||||
> input[type="range"] {
|
||||
&::-webkit-slider-thumb {
|
||||
opacity: 1;
|
||||
transform: scale(1);
|
||||
|
@ -445,7 +436,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
input[type=range] {
|
||||
input[type="range"] {
|
||||
appearance: none;
|
||||
width: 100%;
|
||||
height: 4px;
|
||||
|
@ -462,7 +453,7 @@
|
|||
border-radius: 100%;
|
||||
background: var(--songProgressColor);
|
||||
cursor: default;
|
||||
transition: opacity .10s var(--appleEase), transform .10s var(--appleEase);
|
||||
transition: opacity 0.1s var(--appleEase), transform 0.1s var(--appleEase);
|
||||
}
|
||||
|
||||
&::-moz-range-thumb {
|
||||
|
@ -482,7 +473,6 @@
|
|||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.cd-mediaitem-square {
|
||||
|
@ -556,18 +546,18 @@
|
|||
.playlist-page .playlist-display {
|
||||
width: 100%;
|
||||
max-width: 500px;
|
||||
flex:1;
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
|
||||
.playlistInfo {
|
||||
>.row {
|
||||
> .row {
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
|
||||
.playlist-controls {
|
||||
div {
|
||||
width:100%;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -156,8 +156,7 @@
|
|||
}
|
||||
|
||||
.close-btn {
|
||||
.menu-panel.menu-header-text.close-btn
|
||||
|
||||
.menu-panel.menu-header-text.close-btn;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -180,7 +179,7 @@
|
|||
}
|
||||
|
||||
.close-btn {
|
||||
.menu-panel.menu-header-text.close-btn
|
||||
.menu-panel.menu-header-text.close-btn;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -294,7 +293,6 @@
|
|||
overflow: hidden;
|
||||
font-size: 13px;
|
||||
|
||||
|
||||
.menu-option {
|
||||
text-align: left;
|
||||
display: flex;
|
||||
|
@ -323,7 +321,7 @@
|
|||
opacity: 0;
|
||||
transform: scale(0.98);
|
||||
z-index: -1;
|
||||
transition: transform .25s ease-out, opacity .25s ease-out;
|
||||
transition: transform 0.25s ease-out, opacity 0.25s ease-out;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
|
@ -336,7 +334,7 @@
|
|||
|
||||
&:active {
|
||||
&::before {
|
||||
transition: transform .1s ease-in-out, opacity .1s ease-in-out;
|
||||
transition: transform 0.1s ease-in-out, opacity 0.1s ease-in-out;
|
||||
opacity: 1;
|
||||
transform: scale(0.98);
|
||||
background: var(--selected-click);
|
||||
|
@ -372,7 +370,7 @@
|
|||
}
|
||||
|
||||
&:hover {
|
||||
background-color: rgb(196, 43, 28)
|
||||
background-color: rgb(196, 43, 28);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -430,7 +428,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
.moreinfo-modal {
|
||||
.modal-window {
|
||||
height: 70%;
|
||||
|
@ -496,7 +493,8 @@
|
|||
font-weight: 600;
|
||||
}
|
||||
|
||||
.song-artist, .song-album {
|
||||
.song-artist,
|
||||
.song-album {
|
||||
opacity: 0.75;
|
||||
cursor: pointer;
|
||||
|
||||
|
@ -521,4 +519,4 @@
|
|||
&.svg-md {
|
||||
--size: 1.2em;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,59 +1,59 @@
|
|||
// Linux
|
||||
body[platform="linux"] {
|
||||
#window-controls-container {
|
||||
//display: none;
|
||||
}
|
||||
#window-controls-container {
|
||||
//display: none;
|
||||
}
|
||||
|
||||
.window-controls {
|
||||
justify-content: flex-end;
|
||||
align-items : center;
|
||||
padding-right : 6px;
|
||||
.window-controls {
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
padding-right: 6px;
|
||||
|
||||
>div {
|
||||
--iconSize: 16px;
|
||||
> div {
|
||||
--iconSize: 16px;
|
||||
|
||||
&.close,
|
||||
&.minmax,
|
||||
&.minimize,
|
||||
&.minmax.restore {
|
||||
background-image: unset!important;
|
||||
position : relative;
|
||||
display : grid;
|
||||
align-content : center;
|
||||
text-align : center;
|
||||
height : 36px!important;
|
||||
width : 36px!important;
|
||||
border-radius : 50px;
|
||||
transition: background-color .1s ease-in-out;
|
||||
&.close,
|
||||
&.minmax,
|
||||
&.minimize,
|
||||
&.minmax.restore {
|
||||
background-image: unset !important;
|
||||
position: relative;
|
||||
display: grid;
|
||||
align-content: center;
|
||||
text-align: center;
|
||||
height: 36px !important;
|
||||
width: 36px !important;
|
||||
border-radius: 50px;
|
||||
transition: background-color 0.1s ease-in-out;
|
||||
|
||||
&:hover {
|
||||
background: rgb(200 200 200 / 10%)!important;
|
||||
}
|
||||
}
|
||||
|
||||
&.close::before {
|
||||
font-family: "codicon";
|
||||
font-size : var(--iconSize);
|
||||
content : "";
|
||||
}
|
||||
|
||||
&.minmax::before {
|
||||
font-family: "codicon";
|
||||
font-size : var(--iconSize);
|
||||
content : "";
|
||||
}
|
||||
|
||||
&.minimize::before {
|
||||
font-family: "codicon";
|
||||
font-size : var(--iconSize);
|
||||
content : "";
|
||||
}
|
||||
|
||||
&.restore::before {
|
||||
font-family: "codicon";
|
||||
font-size : var(--iconSize);
|
||||
content : "";
|
||||
}
|
||||
&:hover {
|
||||
background: rgb(200 200 200 / 10%) !important;
|
||||
}
|
||||
}
|
||||
|
||||
&.close::before {
|
||||
font-family: "codicon";
|
||||
font-size: var(--iconSize);
|
||||
content: "";
|
||||
}
|
||||
|
||||
&.minmax::before {
|
||||
font-family: "codicon";
|
||||
font-size: var(--iconSize);
|
||||
content: "";
|
||||
}
|
||||
|
||||
&.minimize::before {
|
||||
font-family: "codicon";
|
||||
font-size: var(--iconSize);
|
||||
content: "";
|
||||
}
|
||||
|
||||
&.restore::before {
|
||||
font-family: "codicon";
|
||||
font-size: var(--iconSize);
|
||||
content: "";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,79 +1,79 @@
|
|||
body[platform="darwin"] {
|
||||
html {
|
||||
background: transparent !important;
|
||||
html {
|
||||
background: transparent !important;
|
||||
}
|
||||
|
||||
&.notransparency::before {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#app {
|
||||
&.simplebg {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
&.notransparency::before {
|
||||
display: none;
|
||||
&::before {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#app {
|
||||
&.simplebg {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
&::before {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.app-chrome {
|
||||
background-color: var(--macOSChromeColor);
|
||||
}
|
||||
|
||||
&.twopanel {
|
||||
--chromeHeight1: 55px;
|
||||
--chromeHeight: calc(var(--chromeHeight1) + var(--chromeHeight2));
|
||||
|
||||
.app-chrome .app-chrome-item.search {
|
||||
margin-right: 12px;
|
||||
}
|
||||
|
||||
.app-chrome .app-mainmenu {
|
||||
width: 46px;
|
||||
}
|
||||
|
||||
.app-chrome.chrome-bottom {
|
||||
background-color: var(--macOSChromeColor);
|
||||
}
|
||||
}
|
||||
|
||||
&[window-state="normal"] {
|
||||
&::after {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
box-shadow: inset 0px 0px .5px 1px rgb(200 200 200 / 40%);
|
||||
border-radius: 10px;
|
||||
content: " ";
|
||||
z-index: 999999;
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
.app-chrome {
|
||||
background-color: var(--macOSChromeColor);
|
||||
}
|
||||
|
||||
#app-main {
|
||||
background-color: transparent;
|
||||
&.twopanel {
|
||||
--chromeHeight1: 55px;
|
||||
--chromeHeight: calc(var(--chromeHeight1) + var(--chromeHeight2));
|
||||
|
||||
.app-navigation {
|
||||
background: transparent;
|
||||
}
|
||||
.app-chrome .app-chrome-item.search {
|
||||
margin-right: 12px;
|
||||
}
|
||||
|
||||
#app-content {
|
||||
background-color: #1e1e1e6b;
|
||||
}
|
||||
.app-chrome .app-mainmenu {
|
||||
width: 46px;
|
||||
}
|
||||
|
||||
.app-chrome.chrome-bottom {
|
||||
background-color: var(--macOSChromeColor);
|
||||
}
|
||||
}
|
||||
|
||||
.settings-window.maxed {
|
||||
.tabs>.col-auto {
|
||||
transition: padding-top .3s linear;
|
||||
padding-top: var(--chromeHeight1);
|
||||
}
|
||||
&[window-state="normal"] {
|
||||
&::after {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
box-shadow: inset 0px 0px 0.5px 1px rgb(200 200 200 / 40%);
|
||||
border-radius: 10px;
|
||||
content: " ";
|
||||
z-index: 999999;
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#app-main {
|
||||
background-color: transparent;
|
||||
|
||||
.app-navigation {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
#apple-music-video-player-controls #player-exit {
|
||||
margin-top: 18px;
|
||||
left: 70px;
|
||||
#app-content {
|
||||
background-color: #1e1e1e6b;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.settings-window.maxed {
|
||||
.tabs > .col-auto {
|
||||
transition: padding-top 0.3s linear;
|
||||
padding-top: var(--chromeHeight1);
|
||||
}
|
||||
}
|
||||
|
||||
#apple-music-video-player-controls #player-exit {
|
||||
margin-top: 18px;
|
||||
left: 70px;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,4 @@
|
|||
#app.macosemu {
|
||||
|
||||
|
||||
|
||||
.app-chrome .app-chrome-item > .window-controls-macos {
|
||||
@controlSize: 12px;
|
||||
display: flex;
|
||||
|
@ -42,8 +39,8 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
.usermenu-body{
|
||||
.usermenu-body {
|
||||
left: calc(100vw - 260px);
|
||||
position: relative;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -65,7 +65,7 @@
|
|||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 100%
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.volume-button--small {
|
||||
|
@ -79,7 +79,7 @@
|
|||
width: 30px;
|
||||
border: 0px;
|
||||
box-shadow: unset;
|
||||
opacity: 0.70;
|
||||
opacity: 0.7;
|
||||
background-image: url("./assets/feather/volume-2.svg");
|
||||
}
|
||||
|
||||
|
@ -91,7 +91,7 @@
|
|||
background-image: url("./assets/feather/volume.svg");
|
||||
}
|
||||
|
||||
input[type=range] {
|
||||
input[type="range"] {
|
||||
-webkit-appearance: none;
|
||||
height: 4px;
|
||||
background: rgba(255, 255, 255, 0.4);
|
||||
|
@ -129,7 +129,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
.background {
|
||||
position: absolute;
|
||||
background-size: cover;
|
||||
|
@ -157,9 +156,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
.lyrics-col {
|
||||
|
||||
height: 62vh;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
|
@ -184,11 +181,9 @@
|
|||
.lyric-line {
|
||||
font-size: 35px;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.queue-col {
|
||||
|
||||
width: 60vh;
|
||||
height: 50vh;
|
||||
|
||||
|
@ -281,11 +276,11 @@
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
.app-playback-controls {
|
||||
-webkit-app-region: no-drag;
|
||||
|
||||
.song-artist, .song-name {
|
||||
.song-artist,
|
||||
.song-name {
|
||||
font-weight: 600;
|
||||
text-align: center;
|
||||
font-size: 0.9em;
|
||||
|
@ -338,8 +333,6 @@
|
|||
width: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
.app-playback-controls .song-progress {
|
||||
|
@ -360,7 +353,7 @@
|
|||
}
|
||||
|
||||
&:hover {
|
||||
> input[type=range] {
|
||||
> input[type="range"] {
|
||||
&::-webkit-slider-thumb {
|
||||
opacity: 1;
|
||||
transform: scale(1);
|
||||
|
@ -369,7 +362,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
input[type=range] {
|
||||
input[type="range"] {
|
||||
appearance: none;
|
||||
width: 100%;
|
||||
height: 4px;
|
||||
|
@ -386,7 +379,7 @@
|
|||
border-radius: 100%;
|
||||
background: var(--songProgressColor);
|
||||
cursor: default;
|
||||
transition: opacity .10s var(--appleEase), transform .10s var(--appleEase);
|
||||
transition: opacity 0.1s var(--appleEase), transform 0.1s var(--appleEase);
|
||||
}
|
||||
|
||||
&::-moz-range-thumb {
|
||||
|
@ -405,6 +398,5 @@
|
|||
width: 100%;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,370 +1,370 @@
|
|||
@-webkit-keyframes notyf-fadeinup {
|
||||
0% {
|
||||
opacity: 0;
|
||||
transform: translateY(25%)
|
||||
}
|
||||
0% {
|
||||
opacity: 0;
|
||||
transform: translateY(25%);
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0)
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes notyf-fadeinup {
|
||||
0% {
|
||||
opacity: 0;
|
||||
transform: translateY(25%)
|
||||
}
|
||||
0% {
|
||||
opacity: 0;
|
||||
transform: translateY(25%);
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0)
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
@-webkit-keyframes notyf-fadeinleft {
|
||||
0% {
|
||||
opacity: 0;
|
||||
transform: translateX(25%)
|
||||
}
|
||||
0% {
|
||||
opacity: 0;
|
||||
transform: translateX(25%);
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateX(0)
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateX(0);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes notyf-fadeinleft {
|
||||
0% {
|
||||
opacity: 0;
|
||||
transform: translateX(25%)
|
||||
}
|
||||
0% {
|
||||
opacity: 0;
|
||||
transform: translateX(25%);
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateX(0)
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateX(0);
|
||||
}
|
||||
}
|
||||
|
||||
@-webkit-keyframes notyf-fadeoutright {
|
||||
0% {
|
||||
opacity: 1;
|
||||
transform: translateX(0)
|
||||
}
|
||||
0% {
|
||||
opacity: 1;
|
||||
transform: translateX(0);
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 0;
|
||||
transform: translateX(25%)
|
||||
}
|
||||
to {
|
||||
opacity: 0;
|
||||
transform: translateX(25%);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes notyf-fadeoutright {
|
||||
0% {
|
||||
opacity: 1;
|
||||
transform: translateX(0)
|
||||
}
|
||||
0% {
|
||||
opacity: 1;
|
||||
transform: translateX(0);
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 0;
|
||||
transform: translateX(25%)
|
||||
}
|
||||
to {
|
||||
opacity: 0;
|
||||
transform: translateX(25%);
|
||||
}
|
||||
}
|
||||
|
||||
@-webkit-keyframes notyf-fadeoutdown {
|
||||
0% {
|
||||
opacity: 1;
|
||||
transform: translateY(0)
|
||||
}
|
||||
0% {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 0;
|
||||
transform: translateY(25%)
|
||||
}
|
||||
to {
|
||||
opacity: 0;
|
||||
transform: translateY(25%);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes notyf-fadeoutdown {
|
||||
0% {
|
||||
opacity: 1;
|
||||
transform: translateY(0)
|
||||
}
|
||||
0% {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 0;
|
||||
transform: translateY(25%)
|
||||
}
|
||||
to {
|
||||
opacity: 0;
|
||||
transform: translateY(25%);
|
||||
}
|
||||
}
|
||||
|
||||
@-webkit-keyframes ripple {
|
||||
0% {
|
||||
transform: scale(0) translateY(-45%) translateX(13%)
|
||||
}
|
||||
0% {
|
||||
transform: scale(0) translateY(-45%) translateX(13%);
|
||||
}
|
||||
|
||||
to {
|
||||
transform: scale(1) translateY(-45%) translateX(13%)
|
||||
}
|
||||
to {
|
||||
transform: scale(1) translateY(-45%) translateX(13%);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes ripple {
|
||||
0% {
|
||||
transform: scale(0) translateY(-45%) translateX(13%)
|
||||
}
|
||||
0% {
|
||||
transform: scale(0) translateY(-45%) translateX(13%);
|
||||
}
|
||||
|
||||
to {
|
||||
transform: scale(1) translateY(-45%) translateX(13%)
|
||||
}
|
||||
to {
|
||||
transform: scale(1) translateY(-45%) translateX(13%);
|
||||
}
|
||||
}
|
||||
|
||||
.notyf {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
color: #fff;
|
||||
z-index: 9999;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-end;
|
||||
justify-content: flex-end;
|
||||
pointer-events: none;
|
||||
box-sizing: border-box;
|
||||
padding: 20px
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
color: #fff;
|
||||
z-index: 9999;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-end;
|
||||
justify-content: flex-end;
|
||||
pointer-events: none;
|
||||
box-sizing: border-box;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.notyf__icon--error,
|
||||
.notyf__icon--success {
|
||||
height: 21px;
|
||||
width: 21px;
|
||||
background: #fff;
|
||||
border-radius: 50%;
|
||||
display: block;
|
||||
margin: 0 auto;
|
||||
position: relative
|
||||
height: 21px;
|
||||
width: 21px;
|
||||
background: #fff;
|
||||
border-radius: 50%;
|
||||
display: block;
|
||||
margin: 0 auto;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.notyf__icon--error:after,
|
||||
.notyf__icon--error:before {
|
||||
content: "";
|
||||
background: currentColor;
|
||||
display: block;
|
||||
position: absolute;
|
||||
width: 3px;
|
||||
border-radius: 3px;
|
||||
left: 9px;
|
||||
height: 12px;
|
||||
top: 5px
|
||||
content: "";
|
||||
background: currentColor;
|
||||
display: block;
|
||||
position: absolute;
|
||||
width: 3px;
|
||||
border-radius: 3px;
|
||||
left: 9px;
|
||||
height: 12px;
|
||||
top: 5px;
|
||||
}
|
||||
|
||||
.notyf__icon--error:after {
|
||||
transform: rotate(-45deg)
|
||||
transform: rotate(-45deg);
|
||||
}
|
||||
|
||||
.notyf__icon--error:before {
|
||||
transform: rotate(45deg)
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
|
||||
.notyf__icon--success:after,
|
||||
.notyf__icon--success:before {
|
||||
content: "";
|
||||
background: currentColor;
|
||||
display: block;
|
||||
position: absolute;
|
||||
width: 3px;
|
||||
border-radius: 3px
|
||||
content: "";
|
||||
background: currentColor;
|
||||
display: block;
|
||||
position: absolute;
|
||||
width: 3px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.notyf__icon--success:after {
|
||||
height: 6px;
|
||||
transform: rotate(-45deg);
|
||||
top: 9px;
|
||||
left: 6px
|
||||
height: 6px;
|
||||
transform: rotate(-45deg);
|
||||
top: 9px;
|
||||
left: 6px;
|
||||
}
|
||||
|
||||
.notyf__icon--success:before {
|
||||
height: 11px;
|
||||
transform: rotate(45deg);
|
||||
top: 5px;
|
||||
left: 10px
|
||||
height: 11px;
|
||||
transform: rotate(45deg);
|
||||
top: 5px;
|
||||
left: 10px;
|
||||
}
|
||||
|
||||
.notyf__toast {
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
pointer-events: auto;
|
||||
-webkit-animation: notyf-fadeinup .3s ease-in forwards;
|
||||
animation: notyf-fadeinup .3s ease-in forwards;
|
||||
box-shadow: 0 3px 7px 0 rgba(0, 0, 0, .25);
|
||||
position: relative;
|
||||
padding: 0 15px;
|
||||
border-radius: 2px;
|
||||
max-width: 300px;
|
||||
transform: translateY(25%);
|
||||
box-sizing: border-box;
|
||||
flex-shrink: 0
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
pointer-events: auto;
|
||||
-webkit-animation: notyf-fadeinup 0.3s ease-in forwards;
|
||||
animation: notyf-fadeinup 0.3s ease-in forwards;
|
||||
box-shadow: 0 3px 7px 0 rgba(0, 0, 0, 0.25);
|
||||
position: relative;
|
||||
padding: 0 15px;
|
||||
border-radius: 2px;
|
||||
max-width: 300px;
|
||||
transform: translateY(25%);
|
||||
box-sizing: border-box;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.notyf__toast--disappear {
|
||||
transform: translateY(0);
|
||||
-webkit-animation: notyf-fadeoutdown .3s forwards;
|
||||
animation: notyf-fadeoutdown .3s forwards;
|
||||
-webkit-animation-delay: .25s;
|
||||
animation-delay: .25s
|
||||
transform: translateY(0);
|
||||
-webkit-animation: notyf-fadeoutdown 0.3s forwards;
|
||||
animation: notyf-fadeoutdown 0.3s forwards;
|
||||
-webkit-animation-delay: 0.25s;
|
||||
animation-delay: 0.25s;
|
||||
}
|
||||
|
||||
.notyf__toast--disappear .notyf__icon,
|
||||
.notyf__toast--disappear .notyf__message {
|
||||
-webkit-animation: notyf-fadeoutdown .3s forwards;
|
||||
animation: notyf-fadeoutdown .3s forwards;
|
||||
opacity: 1;
|
||||
transform: translateY(0)
|
||||
-webkit-animation: notyf-fadeoutdown 0.3s forwards;
|
||||
animation: notyf-fadeoutdown 0.3s forwards;
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
.notyf__toast--disappear .notyf__dismiss {
|
||||
-webkit-animation: notyf-fadeoutright .3s forwards;
|
||||
animation: notyf-fadeoutright .3s forwards;
|
||||
opacity: 1;
|
||||
transform: translateX(0)
|
||||
-webkit-animation: notyf-fadeoutright 0.3s forwards;
|
||||
animation: notyf-fadeoutright 0.3s forwards;
|
||||
opacity: 1;
|
||||
transform: translateX(0);
|
||||
}
|
||||
|
||||
.notyf__toast--disappear .notyf__message {
|
||||
-webkit-animation-delay: .05s;
|
||||
animation-delay: .05s
|
||||
-webkit-animation-delay: 0.05s;
|
||||
animation-delay: 0.05s;
|
||||
}
|
||||
|
||||
.notyf__toast--upper {
|
||||
margin-bottom: 20px
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.notyf__toast--lower {
|
||||
margin-top: 20px
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.notyf__toast--dismissible .notyf__wrapper {
|
||||
padding-right: 30px
|
||||
padding-right: 30px;
|
||||
}
|
||||
|
||||
.notyf__ripple {
|
||||
height: 400px;
|
||||
width: 400px;
|
||||
position: absolute;
|
||||
transform-origin: bottom right;
|
||||
right: 0;
|
||||
top: 0;
|
||||
border-radius: 50%;
|
||||
transform: scale(0) translateY(-51%) translateX(13%);
|
||||
z-index: 5;
|
||||
-webkit-animation: ripple .4s ease-out forwards;
|
||||
animation: ripple .4s ease-out forwards
|
||||
height: 400px;
|
||||
width: 400px;
|
||||
position: absolute;
|
||||
transform-origin: bottom right;
|
||||
right: 0;
|
||||
top: 0;
|
||||
border-radius: 50%;
|
||||
transform: scale(0) translateY(-51%) translateX(13%);
|
||||
z-index: 5;
|
||||
-webkit-animation: ripple 0.4s ease-out forwards;
|
||||
animation: ripple 0.4s ease-out forwards;
|
||||
}
|
||||
|
||||
.notyf__wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-top: 17px;
|
||||
padding-bottom: 17px;
|
||||
padding-right: 15px;
|
||||
border-radius: 3px;
|
||||
position: relative;
|
||||
z-index: 10
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-top: 17px;
|
||||
padding-bottom: 17px;
|
||||
padding-right: 15px;
|
||||
border-radius: 3px;
|
||||
position: relative;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.notyf__icon {
|
||||
width: 22px;
|
||||
text-align: center;
|
||||
font-size: 1.3em;
|
||||
opacity: 0;
|
||||
-webkit-animation: notyf-fadeinup .3s forwards;
|
||||
animation: notyf-fadeinup .3s forwards;
|
||||
-webkit-animation-delay: .3s;
|
||||
animation-delay: .3s;
|
||||
margin-right: 13px
|
||||
width: 22px;
|
||||
text-align: center;
|
||||
font-size: 1.3em;
|
||||
opacity: 0;
|
||||
-webkit-animation: notyf-fadeinup 0.3s forwards;
|
||||
animation: notyf-fadeinup 0.3s forwards;
|
||||
-webkit-animation-delay: 0.3s;
|
||||
animation-delay: 0.3s;
|
||||
margin-right: 13px;
|
||||
}
|
||||
|
||||
.notyf__dismiss {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
height: 100%;
|
||||
width: 26px;
|
||||
margin-right: -15px;
|
||||
-webkit-animation: notyf-fadeinleft .3s forwards;
|
||||
animation: notyf-fadeinleft .3s forwards;
|
||||
-webkit-animation-delay: .35s;
|
||||
animation-delay: .35s;
|
||||
opacity: 0
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
height: 100%;
|
||||
width: 26px;
|
||||
margin-right: -15px;
|
||||
-webkit-animation: notyf-fadeinleft 0.3s forwards;
|
||||
animation: notyf-fadeinleft 0.3s forwards;
|
||||
-webkit-animation-delay: 0.35s;
|
||||
animation-delay: 0.35s;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.notyf__dismiss-btn {
|
||||
background-color: rgba(0, 0, 0, .25);
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
transition: opacity .2s ease, background-color .2s ease;
|
||||
outline: none;
|
||||
opacity: .35;
|
||||
height: 100%;
|
||||
width: 100%
|
||||
background-color: rgba(0, 0, 0, 0.25);
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
transition: opacity 0.2s ease, background-color 0.2s ease;
|
||||
outline: none;
|
||||
opacity: 0.35;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.notyf__dismiss-btn:after,
|
||||
.notyf__dismiss-btn:before {
|
||||
content: "";
|
||||
background: #fff;
|
||||
height: 12px;
|
||||
width: 2px;
|
||||
border-radius: 3px;
|
||||
position: absolute;
|
||||
left: calc(50% - 1px);
|
||||
top: calc(50% - 5px)
|
||||
content: "";
|
||||
background: #fff;
|
||||
height: 12px;
|
||||
width: 2px;
|
||||
border-radius: 3px;
|
||||
position: absolute;
|
||||
left: calc(50% - 1px);
|
||||
top: calc(50% - 5px);
|
||||
}
|
||||
|
||||
.notyf__dismiss-btn:after {
|
||||
transform: rotate(-45deg)
|
||||
transform: rotate(-45deg);
|
||||
}
|
||||
|
||||
.notyf__dismiss-btn:before {
|
||||
transform: rotate(45deg)
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
|
||||
.notyf__dismiss-btn:hover {
|
||||
opacity: .7;
|
||||
background-color: rgba(0, 0, 0, .15)
|
||||
opacity: 0.7;
|
||||
background-color: rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
.notyf__dismiss-btn:active {
|
||||
opacity: .8
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.notyf__message {
|
||||
vertical-align: middle;
|
||||
position: relative;
|
||||
opacity: 0;
|
||||
-webkit-animation: notyf-fadeinup .3s forwards;
|
||||
animation: notyf-fadeinup .3s forwards;
|
||||
-webkit-animation-delay: .25s;
|
||||
animation-delay: .25s;
|
||||
line-height: 1.5em
|
||||
vertical-align: middle;
|
||||
position: relative;
|
||||
opacity: 0;
|
||||
-webkit-animation: notyf-fadeinup 0.3s forwards;
|
||||
animation: notyf-fadeinup 0.3s forwards;
|
||||
-webkit-animation-delay: 0.25s;
|
||||
animation-delay: 0.25s;
|
||||
line-height: 1.5em;
|
||||
}
|
||||
|
||||
@media only screen and (max-width:480px) {
|
||||
.notyf {
|
||||
padding: 0
|
||||
}
|
||||
@media only screen and (max-width: 480px) {
|
||||
.notyf {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.notyf__ripple {
|
||||
height: 600px;
|
||||
width: 600px;
|
||||
-webkit-animation-duration: .5s;
|
||||
animation-duration: .5s
|
||||
}
|
||||
.notyf__ripple {
|
||||
height: 600px;
|
||||
width: 600px;
|
||||
-webkit-animation-duration: 0.5s;
|
||||
animation-duration: 0.5s;
|
||||
}
|
||||
|
||||
.notyf__toast {
|
||||
max-width: none;
|
||||
border-radius: 0;
|
||||
box-shadow: 0 -2px 7px 0 rgba(0, 0, 0, .13);
|
||||
width: 100%
|
||||
}
|
||||
.notyf__toast {
|
||||
max-width: none;
|
||||
border-radius: 0;
|
||||
box-shadow: 0 -2px 7px 0 rgba(0, 0, 0, 0.13);
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.notyf__dismiss {
|
||||
width: 56px
|
||||
}
|
||||
}
|
||||
.notyf__dismiss {
|
||||
width: 56px;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1277,7 +1277,7 @@
|
|||
}
|
||||
.audiolabs-page .spprofile-line .spprofile-viewport .spprev:before,
|
||||
.audiolabs-page .spprofile-line .spprofile-viewport .nextprev:before {
|
||||
content: '';
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
|
@ -1309,7 +1309,7 @@
|
|||
background: black;
|
||||
}
|
||||
.audiolabs-page .spprofile-line .spprofile-viewport .spslide > img {
|
||||
WIDTH: 100%;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
|
|
@ -242,7 +242,6 @@
|
|||
}
|
||||
|
||||
.list-group-item {
|
||||
|
||||
&:hover {
|
||||
cursor: grab;
|
||||
}
|
||||
|
@ -294,7 +293,6 @@
|
|||
|
||||
// Search Page
|
||||
&.search-page {
|
||||
|
||||
.searchToggle {
|
||||
float: right;
|
||||
|
||||
|
@ -302,7 +300,7 @@
|
|||
min-width: 120px;
|
||||
}
|
||||
}
|
||||
.categories{
|
||||
.categories {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, minmax(200px, 1fr));
|
||||
gap: 1rem;
|
||||
|
@ -316,7 +314,7 @@
|
|||
width: 100% !important;
|
||||
z-index: 1;
|
||||
}
|
||||
.info-rect{
|
||||
.info-rect {
|
||||
height: max-content;
|
||||
}
|
||||
.title {
|
||||
|
@ -452,7 +450,7 @@
|
|||
right: 0;
|
||||
|
||||
&:hover {
|
||||
background-color: rgb(196, 43, 28)
|
||||
background-color: rgb(196, 43, 28);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -488,10 +486,7 @@
|
|||
display: block;
|
||||
line-break: anywhere;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Podcast Page
|
||||
|
@ -622,7 +617,7 @@
|
|||
right: 0;
|
||||
|
||||
&:hover {
|
||||
background-color: rgb(196, 43, 28)
|
||||
background-color: rgb(196, 43, 28);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -657,10 +652,7 @@
|
|||
display: block;
|
||||
line-break: anywhere;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 1230px) {
|
||||
|
@ -828,7 +820,7 @@
|
|||
margin-bottom: -10px;
|
||||
padding: 0;
|
||||
-webkit-mask-image: radial-gradient(at top left, black, transparent 70%), radial-gradient(at top right, black, transparent 70%), linear-gradient(180deg, rgb(200 200 200), transparent 98%);
|
||||
opacity: .7;
|
||||
opacity: 0.7;
|
||||
animation: playlistArtworkFadeIn 1s var(--appleEase);
|
||||
|
||||
.artworkMaterial img {
|
||||
|
@ -898,7 +890,7 @@
|
|||
}
|
||||
|
||||
.search-input::placeholder {
|
||||
color: var(--heroplaceholdercolor)
|
||||
color: var(--heroplaceholdercolor);
|
||||
}
|
||||
|
||||
.nameEdit {
|
||||
|
@ -939,7 +931,7 @@
|
|||
}
|
||||
|
||||
.playlist-desc {
|
||||
transition: height .2s ease-in-out, opacity .2s ease-in-out;
|
||||
transition: height 0.2s ease-in-out, opacity 0.2s ease-in-out;
|
||||
box-sizing: border-box;
|
||||
font-size: 14px;
|
||||
flex-shrink: unset;
|
||||
|
@ -1043,8 +1035,6 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
.friends-info {
|
||||
|
@ -1061,7 +1051,7 @@
|
|||
border-radius: 100%;
|
||||
overflow: hidden;
|
||||
box-shadow: var(--mediaItemShadow-ShadowSubtle);
|
||||
transition: transform .2s var(--appleEase);
|
||||
transition: transform 0.2s var(--appleEase);
|
||||
margin: 6px;
|
||||
|
||||
&:hover {
|
||||
|
@ -1081,7 +1071,7 @@
|
|||
font-size: 0.9em;
|
||||
margin: 6px;
|
||||
opacity: 0.7;
|
||||
transition: height .2s ease-in-out, opacity .2s ease-in-out;
|
||||
transition: height 0.2s ease-in-out, opacity 0.2s ease-in-out;
|
||||
height: 0.9em;
|
||||
}
|
||||
|
||||
|
@ -1151,13 +1141,13 @@
|
|||
}
|
||||
|
||||
.playlist-time {
|
||||
transition: height .2s ease-in-out, opacity .2s ease-in-out;
|
||||
transition: height 0.2s ease-in-out, opacity 0.2s ease-in-out;
|
||||
height: 0px;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.playlist-desc {
|
||||
transition: height .2s ease-in-out, opacity .2s ease-in-out;
|
||||
transition: height 0.2s ease-in-out, opacity 0.2s ease-in-out;
|
||||
height: 0px !important;
|
||||
opacity: 0;
|
||||
}
|
||||
|
@ -1272,7 +1262,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
.artworkContainer {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
|
@ -1282,7 +1271,7 @@
|
|||
margin: 0;
|
||||
padding: 0;
|
||||
-webkit-mask-image: radial-gradient(at top left, black, transparent 70%), radial-gradient(at top right, black, transparent 70%), linear-gradient(180deg, rgb(200 200 200), transparent 98%);
|
||||
opacity: .7;
|
||||
opacity: 0.7;
|
||||
animation: playlistArtworkFadeIn 1s var(--appleEase);
|
||||
|
||||
.artworkMaterial img {
|
||||
|
@ -1412,7 +1401,6 @@
|
|||
}
|
||||
|
||||
.artist-title {
|
||||
|
||||
.artist-play {
|
||||
transform: translateY(3px);
|
||||
margin: 14px;
|
||||
|
@ -1490,7 +1478,6 @@
|
|||
width: 90%;
|
||||
margin: 16px auto 0px;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// AudioLabs page
|
||||
|
@ -1502,7 +1489,7 @@
|
|||
border-bottom: unset;
|
||||
border-top: unset;
|
||||
font-weight: 600;
|
||||
font-size: 1.0em;
|
||||
font-size: 1em;
|
||||
background: rgb(255 255 255 / 3%);
|
||||
}
|
||||
|
||||
|
@ -1548,7 +1535,7 @@
|
|||
}
|
||||
|
||||
&:before {
|
||||
content: '';
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
|
@ -1568,7 +1555,6 @@
|
|||
&:before {
|
||||
-webkit-mask-image: url("./views/svg/chevron-left.svg");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.nextprev {
|
||||
|
@ -1577,7 +1563,6 @@
|
|||
&:before {
|
||||
-webkit-mask-image: url("./views/svg/chevron-right.svg");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.spslide {
|
||||
|
@ -1588,7 +1573,7 @@
|
|||
background: black;
|
||||
|
||||
> img {
|
||||
WIDTH: 100%;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
@ -1646,7 +1631,6 @@
|
|||
|
||||
//Home
|
||||
.home-page {
|
||||
|
||||
.md-btn-replay {
|
||||
background-image: linear-gradient(-45deg, #2e2173, #925042);
|
||||
animation: gradient-animation 5s ease-in-out infinite;
|
||||
|
@ -1738,8 +1722,8 @@
|
|||
border-radius: var(--mediaItemRadius);
|
||||
overflow: hidden;
|
||||
cursor: pointer;
|
||||
transition: transform .2s var(--appleEase);
|
||||
transition-delay: .1s;
|
||||
transition: transform 0.2s var(--appleEase);
|
||||
transition-delay: 0.1s;
|
||||
align-self: center;
|
||||
|
||||
&:hover {
|
||||
|
@ -1780,7 +1764,6 @@
|
|||
}
|
||||
|
||||
.top-genres-container {
|
||||
|
||||
.genre-name {
|
||||
font-size: 0.9em;
|
||||
margin: 6px 0px;
|
||||
|
@ -1810,11 +1793,11 @@
|
|||
|
||||
.cd-mediaitem-square {
|
||||
.mediaitem-artwork {
|
||||
animation: replayFadeIn .5s var(--appleEase);
|
||||
animation: replayFadeIn 0.5s var(--appleEase);
|
||||
}
|
||||
|
||||
transition: transform .2s var(--appleEase);
|
||||
transition-delay: .1s;
|
||||
transition: transform 0.2s var(--appleEase);
|
||||
transition-delay: 0.1s;
|
||||
|
||||
&:hover {
|
||||
transform: scale(1.1);
|
||||
|
@ -1883,7 +1866,6 @@
|
|||
height: 100%;
|
||||
width: 100%;
|
||||
|
||||
|
||||
.oobe-header {
|
||||
font-size: 3em;
|
||||
text-shadow: var(--replayTextShadow);
|
||||
|
@ -1927,7 +1909,7 @@
|
|||
|
||||
.visualPreview {
|
||||
pointer-events: none;
|
||||
transition: .25s all;
|
||||
transition: 0.25s all;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
|
@ -1954,9 +1936,8 @@
|
|||
outline: 4px solid var(--keyColor);
|
||||
}
|
||||
|
||||
|
||||
&:hover {
|
||||
transform: scale(1.10) translateZ(-1px) translateY(10px);
|
||||
transform: scale(1.1) translateZ(-1px) translateY(10px);
|
||||
z-index: 1;
|
||||
box-shadow: 0px 12px 16px rgb(0 0 0 / 25%);
|
||||
}
|
||||
|
@ -1981,10 +1962,8 @@
|
|||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
.oobe-titlebar {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
|
@ -2125,7 +2104,6 @@
|
|||
|
||||
.nav-pills {
|
||||
gap: 6px;
|
||||
|
||||
}
|
||||
|
||||
.nav-pills .nav-link {
|
||||
|
@ -2139,7 +2117,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
.md-option-header {
|
||||
padding: 0px 26px;
|
||||
border-bottom: unset;
|
||||
|
@ -2192,7 +2169,7 @@
|
|||
}
|
||||
|
||||
&:hover {
|
||||
background-color: rgb(196, 43, 28)
|
||||
background-color: rgb(196, 43, 28);
|
||||
}
|
||||
|
||||
&.back-btn {
|
||||
|
@ -2241,35 +2218,36 @@
|
|||
overflow-y: overlay;
|
||||
height: 100%;
|
||||
background-color: var(--panelColor2);
|
||||
padding:0px;
|
||||
padding: 0px;
|
||||
padding-top: 48px;
|
||||
border-left: 1px solid var(--borderColor);
|
||||
}
|
||||
|
||||
.github-themes-page, .installed-themes-page {
|
||||
.github-themes-page,
|
||||
.installed-themes-page {
|
||||
.header-text {
|
||||
font-size: 1.25em;
|
||||
}
|
||||
}
|
||||
|
||||
.tab-pane {
|
||||
height:100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.settings-tab-content {
|
||||
height:100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
&.no-sidebar {
|
||||
.gh-header {
|
||||
>.row {
|
||||
> .row {
|
||||
&:last-child {
|
||||
padding-right: 90px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.tab-content {
|
||||
padding-top:0px;
|
||||
padding-top: 0px;
|
||||
}
|
||||
|
||||
.tabs {
|
||||
|
@ -2277,10 +2255,10 @@
|
|||
width: 50px;
|
||||
:nth-child(2) {
|
||||
// font-size: 0px;
|
||||
opacity:0;
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
>.col-auto {
|
||||
> .col-auto {
|
||||
width: 80px;
|
||||
}
|
||||
}
|
||||
|
@ -2290,4 +2268,4 @@
|
|||
|
||||
#hid___BV_tab_button__ {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,48 +1,46 @@
|
|||
import { app } from "./vueapp.js"
|
||||
import {CiderCache} from './cidercache.js'
|
||||
import {CiderFrontAPI} from './ciderfrontapi.js'
|
||||
import {simulateGamepad} from './gamepad.js'
|
||||
import {CiderAudio} from '../audio/cideraudio.js'
|
||||
import {Events} from './events.js'
|
||||
import { wsapi } from "./wsapi_interop.js"
|
||||
import { MusicKitTools } from "./musickittools.js"
|
||||
import { spawnMica } from "./mica.js"
|
||||
import { svgIcon } from './components/svg-icon.js'
|
||||
import { sidebarLibraryItem } from './components/sidebar-library-item.js'
|
||||
|
||||
import { app } from "./vueapp.js";
|
||||
import { CiderCache } from "./cidercache.js";
|
||||
import { CiderFrontAPI } from "./ciderfrontapi.js";
|
||||
import { simulateGamepad } from "./gamepad.js";
|
||||
import { CiderAudio } from "../audio/cideraudio.js";
|
||||
import { Events } from "./events.js";
|
||||
import { wsapi } from "./wsapi_interop.js";
|
||||
import { MusicKitTools } from "./musickittools.js";
|
||||
import { spawnMica } from "./mica.js";
|
||||
import { svgIcon } from "./components/svg-icon.js";
|
||||
import { sidebarLibraryItem } from "./components/sidebar-library-item.js";
|
||||
|
||||
// Define window objects
|
||||
window.app = app
|
||||
window.MusicKitTools = MusicKitTools
|
||||
window.CiderAudio = CiderAudio
|
||||
window.CiderCache = CiderCache
|
||||
window.CiderFrontAPI = CiderFrontAPI
|
||||
window.wsapi = wsapi
|
||||
window.app = app;
|
||||
window.MusicKitTools = MusicKitTools;
|
||||
window.CiderAudio = CiderAudio;
|
||||
window.CiderCache = CiderCache;
|
||||
window.CiderFrontAPI = CiderFrontAPI;
|
||||
window.wsapi = wsapi;
|
||||
|
||||
if (app.cfg.advanced.disableLogging === true) {
|
||||
window.console = {
|
||||
log: function() {},
|
||||
error: function() {},
|
||||
warn: function() {},
|
||||
assert: function() {},
|
||||
debug: function() {}
|
||||
}
|
||||
window.console = {
|
||||
log: function () {},
|
||||
error: function () {},
|
||||
warn: function () {},
|
||||
assert: function () {},
|
||||
debug: function () {},
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
// Mount Vue to #app
|
||||
app.$mount("#app")
|
||||
app.$mount("#app");
|
||||
|
||||
// Init CiderAudio and force audiocontext
|
||||
if (app.cfg.advanced.AudioContext != true) {
|
||||
app.cfg.advanced.AudioContext = true;
|
||||
window.location.reload();
|
||||
app.cfg.advanced.AudioContext = true;
|
||||
window.location.reload();
|
||||
}
|
||||
|
||||
CiderAudio.init()
|
||||
CiderAudio.init();
|
||||
|
||||
// Import gamepad support
|
||||
app.simulateGamepad = simulateGamepad
|
||||
app.spawnMica = spawnMica
|
||||
app.simulateGamepad = simulateGamepad;
|
||||
app.spawnMica = spawnMica;
|
||||
|
||||
Events.InitEvents()
|
||||
Events.InitEvents();
|
||||
|
|
|
@ -1,24 +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
|
||||
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}
|
||||
export { CiderCache };
|
||||
|
|
|
@ -1,32 +1,31 @@
|
|||
const CiderFrontAPI = {
|
||||
Objects: {
|
||||
MenuEntry: function () {
|
||||
this.id = ""
|
||||
this.name = ""
|
||||
this.onClick = () => {
|
||||
}
|
||||
}
|
||||
Objects: {
|
||||
MenuEntry: function () {
|
||||
this.id = "";
|
||||
this.name = "";
|
||||
this.onClick = () => {};
|
||||
},
|
||||
AddMenuEntry(entry) {
|
||||
app.pluginMenuEntries.push(entry)
|
||||
app.pluginInstalled = true
|
||||
},
|
||||
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;
|
||||
},
|
||||
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}
|
||||
export { CiderFrontAPI };
|
||||
|
|
|
@ -1,46 +1,45 @@
|
|||
import {html} from "../html.js"
|
||||
import { html } from "../html.js";
|
||||
|
||||
export const sidebarLibraryItem = Vue.component("sidebar-library-item", {
|
||||
template: html`
|
||||
<button class="app-sidebar-item"
|
||||
:class="$root.getSidebarItemClass(page)" @click="$root.setWindowHash(page)">
|
||||
<svg-icon :url="svgIconData" :name="'sidebar-' + svgIconName" v-if="svgIconData != ''"/>
|
||||
<span class="sidebar-item-text">{{ name }}</span>
|
||||
</button>
|
||||
`,
|
||||
props: {
|
||||
name: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
page: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
svgIcon: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: "",
|
||||
},
|
||||
svgIconName: {
|
||||
type: String,
|
||||
required: false
|
||||
},
|
||||
cdClick: {
|
||||
type: Function,
|
||||
required: false,
|
||||
},
|
||||
template: html`
|
||||
<button class="app-sidebar-item" :class="$root.getSidebarItemClass(page)" @click="$root.setWindowHash(page)">
|
||||
<svg-icon :url="svgIconData" :name="'sidebar-' + svgIconName" v-if="svgIconData != ''" />
|
||||
<span class="sidebar-item-text">{{ name }}</span>
|
||||
</button>
|
||||
`,
|
||||
props: {
|
||||
name: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
data: function () {
|
||||
return {
|
||||
app: app,
|
||||
svgIconData: "",
|
||||
};
|
||||
page: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
async mounted() {
|
||||
if (this.svgIcon) {
|
||||
this.svgIconData = this.svgIcon;
|
||||
}
|
||||
svgIcon: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: "",
|
||||
},
|
||||
methods: {},
|
||||
})
|
||||
svgIconName: {
|
||||
type: String,
|
||||
required: false,
|
||||
},
|
||||
cdClick: {
|
||||
type: Function,
|
||||
required: false,
|
||||
},
|
||||
},
|
||||
data: function () {
|
||||
return {
|
||||
app: app,
|
||||
svgIconData: "",
|
||||
};
|
||||
},
|
||||
async mounted() {
|
||||
if (this.svgIcon) {
|
||||
this.svgIconData = this.svgIcon;
|
||||
}
|
||||
},
|
||||
methods: {},
|
||||
});
|
||||
|
|
|
@ -1,22 +1,20 @@
|
|||
import {html} from "../html.js"
|
||||
import { html } from "../html.js";
|
||||
|
||||
export const svgIcon = Vue.component("svg-icon", {
|
||||
template: html`
|
||||
<div class="_svg-icon" :class="classes" :svg-name="name" :style="{'--icon': 'url(' + url + ')'}"></div>
|
||||
`,
|
||||
props: {
|
||||
name: {
|
||||
type: String,
|
||||
required: false
|
||||
},
|
||||
classes: {
|
||||
type: String,
|
||||
required: false
|
||||
},
|
||||
url: {
|
||||
type: String,
|
||||
required: true,
|
||||
default: "./assets/repeat.svg"
|
||||
}
|
||||
}
|
||||
})
|
||||
template: html` <div class="_svg-icon" :class="classes" :svg-name="name" :style="{'--icon': 'url(' + url + ')'}"></div> `,
|
||||
props: {
|
||||
name: {
|
||||
type: String,
|
||||
required: false,
|
||||
},
|
||||
classes: {
|
||||
type: String,
|
||||
required: false,
|
||||
},
|
||||
url: {
|
||||
type: String,
|
||||
required: true,
|
||||
default: "./assets/repeat.svg",
|
||||
},
|
||||
},
|
||||
});
|
||||
|
|
|
@ -1,98 +1,94 @@
|
|||
const Events = {
|
||||
InitEvents() {
|
||||
const app = window.app
|
||||
InitEvents() {
|
||||
const app = window.app;
|
||||
|
||||
// add event listener for when window.location.hash changes
|
||||
window.addEventListener("hashchange", function () {
|
||||
app.page = "blank"
|
||||
setTimeout(()=>{
|
||||
app.appRoute(window.location.hash)
|
||||
}, 100)
|
||||
// add event listener for when window.location.hash changes
|
||||
window.addEventListener("hashchange", function () {
|
||||
app.page = "blank";
|
||||
setTimeout(() => {
|
||||
app.appRoute(window.location.hash);
|
||||
}, 100);
|
||||
});
|
||||
|
||||
window.addEventListener("mouseup", (e) => {
|
||||
if (e.button === 3) {
|
||||
e.preventDefault();
|
||||
app.navigateBack();
|
||||
} else if (e.button === 4) {
|
||||
e.preventDefault();
|
||||
app.navigateForward();
|
||||
}
|
||||
});
|
||||
|
||||
document.addEventListener("keydown", async function (event) {
|
||||
// CTRL + R
|
||||
if (event.keyCode === 82 && event.ctrlKey) {
|
||||
event.preventDefault();
|
||||
app.confirm(app.getLz("term.reload"), (res) => {
|
||||
if (res) {
|
||||
window.location.reload();
|
||||
}
|
||||
});
|
||||
|
||||
window.addEventListener("mouseup", (e) => {
|
||||
if (e.button === 3) {
|
||||
e.preventDefault()
|
||||
app.navigateBack()
|
||||
} else if (e.button === 4) {
|
||||
e.preventDefault()
|
||||
app.navigateForward()
|
||||
}
|
||||
}
|
||||
// CTRL + SHIFT + R
|
||||
if (event.keyCode === 82 && event.ctrlKey && event.shiftKey) {
|
||||
event.preventDefault();
|
||||
window.location.reload();
|
||||
}
|
||||
// CTRL + E
|
||||
if (event.keyCode === 69 && event.ctrlKey) {
|
||||
app.invokeDrawer("queue");
|
||||
}
|
||||
// CTRL+H
|
||||
if (event.keyCode === 72 && event.ctrlKey) {
|
||||
app.appRoute("home");
|
||||
}
|
||||
// CTRL+SHIFT+H
|
||||
if (event.ctrlKey && event.shiftKey && event.keyCode == 72) {
|
||||
let hist = await app.mk.api.v3.music(`/v1/me/recent/played/tracks`, {
|
||||
l: app.mklang,
|
||||
});
|
||||
app.showCollection(hist.data, app.getLz("term.history"));
|
||||
}
|
||||
if (event.ctrlKey && event.keyCode == 121) {
|
||||
try {
|
||||
app.mk._services.mediaItemPlayback._currentPlayer.stop();
|
||||
} catch (e) {}
|
||||
try {
|
||||
app.mk._services.mediaItemPlayback._currentPlayer.destroy();
|
||||
} catch (e) {}
|
||||
}
|
||||
if (event.ctrlKey && event.keyCode == 122) {
|
||||
try {
|
||||
ipcRenderer.send("detachDT", "");
|
||||
} catch (e) {}
|
||||
}
|
||||
// Prevent Scrolling on spacebar
|
||||
if (event.keyCode === 32 && event.target === document.body) {
|
||||
event.preventDefault();
|
||||
app.SpacePause();
|
||||
}
|
||||
});
|
||||
|
||||
document.addEventListener('keydown', async function (event) {
|
||||
// CTRL + R
|
||||
if (event.keyCode === 82 && event.ctrlKey) {
|
||||
event.preventDefault()
|
||||
app.confirm(app.getLz('term.reload'), (res)=>{
|
||||
if (res) {
|
||||
window.location.reload()
|
||||
}
|
||||
})
|
||||
}
|
||||
// CTRL + SHIFT + R
|
||||
if (event.keyCode === 82 && event.ctrlKey && event.shiftKey) {
|
||||
event.preventDefault()
|
||||
window.location.reload()
|
||||
}
|
||||
// CTRL + E
|
||||
if (event.keyCode === 69 && event.ctrlKey) {
|
||||
app.invokeDrawer('queue')
|
||||
}
|
||||
// CTRL+H
|
||||
if (event.keyCode === 72 && event.ctrlKey) {
|
||||
app.appRoute("home")
|
||||
}
|
||||
// CTRL+SHIFT+H
|
||||
if (event.ctrlKey && event.shiftKey && event.keyCode == 72) {
|
||||
let hist = await app.mk.api.v3.music(`/v1/me/recent/played/tracks`, {
|
||||
l: app.mklang
|
||||
})
|
||||
app.showCollection(hist.data, app.getLz('term.history'))
|
||||
}
|
||||
if (event.ctrlKey && event.keyCode == 121) {
|
||||
try {
|
||||
app.mk._services.mediaItemPlayback._currentPlayer.stop()
|
||||
} catch (e) {
|
||||
}
|
||||
try {
|
||||
app.mk._services.mediaItemPlayback._currentPlayer.destroy()
|
||||
} catch (e) {
|
||||
}
|
||||
}
|
||||
if (event.ctrlKey && event.keyCode == 122) {
|
||||
try {
|
||||
ipcRenderer.send('detachDT', '')
|
||||
} catch (e) {
|
||||
}
|
||||
}
|
||||
// Prevent Scrolling on spacebar
|
||||
if (event.keyCode === 32 && event.target === document.body) {
|
||||
event.preventDefault()
|
||||
app.SpacePause()
|
||||
// Hang Timer
|
||||
app.hangtimer = setTimeout(() => {
|
||||
if (confirm("Cider is not responding. Reload the app?")) {
|
||||
window.location.reload();
|
||||
}
|
||||
}, 10000);
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
refreshFocus();
|
||||
// Refresh Focus
|
||||
function refreshFocus() {
|
||||
if (document.hasFocus() == false) {
|
||||
app.windowFocus(false);
|
||||
} else {
|
||||
app.windowFocus(true);
|
||||
}
|
||||
setTimeout(refreshFocus, 200);
|
||||
}
|
||||
}
|
||||
|
||||
export {Events}
|
||||
refreshFocus();
|
||||
},
|
||||
};
|
||||
|
||||
export { Events };
|
||||
|
|
|
@ -1,327 +1,313 @@
|
|||
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;
|
||||
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 cursorSpeed = cursorSpeedPvt;
|
||||
|
||||
let lastButtonPress = {
|
||||
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 sounds = {
|
||||
Confirm: new Audio("./sounds/confirm.ogg"),
|
||||
Menu: new Audio("./sounds/btn1.ogg"),
|
||||
Hover: new Audio("./sounds/hover.ogg")
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
if (gp.axes[1] > stickDeadZone) {
|
||||
cursorPos[1] += gp.axes[1] * cursorSpeed;
|
||||
} else if (gp.axes[1] < -stickDeadZone) {
|
||||
cursorPos[1] += gp.axes[1] * cursorSpeed;
|
||||
}
|
||||
|
||||
// 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 });
|
||||
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;
|
||||
}
|
||||
|
||||
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()
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
cursorPos[0] -= cursorSpeed
|
||||
break;
|
||||
case "ArrowRight":
|
||||
e.preventDefault()
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
$(".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}
|
||||
export { simulateGamepad };
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
export function html (str) {
|
||||
return str[0]
|
||||
}
|
||||
export function html(str) {
|
||||
return str[0];
|
||||
}
|
||||
|
|
|
@ -31,9 +31,9 @@ async function spawnMica() {
|
|||
}
|
||||
if (micaCache.path == imgSrc.path) {
|
||||
imgSrc = micaCache;
|
||||
}else{
|
||||
} else {
|
||||
imgSrc = await ipcRenderer.sendSync("get-wallpaper", {
|
||||
blurAmount: 256
|
||||
blurAmount: 256,
|
||||
});
|
||||
CiderCache.putCache("mica-cache", imgSrc);
|
||||
}
|
||||
|
@ -51,10 +51,7 @@ async function spawnMica() {
|
|||
cb();
|
||||
}
|
||||
// window size change
|
||||
if (
|
||||
lastScreenWidth !== window.innerWidth ||
|
||||
lastScreenHeight !== window.innerHeight
|
||||
) {
|
||||
if (lastScreenWidth !== window.innerWidth || lastScreenHeight !== window.innerHeight) {
|
||||
lastScreenWidth = window.innerWidth;
|
||||
lastScreenHeight = window.innerHeight;
|
||||
cb();
|
||||
|
|
|
@ -1,56 +1,44 @@
|
|||
const MusicKitTools = {
|
||||
async v3Backend({
|
||||
route = "", getBody = {}, options = {}
|
||||
}) {
|
||||
return await (await ipcRenderer.invoke("mkv3", {
|
||||
token: MusicKit.getInstance().developerToken,
|
||||
route: route,
|
||||
mediaToken: MusicKit.getInstance().musicUserToken,
|
||||
GETBody: getBody
|
||||
}))
|
||||
},
|
||||
async v3Continuous({
|
||||
href,
|
||||
options = {},
|
||||
reqOptions = {},
|
||||
onProgress = () => {
|
||||
},
|
||||
onError = () => {
|
||||
},
|
||||
onSuccess = () => {
|
||||
}
|
||||
} = {}) {
|
||||
let returnData = []
|
||||
async v3Backend({ route = "", getBody = {}, options = {} }) {
|
||||
return await await ipcRenderer.invoke("mkv3", {
|
||||
token: MusicKit.getInstance().developerToken,
|
||||
route: route,
|
||||
mediaToken: MusicKit.getInstance().musicUserToken,
|
||||
GETBody: getBody,
|
||||
});
|
||||
},
|
||||
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)
|
||||
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
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export {MusicKitTools}
|
||||
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 };
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,38 +1,38 @@
|
|||
const store = new Vuex.Store({
|
||||
state: {
|
||||
windowRelativeScale: 1,
|
||||
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")
|
||||
},
|
||||
pageState: {
|
||||
recentlyAdded: {
|
||||
loaded: false,
|
||||
nextUrl: null,
|
||||
items: [],
|
||||
size: "normal"
|
||||
},
|
||||
settings: {
|
||||
currentTabIndex: 0,
|
||||
fullscreen: false
|
||||
}
|
||||
},
|
||||
artwork: {
|
||||
playerLCD: ""
|
||||
}
|
||||
state: {
|
||||
windowRelativeScale: 1,
|
||||
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")
|
||||
},
|
||||
mutations: {
|
||||
resetRecentlyAdded(state) {
|
||||
state.pageState.recentlyAdded.loaded = false;
|
||||
state.pageState.recentlyAdded.nextUrl = null;
|
||||
state.pageState.recentlyAdded.items = [];
|
||||
},
|
||||
setLCDArtwork(state, artwork) {
|
||||
state.artwork.playerLCD = artwork
|
||||
}
|
||||
}
|
||||
})
|
||||
pageState: {
|
||||
recentlyAdded: {
|
||||
loaded: false,
|
||||
nextUrl: null,
|
||||
items: [],
|
||||
size: "normal",
|
||||
},
|
||||
settings: {
|
||||
currentTabIndex: 0,
|
||||
fullscreen: false,
|
||||
},
|
||||
},
|
||||
artwork: {
|
||||
playerLCD: "",
|
||||
},
|
||||
},
|
||||
mutations: {
|
||||
resetRecentlyAdded(state) {
|
||||
state.pageState.recentlyAdded.loaded = false;
|
||||
state.pageState.recentlyAdded.nextUrl = null;
|
||||
state.pageState.recentlyAdded.items = [];
|
||||
},
|
||||
setLCDArtwork(state, artwork) {
|
||||
state.artwork.playerLCD = artwork;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export {store}
|
||||
export { store };
|
||||
|
|
|
@ -1,194 +1,230 @@
|
|||
const wsapi = {
|
||||
cache: {playParams: {id: 0}, status: null, remainingTime: 0},
|
||||
playbackCache: {status: null, time: Date.now()},
|
||||
async v3(encoded = "") {
|
||||
let decoded = atob(encoded);
|
||||
let json = JSON.parse(decoded);
|
||||
console.log(json)
|
||||
let response = await (await MusicKit.getInstance().api.v3.music(json.route, json.body, json.options))
|
||||
let ret = response.data
|
||||
return JSON.stringify(ret)
|
||||
},
|
||||
search(term, limit) {
|
||||
MusicKit.getInstance().api.search(term, {limit: limit, types: 'songs,artists,albums,playlists'}).then((results)=>{
|
||||
ipcRenderer.send('wsapi-returnSearch', JSON.stringify(results))
|
||||
})
|
||||
},
|
||||
searchLibrary(term, limit) {
|
||||
MusicKit.getInstance().api.library.search(term, {limit: limit, types: 'library-songs,library-artists,library-albums,library-playlists'}).then((results)=>{
|
||||
ipcRenderer.send('wsapi-returnSearchLibrary', JSON.stringify(results))
|
||||
})
|
||||
},
|
||||
getAttributes: function () {
|
||||
const mk = MusicKit.getInstance();
|
||||
const nowPlayingItem = mk.nowPlayingItem;
|
||||
const isPlayingExport = mk.isPlaying;
|
||||
const remainingTimeExport = mk.currentPlaybackTimeRemaining;
|
||||
const attributes = (nowPlayingItem != null ? nowPlayingItem.attributes : {});
|
||||
cache: { playParams: { id: 0 }, status: null, remainingTime: 0 },
|
||||
playbackCache: { status: null, time: Date.now() },
|
||||
async v3(encoded = "") {
|
||||
let decoded = atob(encoded);
|
||||
let json = JSON.parse(decoded);
|
||||
console.log(json);
|
||||
let response = await await MusicKit.getInstance().api.v3.music(json.route, json.body, json.options);
|
||||
let ret = response.data;
|
||||
return JSON.stringify(ret);
|
||||
},
|
||||
search(term, limit) {
|
||||
MusicKit.getInstance()
|
||||
.api.search(term, {
|
||||
limit: limit,
|
||||
types: "songs,artists,albums,playlists",
|
||||
})
|
||||
.then((results) => {
|
||||
ipcRenderer.send("wsapi-returnSearch", JSON.stringify(results));
|
||||
});
|
||||
},
|
||||
searchLibrary(term, limit) {
|
||||
MusicKit.getInstance()
|
||||
.api.library.search(term, {
|
||||
limit: limit,
|
||||
types: "library-songs,library-artists,library-albums,library-playlists",
|
||||
})
|
||||
.then((results) => {
|
||||
ipcRenderer.send("wsapi-returnSearchLibrary", JSON.stringify(results));
|
||||
});
|
||||
},
|
||||
getAttributes: function () {
|
||||
const mk = MusicKit.getInstance();
|
||||
const nowPlayingItem = mk.nowPlayingItem;
|
||||
const isPlayingExport = mk.isPlaying;
|
||||
const remainingTimeExport = mk.currentPlaybackTimeRemaining;
|
||||
const attributes = nowPlayingItem != null ? nowPlayingItem.attributes : {};
|
||||
|
||||
attributes.status = isPlayingExport ? isPlayingExport : false;
|
||||
attributes.name = attributes.name ? attributes.name : 'No Title Found';
|
||||
attributes.artwork = attributes.artwork ? attributes.artwork : {url: ''};
|
||||
attributes.artwork.url = attributes.artwork.url ? attributes.artwork.url : '';
|
||||
attributes.playParams = attributes.playParams ? attributes.playParams : {id: 'no-id-found'};
|
||||
attributes.playParams.id = attributes.playParams.id ? attributes.playParams.id : 'no-id-found';
|
||||
attributes.albumName = attributes.albumName ? attributes.albumName : '';
|
||||
attributes.artistName = attributes.artistName ? attributes.artistName : '';
|
||||
attributes.genreNames = attributes.genreNames ? attributes.genreNames : [];
|
||||
attributes.remainingTime = remainingTimeExport ? (remainingTimeExport * 1000) : 0;
|
||||
attributes.durationInMillis = attributes.durationInMillis ? attributes.durationInMillis : 0;
|
||||
attributes.startTime = Date.now();
|
||||
attributes.endTime = attributes.endTime ? attributes.endTime : Date.now();
|
||||
attributes.volume = mk.volume;
|
||||
attributes.shuffleMode = mk.shuffleMode;
|
||||
attributes.repeatMode = mk.repeatMode;
|
||||
attributes.autoplayEnabled = mk.autoplayEnabled;
|
||||
return attributes
|
||||
},
|
||||
moveQueueItem(oldPosition, newPosition) {
|
||||
MusicKit.getInstance().queue._queueItems.splice(newPosition,0,MusicKit.getInstance().queue._queueItems.splice(oldPosition,1)[0])
|
||||
MusicKit.getInstance().queue._reindex()
|
||||
},
|
||||
setAutoplay(value) {
|
||||
MusicKit.getInstance().autoplayEnabled = value
|
||||
},
|
||||
returnDynamic(data, type) {
|
||||
ipcRenderer.send('wsapi-returnDynamic', JSON.stringify(data), type)
|
||||
},
|
||||
musickitApi(method, id, params, library = false) {
|
||||
if (library) {
|
||||
MusicKit.getInstance().api.library[method](id, params).then((results)=>{
|
||||
ipcRenderer.send('wsapi-returnMusicKitApi', JSON.stringify(results), method)
|
||||
})
|
||||
} else {
|
||||
MusicKit.getInstance().api[method](id, params).then((results)=>{
|
||||
ipcRenderer.send('wsapi-returnMusicKitApi', JSON.stringify(results), method)
|
||||
})
|
||||
}
|
||||
},
|
||||
getPlaybackState () {
|
||||
ipcRenderer.send('wsapi-updatePlaybackState', MusicKitInterop.getAttributes());
|
||||
},
|
||||
getLyrics() {
|
||||
ipcRenderer.send('wsapi-returnLyrics',JSON.stringify(app.lyrics));
|
||||
},
|
||||
getQueue() {
|
||||
ipcRenderer.send('wsapi-returnQueue', JSON.stringify(MusicKit.getInstance().queue))
|
||||
},
|
||||
playNext(type, id) {
|
||||
var request = {}
|
||||
request[type] = id
|
||||
MusicKit.getInstance().playNext(request)
|
||||
},
|
||||
playLater(type, id) {
|
||||
var request = {}
|
||||
request[type] = id
|
||||
MusicKit.getInstance().playLater(request)
|
||||
},
|
||||
love() {
|
||||
|
||||
},
|
||||
playTrackById(id, kind = "song") {
|
||||
MusicKit.getInstance().setQueue({ [kind]: id , 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"],parameters : {l : app.mklang} }).then(function (queue) {
|
||||
MusicKit.getInstance().play()
|
||||
})
|
||||
})
|
||||
},
|
||||
toggleShuffle() {
|
||||
MusicKit.getInstance().shuffleMode = MusicKit.getInstance().shuffleMode === 0 ? 1 : 0
|
||||
},
|
||||
togglePlayPause() {
|
||||
app.mk.isPlaying ? app.mk.pause() : app.mk.play()
|
||||
},
|
||||
toggleRepeat() {
|
||||
if (MusicKit.getInstance().repeatMode == 0) {
|
||||
MusicKit.getInstance().repeatMode = 1
|
||||
} else if (MusicKit.getInstance().repeatMode == 1){
|
||||
MusicKit.getInstance().repeatMode = 2
|
||||
} else {
|
||||
MusicKit.getInstance().repeatMode = 0
|
||||
}
|
||||
},
|
||||
getmaxVolume() {
|
||||
ipcRenderer.send('wsapi-returnvolumeMax',JSON.stringify(app.cfg.audio.maxVolume));
|
||||
},
|
||||
getLibraryStatus(kind, id) {
|
||||
if (kind === undefined || id === "no-id-found") return;
|
||||
|
||||
let truekind = (!kind.endsWith("s")) ? (kind + "s") : kind;
|
||||
app.mk.api.v3.music(`/v1/catalog/${app.mk.storefrontId}/?ids[${truekind}]=${id}`, {
|
||||
relate: "library",
|
||||
fields: "inLibrary"
|
||||
}).then(data => {
|
||||
const res = data.data.data[0];
|
||||
const inLibrary = res && res.attributes && res.attributes.inLibrary;
|
||||
|
||||
app.getRating({ type: truekind, id: id }).then(rating => {
|
||||
ipcRenderer.send('wsapi-libraryStatus', inLibrary, rating);
|
||||
})
|
||||
})
|
||||
},
|
||||
rate(kind, id, rating) {
|
||||
if (kind === undefined || id === "no-id-found") return;
|
||||
|
||||
let truekind = (!kind.endsWith("s")) ? (kind + "s") : kind;
|
||||
|
||||
if (rating === 0) {
|
||||
app.mk.api.v3.music(`/v1/me/ratings/${truekind}/${id}`, {}, {
|
||||
fetchOptions: {
|
||||
method: "DELETE",
|
||||
}
|
||||
}).then(function () {
|
||||
ipcRenderer.send('wsapi-rate', kind, id, rating);
|
||||
})
|
||||
} else {
|
||||
app.mk.api.v3.music(`/v1/me/ratings/${truekind}/${id}`, {}, {
|
||||
fetchOptions: {
|
||||
method: "PUT",
|
||||
body: JSON.stringify({
|
||||
"type": "rating",
|
||||
"attributes": {
|
||||
"value": rating
|
||||
}
|
||||
})
|
||||
}
|
||||
}).then(function () {
|
||||
ipcRenderer.send('wsapi-rate', kind, id, rating);
|
||||
})
|
||||
}
|
||||
},
|
||||
changeLibrary(kind, id, shouldAdd) {
|
||||
if (shouldAdd) {
|
||||
app.addToLibrary(id);
|
||||
ipcRenderer.send('wsapi-change-library', kind, id, shouldAdd);
|
||||
} else {
|
||||
let truekind = (!kind.endsWith("s")) ? (kind + "s") : kind;
|
||||
|
||||
app.mk.api.v3.music(`/v1/catalog/${app.mk.storefrontId}/?ids[${truekind}]=${id}`, {
|
||||
relate: "library",
|
||||
fields: "inLibrary"
|
||||
})
|
||||
.then(res => {
|
||||
res = res.data.data[0]
|
||||
if (res && res.relationships && res.relationships.library && res.relationships.library.data) {
|
||||
const item = res.relationships.library.data[0];
|
||||
|
||||
if (item) {
|
||||
app.removeFromLibrary(kind, item.id)
|
||||
}
|
||||
|
||||
ipcRenderer.send('wsapi-change-library', kind, id, shouldAdd);
|
||||
}
|
||||
});
|
||||
}
|
||||
attributes.status = isPlayingExport ? isPlayingExport : false;
|
||||
attributes.name = attributes.name ? attributes.name : "No Title Found";
|
||||
attributes.artwork = attributes.artwork ? attributes.artwork : { url: "" };
|
||||
attributes.artwork.url = attributes.artwork.url ? attributes.artwork.url : "";
|
||||
attributes.playParams = attributes.playParams ? attributes.playParams : { id: "no-id-found" };
|
||||
attributes.playParams.id = attributes.playParams.id ? attributes.playParams.id : "no-id-found";
|
||||
attributes.albumName = attributes.albumName ? attributes.albumName : "";
|
||||
attributes.artistName = attributes.artistName ? attributes.artistName : "";
|
||||
attributes.genreNames = attributes.genreNames ? attributes.genreNames : [];
|
||||
attributes.remainingTime = remainingTimeExport ? remainingTimeExport * 1000 : 0;
|
||||
attributes.durationInMillis = attributes.durationInMillis ? attributes.durationInMillis : 0;
|
||||
attributes.startTime = Date.now();
|
||||
attributes.endTime = attributes.endTime ? attributes.endTime : Date.now();
|
||||
attributes.volume = mk.volume;
|
||||
attributes.shuffleMode = mk.shuffleMode;
|
||||
attributes.repeatMode = mk.repeatMode;
|
||||
attributes.autoplayEnabled = mk.autoplayEnabled;
|
||||
return attributes;
|
||||
},
|
||||
moveQueueItem(oldPosition, newPosition) {
|
||||
MusicKit.getInstance().queue._queueItems.splice(newPosition, 0, MusicKit.getInstance().queue._queueItems.splice(oldPosition, 1)[0]);
|
||||
MusicKit.getInstance().queue._reindex();
|
||||
},
|
||||
setAutoplay(value) {
|
||||
MusicKit.getInstance().autoplayEnabled = value;
|
||||
},
|
||||
returnDynamic(data, type) {
|
||||
ipcRenderer.send("wsapi-returnDynamic", JSON.stringify(data), type);
|
||||
},
|
||||
musickitApi(method, id, params, library = false) {
|
||||
if (library) {
|
||||
MusicKit.getInstance()
|
||||
.api.library[method](id, params)
|
||||
.then((results) => {
|
||||
ipcRenderer.send("wsapi-returnMusicKitApi", JSON.stringify(results), method);
|
||||
});
|
||||
} else {
|
||||
MusicKit.getInstance()
|
||||
.api[method](id, params)
|
||||
.then((results) => {
|
||||
ipcRenderer.send("wsapi-returnMusicKitApi", JSON.stringify(results), method);
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
getPlaybackState() {
|
||||
ipcRenderer.send("wsapi-updatePlaybackState", MusicKitInterop.getAttributes());
|
||||
},
|
||||
getLyrics() {
|
||||
ipcRenderer.send("wsapi-returnLyrics", JSON.stringify(app.lyrics));
|
||||
},
|
||||
getQueue() {
|
||||
ipcRenderer.send("wsapi-returnQueue", JSON.stringify(MusicKit.getInstance().queue));
|
||||
},
|
||||
playNext(type, id) {
|
||||
var request = {};
|
||||
request[type] = id;
|
||||
MusicKit.getInstance().playNext(request);
|
||||
},
|
||||
playLater(type, id) {
|
||||
var request = {};
|
||||
request[type] = id;
|
||||
MusicKit.getInstance().playLater(request);
|
||||
},
|
||||
love() {},
|
||||
playTrackById(id, kind = "song") {
|
||||
MusicKit.getInstance()
|
||||
.setQueue({ [kind]: id, 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"],
|
||||
parameters: { l: app.mklang },
|
||||
})
|
||||
.then(function (queue) {
|
||||
MusicKit.getInstance().play();
|
||||
});
|
||||
});
|
||||
},
|
||||
toggleShuffle() {
|
||||
MusicKit.getInstance().shuffleMode = MusicKit.getInstance().shuffleMode === 0 ? 1 : 0;
|
||||
},
|
||||
togglePlayPause() {
|
||||
app.mk.isPlaying ? app.mk.pause() : app.mk.play();
|
||||
},
|
||||
toggleRepeat() {
|
||||
if (MusicKit.getInstance().repeatMode == 0) {
|
||||
MusicKit.getInstance().repeatMode = 1;
|
||||
} else if (MusicKit.getInstance().repeatMode == 1) {
|
||||
MusicKit.getInstance().repeatMode = 2;
|
||||
} else {
|
||||
MusicKit.getInstance().repeatMode = 0;
|
||||
}
|
||||
},
|
||||
getmaxVolume() {
|
||||
ipcRenderer.send("wsapi-returnvolumeMax", JSON.stringify(app.cfg.audio.maxVolume));
|
||||
},
|
||||
getLibraryStatus(kind, id) {
|
||||
if (kind === undefined || id === "no-id-found") return;
|
||||
|
||||
export {wsapi}
|
||||
let truekind = !kind.endsWith("s") ? kind + "s" : kind;
|
||||
app.mk.api.v3
|
||||
.music(`/v1/catalog/${app.mk.storefrontId}/?ids[${truekind}]=${id}`, {
|
||||
relate: "library",
|
||||
fields: "inLibrary",
|
||||
})
|
||||
.then((data) => {
|
||||
const res = data.data.data[0];
|
||||
const inLibrary = res && res.attributes && res.attributes.inLibrary;
|
||||
|
||||
app.getRating({ type: truekind, id: id }).then((rating) => {
|
||||
ipcRenderer.send("wsapi-libraryStatus", inLibrary, rating);
|
||||
});
|
||||
});
|
||||
},
|
||||
rate(kind, id, rating) {
|
||||
if (kind === undefined || id === "no-id-found") return;
|
||||
|
||||
let truekind = !kind.endsWith("s") ? kind + "s" : kind;
|
||||
|
||||
if (rating === 0) {
|
||||
app.mk.api.v3
|
||||
.music(
|
||||
`/v1/me/ratings/${truekind}/${id}`,
|
||||
{},
|
||||
{
|
||||
fetchOptions: {
|
||||
method: "DELETE",
|
||||
},
|
||||
}
|
||||
)
|
||||
.then(function () {
|
||||
ipcRenderer.send("wsapi-rate", kind, id, rating);
|
||||
});
|
||||
} else {
|
||||
app.mk.api.v3
|
||||
.music(
|
||||
`/v1/me/ratings/${truekind}/${id}`,
|
||||
{},
|
||||
{
|
||||
fetchOptions: {
|
||||
method: "PUT",
|
||||
body: JSON.stringify({
|
||||
type: "rating",
|
||||
attributes: {
|
||||
value: rating,
|
||||
},
|
||||
}),
|
||||
},
|
||||
}
|
||||
)
|
||||
.then(function () {
|
||||
ipcRenderer.send("wsapi-rate", kind, id, rating);
|
||||
});
|
||||
}
|
||||
},
|
||||
changeLibrary(kind, id, shouldAdd) {
|
||||
if (shouldAdd) {
|
||||
app.addToLibrary(id);
|
||||
ipcRenderer.send("wsapi-change-library", kind, id, shouldAdd);
|
||||
} else {
|
||||
let truekind = !kind.endsWith("s") ? kind + "s" : kind;
|
||||
|
||||
app.mk.api.v3
|
||||
.music(`/v1/catalog/${app.mk.storefrontId}/?ids[${truekind}]=${id}`, {
|
||||
relate: "library",
|
||||
fields: "inLibrary",
|
||||
})
|
||||
.then((res) => {
|
||||
res = res.data.data[0];
|
||||
if (res && res.relationships && res.relationships.library && res.relationships.library.data) {
|
||||
const item = res.relationships.library.data[0];
|
||||
|
||||
if (item) {
|
||||
app.removeFromLibrary(kind, item.id);
|
||||
}
|
||||
|
||||
ipcRenderer.send("wsapi-change-library", kind, id, shouldAdd);
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
export { wsapi };
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,2 +1,68 @@
|
|||
if(!self.define){let e,i={};const s=(s,r)=>(s=new URL(s+".js",r).href,i[s]||new Promise((i=>{if("document"in self){const e=document.createElement("script");e.src=s,e.onload=i,document.head.appendChild(e)}else e=s,importScripts(s),i()})).then((()=>{let e=i[s];if(!e)throw new Error(`Module ${s} didn’t register its module`);return e})));self.define=(r,c)=>{const n=e||("document"in self?document.currentScript.src:"")||location.href;if(i[n])return;let o={};const t=e=>s(e,n),a={module:{uri:n},exports:o,require:t};i[n]=Promise.all(r.map((e=>a[e]||t(e)))).then((e=>(c(...e),o)))}}define(["./workbox-962786f2"],(function(e){"use strict";self.addEventListener("message",(e=>{e.data&&"SKIP_WAITING"===e.data.type&&self.skipWaiting()})),e.precacheAndRoute([{url:"ameframework.css",revision:"4bcc8646bb5742638fad52b94e231601"},{url:"apple-hls.js",revision:"2b74055662676b0fcc2d4a4bf994a9dc"},{url:"hlscider.js",revision:"cf7f512e83e32694f2c94f904714fe4c"},{url:"index_old.html",revision:"c21f3e9c5b015599d3ab07639f64a7a8"},{url:"index.js",revision:"8591a69fc9c975a063eb264b7447f173"},{url:"less.js",revision:"b6e574e4d680686786a28e7e71a17bbc"},{url:"musickit.js",revision:"211d80891c3336c1795cb83df58d4b63"},{url:"sortable.min.js",revision:"5cbc31ebec32adf60e27b76418e79d93"},{url:"style-old.css",revision:"aea9ea49df13f2deee42b68654aeea06"},{url:"todo.js",revision:"18d49fabcb96de8bd11455877d8eacb6"},{url:"vue-observe-visibility.min.js",revision:"5a52e761f6aa71b4f65a7b458f698b95"},{url:"vue.js",revision:"0a9a4681294d8c5f476687eea6e74842"},{url:"vuedraggable.umd.min.js",revision:"9a84fec5263bb510cee88e1c3b9583cc"}],{ignoreURLParametersMatching:[/^utm_/,/^fbclid$/,/^X-Amz-Algorithm/,/^X-Amz-Date/,/^X-Amz-SignedHeaders/,/^X-Amz-Expires/,/^X-Amz-Credential/,/^X-Amz-Signature/]}),e.registerRoute(/\.(?:png|jpg|jpeg|svg|webp)$/,new e.CacheFirst({cacheName:"imageinternet",plugins:[]}),"GET"),e.registerRoute(/https:\/\/is[0-9]-ssl\.mzstatic\.com\/image+/,new e.CacheFirst,"GET"),e.registerRoute(/^https:\/\/store-\d{3}\.blobstore\.apple\.com\/.{65}\/image+/,new e.CacheFirst,"GET")}));
|
||||
if (!self.define) {
|
||||
let e,
|
||||
i = {};
|
||||
const s = (s, r) => (
|
||||
(s = new URL(s + ".js", r).href),
|
||||
i[s] ||
|
||||
new Promise((i) => {
|
||||
if ("document" in self) {
|
||||
const e = document.createElement("script");
|
||||
(e.src = s), (e.onload = i), document.head.appendChild(e);
|
||||
} else (e = s), importScripts(s), i();
|
||||
}).then(() => {
|
||||
let e = i[s];
|
||||
if (!e) throw new Error(`Module ${s} didn’t register its module`);
|
||||
return e;
|
||||
})
|
||||
);
|
||||
self.define = (r, c) => {
|
||||
const n = e || ("document" in self ? document.currentScript.src : "") || location.href;
|
||||
if (i[n]) return;
|
||||
let o = {};
|
||||
const t = (e) => s(e, n),
|
||||
a = { module: { uri: n }, exports: o, require: t };
|
||||
i[n] = Promise.all(r.map((e) => a[e] || t(e))).then((e) => (c(...e), o));
|
||||
};
|
||||
}
|
||||
define(["./workbox-962786f2"], function (e) {
|
||||
"use strict";
|
||||
self.addEventListener("message", (e) => {
|
||||
e.data && "SKIP_WAITING" === e.data.type && self.skipWaiting();
|
||||
}),
|
||||
e.precacheAndRoute(
|
||||
[
|
||||
{
|
||||
url: "ameframework.css",
|
||||
revision: "4bcc8646bb5742638fad52b94e231601",
|
||||
},
|
||||
{ url: "apple-hls.js", revision: "2b74055662676b0fcc2d4a4bf994a9dc" },
|
||||
{ url: "hlscider.js", revision: "cf7f512e83e32694f2c94f904714fe4c" },
|
||||
{ url: "index_old.html", revision: "c21f3e9c5b015599d3ab07639f64a7a8" },
|
||||
{ url: "index.js", revision: "8591a69fc9c975a063eb264b7447f173" },
|
||||
{ url: "less.js", revision: "b6e574e4d680686786a28e7e71a17bbc" },
|
||||
{ url: "musickit.js", revision: "211d80891c3336c1795cb83df58d4b63" },
|
||||
{
|
||||
url: "sortable.min.js",
|
||||
revision: "5cbc31ebec32adf60e27b76418e79d93",
|
||||
},
|
||||
{ url: "style-old.css", revision: "aea9ea49df13f2deee42b68654aeea06" },
|
||||
{ url: "todo.js", revision: "18d49fabcb96de8bd11455877d8eacb6" },
|
||||
{
|
||||
url: "vue-observe-visibility.min.js",
|
||||
revision: "5a52e761f6aa71b4f65a7b458f698b95",
|
||||
},
|
||||
{ url: "vue.js", revision: "0a9a4681294d8c5f476687eea6e74842" },
|
||||
{
|
||||
url: "vuedraggable.umd.min.js",
|
||||
revision: "9a84fec5263bb510cee88e1c3b9583cc",
|
||||
},
|
||||
],
|
||||
{
|
||||
ignoreURLParametersMatching: [/^utm_/, /^fbclid$/, /^X-Amz-Algorithm/, /^X-Amz-Date/, /^X-Amz-SignedHeaders/, /^X-Amz-Expires/, /^X-Amz-Credential/, /^X-Amz-Signature/],
|
||||
}
|
||||
),
|
||||
e.registerRoute(/\.(?:png|jpg|jpeg|svg|webp)$/, new e.CacheFirst({ cacheName: "imageinternet", plugins: [] }), "GET"),
|
||||
e.registerRoute(/https:\/\/is[0-9]-ssl\.mzstatic\.com\/image+/, new e.CacheFirst(), "GET"),
|
||||
e.registerRoute(/^https:\/\/store-\d{3}\.blobstore\.apple\.com\/.{65}\/image+/, new e.CacheFirst(), "GET");
|
||||
});
|
||||
//# sourceMappingURL=sw.js.map
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
#app {
|
||||
--color1: #111;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1 +1 @@
|
|||
// Default theme
|
||||
// Default theme
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
body.notransparency::before {
|
||||
display: block;
|
||||
}
|
||||
display: block;
|
||||
}
|
||||
|
|
|
@ -1,41 +1,40 @@
|
|||
&:not(.modular-fs) {
|
||||
.app-drawer {
|
||||
border-radius: 0px;
|
||||
top: 0;
|
||||
right: 0;
|
||||
height: 100%;
|
||||
box-shadow: unset;
|
||||
border-left: 1px solid var(--color2);
|
||||
background: var(--color1);
|
||||
margin-right: 0px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.drawertransition-enter-active,
|
||||
.drawertransition-leave-active {
|
||||
transition: margin 0.25s var(--appleEase), opacity 0.25s var(--appleEase);
|
||||
}
|
||||
|
||||
.drawertransition-enter,
|
||||
.drawertransition-leave-to {
|
||||
margin-right: -300px;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 1120px) {
|
||||
.app-drawer {
|
||||
border-radius: 0px;
|
||||
top : 0;
|
||||
right : 0;
|
||||
height : 100%;
|
||||
box-shadow : unset;
|
||||
border-left : 1px solid var(--color2);
|
||||
background : var(--color1);
|
||||
margin-right : 0px;
|
||||
position : relative;
|
||||
margin-right: 0px;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.drawertransition-enter-active,
|
||||
.drawertransition-leave-active {
|
||||
transition: margin .25s var(--appleEase), opacity .25s var(--appleEase);
|
||||
transition: right 0.25s var(--appleEase), opacity 0.25s var(--appleEase);
|
||||
}
|
||||
|
||||
.drawertransition-enter,
|
||||
.drawertransition-leave-to {
|
||||
margin-right: -300px;
|
||||
right: -300px;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 1120px) {
|
||||
.app-drawer {
|
||||
margin-right: 0px;
|
||||
position : absolute;
|
||||
}
|
||||
|
||||
.drawertransition-enter-active,
|
||||
.drawertransition-leave-active {
|
||||
transition: right .25s var(--appleEase), opacity .25s var(--appleEase);
|
||||
}
|
||||
|
||||
.drawertransition-enter,
|
||||
.drawertransition-leave-to {
|
||||
right: -300px;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,141 +1,139 @@
|
|||
body {
|
||||
--ciderShadow-Generic : var(--mediaItemShadow);
|
||||
--mediaItemShadow-Shadow : var(--mediaItemShadow);
|
||||
--mediaItemShadow-ShadowSubtle: var(--mediaItemShadow);
|
||||
--ciderShadow-Generic: var(--mediaItemShadow);
|
||||
--mediaItemShadow-Shadow: var(--mediaItemShadow);
|
||||
--mediaItemShadow-ShadowSubtle: var(--mediaItemShadow);
|
||||
}
|
||||
|
||||
.bg-artwork-container {
|
||||
display : none;
|
||||
animation: none !important;
|
||||
display: none;
|
||||
animation: none !important;
|
||||
|
||||
.bg-artwork {
|
||||
animation: none !important;
|
||||
}
|
||||
.bg-artwork {
|
||||
animation: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.app-chrome:not(.chrome-bottom) {
|
||||
backdrop-filter: unset;
|
||||
background-color: var(--baseColor);
|
||||
backdrop-filter: unset;
|
||||
background-color: var(--baseColor);
|
||||
}
|
||||
|
||||
.menu-panel .menu-panel-body {
|
||||
background: rgb(30 30 30);
|
||||
background: rgb(30 30 30);
|
||||
}
|
||||
.menu-panel .menu-panel-body .menu-option::before {
|
||||
transition: unset!important;
|
||||
transition: unset !important;
|
||||
}
|
||||
|
||||
#app.twopanel .app-chrome:not(.chrome-bottom) .app-chrome--center .top-nav-group .app-sidebar-item:before {
|
||||
transition: unset!important;
|
||||
transition: unset !important;
|
||||
}
|
||||
|
||||
.playback-button:before, .playback-button--small:before {
|
||||
transition: unset!important;
|
||||
.playback-button:before,
|
||||
.playback-button--small:before {
|
||||
transition: unset !important;
|
||||
}
|
||||
|
||||
.floating-header {
|
||||
backdrop-filter: unset!important;
|
||||
background: rgb(0 0 0 / 80%)!important;
|
||||
backdrop-filter: unset !important;
|
||||
background: rgb(0 0 0 / 80%) !important;
|
||||
}
|
||||
|
||||
.replaycard-enter-active,
|
||||
.replaycard-leave-active {
|
||||
transition: unset;
|
||||
transition: unset;
|
||||
}
|
||||
|
||||
.replaycard-enter,
|
||||
.replaycard-leave-to {
|
||||
opacity : 0;
|
||||
transform: translateY(20px);
|
||||
opacity: 0;
|
||||
transform: translateY(20px);
|
||||
}
|
||||
|
||||
.modal-enter-active,
|
||||
.modal-leave-active {
|
||||
transition: unset;
|
||||
transition: unset;
|
||||
}
|
||||
|
||||
.modal-enter,
|
||||
.modal-leave-to {
|
||||
opacity : 0;
|
||||
transform: scale(1.10);
|
||||
opacity: 0;
|
||||
transform: scale(1.1);
|
||||
}
|
||||
|
||||
.wpfade-enter-active,
|
||||
.wpfade-leave-active {
|
||||
transition: opacity .1s var(--appleEase);
|
||||
transition: opacity 0.1s var(--appleEase);
|
||||
}
|
||||
|
||||
.wpfade-enter,
|
||||
.wpfade-leave-to {
|
||||
opacity: 0;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.wpfade_transform-enter-active,
|
||||
.wpfade_transform-leave-active {
|
||||
transition : unset;
|
||||
will-change: unset;
|
||||
transition: unset;
|
||||
will-change: unset;
|
||||
}
|
||||
|
||||
.wpfade_transform-enter {
|
||||
opacity : 0;
|
||||
transform : unset;
|
||||
will-change: unset;
|
||||
opacity: 0;
|
||||
transform: unset;
|
||||
will-change: unset;
|
||||
}
|
||||
|
||||
.wpfade_transform-leave-to {
|
||||
opacity : 0;
|
||||
transform : unset;
|
||||
will-change: unset;
|
||||
opacity: 0;
|
||||
transform: unset;
|
||||
will-change: unset;
|
||||
}
|
||||
|
||||
|
||||
.wpfade_transform_backwards-enter-active,
|
||||
.wpfade_transform_backwards-leave-active {
|
||||
transition: unset;
|
||||
transition: unset;
|
||||
}
|
||||
|
||||
.wpfade_transform_backwards-enter {
|
||||
opacity : 0;
|
||||
transform : unset;
|
||||
will-change: unset;
|
||||
opacity: 0;
|
||||
transform: unset;
|
||||
will-change: unset;
|
||||
}
|
||||
|
||||
.wpfade_transform_backwards-leave-to {
|
||||
opacity : 0;
|
||||
transform : unset;
|
||||
will-change: unset;
|
||||
opacity: 0;
|
||||
transform: unset;
|
||||
will-change: unset;
|
||||
}
|
||||
|
||||
.fabfade-enter-active,
|
||||
.fabfade-leave-active {
|
||||
transition: unset;
|
||||
transition: unset;
|
||||
}
|
||||
|
||||
.fabfade-enter,
|
||||
.fabfade-leave-to {
|
||||
opacity : 0;
|
||||
transform: scale(0.5);
|
||||
opacity: 0;
|
||||
transform: scale(0.5);
|
||||
}
|
||||
|
||||
.fsModeSwitch-enter-active,
|
||||
.fsModeSwitch-leave-active {
|
||||
transition: unset;
|
||||
transition: unset;
|
||||
}
|
||||
|
||||
.fsModeSwitch-enter,
|
||||
.fsModeSwitch-leave-to {
|
||||
transform: scale(1.10);
|
||||
opacity : 0;
|
||||
transform: scale(1.1);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
|
||||
.drawertransition-enter-active,
|
||||
.drawertransition-leave-active {
|
||||
transition: unset;
|
||||
transition: unset;
|
||||
}
|
||||
|
||||
.drawertransition-enter,
|
||||
.drawertransition-leave-to {
|
||||
right: -300px;
|
||||
}
|
||||
right: -300px;
|
||||
}
|
||||
|
|
|
@ -1,49 +1,47 @@
|
|||
@panelColorsFallback: rgb(30 30 30);
|
||||
@panelColors : rgb(30 30 30 / 45%);
|
||||
@panelColors: rgb(30 30 30 / 45%);
|
||||
|
||||
.menu-panel {
|
||||
.menu-panel-body {
|
||||
background-color: @panelColors;
|
||||
backdrop-filter : blur(32px) saturate(180%);
|
||||
.menu-panel-body {
|
||||
background-color: @panelColors;
|
||||
backdrop-filter: blur(32px) saturate(180%);
|
||||
|
||||
&.menu-panel-body-down {
|
||||
animation: menuInDown .10s var(--appleEase);
|
||||
}
|
||||
|
||||
&.menu-panel-body-up {
|
||||
animation: menuInUp .10s var(--appleEase);
|
||||
}
|
||||
|
||||
&.menu-panel-body-down {
|
||||
animation: menuInDown 0.1s var(--appleEase);
|
||||
}
|
||||
|
||||
@keyframes menuInUp {
|
||||
0% {
|
||||
opacity : 0;
|
||||
transform : translateY(-10px) translate3d(0,0,0);
|
||||
background: @panelColorsFallback;
|
||||
}
|
||||
&.menu-panel-body-up {
|
||||
animation: menuInUp 0.1s var(--appleEase);
|
||||
}
|
||||
}
|
||||
|
||||
100% {
|
||||
opacity : 1;
|
||||
transform : translateY(0);
|
||||
background: @panelColors;
|
||||
}
|
||||
@keyframes menuInUp {
|
||||
0% {
|
||||
opacity: 0;
|
||||
transform: translateY(-10px) translate3d(0, 0, 0);
|
||||
background: @panelColorsFallback;
|
||||
}
|
||||
|
||||
@keyframes menuInDown {
|
||||
0% {
|
||||
opacity : 0;
|
||||
transform : translateY(10px) translate3d(0,0,0);
|
||||
background: @panelColorsFallback;
|
||||
}
|
||||
100% {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
background: @panelColors;
|
||||
}
|
||||
}
|
||||
|
||||
100% {
|
||||
opacity : 1;
|
||||
transform : translateY(0);
|
||||
background: @panelColors;
|
||||
}
|
||||
@keyframes menuInDown {
|
||||
0% {
|
||||
opacity: 0;
|
||||
transform: translateY(10px) translate3d(0, 0, 0);
|
||||
background: @panelColorsFallback;
|
||||
}
|
||||
|
||||
100% {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
background: @panelColors;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.cd-mediaitem-square {
|
||||
|
@ -55,47 +53,46 @@
|
|||
}
|
||||
|
||||
.cd-mediaitem-square:not(.mediaitem-card) {
|
||||
transition : transform .2s var(--appleEase);
|
||||
transition-delay: .1s;
|
||||
transition: transform 0.2s var(--appleEase);
|
||||
transition-delay: 0.1s;
|
||||
|
||||
.artwork-container {
|
||||
}
|
||||
|
||||
.artwork-container {}
|
||||
.info-rect {
|
||||
}
|
||||
|
||||
.info-rect {}
|
||||
.artwork-container,
|
||||
.info-rect {
|
||||
transition: transform 0.22s var(--appleEase);
|
||||
transition-delay: 0.05s;
|
||||
}
|
||||
|
||||
.artwork-container,
|
||||
.info-rect {
|
||||
transition : transform .22s var(--appleEase);
|
||||
transition-delay: .05s;
|
||||
}
|
||||
.artwork-container {
|
||||
transform: scale(0.962) translateZ(0);
|
||||
transition: transform 0.1s var(--appleEase);
|
||||
transition-delay: 0s;
|
||||
transform-origin: center;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
.artwork-container {
|
||||
transform : scale(0.962) translateZ(0);
|
||||
transition : transform .1s var(--appleEase);
|
||||
transform: scale(1);
|
||||
transition: transform 0.1s var(--appleEase);
|
||||
transition-delay: 0s;
|
||||
transform-origin: center;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
.artwork-container {
|
||||
transform : scale(1.0);
|
||||
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);
|
||||
}
|
||||
.info-rect {
|
||||
z-index: 1;
|
||||
transition: transform 0.1s var(--appleEase);
|
||||
transition-delay: 0s;
|
||||
transform: translateY(8px) translate3d(0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
&:active {
|
||||
|
||||
}
|
||||
&:active {
|
||||
}
|
||||
}
|
||||
|
||||
.wpfade_transform-enter-active,
|
||||
|
@ -107,16 +104,15 @@
|
|||
|
||||
.wpfade_transform-enter {
|
||||
opacity: 0;
|
||||
transform: translateX(50%) translate3d(0,0,0);
|
||||
transform: translateX(50%) translate3d(0, 0, 0);
|
||||
will-change: opacity, transform;
|
||||
}
|
||||
.wpfade_transform-leave-to {
|
||||
opacity: 0;
|
||||
transform: translateX(-50%) translate3d(0,0,0);
|
||||
transform: translateX(-50%) translate3d(0, 0, 0);
|
||||
will-change: opacity, transform;
|
||||
}
|
||||
|
||||
|
||||
.wpfade_transform_backwards-enter-active,
|
||||
.wpfade_transform_backwards-leave-active {
|
||||
--transitionTime: 0.2s;
|
||||
|
@ -125,11 +121,11 @@
|
|||
|
||||
.wpfade_transform_backwards-enter {
|
||||
opacity: 0;
|
||||
transform: translateX(-50%) translate3d(0,0,0);
|
||||
transform: translateX(-50%) translate3d(0, 0, 0);
|
||||
will-change: opacity, transform;
|
||||
}
|
||||
.wpfade_transform_backwards-leave-to {
|
||||
opacity: 0;
|
||||
transform: translateX(50%) translate3d(0,0,0);
|
||||
transform: translateX(50%) translate3d(0, 0, 0);
|
||||
will-change: opacity, transform;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,180 +1,193 @@
|
|||
// Apple Music Listen Now Page
|
||||
// URL : https://amp-api.music.apple.com/v1/me/recommendations?timezone=+00:00
|
||||
// &with=friendsMix,library,social&art[social-profiles:url]=c
|
||||
// &name=listen-now&art[url]=c,f&omit[resource]=autos
|
||||
// &relate[editorial-items]=contents
|
||||
// &extend=editorialCard,editorialVideo
|
||||
// &extend[albums]=artistUrl
|
||||
// &extend[library-albums]=artistUrl
|
||||
// &extend[playlists]=artistNames,editorialArtwork
|
||||
// &extend[library-playlists]=artistNames,editorialArtwork
|
||||
// &extend[social-profiles]=topGenreNames&include[albums]=artists
|
||||
// &include[songs]=artists&include[music-videos]=artists
|
||||
// &fields[albums]=artistName,artistUrl,artwork,contentRating,editorialArtwork,editorialVideo,name,playParams,releaseDate,url
|
||||
// &fields[artists]=name,url&extend[stations]=airDate,supportsAirTimeUpdates&meta[stations]=inflectionPoints
|
||||
// &types=artists,albums,editorial-items,library-albums,library-playlists,music-movies,music-videos,playlists,stations,uploaded-audios,uploaded-videos,activities,apple-curators,curators,tv-shows,social-profiles,social-upsells
|
||||
// &l=en-gb&platform=web
|
||||
// &with=friendsMix,library,social&art[social-profiles:url]=c
|
||||
// &name=listen-now&art[url]=c,f&omit[resource]=autos
|
||||
// &relate[editorial-items]=contents
|
||||
// &extend=editorialCard,editorialVideo
|
||||
// &extend[albums]=artistUrl
|
||||
// &extend[library-albums]=artistUrl
|
||||
// &extend[playlists]=artistNames,editorialArtwork
|
||||
// &extend[library-playlists]=artistNames,editorialArtwork
|
||||
// &extend[social-profiles]=topGenreNames&include[albums]=artists
|
||||
// &include[songs]=artists&include[music-videos]=artists
|
||||
// &fields[albums]=artistName,artistUrl,artwork,contentRating,editorialArtwork,editorialVideo,name,playParams,releaseDate,url
|
||||
// &fields[artists]=name,url&extend[stations]=airDate,supportsAirTimeUpdates&meta[stations]=inflectionPoints
|
||||
// &types=artists,albums,editorial-items,library-albums,library-playlists,music-movies,music-videos,playlists,stations,uploaded-audios,uploaded-videos,activities,apple-curators,curators,tv-shows,social-profiles,social-upsells
|
||||
// &l=en-gb&platform=web
|
||||
|
||||
await app.mk.api.personalRecommendations("",
|
||||
{
|
||||
name: "listen-now",
|
||||
with: "friendsMix,library,social",
|
||||
"art[social-profiles:url]":"c",
|
||||
"art[url]": "c,f",
|
||||
"omit[resource]": "autos",
|
||||
"relate[editorial-items]": "contents",
|
||||
extend: ["editorialCard", "editorialVideo"],
|
||||
"extend[albums]": ["artistUrl"],
|
||||
"extend[library-albums]": ["artistUrl"],
|
||||
"extend[playlists]": ["artistNames", "editorialArtwork"],
|
||||
"extend[library-playlists]": ["artistNames", "editorialArtwork"],
|
||||
"extend[social-profiles]": "topGenreNames",
|
||||
"include[albums]": "artists",
|
||||
"include[songs]": "artists",
|
||||
"include[music-videos]": "artists",
|
||||
"fields[albums]": ["artistName", "artistUrl", "artwork", "contentRating", "editorialArtwork", "editorialVideo", "name", "playParams", "releaseDate", "url"],
|
||||
"fields[artists]": ["name", "url"],
|
||||
"extend[stations]": ["airDate", "supportsAirTimeUpdates"],
|
||||
"meta[stations]": "inflectionPoints",
|
||||
types: "artists,albums,editorial-items,library-albums,library-playlists,music-movies,music-videos,playlists,stations,uploaded-audios,uploaded-videos,activities,apple-curators,curators,tv-shows,social-profiles,social-upsells",
|
||||
l:"en-gb",
|
||||
platform:"web"
|
||||
},
|
||||
{
|
||||
includeResponseMeta: !0,
|
||||
reload: !0
|
||||
});
|
||||
await app.mk.api.personalRecommendations(
|
||||
"",
|
||||
{
|
||||
name: "listen-now",
|
||||
with: "friendsMix,library,social",
|
||||
"art[social-profiles:url]": "c",
|
||||
"art[url]": "c,f",
|
||||
"omit[resource]": "autos",
|
||||
"relate[editorial-items]": "contents",
|
||||
extend: ["editorialCard", "editorialVideo"],
|
||||
"extend[albums]": ["artistUrl"],
|
||||
"extend[library-albums]": ["artistUrl"],
|
||||
"extend[playlists]": ["artistNames", "editorialArtwork"],
|
||||
"extend[library-playlists]": ["artistNames", "editorialArtwork"],
|
||||
"extend[social-profiles]": "topGenreNames",
|
||||
"include[albums]": "artists",
|
||||
"include[songs]": "artists",
|
||||
"include[music-videos]": "artists",
|
||||
"fields[albums]": ["artistName", "artistUrl", "artwork", "contentRating", "editorialArtwork", "editorialVideo", "name", "playParams", "releaseDate", "url"],
|
||||
"fields[artists]": ["name", "url"],
|
||||
"extend[stations]": ["airDate", "supportsAirTimeUpdates"],
|
||||
"meta[stations]": "inflectionPoints",
|
||||
types: "artists,albums,editorial-items,library-albums,library-playlists,music-movies,music-videos,playlists,stations,uploaded-audios,uploaded-videos,activities,apple-curators,curators,tv-shows,social-profiles,social-upsells",
|
||||
l: "en-gb",
|
||||
platform: "web",
|
||||
},
|
||||
{
|
||||
includeResponseMeta: !0,
|
||||
reload: !0,
|
||||
}
|
||||
);
|
||||
|
||||
// Browse page
|
||||
await app.mk.api.groupings("",
|
||||
{
|
||||
platform: "web",
|
||||
name: "music",
|
||||
l: "en-gb",
|
||||
"omit[resource:artists]": "relationships",
|
||||
"include[albums]": "artists",
|
||||
"include[songs]": "artists",
|
||||
"include[music-videos]": "artists",
|
||||
extend: "editorialArtwork,artistUrl",
|
||||
"fields[artists]": "name,url,artwork,editorialArtwork,genreNames,editorialNotes",
|
||||
"art[url]": "f"
|
||||
});
|
||||
await app.mk.api.groupings("", {
|
||||
platform: "web",
|
||||
name: "music",
|
||||
l: "en-gb",
|
||||
"omit[resource:artists]": "relationships",
|
||||
"include[albums]": "artists",
|
||||
"include[songs]": "artists",
|
||||
"include[music-videos]": "artists",
|
||||
extend: "editorialArtwork,artistUrl",
|
||||
"fields[artists]": "name,url,artwork,editorialArtwork,genreNames,editorialNotes",
|
||||
"art[url]": "f",
|
||||
});
|
||||
|
||||
// Radio page
|
||||
await app.mk.api.recentRadioStations("",
|
||||
{l: "en-gb",
|
||||
"platform": "web",
|
||||
"art[url]": "f"});
|
||||
await app.mk.api.recentRadioStations("", {
|
||||
l: "en-gb",
|
||||
platform: "web",
|
||||
"art[url]": "f",
|
||||
});
|
||||
|
||||
// Recently Added
|
||||
await app.mk.api.library.recentlyAdded({
|
||||
"platform": "web",
|
||||
await app.mk.api.library.recentlyAdded(
|
||||
{
|
||||
platform: "web",
|
||||
include: {
|
||||
"library-albums": ["artists"],
|
||||
"library-artists": ["catalog"]
|
||||
"library-albums": ["artists"],
|
||||
"library-artists": ["catalog"],
|
||||
},
|
||||
fields: {
|
||||
artists: ["url"],
|
||||
albums: "artistName,artistUrl,artwork,contentRating,editorialArtwork,name,playParams,releaseDate,url"
|
||||
artists: ["url"],
|
||||
albums: "artistName,artistUrl,artwork,contentRating,editorialArtwork,name,playParams,releaseDate,url",
|
||||
},
|
||||
includeOnly: ["catalog", "artists"],
|
||||
limit: 25
|
||||
}, {
|
||||
limit: 25,
|
||||
},
|
||||
{
|
||||
reload: !0,
|
||||
includePagination: !0
|
||||
})
|
||||
includePagination: !0,
|
||||
}
|
||||
);
|
||||
|
||||
// Songs
|
||||
await app.mk.api.library.songs({limit: 100}).then((data)=>{
|
||||
console.log(data)
|
||||
})
|
||||
// Songs
|
||||
await app.mk.api.library.songs({ limit: 100 }).then((data) => {
|
||||
console.log(data);
|
||||
});
|
||||
|
||||
// Artists
|
||||
await app.mk.api.library.artists({limit: 100}).then((data)=>{
|
||||
console.log(data)
|
||||
})
|
||||
// Artists
|
||||
await app.mk.api.library.artists({ limit: 100 }).then((data) => {
|
||||
console.log(data);
|
||||
});
|
||||
|
||||
// Artists
|
||||
await app.mk.api.library.albums({limit: 100}).then((data)=>{
|
||||
console.log(data)
|
||||
})
|
||||
// Artists
|
||||
await app.mk.api.library.albums({ limit: 100 }).then((data) => {
|
||||
console.log(data);
|
||||
});
|
||||
|
||||
// Albums
|
||||
// does not like limit = 100 for some reason
|
||||
await app.mk.api.library.albums({limit: 50}).then((data)=>{
|
||||
console.log(data)
|
||||
})
|
||||
await app.mk.api.library.albums({ limit: 50 }).then((data) => {
|
||||
console.log(data);
|
||||
});
|
||||
|
||||
// Made For You
|
||||
app.mk.api.recommendations("",{extend: "editorialArtwork,artistUrl"})
|
||||
app.mk.api.recommendations("", { extend: "editorialArtwork,artistUrl" });
|
||||
|
||||
// Library with library length
|
||||
await app.mk.api.library.songs("", {limit: 100}, {includeResponseMeta: !0}).then((data)=>{
|
||||
console.log(data)
|
||||
})
|
||||
await app.mk.api.library.songs("", { limit: 100 }, { includeResponseMeta: !0 }).then((data) => {
|
||||
console.log(data);
|
||||
});
|
||||
|
||||
// Artist View Top Songs
|
||||
app.mk.api.artistView("325096253", "top-songs", {}, {view: "top-songs", includeResponseMeta: !0})
|
||||
app.mk.api.artistView("325096253", "top-songs", {}, { view: "top-songs", includeResponseMeta: !0 });
|
||||
|
||||
// Artist Page Data
|
||||
app.mkapi("artists", false, "412778295", {
|
||||
"views": "featured-release,full-albums,appears-on-albums,featured-albums,featured-on-albums,singles,compilation-albums,live-albums,latest-release,top-music-videos,similar-artists,top-songs,playlists,more-to-hear,more-to-see",
|
||||
"extend": "artistBio,bornOrFormed,editorialArtwork,editorialVideo,isGroup,origin,hero",
|
||||
"extend[playlists]": "trackCount",
|
||||
"omit[resource:songs]": "relationships",
|
||||
"fields[albums]": "artistName,artistUrl,artwork,contentRating,editorialArtwork,name,playParams,releaseDate,url,trackCount",
|
||||
"limit[artists:top-songs]": 20,
|
||||
"art[url]": "f"
|
||||
}, {includeResponseMeta: !0}).then((data)=>{
|
||||
console.log(data)
|
||||
})
|
||||
app
|
||||
.mkapi(
|
||||
"artists",
|
||||
false,
|
||||
"412778295",
|
||||
{
|
||||
views: "featured-release,full-albums,appears-on-albums,featured-albums,featured-on-albums,singles,compilation-albums,live-albums,latest-release,top-music-videos,similar-artists,top-songs,playlists,more-to-hear,more-to-see",
|
||||
extend: "artistBio,bornOrFormed,editorialArtwork,editorialVideo,isGroup,origin,hero",
|
||||
"extend[playlists]": "trackCount",
|
||||
"omit[resource:songs]": "relationships",
|
||||
"fields[albums]": "artistName,artistUrl,artwork,contentRating,editorialArtwork,name,playParams,releaseDate,url,trackCount",
|
||||
"limit[artists:top-songs]": 20,
|
||||
"art[url]": "f",
|
||||
},
|
||||
{ includeResponseMeta: !0 }
|
||||
)
|
||||
.then((data) => {
|
||||
console.log(data);
|
||||
});
|
||||
|
||||
// download entire library
|
||||
var library = []
|
||||
var library = [];
|
||||
var downloaded = null;
|
||||
function downloadChunk () {
|
||||
if (downloaded == null) {
|
||||
app.mk.api.library.songs("", {limit: 100}, {includeResponseMeta: !0}).then((response)=>{
|
||||
processChunk(response)
|
||||
})
|
||||
} else {
|
||||
downloaded.next("", {limit: 100}, {includeResponseMeta: !0}).then((response)=>{
|
||||
processChunk(response)
|
||||
})
|
||||
}
|
||||
function downloadChunk() {
|
||||
if (downloaded == null) {
|
||||
app.mk.api.library.songs("", { limit: 100 }, { includeResponseMeta: !0 }).then((response) => {
|
||||
processChunk(response);
|
||||
});
|
||||
} else {
|
||||
downloaded.next("", { limit: 100 }, { includeResponseMeta: !0 }).then((response) => {
|
||||
processChunk(response);
|
||||
});
|
||||
}
|
||||
}
|
||||
function processChunk (response) {
|
||||
downloaded = response
|
||||
library = library.concat(downloaded.data)
|
||||
if (downloaded.meta.total > library.length) {
|
||||
console.log(`downloading next chunk - ${library.length} songs so far`)
|
||||
downloadChunk()
|
||||
} else {
|
||||
console.log(library)
|
||||
}
|
||||
function processChunk(response) {
|
||||
downloaded = response;
|
||||
library = library.concat(downloaded.data);
|
||||
if (downloaded.meta.total > library.length) {
|
||||
console.log(`downloading next chunk - ${library.length} songs so far`);
|
||||
downloadChunk();
|
||||
} else {
|
||||
console.log(library);
|
||||
}
|
||||
}
|
||||
|
||||
//Some Available Functions from MusicKit
|
||||
// recentPlayed() -> recently played songs ?
|
||||
|
||||
// create Artist / Song/ Album stations:
|
||||
app.mk.setStationQueue({artist:"1258279972"})
|
||||
app.mk.setStationQueue({song:"1437308307"}) // yes the song id here can be the albumId, but just keep using the song:
|
||||
app.mk.setStationQueue({ artist: "1258279972" });
|
||||
app.mk.setStationQueue({ song: "1437308307" }); // yes the song id here can be the albumId, but just keep using the song:
|
||||
|
||||
// Sorting Playlists, send an array of tracks in the format below
|
||||
// playlist must be fully recursively downloaded first before sorting
|
||||
|
||||
app.mk.api.library.putPlaylistTracklisting(app.showingPlaylist.attributes.playParams.id, [
|
||||
{
|
||||
"id": relationships.tracks.data[X].id,
|
||||
"type": relationships.tracks.data[X].type
|
||||
},
|
||||
{
|
||||
"id": relationships.tracks.data[X].id,
|
||||
"type": relationships.tracks.data[X].type
|
||||
},
|
||||
{
|
||||
"id": relationships.tracks.data[X].id,
|
||||
"type": relationships.tracks.data[X].type
|
||||
},
|
||||
])
|
||||
{
|
||||
id: relationships.tracks.data[X].id,
|
||||
type: relationships.tracks.data[X].type,
|
||||
},
|
||||
{
|
||||
id: relationships.tracks.data[X].id,
|
||||
type: relationships.tracks.data[X].type,
|
||||
},
|
||||
{
|
||||
id: relationships.tracks.data[X].id,
|
||||
type: relationships.tracks.data[X].type,
|
||||
},
|
||||
]);
|
||||
|
|
|
@ -1,136 +1,136 @@
|
|||
<div class="app-navigation" v-cloak>
|
||||
<transition name="wpfade">
|
||||
<div class="usermenu-container" v-if="chrome.menuOpened">
|
||||
<div class="usermenu-body">
|
||||
<button
|
||||
class="app-sidebar-button"
|
||||
style="width: 100%"
|
||||
@click="appRoute('apple-account-settings')"
|
||||
>
|
||||
<img
|
||||
class="sidebar-user-icon"
|
||||
loading="lazy"
|
||||
:src="getMediaItemArtwork(chrome.hideUserInfo ? './assets/logocut.png' : (chrome.userinfo.attributes['artwork'] ? chrome.userinfo.attributes['artwork']['url'] : ''), 26)"
|
||||
/>
|
||||
<div class="usermenu-container" v-if="chrome.menuOpened">
|
||||
<div class="usermenu-body">
|
||||
<button
|
||||
class="app-sidebar-button"
|
||||
style="width: 100%"
|
||||
@click="appRoute('apple-account-settings')"
|
||||
>
|
||||
<img
|
||||
class="sidebar-user-icon"
|
||||
loading="lazy"
|
||||
:src="getMediaItemArtwork(chrome.hideUserInfo ? './assets/logocut.png' : (chrome.userinfo.attributes['artwork'] ? chrome.userinfo.attributes['artwork']['url'] : ''), 26)"
|
||||
/>
|
||||
|
||||
<div class="sidebar-user-text" v-if="!chrome.hideUserInfo">
|
||||
<template v-if="chrome.userinfo.id || mk.isAuthorized">
|
||||
<div class="fullname text-overflow-elipsis">
|
||||
{{
|
||||
chrome.userinfo != null &&
|
||||
chrome.userinfo.attributes != null
|
||||
? chrome.userinfo.attributes.name ?? ""
|
||||
: ""
|
||||
}}
|
||||
</div>
|
||||
<div class="handle-text text-overflow-elipsis">
|
||||
{{
|
||||
chrome.userinfo != null &&
|
||||
chrome.userinfo.attributes != null
|
||||
? chrome.userinfo.attributes.handle ?? ""
|
||||
: ""
|
||||
}}
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div @click="mk.authorize()">
|
||||
{{ $root.getLz("term.login") }}
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
<div class="sidebar-user-text" v-else>
|
||||
{{ $root.getLz("app.name") }}
|
||||
</div>
|
||||
</button>
|
||||
<!-- Use 20px SVG for usermenu icon -->
|
||||
<button
|
||||
class="usermenu-item"
|
||||
v-if="cfg.general.privateEnabled"
|
||||
@click="cfg.general.privateEnabled = false"
|
||||
>
|
||||
<div class="sidebar-user-text" v-if="!chrome.hideUserInfo">
|
||||
<template v-if="chrome.userinfo.id || mk.isAuthorized">
|
||||
<div class="fullname text-overflow-elipsis">
|
||||
{{
|
||||
chrome.userinfo != null &&
|
||||
chrome.userinfo.attributes != null
|
||||
? chrome.userinfo.attributes.name ?? ""
|
||||
: ""
|
||||
}}
|
||||
</div>
|
||||
<div class="handle-text text-overflow-elipsis">
|
||||
{{
|
||||
chrome.userinfo != null &&
|
||||
chrome.userinfo.attributes != null
|
||||
? chrome.userinfo.attributes.handle ?? ""
|
||||
: ""
|
||||
}}
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div @click="mk.authorize()">
|
||||
{{ $root.getLz("term.login") }}
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
<div class="sidebar-user-text" v-else>
|
||||
{{ $root.getLz("app.name") }}
|
||||
</div>
|
||||
</button>
|
||||
<!-- Use 20px SVG for usermenu icon -->
|
||||
<button
|
||||
class="usermenu-item"
|
||||
v-if="cfg.general.privateEnabled"
|
||||
@click="cfg.general.privateEnabled = false"
|
||||
>
|
||||
<span class="usermenu-item-icon">
|
||||
<%- include("../svg/x.svg") %>
|
||||
</span>
|
||||
<span class="usermenu-item-name">{{
|
||||
<span class="usermenu-item-name">{{
|
||||
$root.getLz("term.disablePrivateSession")
|
||||
}}</span>
|
||||
</button>
|
||||
<button class="usermenu-item" @click="appRoute('remote-pair')">
|
||||
</button>
|
||||
<button class="usermenu-item" @click="appRoute('remote-pair')">
|
||||
<span class="usermenu-item-icon">
|
||||
<%- include("../svg/smartphone.svg") %>
|
||||
</span>
|
||||
<span class="usermenu-item-name">{{
|
||||
<span class="usermenu-item-name">{{
|
||||
$root.getLz("action.showWebRemoteQR")
|
||||
}}</span>
|
||||
</button>
|
||||
<button
|
||||
class="usermenu-item"
|
||||
@click="modals.castMenu = true"
|
||||
>
|
||||
</button>
|
||||
<button
|
||||
class="usermenu-item"
|
||||
@click="modals.castMenu = true"
|
||||
>
|
||||
<span class="usermenu-item-icon">
|
||||
<%- include("../svg/cast.svg") %>
|
||||
</span>
|
||||
<span class="usermenu-item-name">{{
|
||||
<span class="usermenu-item-name">{{
|
||||
$root.getLz("term.cast")
|
||||
}}</span>
|
||||
</button>
|
||||
<button
|
||||
class="usermenu-item"
|
||||
@click="modals.audioSettings = true"
|
||||
>
|
||||
</button>
|
||||
<button
|
||||
class="usermenu-item"
|
||||
@click="modals.audioSettings = true"
|
||||
>
|
||||
<span class="usermenu-item-icon">
|
||||
<%- include("../svg/headphones.svg") %>
|
||||
</span>
|
||||
<span class="usermenu-item-name">{{
|
||||
<span class="usermenu-item-name">{{
|
||||
$root.getLz("term.audioSettings")
|
||||
}}</span>
|
||||
</button>
|
||||
<button
|
||||
class="usermenu-item"
|
||||
v-if="pluginInstalled"
|
||||
@click="modals.pluginMenu = true"
|
||||
>
|
||||
</button>
|
||||
<button
|
||||
class="usermenu-item"
|
||||
v-if="pluginInstalled"
|
||||
@click="modals.pluginMenu = true"
|
||||
>
|
||||
<span class="usermenu-item-icon">
|
||||
<%- include("../svg/grid.svg") %>
|
||||
</span>
|
||||
<span class="usermenu-item-name">{{
|
||||
<span class="usermenu-item-name">{{
|
||||
$root.getLz("term.plugin")
|
||||
}}</span>
|
||||
</button>
|
||||
<button class="usermenu-item" @click="appRoute('about')">
|
||||
</button>
|
||||
<button class="usermenu-item" @click="appRoute('about')">
|
||||
<span class="usermenu-item-icon">
|
||||
<%- include("../svg/info.svg") %>
|
||||
</span>
|
||||
<span class="usermenu-item-name">{{
|
||||
<span class="usermenu-item-name">{{
|
||||
$root.getLz("term.about")
|
||||
}}</span>
|
||||
</button>
|
||||
<button class="usermenu-item" @click="modals.settings = true">
|
||||
</button>
|
||||
<button class="usermenu-item" @click="modals.settings = true">
|
||||
<span class="usermenu-item-icon">
|
||||
<%- include("../svg/settings.svg") %>
|
||||
</span>
|
||||
<span class="usermenu-item-name">{{
|
||||
<span class="usermenu-item-name">{{
|
||||
$root.getLz("term.settings")
|
||||
}}</span>
|
||||
</button>
|
||||
<button class="usermenu-item" @click="unauthorize()">
|
||||
</button>
|
||||
<button class="usermenu-item" @click="unauthorize()">
|
||||
<span class="usermenu-item-icon" style="right: 2.5px">
|
||||
<%- include("../svg/log-out.svg") %>
|
||||
</span>
|
||||
<span class="usermenu-item-name">{{
|
||||
<span class="usermenu-item-name">{{
|
||||
$root.getLz("term.logout")
|
||||
}}</span>
|
||||
</button>
|
||||
<button class="usermenu-item" @click="quit()">
|
||||
</button>
|
||||
<button class="usermenu-item" @click="quit()">
|
||||
<span class="usermenu-item-icon" style="right: 2.5px">
|
||||
<%- include("../svg/x.svg") %>
|
||||
</span>
|
||||
<span class="usermenu-item-name">{{
|
||||
<span class="usermenu-item-name">{{
|
||||
$root.getLz("term.quit")
|
||||
}}</span>
|
||||
</button>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
<transition name="sidebartransition">
|
||||
<cider-app-sidebar v-if="!chrome.sidebarCollapsed"></cider-app-sidebar>
|
||||
|
@ -141,9 +141,12 @@
|
|||
v-if="drawer.open && drawer.panel == 'lyrics' && lyrics && lyrics != [] && lyrics.length > 0">
|
||||
<div class="bgArtworkMaterial">
|
||||
<div class="bg-artwork-container">
|
||||
<img v-if="(cfg.visual.bg_artwork_rotation && animateBackground)" class="bg-artwork a" :src="$store.state.artwork.playerLCD">
|
||||
<img v-if="(cfg.visual.bg_artwork_rotation && animateBackground)" class="bg-artwork b" :src="$store.state.artwork.playerLCD">
|
||||
<img v-if="!(cfg.visual.bg_artwork_rotation && animateBackground)" class="bg-artwork no-animation" :src="$store.state.artwork.playerLCD">
|
||||
<img v-if="(cfg.visual.bg_artwork_rotation && animateBackground)" class="bg-artwork a"
|
||||
:src="$store.state.artwork.playerLCD">
|
||||
<img v-if="(cfg.visual.bg_artwork_rotation && animateBackground)" class="bg-artwork b"
|
||||
:src="$store.state.artwork.playerLCD">
|
||||
<img v-if="!(cfg.visual.bg_artwork_rotation && animateBackground)" class="bg-artwork no-animation"
|
||||
:src="$store.state.artwork.playerLCD">
|
||||
</div>
|
||||
</div>
|
||||
<lyrics-view v-if="drawer.panel == 'lyrics'" :time="mk.currentPlaybackTime - lyricOffset" :lyrics="lyrics"
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
<div class="app-chrome chrome-bottom" v-if="getThemeDirective('windowLayout') == 'twopanel'" :style="{'display': chrome.topChromeVisible ? '' : 'none'}">
|
||||
<div class="app-chrome chrome-bottom" v-if="getThemeDirective('windowLayout') == 'twopanel'"
|
||||
:style="{'display': chrome.topChromeVisible ? '' : 'none'}">
|
||||
<div class="app-chrome--left">
|
||||
<div class="app-chrome-item playback-controls">
|
||||
<template v-if="mkReady()">
|
||||
|
@ -16,15 +17,23 @@
|
|||
<mediaitem-artwork :url="currentArtUrl"></mediaitem-artwork>
|
||||
</div>
|
||||
<div class="song-name">{{ mk.nowPlayingItem["attributes"]["name"] }}</div>
|
||||
<div class="song-artist" @click="getNowPlayingItemDetailed(`artist`)">{{ mk.nowPlayingItem["attributes"]["artistName"] }}</div>
|
||||
<div class="song-artist" @click="getNowPlayingItemDetailed(`artist`)">{{
|
||||
mk.nowPlayingItem["attributes"]["artistName"] }}
|
||||
</div>
|
||||
<div class="song-album" @click="getNowPlayingItemDetailed(`album`)">
|
||||
{{(mk.nowPlayingItem["attributes"]["albumName"]) ?
|
||||
(mk.nowPlayingItem["attributes"]["albumName"]) : "" }}
|
||||
</div>
|
||||
<hr>
|
||||
<div class="btn-group" style="width:100%;">
|
||||
<button class="md-btn md-btn-small" style="width: 100%;" @click="drawer.open = false; miniPlayer(true)">{{ $root.getLz("term.miniplayer") }}</button>
|
||||
<button class="md-btn md-btn-small" style="width: 100%;" @click="drawer.open = false; fullscreen(true)">{{ $root.getLz("term.fullscreenView") }}</button>
|
||||
<button class="md-btn md-btn-small" style="width: 100%;"
|
||||
@click="drawer.open = false; miniPlayer(true)">{{ $root.getLz("term.miniplayer")
|
||||
}}
|
||||
</button>
|
||||
<button class="md-btn md-btn-small" style="width: 100%;"
|
||||
@click="drawer.open = false; fullscreen(true)">{{
|
||||
$root.getLz("term.fullscreenView") }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</b-popover>
|
||||
|
@ -39,20 +48,26 @@
|
|||
<div class="song-artist" @click="getNowPlayingItemDetailed(`artist`)">
|
||||
{{ mk.nowPlayingItem["attributes"]["artistName"] }}
|
||||
</div>
|
||||
<div class="song-album" @click="getNowPlayingItemDetailed('album')" v-if='mk.nowPlayingItem["attributes"]["albumName"]'>
|
||||
<div class="song-album" @click="getNowPlayingItemDetailed('album')"
|
||||
v-if='mk.nowPlayingItem["attributes"]["albumName"]'>
|
||||
{{(mk.nowPlayingItem["attributes"]["albumName"]) ?
|
||||
(mk.nowPlayingItem["attributes"]["albumName"]) : "" }}
|
||||
</div>
|
||||
<div class="chrome-icon-container">
|
||||
<div class="audio-type private-icon" v-if="cfg.general.privateEnabled === true"></div>
|
||||
<div class="audio-type spatial-icon" v-if="cfg.audio.maikiwiAudio.spatial === true"
|
||||
:title="$root.getLz('settings.option.audio.enableAdvancedFunctionality.tunedAudioSpatialization') + ' (' + getProfileLz('CTS', cfg.audio.maikiwiAudio.spatialProfile) + ')'" v-b-tooltip.hover
|
||||
<div class="audio-type spatial-icon" v-if="cfg.audio.maikiwiAudio.spatial === true"
|
||||
:title="$root.getLz('settings.option.audio.enableAdvancedFunctionality.tunedAudioSpatialization') + ' (' + getProfileLz('CTS', cfg.audio.maikiwiAudio.spatialProfile) + ')'"
|
||||
v-b-tooltip.hover
|
||||
></div>
|
||||
<div class="audio-type lossless-icon" v-if="(mk.nowPlayingItem?.localFilesMetadata?.lossless ?? false) === true"
|
||||
:title="mk.nowPlayingItem?.localFilesMetadata?.bitDepth +'-bit / '+ mk.nowPlayingItem?.localFilesMetadata?.sampleRate/1000 + ' kHz ' + mk.nowPlayingItem.localFilesMetadata.container" v-b-tooltip.hover
|
||||
></div>
|
||||
<div class="audio-type ppe-icon" v-if="mk.nowPlayingItem.localFilesMetadata == null && cfg.audio.maikiwiAudio.ciderPPE === true"
|
||||
:title="$root.getLz('settings.option.audio.enableAdvancedFunctionality.ciderPPE')" v-b-tooltip.hover
|
||||
<div class="audio-type lossless-icon"
|
||||
v-if="(mk.nowPlayingItem?.localFilesMetadata?.lossless ?? false) === true"
|
||||
:title="mk.nowPlayingItem?.localFilesMetadata?.bitDepth +'-bit / '+ mk.nowPlayingItem?.localFilesMetadata?.sampleRate/1000 + ' kHz ' + mk.nowPlayingItem.localFilesMetadata.container"
|
||||
v-b-tooltip.hover
|
||||
></div>
|
||||
<div class="audio-type ppe-icon"
|
||||
v-if="mk.nowPlayingItem.localFilesMetadata == null && cfg.audio.maikiwiAudio.ciderPPE === true"
|
||||
:title="$root.getLz('settings.option.audio.enableAdvancedFunctionality.ciderPPE')"
|
||||
v-b-tooltip.hover
|
||||
></div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -75,7 +90,7 @@
|
|||
</div>
|
||||
<div class="playback-info">
|
||||
<div class="song-name">
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -86,8 +101,9 @@
|
|||
</div>
|
||||
<div class="app-chrome--center">
|
||||
<div class="app-chrome-playback-duration-bottom">
|
||||
<b-row v-if="mkReady()">
|
||||
<b-col sm="auto" v-if="!mk.nowPlayingItem?.isLiveRadioStation">{{ convertTime(getSongProgress()) }}</b-col>
|
||||
<b-row v-if="mkReady()">
|
||||
<b-col sm="auto" v-if="!mk.nowPlayingItem?.isLiveRadioStation">{{ convertTime(getSongProgress()) }}
|
||||
</b-col>
|
||||
<b-col sm="auto" v-else>--:--</b-col>
|
||||
<b-col>
|
||||
<input type="range" step="0.01" min="0" :style="progressBarStyle()"
|
||||
|
@ -96,13 +112,16 @@
|
|||
@touchend="mk.seekToTime($event.target.value);setTimeout(()=>{playerLCD.desiredDuration = 0;playerLCD.userInteraction = false}, 1000);"
|
||||
:max="mk.currentPlaybackDuration" :value="getSongProgress()">
|
||||
</b-col>
|
||||
<b-col sm="auto" v-if="!mk.nowPlayingItem?.isLiveRadioStation">{{ convertTime(mk.currentPlaybackDuration) }}</b-col>
|
||||
<b-col sm="auto" v-if="!mk.nowPlayingItem?.isLiveRadioStation">{{
|
||||
convertTime(mk.currentPlaybackDuration) }}
|
||||
</b-col>
|
||||
<b-col sm="auto" v-else>{{ getLz("term.live") }}</b-col>
|
||||
</b-row>
|
||||
</div>
|
||||
<div class="app-chrome-playback-controls">
|
||||
<div class="app-chrome-item">
|
||||
<button class="playback-button--small shuffle" v-if="mk.shuffleMode == 0" :class="isDisabled() && 'disabled'"
|
||||
<button class="playback-button--small shuffle" v-if="mk.shuffleMode == 0"
|
||||
:class="isDisabled() && 'disabled'"
|
||||
@click="mk.shuffleMode = 1" :title="$root.getLz('term.enableShuffle')"
|
||||
v-b-tooltip.hover></button>
|
||||
<button class="playback-button--small shuffle active" v-else :class="isDisabled() && 'disabled'"
|
||||
|
@ -114,7 +133,8 @@
|
|||
:title="$root.getLz('term.previous')" v-b-tooltip.hover></button>
|
||||
</div>
|
||||
<div class="app-chrome-item">
|
||||
<button class="playback-button stop" @click="mk.stop()" v-if="mk.isPlaying && mk.nowPlayingItem.attributes.playParams.kind == 'radioStation'"
|
||||
<button class="playback-button stop" @click="mk.stop()"
|
||||
v-if="mk.isPlaying && mk.nowPlayingItem.attributes.playParams.kind == 'radioStation'"
|
||||
:title="$root.getLz('term.stop')" v-b-tooltip.hover></button>
|
||||
<button class="playback-button pause" @click="mk.pause()" v-else-if="mk.isPlaying"
|
||||
:title="$root.getLz('term.pause')" v-b-tooltip.hover></button>
|
||||
|
@ -126,13 +146,16 @@
|
|||
:title="$root.getLz('term.next')" v-b-tooltip.hover></button>
|
||||
</div>
|
||||
<div class="app-chrome-item">
|
||||
<button class="playback-button--small repeat" v-if="mk.repeatMode == 0" :class="isDisabled() && 'disabled'"
|
||||
<button class="playback-button--small repeat" v-if="mk.repeatMode == 0"
|
||||
:class="isDisabled() && 'disabled'"
|
||||
@click="mk.repeatMode = 1" :title="$root.getLz('term.enableRepeatOne')"
|
||||
v-b-tooltip.hover></button>
|
||||
<button class="playback-button--small repeat repeatOne" @click="mk.repeatMode = 2" :class="isDisabled() && 'disabled'"
|
||||
<button class="playback-button--small repeat repeatOne" @click="mk.repeatMode = 2"
|
||||
:class="isDisabled() && 'disabled'"
|
||||
v-else-if="mk.repeatMode == 1" :title="$root.getLz('term.disableRepeatOne')"
|
||||
v-b-tooltip.hover></button>
|
||||
<button class="playback-button--small repeat active" @click="mk.repeatMode = 0" :class="isDisabled() && 'disabled'"
|
||||
<button class="playback-button--small repeat active" @click="mk.repeatMode = 0"
|
||||
:class="isDisabled() && 'disabled'"
|
||||
v-else-if="mk.repeatMode == 2" :title="$root.getLz('term.disableRepeat')"
|
||||
v-b-tooltip.hover></button>
|
||||
</div>
|
||||
|
@ -149,27 +172,27 @@
|
|||
v-b-tooltip.hover :title="formatVolumeTooltip()">
|
||||
</div>
|
||||
<div class="app-chrome-item generic">
|
||||
<button class="playback-button--small cast"
|
||||
<button class="playback-button--small cast"
|
||||
:title="$root.getLz('term.cast')"
|
||||
v-b-tooltip.hover
|
||||
@click="modals.castMenu = true"></button>
|
||||
</div>
|
||||
<div class="app-chrome-item generic">
|
||||
<button class="playback-button--small queue" :class="{'active': drawer.panel == 'queue'}"
|
||||
<button class="playback-button--small queue" :class="{'active': drawer.panel == 'queue'}"
|
||||
:title="$root.getLz('term.queue')"
|
||||
v-b-tooltip.hover
|
||||
@click="invokeDrawer('queue')"></button>
|
||||
</div>
|
||||
<div class="app-chrome-item generic">
|
||||
<template v-if="lyrics && lyrics != [] && lyrics.length > 0">
|
||||
<button class="playback-button--small lyrics"
|
||||
<button class="playback-button--small lyrics"
|
||||
:title="$root.getLz('term.lyrics')"
|
||||
v-b-tooltip.hover
|
||||
:class="{'active': drawer.panel == 'lyrics'}"
|
||||
@click="invokeDrawer('lyrics')"></button>
|
||||
</template>
|
||||
<template v-else>
|
||||
<button class="playback-button--small lyrics"
|
||||
<button class="playback-button--small lyrics"
|
||||
:style="{'opacity': 0.3, 'pointer-events': 'none'}"></button>
|
||||
</template>
|
||||
|
||||
|
|
|
@ -1,286 +1,313 @@
|
|||
<div class="app-chrome" :style="{'display': chrome.topChromeVisible ? '' : 'none'}">
|
||||
<div class="app-chrome--left">
|
||||
<div class="app-chrome-item full-height" v-if="chrome.windowControlPosition == 'left' && !chrome.nativeControls">
|
||||
<div class="window-controls-macos">
|
||||
<div class="close" @click="ipcRenderer.send('close')"></div>
|
||||
<div class="minimize" @click="ipcRenderer.send('minimize')"></div>
|
||||
<div class="minmax restore" v-if="chrome.maximized" @click="ipcRenderer.send('maximize')"></div>
|
||||
<div class="minmax" v-else @click="ipcRenderer.send('maximize')"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="app-chrome-item full-height" v-else>
|
||||
<button class="app-mainmenu" @blur="mainMenuVisibility(false)" @click="mainMenuVisibility(true)"
|
||||
@contextmenu="mainMenuVisibility(true)" :class="{active: chrome.menuOpened}"
|
||||
:aria-label="$root.getLz('term.quickNav')"></button>
|
||||
</div>
|
||||
<template v-if="getThemeDirective('appNavigation') != 'seperate'">
|
||||
<div class="vdiv" v-if="getThemeDirective('windowLayout') == 'twopanel'"></div>
|
||||
<div class="app-chrome-item">
|
||||
<button class="playback-button navigation" @click="navigateBack()" :title="$root.getLz('term.navigateBack')"
|
||||
v-b-tooltip.hover>
|
||||
<svg-icon url="./views/svg/chevron-left.svg"></svg-icon>
|
||||
</button>
|
||||
</div>
|
||||
<div class="app-chrome-item">
|
||||
<button class="playback-button navigation" @click="navigateForward()"
|
||||
:title="$root.getLz('term.navigateForward')" v-b-tooltip.hover>
|
||||
<svg-icon url="./views/svg/chevron-right.svg"></svg-icon>
|
||||
</button>
|
||||
</div>
|
||||
<div class="app-chrome-item" v-if="getThemeDirective('windowLayout') == 'twopanel'">
|
||||
<button class="playback-button collapseLibrary" v-b-tooltip.hover
|
||||
:title="chrome.sidebarCollapsed ? getLz('action.showLibrary') : getLz('action.hideLibrary')"
|
||||
@click="chrome.sidebarCollapsed = !chrome.sidebarCollapsed">
|
||||
<transition name="fade">
|
||||
<span v-if="chrome.sidebarCollapsed"></span>
|
||||
</transition>
|
||||
<transition name="fade">
|
||||
<span v-if="!chrome.sidebarCollapsed"></span>
|
||||
</transition>
|
||||
<div class="app-chrome--left">
|
||||
<div class="app-chrome-item full-height"
|
||||
v-if="chrome.windowControlPosition == 'left' && !chrome.nativeControls">
|
||||
<div class="window-controls-macos">
|
||||
<div class="close" @click="ipcRenderer.send('close')"></div>
|
||||
<div class="minimize" @click="ipcRenderer.send('minimize')"></div>
|
||||
<div class="minmax restore" v-if="chrome.maximized" @click="ipcRenderer.send('maximize')"></div>
|
||||
<div class="minmax" v-else @click="ipcRenderer.send('maximize')"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="app-chrome-item full-height" v-else>
|
||||
<button class="app-mainmenu" @blur="mainMenuVisibility(false)" @click="mainMenuVisibility(true)"
|
||||
@contextmenu="mainMenuVisibility(true)" :class="{active: chrome.menuOpened}"
|
||||
:aria-label="$root.getLz('term.quickNav')"></button>
|
||||
</div>
|
||||
<template v-if="getThemeDirective('appNavigation') != 'seperate'">
|
||||
<div class="vdiv" v-if="getThemeDirective('windowLayout') == 'twopanel'"></div>
|
||||
<div class="app-chrome-item">
|
||||
<button class="playback-button navigation" @click="navigateBack()"
|
||||
:title="$root.getLz('term.navigateBack')"
|
||||
v-b-tooltip.hover>
|
||||
<svg-icon url="./views/svg/chevron-left.svg"></svg-icon>
|
||||
</button>
|
||||
</div>
|
||||
<div class="app-chrome-item">
|
||||
<button class="playback-button navigation" @click="navigateForward()"
|
||||
:title="$root.getLz('term.navigateForward')" v-b-tooltip.hover>
|
||||
<svg-icon url="./views/svg/chevron-right.svg"></svg-icon>
|
||||
</button>
|
||||
</div>
|
||||
<div class="app-chrome-item" v-if="getThemeDirective('windowLayout') == 'twopanel'">
|
||||
<button class="playback-button collapseLibrary" v-b-tooltip.hover
|
||||
:title="chrome.sidebarCollapsed ? getLz('action.showLibrary') : getLz('action.hideLibrary')"
|
||||
@click="chrome.sidebarCollapsed = !chrome.sidebarCollapsed">
|
||||
<transition name="fade">
|
||||
<span v-if="chrome.sidebarCollapsed"></span>
|
||||
</transition>
|
||||
<transition name="fade">
|
||||
<span v-if="!chrome.sidebarCollapsed"></span>
|
||||
</transition>
|
||||
|
||||
</button>
|
||||
</div>
|
||||
<div class="vdiv display--large" v-if="getThemeDirective('windowLayout') != 'twopanel'"></div>
|
||||
</template>
|
||||
<template v-if="getThemeDirective('windowLayout') != 'twopanel'">
|
||||
<div class="app-chrome-item playback-control-buttons">
|
||||
<div class="app-chrome-item display--large">
|
||||
<button class="playback-button--small shuffle" v-if="mk.shuffleMode == 0" :class="isDisabled() && 'disabled'"
|
||||
@click="mk.shuffleMode = 1" :title="$root.getLz('term.enableShuffle')" v-b-tooltip.hover></button>
|
||||
<button class="playback-button--small shuffle active" v-else :class="isDisabled() && 'disabled'"
|
||||
@click="mk.shuffleMode = 0" :title="$root.getLz('term.disableShuffle')" v-b-tooltip.hover></button>
|
||||
</div>
|
||||
<div class="app-chrome-item display--large">
|
||||
<button class="playback-button previous" @click="prevButton()" :class="isPrevDisabled() && 'disabled'"
|
||||
:title="$root.getLz('term.previous')" v-b-tooltip.hover></button>
|
||||
</div>
|
||||
<div class="app-chrome-item display--large">
|
||||
<button class="playback-button stop" @click="mk.stop()"
|
||||
v-if="mk.isPlaying && mk.nowPlayingItem.attributes.playParams.kind == 'radioStation'"
|
||||
:title="$root.getLz('term.stop')" v-b-tooltip.hover></button>
|
||||
<button class="playback-button pause" @click="mk.pause()" v-else-if="mk.isPlaying"
|
||||
:title="$root.getLz('term.pause')" v-b-tooltip.hover></button>
|
||||
<button class="playback-button play" @click="mk.play()" v-else :title="$root.getLz('term.play')"
|
||||
v-b-tooltip.hover></button>
|
||||
</div>
|
||||
<div class="app-chrome-item display--large">
|
||||
<button class="playback-button next" @click="skipToNextItem()" :class="isNextDisabled() && 'disabled'"
|
||||
:title="$root.getLz('term.next')" v-b-tooltip.hover></button>
|
||||
</div>
|
||||
<div class="app-chrome-item display--large">
|
||||
<button class="playback-button--small repeat" v-if="mk.repeatMode == 0" :class="isDisabled() && 'disabled'"
|
||||
@click="mk.repeatMode = 1" :title="$root.getLz('term.enableRepeatOne')" v-b-tooltip.hover></button>
|
||||
<button class="playback-button--small repeat repeatOne" @click="mk.repeatMode = 2"
|
||||
:class="isDisabled() && 'disabled'" v-else-if="mk.repeatMode == 1"
|
||||
:title="$root.getLz('term.disableRepeatOne')" v-b-tooltip.hover></button>
|
||||
<button class="playback-button--small repeat active" @click="mk.repeatMode = 0"
|
||||
:class="isDisabled() && 'disabled'" v-else-if="mk.repeatMode == 2" :title="$root.getLz('term.disableRepeat')"
|
||||
v-b-tooltip.hover></button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
<div class="app-chrome--center">
|
||||
<div class="app-chrome-item playback-controls" v-if="getThemeDirective('windowLayout') != 'twopanel'">
|
||||
<template v-if="mkReady()">
|
||||
<div class="app-playback-controls" @mouseover="chrome.progresshover = true"
|
||||
@mouseleave="chrome.progresshover = false" @contextmenu="nowPlayingContextMenu">
|
||||
<div class="artwork" id="artworkLCD">
|
||||
<mediaitem-artwork :url="currentArtUrl"></mediaitem-artwork>
|
||||
</div>
|
||||
<b-popover custom-class="mediainfo-popover" target="artworkLCD" triggers="hover" placement="bottom">
|
||||
<div class="content">
|
||||
<div class="shadow-artwork">
|
||||
<mediaitem-artwork :url="currentArtUrl"></mediaitem-artwork>
|
||||
</div>
|
||||
<div class="popover-artwork">
|
||||
<mediaitem-artwork :size="210" :url="currentArtUrl"></mediaitem-artwork>
|
||||
</div>
|
||||
<div class="song-name">
|
||||
{{ mk.nowPlayingItem["attributes"]["name"] }}
|
||||
</div>
|
||||
<div class="song-artist" @click="getNowPlayingItemDetailed(`artist`)">
|
||||
{{ mk.nowPlayingItem["attributes"]["artistName"] }}
|
||||
</div>
|
||||
<div class="song-album" @click="getNowPlayingItemDetailed(`album`)">
|
||||
{{
|
||||
mk.nowPlayingItem["attributes"]["albumName"]
|
||||
? mk.nowPlayingItem["attributes"]["albumName"]
|
||||
: ""
|
||||
}}
|
||||
</div>
|
||||
<hr />
|
||||
<div class="btn-group" style="width: 100%">
|
||||
<button class="md-btn md-btn-small" style="width: 100%" @click="drawer.open = false; miniPlayer(true)">
|
||||
{{ $root.getLz("term.miniplayer") }}
|
||||
</button>
|
||||
<button class="md-btn md-btn-small" style="width: 100%" @click="drawer.open = false; fullscreen(true)">
|
||||
{{ $root.getLz("term.fullscreenView") }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</b-popover>
|
||||
<div class="playback-info">
|
||||
<div class="chrome-icon-container">
|
||||
<div class="audio-type private-icon" v-if="cfg.general.privateEnabled === true"></div>
|
||||
<div class="audio-type spatial-icon" v-if="cfg.audio.maikiwiAudio.spatial === true"
|
||||
:title="$root.getLz('settings.option.audio.enableAdvancedFunctionality.tunedAudioSpatialization') + ' (' + getProfileLz('CTS', cfg.audio.maikiwiAudio.spatialProfile) + ')'" v-b-tooltip.hover
|
||||
></div>
|
||||
<div class="audio-type lossless-icon" v-if="(mk.nowPlayingItem?.localFilesMetadata?.lossless ?? false) === true"
|
||||
:title="mk.nowPlayingItem?.localFilesMetadata?.bitDepth +'-bit / '+ mk.nowPlayingItem?.localFilesMetadata?.sampleRate/1000 + ' kHz ' + mk.nowPlayingItem.localFilesMetadata.container" v-b-tooltip.hover
|
||||
></div>
|
||||
<div class="audio-type ppe-icon" v-if="mk.nowPlayingItem.localFilesMetadata == null && cfg.audio.maikiwiAudio.ciderPPE === true"
|
||||
:title="$root.getLz('settings.option.audio.enableAdvancedFunctionality.ciderPPE')" v-b-tooltip.hover
|
||||
></div>
|
||||
<div class="vdiv display--large" v-if="getThemeDirective('windowLayout') != 'twopanel'"></div>
|
||||
</template>
|
||||
<template v-if="getThemeDirective('windowLayout') != 'twopanel'">
|
||||
<div class="app-chrome-item playback-control-buttons">
|
||||
<div class="app-chrome-item display--large">
|
||||
<button class="playback-button--small shuffle" v-if="mk.shuffleMode == 0"
|
||||
:class="isDisabled() && 'disabled'"
|
||||
@click="mk.shuffleMode = 1" :title="$root.getLz('term.enableShuffle')"
|
||||
v-b-tooltip.hover></button>
|
||||
<button class="playback-button--small shuffle active" v-else :class="isDisabled() && 'disabled'"
|
||||
@click="mk.shuffleMode = 0" :title="$root.getLz('term.disableShuffle')"
|
||||
v-b-tooltip.hover></button>
|
||||
</div>
|
||||
<div class="app-chrome-item display--large">
|
||||
<button class="playback-button previous" @click="prevButton()"
|
||||
:class="isPrevDisabled() && 'disabled'"
|
||||
:title="$root.getLz('term.previous')" v-b-tooltip.hover></button>
|
||||
</div>
|
||||
<div class="app-chrome-item display--large">
|
||||
<button class="playback-button stop" @click="mk.stop()"
|
||||
v-if="mk.isPlaying && mk.nowPlayingItem.attributes.playParams.kind == 'radioStation'"
|
||||
:title="$root.getLz('term.stop')" v-b-tooltip.hover></button>
|
||||
<button class="playback-button pause" @click="mk.pause()" v-else-if="mk.isPlaying"
|
||||
:title="$root.getLz('term.pause')" v-b-tooltip.hover></button>
|
||||
<button class="playback-button play" @click="mk.play()" v-else :title="$root.getLz('term.play')"
|
||||
v-b-tooltip.hover></button>
|
||||
</div>
|
||||
<div class="app-chrome-item display--large">
|
||||
<button class="playback-button next" @click="skipToNextItem()"
|
||||
:class="isNextDisabled() && 'disabled'"
|
||||
:title="$root.getLz('term.next')" v-b-tooltip.hover></button>
|
||||
</div>
|
||||
<div class="app-chrome-item display--large">
|
||||
<button class="playback-button--small repeat" v-if="mk.repeatMode == 0"
|
||||
:class="isDisabled() && 'disabled'"
|
||||
@click="mk.repeatMode = 1" :title="$root.getLz('term.enableRepeatOne')"
|
||||
v-b-tooltip.hover></button>
|
||||
<button class="playback-button--small repeat repeatOne" @click="mk.repeatMode = 2"
|
||||
:class="isDisabled() && 'disabled'" v-else-if="mk.repeatMode == 1"
|
||||
:title="$root.getLz('term.disableRepeatOne')" v-b-tooltip.hover></button>
|
||||
<button class="playback-button--small repeat active" @click="mk.repeatMode = 0"
|
||||
:class="isDisabled() && 'disabled'" v-else-if="mk.repeatMode == 2"
|
||||
:title="$root.getLz('term.disableRepeat')"
|
||||
v-b-tooltip.hover></button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="info-rect">
|
||||
<div class="song-name"
|
||||
:class="[isElementOverflowing('#app-main > div.app-chrome > div.app-chrome--center > div > div > div.playback-info > div.song-name') ? 'marquee' : '']">
|
||||
{{ mk.nowPlayingItem["attributes"]["name"] }}
|
||||
<div class="explicit-icon" v-if="mk.nowPlayingItem['attributes']['contentRating'] == 'explicit'"
|
||||
style="display: inline-block"></div>
|
||||
</div>
|
||||
<div class="song-artist-album">
|
||||
<div class="song-artist-album-content"
|
||||
:class="[isElementOverflowing('#app-main > .app-chrome .app-chrome-item > .app-playback-controls > div >.song-artist-album > .song-artist-album-content') ? 'marquee' : '']"
|
||||
style="
|
||||
</template>
|
||||
</div>
|
||||
<div class="app-chrome--center">
|
||||
<div class="app-chrome-item playback-controls" v-if="getThemeDirective('windowLayout') != 'twopanel'">
|
||||
<template v-if="mkReady()">
|
||||
<div class="app-playback-controls" @mouseover="chrome.progresshover = true"
|
||||
@mouseleave="chrome.progresshover = false" @contextmenu="nowPlayingContextMenu">
|
||||
<div class="artwork" id="artworkLCD">
|
||||
<mediaitem-artwork :url="currentArtUrl"></mediaitem-artwork>
|
||||
</div>
|
||||
<b-popover custom-class="mediainfo-popover" target="artworkLCD" triggers="hover" placement="bottom">
|
||||
<div class="content">
|
||||
<div class="shadow-artwork">
|
||||
<mediaitem-artwork :url="currentArtUrl"></mediaitem-artwork>
|
||||
</div>
|
||||
<div class="popover-artwork">
|
||||
<mediaitem-artwork :size="210" :url="currentArtUrl"></mediaitem-artwork>
|
||||
</div>
|
||||
<div class="song-name">
|
||||
{{ mk.nowPlayingItem["attributes"]["name"] }}
|
||||
</div>
|
||||
<div class="song-artist" @click="getNowPlayingItemDetailed(`artist`)">
|
||||
{{ mk.nowPlayingItem["attributes"]["artistName"] }}
|
||||
</div>
|
||||
<div class="song-album" @click="getNowPlayingItemDetailed(`album`)">
|
||||
{{
|
||||
mk.nowPlayingItem["attributes"]["albumName"]
|
||||
? mk.nowPlayingItem["attributes"]["albumName"]
|
||||
: ""
|
||||
}}
|
||||
</div>
|
||||
<hr />
|
||||
<div class="btn-group" style="width: 100%">
|
||||
<button class="md-btn md-btn-small" style="width: 100%"
|
||||
@click="drawer.open = false; miniPlayer(true)">
|
||||
{{ $root.getLz("term.miniplayer") }}
|
||||
</button>
|
||||
<button class="md-btn md-btn-small" style="width: 100%"
|
||||
@click="drawer.open = false; fullscreen(true)">
|
||||
{{ $root.getLz("term.fullscreenView") }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</b-popover>
|
||||
<div class="playback-info">
|
||||
<div class="chrome-icon-container">
|
||||
<div class="audio-type private-icon" v-if="cfg.general.privateEnabled === true"></div>
|
||||
<div class="audio-type spatial-icon" v-if="cfg.audio.maikiwiAudio.spatial === true"
|
||||
:title="$root.getLz('settings.option.audio.enableAdvancedFunctionality.tunedAudioSpatialization') + ' (' + getProfileLz('CTS', cfg.audio.maikiwiAudio.spatialProfile) + ')'"
|
||||
v-b-tooltip.hover
|
||||
></div>
|
||||
<div class="audio-type lossless-icon"
|
||||
v-if="(mk.nowPlayingItem?.localFilesMetadata?.lossless ?? false) === true"
|
||||
:title="mk.nowPlayingItem?.localFilesMetadata?.bitDepth +'-bit / '+ mk.nowPlayingItem?.localFilesMetadata?.sampleRate/1000 + ' kHz ' + mk.nowPlayingItem.localFilesMetadata.container"
|
||||
v-b-tooltip.hover
|
||||
></div>
|
||||
<div class="audio-type ppe-icon"
|
||||
v-if="mk.nowPlayingItem.localFilesMetadata == null && cfg.audio.maikiwiAudio.ciderPPE === true"
|
||||
:title="$root.getLz('settings.option.audio.enableAdvancedFunctionality.ciderPPE')"
|
||||
v-b-tooltip.hover
|
||||
></div>
|
||||
</div>
|
||||
<div class="info-rect">
|
||||
<div class="song-name"
|
||||
:class="[isElementOverflowing('#app-main > div.app-chrome > div.app-chrome--center > div > div > div.playback-info > div.song-name') ? 'marquee' : '']">
|
||||
{{ mk.nowPlayingItem["attributes"]["name"] }}
|
||||
<div class="explicit-icon"
|
||||
v-if="mk.nowPlayingItem['attributes']['contentRating'] == 'explicit'"
|
||||
style="display: inline-block"></div>
|
||||
</div>
|
||||
<div class="song-artist-album">
|
||||
<div class="song-artist-album-content"
|
||||
:class="[isElementOverflowing('#app-main > .app-chrome .app-chrome-item > .app-playback-controls > div >.song-artist-album > .song-artist-album-content') ? 'marquee' : '']"
|
||||
style="
|
||||
display: inline-block;
|
||||
-webkit-box-orient: horizontal;
|
||||
white-space: nowrap;
|
||||
">
|
||||
<div class="item-navigate song-artist" style="display: inline-block"
|
||||
@click="getNowPlayingItemDetailed(`artist`)">
|
||||
{{ mk.nowPlayingItem["attributes"]["artistName"] }}
|
||||
</div>
|
||||
<div class="song-artist item-navigate" style="display: inline-block"
|
||||
@click="getNowPlayingItemDetailed('album')"
|
||||
v-if="mk.nowPlayingItem['attributes']['albumName'] != ''">
|
||||
<div class="separator" style="display: inline-block">
|
||||
{{ "—" }}
|
||||
<div class="item-navigate song-artist" style="display: inline-block"
|
||||
@click="getNowPlayingItemDetailed(`artist`)">
|
||||
{{ mk.nowPlayingItem["attributes"]["artistName"] }}
|
||||
</div>
|
||||
<div class="song-artist item-navigate" style="display: inline-block"
|
||||
@click="getNowPlayingItemDetailed('album')"
|
||||
v-if="mk.nowPlayingItem['attributes']['albumName'] != ''">
|
||||
<div class="separator" style="display: inline-block">
|
||||
{{ "—" }}
|
||||
</div>
|
||||
{{
|
||||
mk.nowPlayingItem["attributes"]["albumName"]
|
||||
? mk.nowPlayingItem["attributes"]["albumName"]
|
||||
: ""
|
||||
}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="song-progress">
|
||||
<div class="song-duration" style="justify-content: space-between; height: 1px"
|
||||
:style="[chrome.progresshover ? {'display': 'flex'} : {'display' : 'none'} ]">
|
||||
<p style="width: auto">{{ convertTime(getSongProgress()) }}</p>
|
||||
<p style="width: auto">
|
||||
{{ convertTime(mk.currentPlaybackDuration) }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<input type="range" step="0.01" min="0" :style="progressBarStyle()"
|
||||
@input="playerLCD.desiredDuration = $event.target.value;playerLCD.userInteraction = true"
|
||||
@mouseup="mk.seekToTime($event.target.value);setTimeout(()=>{playerLCD.desiredDuration = 0;playerLCD.userInteraction = false}, 1000);"
|
||||
@touchend="mk.seekToTime($event.target.value);setTimeout(()=>{playerLCD.desiredDuration = 0;playerLCD.userInteraction = false}, 1000);"
|
||||
:max="mk.currentPlaybackDuration" :value="getSongProgress()" />
|
||||
</div>
|
||||
</div>
|
||||
{{
|
||||
mk.nowPlayingItem["attributes"]["albumName"]
|
||||
? mk.nowPlayingItem["attributes"]["albumName"]
|
||||
: ""
|
||||
}}
|
||||
</div>
|
||||
<template v-if="mk.nowPlayingItem['attributes']['playParams']">
|
||||
<div class="actions">
|
||||
<button class="lcdMenu" @click="nowPlayingContextMenu" :title="$root.getLz('term.more')"
|
||||
v-b-tooltip.hover>
|
||||
<div class="svg-icon"></div>
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="song-progress">
|
||||
<div class="song-duration" style="justify-content: space-between; height: 1px"
|
||||
:style="[chrome.progresshover ? {'display': 'flex'} : {'display' : 'none'} ]">
|
||||
<p style="width: auto">{{ convertTime(getSongProgress()) }}</p>
|
||||
<p style="width: auto">
|
||||
{{ convertTime(mk.currentPlaybackDuration) }}
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div class="app-playback-controls">
|
||||
<div class="artwork" id="artworkLCD" style="pointer-events: none;">
|
||||
<mediaitem-artwork :url="currentArtUrl"></mediaitem-artwork>
|
||||
</div>
|
||||
<div class="playback-info">
|
||||
<div class="info-rect">
|
||||
|
||||
<input type="range" step="0.01" min="0" :style="progressBarStyle()"
|
||||
@input="playerLCD.desiredDuration = $event.target.value;playerLCD.userInteraction = true"
|
||||
@mouseup="mk.seekToTime($event.target.value);setTimeout(()=>{playerLCD.desiredDuration = 0;playerLCD.userInteraction = false}, 1000);"
|
||||
@touchend="mk.seekToTime($event.target.value);setTimeout(()=>{playerLCD.desiredDuration = 0;playerLCD.userInteraction = false}, 1000);"
|
||||
:max="mk.currentPlaybackDuration" :value="getSongProgress()" />
|
||||
</div>
|
||||
</div>
|
||||
<template v-if="mk.nowPlayingItem['attributes']['playParams']">
|
||||
<div class="actions">
|
||||
<button class="lcdMenu" @click="nowPlayingContextMenu" :title="$root.getLz('term.more')"
|
||||
v-b-tooltip.hover>
|
||||
<div class="svg-icon"></div>
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div class="app-playback-controls">
|
||||
<div class="artwork" id="artworkLCD" style="pointer-events: none;">
|
||||
<mediaitem-artwork :url="currentArtUrl"></mediaitem-artwork>
|
||||
</div>
|
||||
<div class="playback-info">
|
||||
<div class="info-rect">
|
||||
|
||||
<div class="app-chrome-item" v-else>
|
||||
<div class="top-nav-group">
|
||||
<sidebar-library-item :name="$root.getLz('home.title')" svg-icon="./assets/feather/home.svg"
|
||||
svg-icon-name="home" page="home">
|
||||
</sidebar-library-item>
|
||||
<sidebar-library-item :name="$root.getLz('term.listenNow')" svg-icon="./assets/feather/play-circle.svg"
|
||||
svg-icon-name="listenNow"
|
||||
page="listen_now"></sidebar-library-item>
|
||||
<sidebar-library-item :name="$root.getLz('term.browse')" svg-icon="./assets/feather/globe.svg"
|
||||
svg-icon-name="browse" page="browse">
|
||||
</sidebar-library-item>
|
||||
<sidebar-library-item :name="$root.getLz('term.radio')" svg-icon="./assets/feather/radio.svg"
|
||||
svg-icon-name="radio" page="radio">
|
||||
</sidebar-library-item>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
<div class="app-chrome-item" v-else>
|
||||
<div class="top-nav-group">
|
||||
<sidebar-library-item :name="$root.getLz('home.title')" svg-icon="./assets/feather/home.svg" svg-icon-name="home" page="home">
|
||||
</sidebar-library-item>
|
||||
<sidebar-library-item :name="$root.getLz('term.listenNow')" svg-icon="./assets/feather/play-circle.svg" svg-icon-name="listenNow"
|
||||
page="listen_now"></sidebar-library-item>
|
||||
<sidebar-library-item :name="$root.getLz('term.browse')" svg-icon="./assets/feather/globe.svg" svg-icon-name="browse" page="browse">
|
||||
</sidebar-library-item>
|
||||
<sidebar-library-item :name="$root.getLz('term.radio')" svg-icon="./assets/feather/radio.svg" svg-icon-name="radio" page="radio">
|
||||
</sidebar-library-item>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="app-chrome--right">
|
||||
<template v-if="getThemeDirective('windowLayout') != 'twopanel'">
|
||||
<div class="app-chrome-item volume display--large">
|
||||
<button class="volume-button--small volume" @click="muteButtonPressed()"
|
||||
:class="{'active': this.cfg.audio.volume == 0}"
|
||||
:title="cfg.audio.muted ? $root.getLz('term.unmute') : $root.getLz('term.mute')" v-b-tooltip.hover></button>
|
||||
<input type="range" @wheel="volumeWheel" :step="cfg.audio.volumeStep" min="0" :max="cfg.audio.maxVolume"
|
||||
v-model="mk.volume" v-if="typeof mk.volume != 'undefined'" @change="checkMuteChange()" v-b-tooltip.hover
|
||||
:title="formatVolumeTooltip()" />
|
||||
</div>
|
||||
<div class="app-chrome-item generic">
|
||||
<button class="playback-button--small cast" :title="$root.getLz('term.cast')"
|
||||
@click="modals.castMenu = true"
|
||||
v-b-tooltip.hover></button>
|
||||
</div>
|
||||
<div class="app-chrome-item generic">
|
||||
<button class="playback-button--small queue" :title="$root.getLz('term.queue')" v-b-tooltip.hover
|
||||
:class="{'active': drawer.panel == 'queue'}" @click="invokeDrawer('queue')"></button>
|
||||
</div>
|
||||
<div class="app-chrome-item generic">
|
||||
<template v-if="lyrics && lyrics != [] && lyrics.length > 0">
|
||||
<button class="playback-button--small lyrics" :title="$root.getLz('term.lyrics')" v-b-tooltip.hover
|
||||
:class="{'active': drawer.panel == 'lyrics'}" @click="invokeDrawer('lyrics')"></button>
|
||||
<div class="app-chrome--right">
|
||||
<template v-if="getThemeDirective('windowLayout') != 'twopanel'">
|
||||
<div class="app-chrome-item volume display--large">
|
||||
<button class="volume-button--small volume" @click="muteButtonPressed()"
|
||||
:class="{'active': this.cfg.audio.volume == 0}"
|
||||
:title="cfg.audio.muted ? $root.getLz('term.unmute') : $root.getLz('term.mute')"
|
||||
v-b-tooltip.hover></button>
|
||||
<input type="range" @wheel="volumeWheel" :step="cfg.audio.volumeStep" min="0" :max="cfg.audio.maxVolume"
|
||||
v-model="mk.volume" v-if="typeof mk.volume != 'undefined'" @change="checkMuteChange()"
|
||||
v-b-tooltip.hover
|
||||
:title="formatVolumeTooltip()" />
|
||||
</div>
|
||||
<div class="app-chrome-item generic">
|
||||
<button class="playback-button--small cast" :title="$root.getLz('term.cast')"
|
||||
@click="modals.castMenu = true"
|
||||
v-b-tooltip.hover></button>
|
||||
</div>
|
||||
<div class="app-chrome-item generic">
|
||||
<button class="playback-button--small queue" :title="$root.getLz('term.queue')" v-b-tooltip.hover
|
||||
:class="{'active': drawer.panel == 'queue'}" @click="invokeDrawer('queue')"></button>
|
||||
</div>
|
||||
<div class="app-chrome-item generic">
|
||||
<template v-if="lyrics && lyrics != [] && lyrics.length > 0">
|
||||
<button class="playback-button--small lyrics" :title="$root.getLz('term.lyrics')" v-b-tooltip.hover
|
||||
:class="{'active': drawer.panel == 'lyrics'}" @click="invokeDrawer('lyrics')"></button>
|
||||
</template>
|
||||
<template v-else>
|
||||
<button class="playback-button--small lyrics"
|
||||
:style="{'opacity': 0.3, 'pointer-events': 'none'}"></button>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<button class="playback-button--small lyrics" :style="{'opacity': 0.3, 'pointer-events': 'none'}" ></button>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div class="app-chrome-item search">
|
||||
<div class="search-input-container">
|
||||
<div class="search-input--icon"></div>
|
||||
<input type="search" spellcheck="false" @click="$root.appRoute('search');" @focus="search.showHints = true"
|
||||
@blur="setTimeout(()=>{search.showHints = false}, 300)"
|
||||
v-on:keyup.enter="searchQuery();search.showHints = false" @change="$root.appRoute('search');" @input="getSearchHints()"
|
||||
:placeholder="$root.getLz('term.search') + '...'" v-model="search.term" ref="searchInput"
|
||||
class="search-input" />
|
||||
<div class="app-chrome-item search">
|
||||
<div class="search-input-container">
|
||||
<div class="search-input--icon"></div>
|
||||
<input type="search" spellcheck="false" @click="$root.appRoute('search');"
|
||||
@focus="search.showHints = true"
|
||||
@blur="setTimeout(()=>{search.showHints = false}, 300)"
|
||||
v-on:keyup.enter="searchQuery();search.showHints = false" @change="$root.appRoute('search');"
|
||||
@input="getSearchHints()"
|
||||
:placeholder="$root.getLz('term.search') + '...'" v-model="search.term" ref="searchInput"
|
||||
class="search-input" />
|
||||
|
||||
<div class="search-hints-container" v-if="search.showHints && search.hints.length != 0">
|
||||
<div class="search-hints">
|
||||
<button class="search-hint text-overflow-elipsis" v-for="hint in search.hints"
|
||||
@click="search.term = hint;search.showHints = false;searchQuery(hint)">
|
||||
{{ hint }}
|
||||
</button>
|
||||
<div class="search-hints-container" v-if="search.showHints && search.hints.length != 0">
|
||||
<div class="search-hints">
|
||||
<button class="search-hint text-overflow-elipsis" v-for="hint in search.hints"
|
||||
@click="search.term = hint;search.showHints = false;searchQuery(hint)">
|
||||
{{ hint }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<div class="app-chrome-item full-height" id="window-controls-container"
|
||||
v-if="chrome.windowControlPosition == 'right' && !chrome.nativeControls">
|
||||
<div class="window-controls">
|
||||
<div class="minimize" @click="ipcRenderer.send('minimize')"></div>
|
||||
<div class="minmax restore" v-if="chrome.maximized" @click="ipcRenderer.send('maximize')"></div>
|
||||
<div class="minmax" v-else @click="ipcRenderer.send('maximize')"></div>
|
||||
<div class="close" @click="ipcRenderer.send('close')"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<div class="app-chrome-item full-height" id="window-controls-container"
|
||||
v-if="chrome.windowControlPosition == 'right' && !chrome.nativeControls">
|
||||
<div class="window-controls">
|
||||
<div class="minimize" @click="ipcRenderer.send('minimize')"></div>
|
||||
<div class="minmax restore" v-if="chrome.maximized" @click="ipcRenderer.send('maximize')"></div>
|
||||
<div class="minmax" v-else @click="ipcRenderer.send('maximize')"></div>
|
||||
<div class="close" @click="ipcRenderer.send('close')"></div>
|
||||
</div>
|
||||
<div class="app-chrome-item full-height" v-else-if="platform != 'darwin' && !chrome.nativeControls">
|
||||
<button class="app-mainmenu" @blur="mainMenuVisibility(false)" @click="mainMenuVisibility(true)"
|
||||
@contextmenu="mainMenuVisibility(true)" :class="{active: chrome.menuOpened}"></button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="app-chrome-item full-height" v-else-if="platform != 'darwin' && !chrome.nativeControls">
|
||||
<button class="app-mainmenu" @blur="mainMenuVisibility(false)" @click="mainMenuVisibility(true)"
|
||||
@contextmenu="mainMenuVisibility(true)" :class="{active: chrome.menuOpened}"></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -50,10 +50,10 @@
|
|||
<div id="apple-music-video-player-controls">
|
||||
<div id="player-exit" title="Close" @click="exitMV();fullscreen(false);">
|
||||
<svg fill="white" xmlns="http://www.w3.org/2000/svg" width="21" height="21" viewBox="0 0 21 21"
|
||||
aria-role="presentation" focusable="false" @click="exitMV();fullscreen(false);">
|
||||
aria-role="presentation" focusable="false" @click="exitMV();fullscreen(false);">
|
||||
<path
|
||||
d="M10.5 21C4.724 21 0 16.275 0 10.5S4.724 0 10.5 0 21 4.725 21 10.5 16.276 21 10.5 21zm-3.543-5.967a.96.96 0 00.693-.295l2.837-2.842 2.85 2.842c.167.167.41.295.693.295.552 0 1.001-.461 1.001-1.012 0-.281-.115-.512-.295-.704L11.899 10.5l2.85-2.855a.875.875 0 00.295-.68c0-.55-.45-.998-1.001-.998a.871.871 0 00-.668.295l-2.888 2.855-2.862-2.843a.891.891 0 00-.668-.281.99.99 0 00-1.001.986c0 .269.116.512.295.678L9.088 10.5l-2.837 2.843a.926.926 0 00-.295.678c0 .551.45 1.012 1.001 1.012z"
|
||||
fill-rule="nonzero"/>
|
||||
fill-rule="nonzero" />
|
||||
</svg>
|
||||
</div>
|
||||
<div id="captions" v-if="lyricon">{{((lyricon) ? ((lyrics.length > 0 && lyrics[currentLyricsLine] &&
|
||||
|
@ -67,7 +67,7 @@
|
|||
</div>
|
||||
<div class="playback-info music-player-info">
|
||||
<div class="song-artist-album-content"
|
||||
style="display: inline-block; -webkit-box-orient: horizontal; white-space: nowrap;">
|
||||
style="display: inline-block; -webkit-box-orient: horizontal; white-space: nowrap;">
|
||||
<div class="song-artist" style="display: inline-block">
|
||||
{{ mk.nowPlayingItem?.attributes?.artistName ?? '' }}
|
||||
</div>
|
||||
|
@ -85,7 +85,7 @@
|
|||
@mouseup="mk.seekToTime($event.target.value);setTimeout(()=>{playerLCD.desiredDuration = 0;playerLCD.userInteraction = false}, 1000);"
|
||||
@touchend="mk.seekToTime($event.target.value);setTimeout(()=>{playerLCD.desiredDuration = 0;playerLCD.userInteraction = false}, 1000);"
|
||||
:max="mk.currentPlaybackDuration" :value="getSongProgress()">
|
||||
<p style="width: auto">{{ convertTime(mk.currentPlaybackDuration) }}
|
||||
<p style="width: auto">{{ convertTime(mk.currentPlaybackDuration) }}
|
||||
</div>
|
||||
<div class="app-chrome-item display--large">
|
||||
<div class="app-chrome-item volume display--large">
|
||||
|
@ -93,7 +93,8 @@
|
|||
:class="{'active': this.cfg.audio.volume == 0}"
|
||||
:title="cfg.audio.muted ? $root.getLz('term.unmute') : $root.getLz('term.mute')"
|
||||
v-b-tooltip.hover></button>
|
||||
<input type="range" @wheel="volumeWheel" :step="cfg.audio.volumeStep" min="0" :max="cfg.audio.maxVolume"
|
||||
<input type="range" @wheel="volumeWheel" :step="cfg.audio.volumeStep" min="0"
|
||||
:max="cfg.audio.maxVolume"
|
||||
v-model="mk.volume" v-if="typeof mk.volume != 'undefined'" @change="checkMuteChange()"
|
||||
v-b-tooltip.hover :title="formatVolumeTooltip()">
|
||||
</div>
|
||||
|
@ -102,30 +103,30 @@
|
|||
<button class="playback-button play" @click="mk.play()" v-else
|
||||
:title="$root.getLz('term.play')" v-b-tooltip.hover></button>
|
||||
<div class="app-chrome-item generic">
|
||||
<template v-if="lyrics && lyrics != [] && lyrics.length > 0">
|
||||
<button class="playback-button--small lyrics"
|
||||
:title="$root.getLz('term.lyrics')"
|
||||
v-b-tooltip.hover
|
||||
:class="{'active': drawer.panel == 'lyrics'}"
|
||||
@click="invokeDrawer('lyrics')"></button>
|
||||
</template>
|
||||
<template v-else>
|
||||
<button class="playback-button--small lyrics"
|
||||
:style="{'opacity': 0.3, 'pointer-events': 'none'}"></button>
|
||||
</template>
|
||||
</div>
|
||||
<template v-if="lyrics && lyrics != [] && lyrics.length > 0">
|
||||
<button class="playback-button--small lyrics"
|
||||
:title="$root.getLz('term.lyrics')"
|
||||
v-b-tooltip.hover
|
||||
:class="{'active': drawer.panel == 'lyrics'}"
|
||||
@click="invokeDrawer('lyrics')"></button>
|
||||
</template>
|
||||
<template v-else>
|
||||
<button class="playback-button--small lyrics"
|
||||
:style="{'opacity': 0.3, 'pointer-events': 'none'}"></button>
|
||||
</template>
|
||||
</div>
|
||||
<div id="player-pip"
|
||||
@click="pip()"
|
||||
title="Picture-in-Picture"
|
||||
v-b-tooltip.hover>
|
||||
@click="pip()"
|
||||
title="Picture-in-Picture"
|
||||
v-b-tooltip.hover>
|
||||
<%- include("../svg/pip.svg") %>
|
||||
</div>
|
||||
<div id="player-fullscreen"
|
||||
@click="fullscreen(!fullscreenState)"
|
||||
title="Fullscreen"
|
||||
v-b-tooltip.hover>
|
||||
@click="fullscreen(!fullscreenState)"
|
||||
title="Fullscreen"
|
||||
v-b-tooltip.hover>
|
||||
<%- include("../svg/fullscreen.svg") %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,88 +1,90 @@
|
|||
<script type="text/x-template" id="add-to-playlist">
|
||||
<div class="modal-fullscreen addtoplaylist-panel" @click.self="app.resetState()" @contextmenu.self="app.resetState()">
|
||||
<div class="modal-window">
|
||||
<div class="modal-header">
|
||||
<div class="modal-title">{{app.getLz('action.addToPlaylist')}}</div>
|
||||
<button class="close-btn" @click="app.resetState()" :aria-label="app.getLz('action.close')"></button>
|
||||
</div>
|
||||
<div class="modal-content">
|
||||
<button class="playlist-item"
|
||||
@click="app.addSelectedToNewPlaylist()" style="width:100%;">
|
||||
<div class="icon"><%- include("../svg/plus.svg") %></div>
|
||||
<div class="name">{{app.getLz('action.createPlaylist')}}</div>
|
||||
</button>
|
||||
<sidebar-playlist :playlist-select="playlistSelect" :relate-media-items="relateItems" v-for="item in $root.getPlaylistFolderChildren('p.playlistsroot')" :item="item">
|
||||
</sidebar-playlist>
|
||||
</div>
|
||||
<div class="modal-search">
|
||||
<div class="search-input-container" style="width:100%;margin: 16px 0;">
|
||||
<div class="search-input--icon"></div>
|
||||
<input type="search"
|
||||
ref="searchInput"
|
||||
style="width:100%;"
|
||||
spellcheck="false"
|
||||
:placeholder="app.getLz('term.search') + '...'"
|
||||
v-model="searchQuery"
|
||||
@input="search()"
|
||||
class="search-input">
|
||||
</div>
|
||||
<div class="modal-fullscreen addtoplaylist-panel" @click.self="app.resetState()"
|
||||
@contextmenu.self="app.resetState()">
|
||||
<div class="modal-window">
|
||||
<div class="modal-header">
|
||||
<div class="modal-title">{{app.getLz('action.addToPlaylist')}}</div>
|
||||
<button class="close-btn" @click="app.resetState()" :aria-label="app.getLz('action.close')"></button>
|
||||
</div>
|
||||
<div class="modal-content">
|
||||
<button class="playlist-item"
|
||||
@click="app.addSelectedToNewPlaylist()" style="width:100%;">
|
||||
<div class="icon"><%- include("../svg/plus.svg") %></div>
|
||||
<div class="name">{{app.getLz('action.createPlaylist')}}</div>
|
||||
</button>
|
||||
<sidebar-playlist :playlist-select="playlistSelect" :relate-media-items="relateItems"
|
||||
v-for="item in $root.getPlaylistFolderChildren('p.playlistsroot')" :item="item">
|
||||
</sidebar-playlist>
|
||||
</div>
|
||||
<div class="modal-search">
|
||||
<div class="search-input-container" style="width:100%;margin: 16px 0;">
|
||||
<div class="search-input--icon"></div>
|
||||
<input type="search"
|
||||
ref="searchInput"
|
||||
style="width:100%;"
|
||||
spellcheck="false"
|
||||
:placeholder="app.getLz('term.search') + '...'"
|
||||
v-model="searchQuery"
|
||||
@input="search()"
|
||||
class="search-input">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script>
|
||||
Vue.component('add-to-playlist', {
|
||||
template: '#add-to-playlist',
|
||||
data: function () {
|
||||
return {
|
||||
playlistSorted: [],
|
||||
searchQuery: "",
|
||||
focused: "",
|
||||
app: this.$root,
|
||||
relateItems: []
|
||||
}
|
||||
},
|
||||
props: {
|
||||
playlists: {
|
||||
type: Array,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.relateItems = [this.$root.selectedMediaItems[0].id]
|
||||
this.search()
|
||||
this.$refs.searchInput.focus()
|
||||
this.$refs.searchInput.addEventListener('keydown', (e) => {
|
||||
if (e.keyCode == 13) {
|
||||
if (this.focused != "") {
|
||||
this.addToPlaylist(this.focused)
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
playlistSelect(playlist) {
|
||||
if (playlist.type != "library-playlist-folders") {
|
||||
this.addToPlaylist(playlist.id)
|
||||
}
|
||||
},
|
||||
addToPlaylist(id) {
|
||||
app.addSelectedToPlaylist(id)
|
||||
},
|
||||
search() {
|
||||
this.focused = ""
|
||||
if (this.searchQuery == "") {
|
||||
this.playlistSorted = this.playlists
|
||||
} else {
|
||||
this.playlistSorted = this.playlists.filter(playlist => {
|
||||
return playlist.attributes.name.toLowerCase().indexOf(this.searchQuery.toLowerCase()) > -1
|
||||
})
|
||||
if (this.playlistSorted.length == 1) {
|
||||
this.focused = this.playlistSorted[0].id
|
||||
}
|
||||
}
|
||||
},
|
||||
Vue.component('add-to-playlist', {
|
||||
template: '#add-to-playlist',
|
||||
data: function() {
|
||||
return {
|
||||
playlistSorted: [],
|
||||
searchQuery: "",
|
||||
focused: "",
|
||||
app: this.$root,
|
||||
relateItems: []
|
||||
}
|
||||
},
|
||||
props: {
|
||||
playlists: {
|
||||
type: Array,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.relateItems = [this.$root.selectedMediaItems[0].id]
|
||||
this.search()
|
||||
this.$refs.searchInput.focus()
|
||||
this.$refs.searchInput.addEventListener('keydown', (e) => {
|
||||
if (e.keyCode == 13) {
|
||||
if (this.focused != "") {
|
||||
this.addToPlaylist(this.focused)
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
playlistSelect(playlist) {
|
||||
if (playlist.type != "library-playlist-folders") {
|
||||
this.addToPlaylist(playlist.id)
|
||||
}
|
||||
},
|
||||
addToPlaylist(id) {
|
||||
app.addSelectedToPlaylist(id)
|
||||
},
|
||||
search() {
|
||||
this.focused = ""
|
||||
if (this.searchQuery == "") {
|
||||
this.playlistSorted = this.playlists
|
||||
} else {
|
||||
this.playlistSorted = this.playlists.filter(playlist => {
|
||||
return playlist.attributes.name.toLowerCase().indexOf(this.searchQuery.toLowerCase()) > -1
|
||||
})
|
||||
if (this.playlistSorted.length == 1) {
|
||||
this.focused = this.playlistSorted[0].id
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -1,42 +1,45 @@
|
|||
<script type="text/x-template" id="airplay-modal">
|
||||
<div class="spatialproperties-panel castmenu modal-fullscreen airplay-modal" @click.self="close()" @contextmenu.self="close()">
|
||||
<div class="modal-window airplay-modal">
|
||||
<div class="modal-header">
|
||||
<div class="modal-title">{{'Enter password'}}</div>
|
||||
<button class="close-btn" @click="close()" :aria-label="this.$root.getLz('action.close')"></button>
|
||||
</div>
|
||||
<div class="modal-content" style="overflow-y: overlay; padding: 3%">
|
||||
<input type="text" v-model="passcode"/>
|
||||
</div>
|
||||
<div class="md-footer">
|
||||
<div class="row">
|
||||
<div class="col" >
|
||||
<button style="width:100%" @click="enterPassword()" class="md-btn md-btn-block md-btn-primary">{{'OK'}}</button>
|
||||
<div class="spatialproperties-panel castmenu modal-fullscreen airplay-modal" @click.self="close()"
|
||||
@contextmenu.self="close()">
|
||||
<div class="modal-window airplay-modal">
|
||||
<div class="modal-header">
|
||||
<div class="modal-title">{{'Enter password'}}</div>
|
||||
<button class="close-btn" @click="close()" :aria-label="this.$root.getLz('action.close')"></button>
|
||||
</div>
|
||||
<div class="modal-content" style="overflow-y: overlay; padding: 3%">
|
||||
<input type="text" v-model="passcode" />
|
||||
</div>
|
||||
<div class="md-footer">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<button style="width:100%" @click="enterPassword()" class="md-btn md-btn-block md-btn-primary">
|
||||
{{'OK'}}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
<script>
|
||||
Vue.component('airplay-modal', {
|
||||
template: '#airplay-modal',
|
||||
data: function () {
|
||||
return {
|
||||
passcode: '',
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
},
|
||||
methods: {
|
||||
close() {
|
||||
this.$root.modals.airplayPW = false
|
||||
},
|
||||
enterPassword() {
|
||||
console.log('Entered passCode: ', this.passcode)
|
||||
ipcRenderer.send("setAirPlayPasscode",this.passcode)
|
||||
this.close()
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
Vue.component('airplay-modal', {
|
||||
template: '#airplay-modal',
|
||||
data: function() {
|
||||
return {
|
||||
passcode: '',
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
},
|
||||
methods: {
|
||||
close() {
|
||||
this.$root.modals.airplayPW = false
|
||||
},
|
||||
enterPassword() {
|
||||
console.log('Entered passCode: ', this.passcode)
|
||||
ipcRenderer.send("setAirPlayPasscode", this.passcode)
|
||||
this.close()
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -5,93 +5,98 @@
|
|||
</script>
|
||||
|
||||
<script>
|
||||
Vue.component('animatedartwork-view', {
|
||||
template: '#animatedartwork-view',
|
||||
data: function () {
|
||||
return {
|
||||
app: this.$root,
|
||||
hls: null,
|
||||
}
|
||||
},
|
||||
props: {
|
||||
video: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
priority: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
async mounted() {
|
||||
if (!this.priority && app.cfg.visual.animated_artwork == "limited") {
|
||||
return
|
||||
} else if (app.cfg.visual.animated_artwork == "disabled") {
|
||||
return
|
||||
}
|
||||
if (this.video) {
|
||||
this.$nextTick(function () {
|
||||
var config = {
|
||||
backBufferLength: 0,
|
||||
enableWebVTT: false,
|
||||
enableCEA708Captions: false,
|
||||
emeEnabled: false,
|
||||
abrEwmaDefaultEstimate: 10000,
|
||||
testBandwidth: false,
|
||||
};
|
||||
if (this.hls) {
|
||||
this.hls.detachMedia();
|
||||
} else {
|
||||
Vue.component('animatedartwork-view', {
|
||||
template: '#animatedartwork-view',
|
||||
data: function() {
|
||||
return {
|
||||
app: this.$root,
|
||||
hls: null,
|
||||
}
|
||||
},
|
||||
props: {
|
||||
video: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
priority: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
async mounted() {
|
||||
if (!this.priority && app.cfg.visual.animated_artwork == "limited") {
|
||||
return
|
||||
} else if (app.cfg.visual.animated_artwork == "disabled") {
|
||||
return
|
||||
}
|
||||
if (this.video) {
|
||||
this.$nextTick(function() {
|
||||
var config = {
|
||||
backBufferLength: 0,
|
||||
enableWebVTT: false,
|
||||
enableCEA708Captions: false,
|
||||
emeEnabled: false,
|
||||
abrEwmaDefaultEstimate: 10000,
|
||||
testBandwidth: false,
|
||||
};
|
||||
if (this.hls) {
|
||||
this.hls.detachMedia();
|
||||
} else {
|
||||
|
||||
this.hls = new CiderHls(config);
|
||||
}
|
||||
// bind them together
|
||||
if (this.$refs.video) {
|
||||
let d = "WIDEVINE_SOFTWARE"
|
||||
let h = {
|
||||
initDataTypes: ["cenc", "keyids"],
|
||||
distinctiveIdentifier: "optional",
|
||||
persistentState: "required"
|
||||
}
|
||||
let p = {
|
||||
platformInfo: {requiresCDMAttachOnStart: !0, maxSecurityLevel: d, keySystemConfig: h},
|
||||
appData: {serviceName: "Apple Music"}
|
||||
}
|
||||
|
||||
this.hls.attachMedia(this.$refs.video);
|
||||
this.hls.loadSource(this.video, p);
|
||||
let u = this.hls;
|
||||
var quality = app.cfg.visual.animated_artwork_qualityLevel;
|
||||
setTimeout(() => {
|
||||
let levelsnum = u.levels.map((level)=>{return level.width})
|
||||
if (levelsnum.length > 0) {
|
||||
let qualities = []
|
||||
let qualities2 = []
|
||||
for (let i = 0; i < levelsnum.length; i++) {
|
||||
if (qualities2.indexOf(levelsnum[i]) == -1) {
|
||||
qualities.push({level: i, quality: levelsnum[i]})
|
||||
qualities2.push(levelsnum[i])
|
||||
}
|
||||
}
|
||||
let actualnum = Math.floor(qualities[qualities.length -1 ].level * (quality / 4))
|
||||
if (quality != 0 ){
|
||||
quality = qualities[Math.min(actualnum,qualities.length -1 )].level
|
||||
}
|
||||
if (quality == 4 ){
|
||||
quality = qualities[qualities.length - 1].level
|
||||
}
|
||||
}
|
||||
try{
|
||||
this.hls.loadLevel = parseInt( quality || 1);} catch(e){}},200)
|
||||
}
|
||||
})
|
||||
this.hls = new CiderHls(config);
|
||||
}
|
||||
// bind them together
|
||||
if (this.$refs.video) {
|
||||
let d = "WIDEVINE_SOFTWARE"
|
||||
let h = {
|
||||
initDataTypes: ["cenc", "keyids"],
|
||||
distinctiveIdentifier: "optional",
|
||||
persistentState: "required"
|
||||
}
|
||||
},
|
||||
async beforeDestroy() {
|
||||
if (this.hls) {
|
||||
await this.hls.destroy();
|
||||
this.hls = null
|
||||
let p = {
|
||||
platformInfo: { requiresCDMAttachOnStart: !0, maxSecurityLevel: d, keySystemConfig: h },
|
||||
appData: { serviceName: "Apple Music" }
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
this.hls.attachMedia(this.$refs.video);
|
||||
this.hls.loadSource(this.video, p);
|
||||
let u = this.hls;
|
||||
var quality = app.cfg.visual.animated_artwork_qualityLevel;
|
||||
setTimeout(() => {
|
||||
let levelsnum = u.levels.map((level) => {
|
||||
return level.width
|
||||
})
|
||||
if (levelsnum.length > 0) {
|
||||
let qualities = []
|
||||
let qualities2 = []
|
||||
for (let i = 0; i < levelsnum.length; i++) {
|
||||
if (qualities2.indexOf(levelsnum[i]) == -1) {
|
||||
qualities.push({ level: i, quality: levelsnum[i] })
|
||||
qualities2.push(levelsnum[i])
|
||||
}
|
||||
}
|
||||
let actualnum = Math.floor(qualities[qualities.length - 1].level * (quality / 4))
|
||||
if (quality != 0) {
|
||||
quality = qualities[Math.min(actualnum, qualities.length - 1)].level
|
||||
}
|
||||
if (quality == 4) {
|
||||
quality = qualities[qualities.length - 1].level
|
||||
}
|
||||
}
|
||||
try {
|
||||
this.hls.loadLevel = parseInt(quality || 1);
|
||||
} catch (e) {
|
||||
}
|
||||
}, 200)
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
async beforeDestroy() {
|
||||
if (this.hls) {
|
||||
await this.hls.destroy();
|
||||
this.hls = null
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -15,14 +15,14 @@
|
|||
<transition
|
||||
<% if(env.appRoutes[i].onEnter) {
|
||||
%>
|
||||
v-on:enter="<%- env.appRoutes[i].onEnter %>"
|
||||
v-on:enter="<%- env.appRoutes[i].onEnter; %>"
|
||||
<%
|
||||
}
|
||||
%>
|
||||
:name="$root.chrome.desiredPageTransition">
|
||||
<template
|
||||
v-if="<%- env.appRoutes[i].condition %>">
|
||||
<%- env.appRoutes[i].component %>
|
||||
v-if="<%- env.appRoutes[i].condition; %>">
|
||||
<%- env.appRoutes[i].component; %>
|
||||
</template>
|
||||
</transition>
|
||||
<% } %>
|
||||
|
@ -38,14 +38,13 @@
|
|||
</script>
|
||||
|
||||
<script>
|
||||
Vue.component('app-content-area', {
|
||||
template: '#app-content-area',
|
||||
data: function () {
|
||||
return {
|
||||
scrollPos: 0
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
}
|
||||
});
|
||||
</script>
|
||||
Vue.component('app-content-area', {
|
||||
template: '#app-content-area',
|
||||
data: function() {
|
||||
return {
|
||||
scrollPos: 0
|
||||
}
|
||||
},
|
||||
methods: {}
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -1,49 +1,53 @@
|
|||
<script type="text/x-template" id="artist-chip">
|
||||
<div class="artist-chip" @click.self="route" tabindex="0">
|
||||
<div class="artist-chip__image" v-if="image" :style="{backgroundColor: '#' + (artist.attributes.artwork?.bgColor ?? '000')}">
|
||||
<mediaitem-artwork v-if="artist.id != null" :url="artist.attributes.artwork.url" :size="80"></mediaitem-artwork>
|
||||
<div class="artist-chip__image" v-if="image"
|
||||
:style="{backgroundColor: '#' + (artist.attributes.artwork?.bgColor ?? '000')}">
|
||||
<mediaitem-artwork v-if="artist.id != null" :url="artist.attributes.artwork.url"
|
||||
:size="80"></mediaitem-artwork>
|
||||
</div>
|
||||
<div class="artist-chip__image" v-else>
|
||||
</div>
|
||||
<div class="artist-chip__name">
|
||||
<span>{{ item.attributes.name }}</span>
|
||||
</div>
|
||||
<button @click="$root.setArtistFavorite(artist.id, true)" title="Follow" v-if="!$root.followingArtist(artist.id)" class="artist-chip__follow codicon codicon-add"></button>
|
||||
<button @click="$root.setArtistFavorite(artist.id, false)" title="Following" v-else class="artist-chip__follow codicon codicon-check"></button>
|
||||
<button @click="$root.setArtistFavorite(artist.id, true)" title="Follow"
|
||||
v-if="!$root.followingArtist(artist.id)" class="artist-chip__follow codicon codicon-add"></button>
|
||||
<button @click="$root.setArtistFavorite(artist.id, false)" title="Following" v-else
|
||||
class="artist-chip__follow codicon codicon-check"></button>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script>
|
||||
Vue.component('artist-chip', {
|
||||
props: {
|
||||
item: {
|
||||
type: Object,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data: function() {
|
||||
return {
|
||||
image: false,
|
||||
artist: {
|
||||
id: null
|
||||
}
|
||||
}
|
||||
},
|
||||
template: '#artist-chip',
|
||||
async mounted() {
|
||||
let artistId = this.item.id
|
||||
if (typeof this.item.relationships == "object") {
|
||||
artistId = this.item.relationships.catalog.data[0].id
|
||||
}
|
||||
app.mk.api.v3.music(`/v1/catalog/${app.mk.storefrontId}/artists/${artistId}`).then(response => {
|
||||
this.artist = response.data.data[0];
|
||||
this.image = true;
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
route() {
|
||||
app.appRoute(`artist/${this.artist.id}`);
|
||||
}
|
||||
Vue.component('artist-chip', {
|
||||
props: {
|
||||
item: {
|
||||
type: Object,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data: function() {
|
||||
return {
|
||||
image: false,
|
||||
artist: {
|
||||
id: null
|
||||
}
|
||||
});
|
||||
</script>
|
||||
}
|
||||
},
|
||||
template: '#artist-chip',
|
||||
async mounted() {
|
||||
let artistId = this.item.id
|
||||
if (typeof this.item.relationships == "object") {
|
||||
artistId = this.item.relationships.catalog.data[0].id
|
||||
}
|
||||
app.mk.api.v3.music(`/v1/catalog/${app.mk.storefrontId}/artists/${artistId}`).then(response => {
|
||||
this.artist = response.data.data[0];
|
||||
this.image = true;
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
route() {
|
||||
app.appRoute(`artist/${this.artist.id}`);
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -1,37 +1,36 @@
|
|||
<script type="text/x-template" id="artwork-material">
|
||||
<div class="artworkMaterial">
|
||||
<mediaitem-artwork :url="src" :size="500" v-for="image in images"/>
|
||||
<mediaitem-artwork :url="src" :size="500" v-for="image in images" />
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script>
|
||||
Vue.component('artwork-material', {
|
||||
template: '#artwork-material',
|
||||
data: function () {
|
||||
return {
|
||||
src: ""
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.src = app.getMediaItemArtwork(this.url, this.size)
|
||||
},
|
||||
props: {
|
||||
url: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
size: {
|
||||
type: [String, Number],
|
||||
required: false,
|
||||
default: '32'
|
||||
},
|
||||
images: {
|
||||
type: [String, Number],
|
||||
required: false,
|
||||
default: '2'
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
}
|
||||
});
|
||||
</script>
|
||||
Vue.component('artwork-material', {
|
||||
template: '#artwork-material',
|
||||
data: function() {
|
||||
return {
|
||||
src: ""
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.src = app.getMediaItemArtwork(this.url, this.size)
|
||||
},
|
||||
props: {
|
||||
url: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
size: {
|
||||
type: [String, Number],
|
||||
required: false,
|
||||
default: '32'
|
||||
},
|
||||
images: {
|
||||
type: [String, Number],
|
||||
required: false,
|
||||
default: '2'
|
||||
}
|
||||
},
|
||||
methods: {}
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -4,7 +4,8 @@
|
|||
<div class="modal-window">
|
||||
<div class="modal-header">
|
||||
<div class="modal-title">{{app.getLz('term.audioControls')}}</div>
|
||||
<button class="close-btn" @click="app.modals.audioControls = false" :aria-label="app.getLz('action.close')"></button>
|
||||
<button class="close-btn" @click="app.modals.audioControls = false"
|
||||
:aria-label="app.getLz('action.close')"></button>
|
||||
</div>
|
||||
<div class="modal-content">
|
||||
<div class="md-option-line">
|
||||
|
@ -14,7 +15,7 @@
|
|||
<div class="md-option-segment md-option-segment_auto percent">
|
||||
<input type="number"
|
||||
style="width: 100%; text-align: center; margin-right: 5px;" min="0"
|
||||
step="2" v-model="volume"/>
|
||||
step="2" v-model="volume" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="md-option-line">
|
||||
|
@ -23,7 +24,7 @@
|
|||
</div>
|
||||
<div class="md-option-segment md-option-segment_auto percent">
|
||||
<input type="number" style="width: 100%; text-align: center; margin-right: 5px;" min="0"
|
||||
v-model="volumeStep"/>
|
||||
v-model="volumeStep" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="md-option-line">
|
||||
|
@ -32,66 +33,66 @@
|
|||
</div>
|
||||
<div class="md-option-segment md-option-segment_auto percent">
|
||||
<input type="number" style="width: 100%; text-align: center; margin-right: 5px;" min="0"
|
||||
v-model="maxVolume"/>
|
||||
v-model="maxVolume" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="md-option-line">
|
||||
<div class="md-option-segment">
|
||||
{{$root.getLz('settings.option.audio.advanced')}}
|
||||
</div>
|
||||
<div class="md-option-segment md-option-segment_auto">
|
||||
<label>
|
||||
<input type="checkbox" v-model="app.cfg.audio.advanced" switch />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="md-option-line">
|
||||
<div class="md-option-segment">
|
||||
{{$root.getLz('settings.option.audio.advanced')}}
|
||||
</div>
|
||||
<div class="md-option-segment md-option-segment_auto">
|
||||
<label>
|
||||
<input type="checkbox" v-model="app.cfg.audio.advanced" switch/>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script>
|
||||
Vue.component('audio-controls', {
|
||||
template: '#audio-controls',
|
||||
data: function () {
|
||||
return {
|
||||
app: this.$root,
|
||||
maxVolume: this.$root.cfg.audio.maxVolume * 100,
|
||||
volumeStep: this.$root.cfg.audio.volumeStep * 100,
|
||||
volume: this.$root.cfg.audio.volume * 100
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
maxVolume: function (newValue, _oldValue) {
|
||||
if (newValue > 100) {
|
||||
newValue = 100
|
||||
} else {
|
||||
newValue = Math.round(newValue)
|
||||
}
|
||||
this.$root.cfg.audio.maxVolume = newValue / 100
|
||||
this.maxVolume = newValue
|
||||
console.log(newValue, _oldValue)
|
||||
},
|
||||
volume: function (newValue, _oldValue) {
|
||||
if (newValue > this.maxVolume) {
|
||||
newValue = 100
|
||||
} else {
|
||||
newValue = Math.round(newValue)
|
||||
}
|
||||
this.$root.mk.volume = newValue / 100
|
||||
this.volume = newValue
|
||||
console.log(newValue, _oldValue)
|
||||
},
|
||||
volumeStep: function (newValue, _oldValue) {
|
||||
if (newValue > this.maxVolume) {
|
||||
newValue = 100
|
||||
} else {
|
||||
newValue = Math.round(newValue)
|
||||
}
|
||||
this.$root.cfg.audio.volumeStep = newValue / 100
|
||||
this.volumeStep = newValue
|
||||
console.log(newValue, _oldValue)
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
Vue.component('audio-controls', {
|
||||
template: '#audio-controls',
|
||||
data: function() {
|
||||
return {
|
||||
app: this.$root,
|
||||
maxVolume: this.$root.cfg.audio.maxVolume * 100,
|
||||
volumeStep: this.$root.cfg.audio.volumeStep * 100,
|
||||
volume: this.$root.cfg.audio.volume * 100
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
maxVolume: function(newValue, _oldValue) {
|
||||
if (newValue > 100) {
|
||||
newValue = 100
|
||||
} else {
|
||||
newValue = Math.round(newValue)
|
||||
}
|
||||
this.$root.cfg.audio.maxVolume = newValue / 100
|
||||
this.maxVolume = newValue
|
||||
console.log(newValue, _oldValue)
|
||||
},
|
||||
volume: function(newValue, _oldValue) {
|
||||
if (newValue > this.maxVolume) {
|
||||
newValue = 100
|
||||
} else {
|
||||
newValue = Math.round(newValue)
|
||||
}
|
||||
this.$root.mk.volume = newValue / 100
|
||||
this.volume = newValue
|
||||
console.log(newValue, _oldValue)
|
||||
},
|
||||
volumeStep: function(newValue, _oldValue) {
|
||||
if (newValue > this.maxVolume) {
|
||||
newValue = 100
|
||||
} else {
|
||||
newValue = Math.round(newValue)
|
||||
}
|
||||
this.$root.cfg.audio.volumeStep = newValue / 100
|
||||
this.volumeStep = newValue
|
||||
console.log(newValue, _oldValue)
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -4,7 +4,8 @@
|
|||
<div class="modal-window">
|
||||
<div class="modal-header">
|
||||
<div class="modal-title">{{app.getLz('settings.option.audio.changePlaybackRate')}}</div>
|
||||
<button class="close-btn" @click="app.modals.audioPlaybackRate = false" :aria-label="app.getLz('action.close')"></button>
|
||||
<button class="close-btn" @click="app.modals.audioPlaybackRate = false"
|
||||
:aria-label="app.getLz('action.close')"></button>
|
||||
</div>
|
||||
<div class="modal-content">
|
||||
<div class="md-option-line">
|
||||
|
@ -15,7 +16,8 @@
|
|||
{{playbackRate}} ×
|
||||
</div>
|
||||
<div class="md-option-segment md-option-segment_auto">
|
||||
<input type="range" :step="0.05" min="0.25" :max="2" @wheel="playbackRateWheel" v-model="playbackRate">
|
||||
<input type="range" :step="0.05" min="0.25" :max="2" @wheel="playbackRateWheel"
|
||||
v-model="playbackRate">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -24,36 +26,36 @@
|
|||
</script>
|
||||
|
||||
<script>
|
||||
Vue.component('audio-playbackrate', {
|
||||
template: '#audio-playbackrate',
|
||||
data: function () {
|
||||
return {
|
||||
app: this.$root,
|
||||
playbackRate: this.$root.cfg.audio.playbackRate
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
playbackRate: function (newValue, _oldValue) {
|
||||
this.saveValue(newValue);
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
playbackRateWheel(event) {
|
||||
if (app.checkScrollDirectionIsUp(event)) {
|
||||
this.saveValue(this.$root.cfg.audio.playbackRate + 0.05);
|
||||
} else {
|
||||
this.saveValue(this.$root.cfg.audio.playbackRate - 0.05);
|
||||
}
|
||||
},
|
||||
saveValue(newValue) {
|
||||
newValue = Number(newValue);
|
||||
if (newValue >= 0.25 && newValue <= 2) {
|
||||
newValue = String(newValue).length > 4 ? newValue.toFixed(2) : newValue;
|
||||
this.$root.mk.playbackRate = newValue;
|
||||
this.$root.cfg.audio.playbackRate = newValue;
|
||||
this.playbackRate = newValue;
|
||||
}
|
||||
}
|
||||
Vue.component('audio-playbackrate', {
|
||||
template: '#audio-playbackrate',
|
||||
data: function() {
|
||||
return {
|
||||
app: this.$root,
|
||||
playbackRate: this.$root.cfg.audio.playbackRate
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
playbackRate: function(newValue, _oldValue) {
|
||||
this.saveValue(newValue);
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
playbackRateWheel(event) {
|
||||
if (app.checkScrollDirectionIsUp(event)) {
|
||||
this.saveValue(this.$root.cfg.audio.playbackRate + 0.05);
|
||||
} else {
|
||||
this.saveValue(this.$root.cfg.audio.playbackRate - 0.05);
|
||||
}
|
||||
});
|
||||
},
|
||||
saveValue(newValue) {
|
||||
newValue = Number(newValue);
|
||||
if (newValue >= 0.25 && newValue <= 2) {
|
||||
newValue = String(newValue).length > 4 ? newValue.toFixed(2) : newValue;
|
||||
this.$root.mk.playbackRate = newValue;
|
||||
this.$root.cfg.audio.playbackRate = newValue;
|
||||
this.playbackRate = newValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
<script type="text/x-template" id="audio-settings">
|
||||
<template>
|
||||
<div class="modal-fullscreen addtoplaylist-panel" @click.self="app.modals.audioSettings = false" @contextmenu.self="app.modals.audioSettings = false">
|
||||
<div class="modal-fullscreen addtoplaylist-panel" @click.self="app.modals.audioSettings = false"
|
||||
@contextmenu.self="app.modals.audioSettings = false">
|
||||
<div class="modal-window">
|
||||
<div class="modal-header">
|
||||
<div class="modal-title">{{app.getLz('term.audioSettings')}}</div>
|
||||
<button class="close-btn" @click="app.modals.audioSettings = false" :aria-label="app.getLz('action.close')"></button>
|
||||
<button class="close-btn" @click="app.modals.audioSettings = false"
|
||||
:aria-label="app.getLz('action.close')"></button>
|
||||
</div>
|
||||
<div class="modal-content">
|
||||
<button class="playlist-item"
|
||||
|
@ -34,29 +36,30 @@
|
|||
</script>
|
||||
|
||||
<script>
|
||||
Vue.component('audio-settings', {
|
||||
template: '#audio-settings',
|
||||
data: function () {
|
||||
return {
|
||||
app: this.$root,
|
||||
}
|
||||
},
|
||||
props: {},
|
||||
mounted() {},
|
||||
methods: {
|
||||
openEqualizer() {
|
||||
app.modals.equalizer = true
|
||||
app.modals.audioSettings = false
|
||||
},
|
||||
openAudioControls() {
|
||||
app.modals.audioControls = true
|
||||
app.modals.audioSettings = false
|
||||
},
|
||||
openAudioPlaybackRate() {
|
||||
app.modals.audioPlaybackRate = true
|
||||
app.modals.audioSettings = false
|
||||
},
|
||||
},
|
||||
Vue.component('audio-settings', {
|
||||
template: '#audio-settings',
|
||||
data: function() {
|
||||
return {
|
||||
app: this.$root,
|
||||
}
|
||||
);
|
||||
</script>
|
||||
},
|
||||
props: {},
|
||||
mounted() {
|
||||
},
|
||||
methods: {
|
||||
openEqualizer() {
|
||||
app.modals.equalizer = true
|
||||
app.modals.audioSettings = false
|
||||
},
|
||||
openAudioControls() {
|
||||
app.modals.audioControls = true
|
||||
app.modals.audioSettings = false
|
||||
},
|
||||
openAudioPlaybackRate() {
|
||||
app.modals.audioPlaybackRate = true
|
||||
app.modals.audioSettings = false
|
||||
},
|
||||
},
|
||||
}
|
||||
);
|
||||
</script>
|
||||
|
|
|
@ -1,130 +1,151 @@
|
|||
<script type="text/x-template" id="castmenu">
|
||||
<div class="spatialproperties-panel castmenu modal-fullscreen" @click.self="close()" @contextmenu.self="close()">
|
||||
<div class="modal-window">
|
||||
<div class="modal-header">
|
||||
<div class="modal-title">{{$root.getLz('action.cast.todevices')}}</div>
|
||||
<button class="close-btn" @click="close()" :aria-label="$root.getLz('action.close')"></button>
|
||||
</div>
|
||||
<div class="modal-content" style="overflow-y: overlay; padding: 3%">
|
||||
<div class="md-labeltext">{{$root.getLz('action.cast.chromecast')}}</div>
|
||||
<div class="md-option-container" style="margin-top: 12px;margin-bottom: 12px;overflow-y: scroll;">
|
||||
<template v-if="!scanning">
|
||||
<template v-for="(device) in devices.cast">
|
||||
<div class="md-option-line" style="cursor: pointer" @click="setCast(device)">
|
||||
<div class="md-option-segment">
|
||||
{{ device.name }}
|
||||
<br>
|
||||
<small>{{ device.host }}</small>
|
||||
</div>
|
||||
<div class="md-option-segment_auto" style="display: flex;justify-content: center;align-items: center" v-if="activeCasts.includes(device)">
|
||||
Connected
|
||||
</div>
|
||||
<div class="md-option-segment_auto" v-else style="display: flex;justify-content: center;align-items: center">
|
||||
<svg width="20" height="20" viewBox="0 0 34 34" fill="#fff" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" class="castPlayIndicator"><path d="M28.228,18.327l-16.023,8.983c-0.99,0.555 -2.205,-0.17 -2.205,-1.318l0,-17.984c0,-1.146 1.215,-1.873 2.205,-1.317l16.023,8.982c1.029,0.577 1.029,2.077 0,2.654Z" style="fill-rule:nonzero"></path></svg>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div class="md-option-line" style="cursor: pointer">
|
||||
<div class="md-option-segment">
|
||||
{{$root.getLz('action.cast.scanning')}}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
<div class="md-labeltext" >{{$root.getLz('action.cast.airplay')}}</div>
|
||||
<div class="md-option-container" style="margin-top: 12px;margin-bottom: 12px;overflow-y: scroll;">
|
||||
<div class="md-option-line">
|
||||
<div class="md-option-segment">
|
||||
{{'EXPERIMENTAL!!! Supports Homepods / Apple TVs / Shairport for now, AirPlay on Samsung/LG/Sony devices will be added later'}}
|
||||
<!-- {{$root.getLz('action.cast.airplay.underdevelopment')}} -->
|
||||
<template v-if="true" v-for="(device) in devices.airplay">
|
||||
<div class="md-option-line" style="cursor: pointer" @click="setAirPlayCast(device)">
|
||||
<div class="spatialproperties-panel castmenu modal-fullscreen" @click.self="close()" @contextmenu.self="close()">
|
||||
<div class="modal-window">
|
||||
<div class="modal-header">
|
||||
<div class="modal-title">{{$root.getLz('action.cast.todevices')}}</div>
|
||||
<button class="close-btn" @click="close()" :aria-label="$root.getLz('action.close')"></button>
|
||||
</div>
|
||||
<div class="modal-content" style="overflow-y: overlay; padding: 3%">
|
||||
<div class="md-labeltext">{{$root.getLz('action.cast.chromecast')}}</div>
|
||||
<div class="md-option-container" style="margin-top: 12px;margin-bottom: 12px;overflow-y: scroll;">
|
||||
<template v-if="!scanning">
|
||||
<template v-for="(device) in devices.cast">
|
||||
<div class="md-option-line" style="cursor: pointer" @click="setCast(device)">
|
||||
<div class="md-option-segment">
|
||||
{{ device.name }}
|
||||
<br>
|
||||
<small>{{ device.host }}</small>
|
||||
</div>
|
||||
<div class="md-option-segment_auto"
|
||||
style="display: flex;justify-content: center;align-items: center"
|
||||
v-if="activeCasts.includes(device)">
|
||||
Connected
|
||||
</div>
|
||||
<div class="md-option-segment_auto" v-else
|
||||
style="display: flex;justify-content: center;align-items: center">
|
||||
<svg width="20" height="20" viewBox="0 0 34 34" fill="#fff" version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xml:space="preserve" class="castPlayIndicator"><path
|
||||
d="M28.228,18.327l-16.023,8.983c-0.99,0.555 -2.205,-0.17 -2.205,-1.318l0,-17.984c0,-1.146 1.215,-1.873 2.205,-1.317l16.023,8.982c1.029,0.577 1.029,2.077 0,2.654Z"
|
||||
style="fill-rule:nonzero"></path></svg>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div class="md-option-line" style="cursor: pointer">
|
||||
<div class="md-option-segment">
|
||||
{{ device.name }}
|
||||
<br>
|
||||
<small>{{ device.host }}</small>
|
||||
</div>
|
||||
<div class="md-option-segment_auto" style="display: flex;justify-content: center;align-items: center" v-if="activeCasts.includes(device)">
|
||||
Connected
|
||||
</div>
|
||||
<div class="md-option-segment_auto" v-else style="display: flex;justify-content: center;align-items: center">
|
||||
<svg width="20" height="20" viewBox="0 0 34 34" fill="#fff" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" class="castPlayIndicator"><path d="M28.228,18.327l-16.023,8.983c-0.99,0.555 -2.205,-0.17 -2.205,-1.318l0,-17.984c0,-1.146 1.215,-1.873 2.205,-1.317l16.023,8.982c1.029,0.577 1.029,2.077 0,2.654Z" style="fill-rule:nonzero"></path></svg>
|
||||
{{$root.getLz('action.cast.scanning')}}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
<div class="md-labeltext">{{$root.getLz('action.cast.airplay')}}</div>
|
||||
<div class="md-option-container" style="margin-top: 12px;margin-bottom: 12px;overflow-y: scroll;">
|
||||
<div class="md-option-line">
|
||||
<div class="md-option-segment">
|
||||
{{'EXPERIMENTAL!!! Supports Homepods / Apple TVs / Shairport for now, AirPlay on
|
||||
Samsung/LG/Sony devices will be added later'}}
|
||||
<!-- {{$root.getLz('action.cast.airplay.underdevelopment')}} -->
|
||||
<template v-if="true" v-for="(device) in devices.airplay">
|
||||
<div class="md-option-line" style="cursor: pointer" @click="setAirPlayCast(device)">
|
||||
<div class="md-option-segment">
|
||||
{{ device.name }}
|
||||
<br>
|
||||
<small>{{ device.host }}</small>
|
||||
</div>
|
||||
<div class="md-option-segment_auto"
|
||||
style="display: flex;justify-content: center;align-items: center"
|
||||
v-if="activeCasts.includes(device)">
|
||||
Connected
|
||||
</div>
|
||||
<div class="md-option-segment_auto" v-else
|
||||
style="display: flex;justify-content: center;align-items: center">
|
||||
<svg width="20" height="20" viewBox="0 0 34 34" fill="#fff" version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xml:space="preserve"
|
||||
class="castPlayIndicator"><path
|
||||
d="M28.228,18.327l-16.023,8.983c-0.99,0.555 -2.205,-0.17 -2.205,-1.318l0,-17.984c0,-1.146 1.215,-1.873 2.205,-1.317l16.023,8.982c1.029,0.577 1.029,2.077 0,2.654Z"
|
||||
style="fill-rule:nonzero"></path></svg>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="md-footer">
|
||||
<div class="row">
|
||||
<div class="col" v-if="activeCasts.length != 0">
|
||||
<button style="width:100%" @click="stopCasting()" class="md-btn md-btn-block md-btn-primary">
|
||||
{{$root.getLz('action.cast.stop')}}
|
||||
</button>
|
||||
</div>
|
||||
<div class="col">
|
||||
<button style="width:100%" class="md-btn md-btn-block" @click="scan()">
|
||||
{{$root.getLz('action.cast.scan')}}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="md-footer">
|
||||
<div class="row">
|
||||
<div class="col" v-if="activeCasts.length != 0">
|
||||
<button style="width:100%" @click="stopCasting()" class="md-btn md-btn-block md-btn-primary">{{$root.getLz('action.cast.stop')}}</button>
|
||||
</div>
|
||||
<div class="col">
|
||||
<button style="width:100%" class="md-btn md-btn-block" @click="scan()">{{$root.getLz('action.cast.scan')}}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
<script>
|
||||
Vue.component('castmenu', {
|
||||
template: '#castmenu',
|
||||
data: function () {
|
||||
return {
|
||||
devices: {
|
||||
cast: [],
|
||||
airplay: []
|
||||
},
|
||||
scanning: false,
|
||||
activeCasts: this.$root.activeCasts,
|
||||
Vue.component('castmenu', {
|
||||
template: '#castmenu',
|
||||
data: function() {
|
||||
return {
|
||||
devices: {
|
||||
cast: [],
|
||||
airplay: []
|
||||
},
|
||||
scanning: false,
|
||||
activeCasts: this.$root.activeCasts,
|
||||
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.scan();
|
||||
},
|
||||
watch:{
|
||||
activeCasts: function (newVal, oldVal) {
|
||||
this.$root.activeCasts = this.activeCasts;
|
||||
}},
|
||||
methods: {
|
||||
close() {
|
||||
this.$root.modals.castMenu = false
|
||||
},
|
||||
scan() {
|
||||
let self = this;
|
||||
this.scanning = true;
|
||||
ipcRenderer.send('getChromeCastDevices', '');
|
||||
ipcRenderer.send("getAirplayDevice","")
|
||||
setTimeout(() => {
|
||||
self.devices.cast = ipcRenderer.sendSync("getKnownCastDevices");
|
||||
self.devices.airplay = ipcRenderer.sendSync("getKnownAirplayDevices");
|
||||
self.scanning = false;
|
||||
}, 2000);
|
||||
console.log(this.devices);
|
||||
// vm.$forceUpdate();
|
||||
},
|
||||
setCast(device) {
|
||||
CiderAudio.sendAudio();
|
||||
this.activeCasts.push(device);
|
||||
ipcRenderer.send('performGCCast', device, "Cider", "Playing ...", "Test build", '');
|
||||
},
|
||||
setAirPlayCast(device) {
|
||||
this.activeCasts.push(device);
|
||||
ipcRenderer.send("performAirplayPCM",device.host,device.port,null,"","","","",device.txt,device.airplay2)
|
||||
},
|
||||
stopCasting() {
|
||||
CiderAudio.stopAudio();
|
||||
ipcRenderer.send('disconnectAirplay', '');
|
||||
ipcRenderer.send('stopGCast', '');
|
||||
this.activeCasts = [];
|
||||
// vm.$forceUpdate();
|
||||
},
|
||||
}
|
||||
});
|
||||
</script>
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.scan();
|
||||
},
|
||||
watch: {
|
||||
activeCasts: function(newVal, oldVal) {
|
||||
this.$root.activeCasts = this.activeCasts;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
close() {
|
||||
this.$root.modals.castMenu = false
|
||||
},
|
||||
scan() {
|
||||
let self = this;
|
||||
this.scanning = true;
|
||||
ipcRenderer.send('getChromeCastDevices', '');
|
||||
ipcRenderer.send("getAirplayDevice", "")
|
||||
setTimeout(() => {
|
||||
self.devices.cast = ipcRenderer.sendSync("getKnownCastDevices");
|
||||
self.devices.airplay = ipcRenderer.sendSync("getKnownAirplayDevices");
|
||||
self.scanning = false;
|
||||
}, 2000);
|
||||
console.log(this.devices);
|
||||
// vm.$forceUpdate();
|
||||
},
|
||||
setCast(device) {
|
||||
CiderAudio.sendAudio();
|
||||
this.activeCasts.push(device);
|
||||
ipcRenderer.send('performGCCast', device, "Cider", "Playing ...", "Test build", '');
|
||||
},
|
||||
setAirPlayCast(device) {
|
||||
this.activeCasts.push(device);
|
||||
ipcRenderer.send("performAirplayPCM", device.host, device.port, null, "", "", "", "", device.txt, device.airplay2)
|
||||
},
|
||||
stopCasting() {
|
||||
CiderAudio.stopAudio();
|
||||
ipcRenderer.send('disconnectAirplay', '');
|
||||
ipcRenderer.send('stopGCast', '');
|
||||
this.activeCasts = [];
|
||||
// vm.$forceUpdate();
|
||||
},
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -4,15 +4,17 @@
|
|||
<div class="modal-window">
|
||||
<div class="modal-header">
|
||||
<div class="modal-title">{{app.getLz('action.addToLibrary')}}</div>
|
||||
<button class="close-btn" @click="app.resetState()" :aria-label="app.getLz('action.close')"></button>
|
||||
<button class="close-btn" @click="app.resetState()"
|
||||
:aria-label="app.getLz('action.close')"></button>
|
||||
</div>
|
||||
<div class="modal-content">
|
||||
<button class="playlist-item"
|
||||
:class="{ focused: playlist.id == focused }"
|
||||
@click="addToPlaylist(playlist.id)" style="width:100%;" v-for="playlist in playlistSorted" v-if="playlist.attributes.canEdit && playlist.type != 'library-playlist-folders'">
|
||||
<div class="icon"><%- include("../svg/playlist.svg") %></div>
|
||||
<div class="name">{{ playlist.attributes.name }}</div>
|
||||
</button>
|
||||
:class="{ focused: playlist.id == focused }"
|
||||
@click="addToPlaylist(playlist.id)" style="width:100%;" v-for="playlist in playlistSorted"
|
||||
v-if="playlist.attributes.canEdit && playlist.type != 'library-playlist-folders'">
|
||||
<div class="icon"><%- include("../svg/playlist.svg") %></div>
|
||||
<div class="name">{{ playlist.attributes.name }}</div>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-search">
|
||||
<div class="search-input-container" style="width:100%;margin: 16px 0;">
|
||||
|
@ -33,50 +35,50 @@
|
|||
</script>
|
||||
|
||||
<script>
|
||||
Vue.component('add-to-playlist', {
|
||||
template: '#add-to-playlist',
|
||||
data: function () {
|
||||
return {
|
||||
playlistSorted: [],
|
||||
searchQuery: "",
|
||||
focused: "",
|
||||
app: this.$root,
|
||||
}
|
||||
},
|
||||
props: {
|
||||
playlists: {
|
||||
type: Array,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.search()
|
||||
this.$refs.searchInput.focus()
|
||||
this.$refs.searchInput.addEventListener('keydown', (e) => {
|
||||
if (e.keyCode == 13) {
|
||||
if (this.focused != "") {
|
||||
this.addToPlaylist(this.focused)
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
addToPlaylist(id) {
|
||||
app.addSelectedToPlaylist(id)
|
||||
},
|
||||
search() {
|
||||
this.focused = ""
|
||||
if (this.searchQuery == "") {
|
||||
this.playlistSorted = this.playlists
|
||||
} else {
|
||||
this.playlistSorted = this.playlists.filter(playlist => {
|
||||
return playlist.attributes.name.toLowerCase().indexOf(this.searchQuery.toLowerCase()) > -1
|
||||
})
|
||||
if (this.playlistSorted.length == 1) {
|
||||
this.focused = this.playlistSorted[0].id
|
||||
}
|
||||
}
|
||||
},
|
||||
Vue.component('add-to-playlist', {
|
||||
template: '#add-to-playlist',
|
||||
data: function() {
|
||||
return {
|
||||
playlistSorted: [],
|
||||
searchQuery: "",
|
||||
focused: "",
|
||||
app: this.$root,
|
||||
}
|
||||
},
|
||||
props: {
|
||||
playlists: {
|
||||
type: Array,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.search()
|
||||
this.$refs.searchInput.focus()
|
||||
this.$refs.searchInput.addEventListener('keydown', (e) => {
|
||||
if (e.keyCode == 13) {
|
||||
if (this.focused != "") {
|
||||
this.addToPlaylist(this.focused)
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
addToPlaylist(id) {
|
||||
app.addSelectedToPlaylist(id)
|
||||
},
|
||||
search() {
|
||||
this.focused = ""
|
||||
if (this.searchQuery == "") {
|
||||
this.playlistSorted = this.playlists
|
||||
} else {
|
||||
this.playlistSorted = this.playlists.filter(playlist => {
|
||||
return playlist.attributes.name.toLowerCase().indexOf(this.searchQuery.toLowerCase()) > -1
|
||||
})
|
||||
if (this.playlistSorted.length == 1) {
|
||||
this.focused = this.playlistSorted[0].id
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -1,434 +1,483 @@
|
|||
<script type="text/x-template" id="eq-view">
|
||||
<div class="modal-fullscreen equalizer-panel" @click.self="close()" @contextmenu.self="close()">
|
||||
<div class="modal-window" >
|
||||
<div class="modal-header">
|
||||
<div class="modal-title">{{$root.getLz('term.equalizer')}}</div>
|
||||
<button class="close-btn" @click="close()" :aria-label="$root.getLz('action.close')"></button>
|
||||
<div class="md-option-segment md-option-segment_auto">
|
||||
<select class="md-select" style="width:220px;text-align:center;margin-right:245px" v-model="$root.cfg.audio.equalizer.preset" v-on:change="changePreset($root.cfg.audio.equalizer.preset)">
|
||||
<optgroup :label="$root.getLz('term.userPresets')">
|
||||
<option v-for="preset in $root.cfg.audio.equalizer.presets" :value="preset.preset">{{preset.name}}</option>
|
||||
</optgroup>
|
||||
<optgroup :label="$root.getLz('term.defaultPresets')">
|
||||
<option v-for="preset in defaultPresets" :value="preset.preset">{{preset.name}}</option>
|
||||
</optgroup>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-content">
|
||||
<!-- BANDS = [60, 170, 310, 600, 1000, 3000, 6000, 12000, 14000, 16000]; -->
|
||||
<div class="inputs-container">
|
||||
<div class="input-container mini">
|
||||
{{$root.cfg.audio.equalizer.vibrantBass}}
|
||||
<input tabindex="0" type="range" class="eq-slider mini" orient="vertical" min="-15" max="15" step="1" v-model="$root.cfg.audio.equalizer.vibrantBass" @change="changeVibrantBass()">
|
||||
Vibrant Bass
|
||||
</div>
|
||||
<div class="input-container mini">
|
||||
{{$root.cfg.audio.equalizer.mix}}
|
||||
<input tabindex="0" type="range" class="eq-slider mini" orient="vertical" min="0" max="2" step="0.1" v-model="$root.cfg.audio.equalizer.mix" @change="changeMix()">
|
||||
Mix
|
||||
</div>
|
||||
<div class="input-container header mini">
|
||||
Gain
|
||||
<input type="range" class="eq-slider" orient="vertical" min="-12" max="12" step="0.1" >
|
||||
<div class="freq-header">Freq</div>
|
||||
<div>Q</div>
|
||||
</div>
|
||||
<div class="input-container">
|
||||
<input tabindex="0" type="number" class="eq-freq" orient="vertical" min="-12" max="12" step="0.1" v-model="$root.cfg.audio.equalizer.gain[0]" @change="changeGain(0)">
|
||||
<input tabindex="0" type="range" class="eq-slider" orient="vertical" min="-12" max="12" step="0.1" v-model="$root.cfg.audio.equalizer.gain[0]" @change="changeGain(0)">
|
||||
<input type="number" class="eq-freq" orient="vertical" min="22" max="44" step="2" v-model="$root.cfg.audio.equalizer.frequencies[0]" @change="changeFreq(0)">
|
||||
<input type="number" class="eq-q" orient="vertical" min="0" max="5" step="0.1" v-model="$root.cfg.audio.equalizer.Q[0]" @change="changeQ(0)">
|
||||
</div>
|
||||
<div class="input-container">
|
||||
<input tabindex="0" type="number" class="eq-freq" orient="vertical" min="-12" max="12" step="0.1" v-model="$root.cfg.audio.equalizer.gain[1]" @change="changeGain(1)">
|
||||
<input tabindex="0" type="range" class="eq-slider" orient="vertical" min="-12" max="12" step="0.1" v-model="$root.cfg.audio.equalizer.gain[1]" @change="changeGain(1)">
|
||||
<input type="number" class="eq-freq" orient="vertical" min="44" max="88" step="4" v-model="$root.cfg.audio.equalizer.frequencies[1]" @change="changeFreq(1)">
|
||||
<input type="number" class="eq-q" orient="vertical" min="0" max="5" step="0.1" v-model="$root.cfg.audio.equalizer.Q[1]" @change="changeQ(1)">
|
||||
</div>
|
||||
<div class="input-container">
|
||||
<input tabindex="0" type="number" class="eq-freq" orient="vertical" min="-12" max="12" step="0.1" v-model="$root.cfg.audio.equalizer.gain[2]" @change="changeGain(2)">
|
||||
<input tabindex="0" type="range" class="eq-slider" orient="vertical" min="-12" max="12" step="0.1" v-model="$root.cfg.audio.equalizer.gain[2]" @change="changeGain(2)">
|
||||
<input type="number" class="eq-freq" orient="vertical" min="88" max="177" step="8" v-model="$root.cfg.audio.equalizer.frequencies[2]" @change="changeFreq(2)">
|
||||
<input type="number" class="eq-q" orient="vertical" min="0" max="5" step="0.1" v-model="$root.cfg.audio.equalizer.Q[2]" @change="changeQ(2)">
|
||||
</div>
|
||||
<div class="input-container">
|
||||
<input tabindex="0" type="number" class="eq-freq" orient="vertical" min="-12" max="12" step="0.1" v-model="$root.cfg.audio.equalizer.gain[3]" @change="changeGain(3)">
|
||||
<input tabindex="0" type="range" class="eq-slider" orient="vertical" min="-12" max="12" step="0.1" v-model="$root.cfg.audio.equalizer.gain[3]" @change="changeGain(3)">
|
||||
<input type="number" class="eq-freq" orient="vertical" min="177" max="355" step="16" v-model="$root.cfg.audio.equalizer.frequencies[3]" @change="changeFreq(3)">
|
||||
<input type="number" class="eq-q" orient="vertical" min="0" max="5" step="0.1" v-model="$root.cfg.audio.equalizer.Q[3]" @change="changeQ(3)">
|
||||
</div>
|
||||
<div class="input-container">
|
||||
<input tabindex="0" type="number" class="eq-freq" orient="vertical" min="-12" max="12" step="0.1" v-model="$root.cfg.audio.equalizer.gain[4]" @change="changeGain(4)">
|
||||
<input tabindex="0" type="range" class="eq-slider" orient="vertical" min="-12" max="12" step="0.1" v-model="$root.cfg.audio.equalizer.gain[4]" @change="changeGain(4)">
|
||||
<input type="number" class="eq-freq" orient="vertical" min="355" max="710" step="32" v-model="$root.cfg.audio.equalizer.frequencies[4]" @change="changeFreq(4)">
|
||||
<input type="number" class="eq-q" orient="vertical" min="0" max="5" step="0.1" v-model="$root.cfg.audio.equalizer.Q[4]" @change="changeQ(4)">
|
||||
</div>
|
||||
<div class="input-container">
|
||||
<input tabindex="0" type="number" class="eq-freq" orient="vertical" min="-12" max="12" step="0.1" v-model="$root.cfg.audio.equalizer.gain[5]" @change="changeGain(5)">
|
||||
<input tabindex="0" type="range" class="eq-slider" orient="vertical" min="-12" max="12" step="0.1" v-model="$root.cfg.audio.equalizer.gain[5]" @change="changeGain(5)">
|
||||
<input type="number" class="eq-freq" orient="vertical" min="710" max="1420" step="64" v-model="$root.cfg.audio.equalizer.frequencies[5]" @change="changeFreq(5)">
|
||||
<input type="number" class="eq-q" orient="vertical" min="0" max="5" step="0.1" v-model="$root.cfg.audio.equalizer.Q[5]" @change="changeQ(5)">
|
||||
</div>
|
||||
<div class="input-container">
|
||||
<input tabindex="0" type="number" class="eq-freq" orient="vertical" min="-12" max="12" step="0.1" v-model="$root.cfg.audio.equalizer.gain[6]" @change="changeGain(6)">
|
||||
<input tabindex="0" type="range" class="eq-slider" orient="vertical" min="-12" max="12" step="0.1" v-model="$root.cfg.audio.equalizer.gain[6]" @change="changeGain(6)">
|
||||
<input type="number" class="eq-freq" orient="vertical" min="1420" max="2840" step="128" v-model="$root.cfg.audio.equalizer.frequencies[6]" @change="changeFreq(6)">
|
||||
<input type="number" class="eq-q" orient="vertical" min="0" max="5" step="0.1" v-model="$root.cfg.audio.equalizer.Q[6]" @change="changeQ(6)">
|
||||
</div>
|
||||
<div class="input-container">
|
||||
<input tabindex="0" type="number" class="eq-freq" orient="vertical" min="-12" max="12" step="0.1" v-model="$root.cfg.audio.equalizer.gain[7]" @change="changeGain(7)">
|
||||
<input tabindex="0" type="range" class="eq-slider" orient="vertical" min="-12" max="12" step="0.1" v-model="$root.cfg.audio.equalizer.gain[7]" @change="changeGain(7)">
|
||||
<input type="number" class="eq-freq" orient="vertical" min="2840" max="5680" step="256" v-model="$root.cfg.audio.equalizer.frequencies[7]" @change="changeFreq(7)">
|
||||
<input type="number" class="eq-q" orient="vertical" min="0" max="5" step="0.1" v-model="$root.cfg.audio.equalizer.Q[7]" @change="changeQ(7)">
|
||||
</div>
|
||||
<div class="input-container">
|
||||
<input tabindex="0" type="number" class="eq-freq" orient="vertical" min="-12" max="12" step="0.1" v-model="$root.cfg.audio.equalizer.gain[8]" @change="changeGain(8)">
|
||||
<input tabindex="0" type="range" class="eq-slider" orient="vertical" min="-12" max="12" step="0.1" v-model="$root.cfg.audio.equalizer.gain[8]" @change="changeGain(8)">
|
||||
<input type="number" class="eq-freq" orient="vertical" min="5680" max="11360" step="512" v-model="$root.cfg.audio.equalizer.frequencies[8]" @change="changeFreq(8)">
|
||||
<input type="number" class="eq-q" orient="vertical" min="0" max="5" step="0.1" v-model="$root.cfg.audio.equalizer.Q[8]" @change="changeQ(8)">
|
||||
</div>
|
||||
<div class="input-container">
|
||||
<input tabindex="0" type="number" class="eq-freq" orient="vertical" min="-12" max="12" step="0.1" v-model="$root.cfg.audio.equalizer.gain[9]" @change="changeGain(9)">
|
||||
<input tabindex="0" type="range" class="eq-slider" orient="vertical" min="-12" max="12" step="0.1" v-model="$root.cfg.audio.equalizer.gain[9]" @change="changeGain(9)">
|
||||
<input type="number" class="eq-freq" orient="vertical" min="11360" max="22720" step="1024" v-model="$root.cfg.audio.equalizer.frequencies[9]" @change="changeFreq(9)">
|
||||
<input type="number" class="eq-q" orient="vertical" min="0" max="5" step="0.1" v-model="$root.cfg.audio.equalizer.Q[9]" @change="changeQ(9)">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="modal-lowercontent">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<button class="md-btn" style="width:100%" @click="resetGain()">{{$root.getLz('term.reset')}}</button>
|
||||
</div>
|
||||
<div class="col">
|
||||
<button class="md-btn" style="width:100%" @click="presetOptions($event)">{{$root.getLz('term.menu')}}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script>
|
||||
Vue.component('eq-view', {
|
||||
template: '#eq-view',
|
||||
data: function () {
|
||||
return {
|
||||
// app: this.$root,
|
||||
eqPreset: function () {
|
||||
this.preset = uuidv4()
|
||||
this.name = ""
|
||||
this.frequencies = []
|
||||
this.gain = []
|
||||
this.Q = []
|
||||
this.mix = 1
|
||||
this.vibrantBass = 0
|
||||
this.userGenerated = true
|
||||
},
|
||||
defaultPresets: [
|
||||
{
|
||||
'preset': 'default',
|
||||
'name': 'Default',
|
||||
'frequencies': [32, 63, 125, 250, 500, 1000, 2000, 4000, 8000, 16000],
|
||||
'gain': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
'Q': [1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
|
||||
'mix': 1,
|
||||
'vibrantBass': 0,
|
||||
'userGenerated': false
|
||||
}, {
|
||||
'preset': 'boostAiriness',
|
||||
'name': 'Boost Airiness',
|
||||
'frequencies': [1169, 1733, 5962, 8688, 14125, 18628, 18628, 19000, 19500, 20000],
|
||||
'gain': [-1.41, 0.25, 3.33, 0.22, -0.53, 0.2, 3.64, 0, 0, 0],
|
||||
'Q': [0.405, 2.102, 0.025, 2.5, 7.071, 1.768, 1.146, 1, 1, 1],
|
||||
'mix': 1,
|
||||
'vibrantBass': 0,
|
||||
'userGenerated': false
|
||||
}, {
|
||||
'preset': 'acoustic',
|
||||
'name': 'Acoustic',
|
||||
'frequencies': [32, 75, 125, 220, 700, 1000, 2000, 4000, 10000, 16000],
|
||||
'gain': [0, -8, 0, -0.1, -3, 0, 0, 0, 4, 0],
|
||||
'Q': [1, 0.2, 1, 2.0, 1.4, 1, 1, 1, 0.1, 1],
|
||||
'mix': 1,
|
||||
'vibrantBass': 0,
|
||||
'userGenerated': false
|
||||
}, {
|
||||
'preset': 'clearVocal',
|
||||
'name': 'Clear Vocal',
|
||||
'frequencies': [20, 63, 125, 250, 400, 1000, 2000, 4000, 8000, 20000],
|
||||
'gain': [-22, 0, 0, 0, -3, 0, 1.8, 0, 0, 3.5],
|
||||
'Q': [0.3, 1, 1, 1, 2.0, 1, 0.7, 1, 1, 0.8],
|
||||
'mix': 1,
|
||||
'vibrantBass': 0,
|
||||
'userGenerated': false
|
||||
}, {
|
||||
'preset': 'instrumentClarity',
|
||||
'name': 'Instrument Clarity',
|
||||
'frequencies': [20, 63, 155, 250, 500, 1000, 2000, 5000, 11000, 16000],
|
||||
'gain': [-15, 0, -3, 0, 0, 0, 0, 3.1, 0, 0],
|
||||
'Q': [0.5, 1, 2, 1, 1, 1, 1, 1.5, 0.1, 1],
|
||||
'mix': 1,
|
||||
'vibrantBass': 0,
|
||||
'userGenerated': false
|
||||
}, {
|
||||
'preset': 'reduceHarshness',
|
||||
'name': 'Reduce Harshness',
|
||||
'frequencies': [32, 63, 125, 250, 500, 1128, 2000, 4057, 8000, 16000],
|
||||
'gain': [0, 0, 0, 0, 0, 2, 0, -6.4, 0, 0],
|
||||
'Q': [1, 1, 1, 1, 1, 2, 1, 1, 1, 1],
|
||||
'mix': 1,
|
||||
'vibrantBass': 0,
|
||||
'userGenerated': false
|
||||
}, {
|
||||
'preset': 'smileyFace',
|
||||
'name': 'Smiley Face',
|
||||
'frequencies': [35, 63, 125, 250, 500, 800, 2000, 4000, 8000, 20000],
|
||||
'gain': [5, 0, 0, 0, 0, -5, 0, 0, 0, 5],
|
||||
'Q': [0.1, 1, 1, 1, 1, 0.6, 1, 1, 1, 0.2],
|
||||
'mix': 1,
|
||||
'vibrantBass': 0,
|
||||
'userGenerated': false
|
||||
},
|
||||
{
|
||||
'preset': 'bassBoostSurgical',
|
||||
'name': 'Surgical Bass Boost',
|
||||
'frequencies': [32, 63, 125, 250, 500, 1000, 2000, 4000, 8000, 16000],
|
||||
'gain': [2.7, 2.2, 1.6, 1.4, 0.6, 0, 0, 0, 0, 0],
|
||||
'Q': [1.4, 1.4, 1.4, 1.4, 1.4, 1, 1, 1, 1, 1],
|
||||
'mix': 1,
|
||||
'vibrantBass': 0,
|
||||
'userGenerated': false
|
||||
}, {
|
||||
'preset': 'bassBoostClassic',
|
||||
'name': 'Classic Bass Boost',
|
||||
'frequencies': [32, 63, 160, 250, 500, 1000, 2000, 3500, 8000, 20000],
|
||||
'gain': [2.7, 2.2, 1.6, 1.4, 0.6, 0, 0, 0, 0, 0],
|
||||
'Q': [0.7, 0.7, 0.7, 0.7, 0.7, 1, 1, 1, 1, 1],
|
||||
'mix': 1,
|
||||
'vibrantBass': 0,
|
||||
'userGenerated': false
|
||||
}]
|
||||
}
|
||||
},
|
||||
props: ["src", "url"],
|
||||
mounted() {
|
||||
},
|
||||
methods: {
|
||||
presetOptions(event) {
|
||||
let menu = {
|
||||
items: {
|
||||
"new": {
|
||||
"icon": "./assets/feather/plus.svg",
|
||||
"name": app.getLz('action.newpreset'),
|
||||
action: () => {
|
||||
this.addPreset()
|
||||
}
|
||||
},
|
||||
"delete": {
|
||||
"icon": "./assets/feather/x-circle.svg",
|
||||
"name": app.getLz('action.deletepreset'),
|
||||
action: () => {
|
||||
this.deletePreset()
|
||||
}
|
||||
},
|
||||
"import": {
|
||||
"icon": "./assets/feather/share.svg",
|
||||
"name": app.getLz('action.import'),
|
||||
action: () => {
|
||||
this.importPreset()
|
||||
}
|
||||
},
|
||||
"export": {
|
||||
"icon": "./assets/feather/share.svg",
|
||||
"name": app.getLz('action.export'),
|
||||
action: () => {
|
||||
this.exportPreset()
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
if (!this.$root.cfg.audio.equalizer.userGenerated) {
|
||||
delete menu.items.delete
|
||||
}
|
||||
|
||||
app.showMenuPanel(menu, event)
|
||||
},
|
||||
sharePreset(event) {
|
||||
let menu = {
|
||||
items: [
|
||||
{
|
||||
"icon": "./assets/feather/share.svg",
|
||||
"name": app.getLz('action.import'),
|
||||
"action": function () {
|
||||
notyf.error("Not implemented yet")
|
||||
}
|
||||
},
|
||||
{
|
||||
"icon": "./assets/feather/share.svg",
|
||||
"name": app.getLz('action.export'),
|
||||
"action": function () {
|
||||
notyf.error("Not implemented yet")
|
||||
}
|
||||
},
|
||||
]
|
||||
}
|
||||
app.showMenuPanel(menu, event)
|
||||
},
|
||||
deletePreset() {
|
||||
let presets = this.$root.cfg.audio.equalizer.presets
|
||||
app.confirm(app.getLz('term.deletepreset.warn'), (result) => {
|
||||
if (result) {
|
||||
this.changePreset("default")
|
||||
// find the preset by id (preset) and remove it
|
||||
let index = presets.findIndex(p => p.preset == this.preset)
|
||||
presets.splice(index, 1)
|
||||
notyf.success(app.getLz('term.deletedpreset'))
|
||||
}
|
||||
})
|
||||
},
|
||||
close() {
|
||||
app.modals.equalizer = false
|
||||
},
|
||||
changeVibrantBass() {
|
||||
if (app.cfg.audio.equalizer.vibrantBass !== '0') {
|
||||
try {
|
||||
for (var i = 0; i < 21; i++) {
|
||||
CiderAudio.audioNodes.vibrantbassNode[i].gain.value = app.cfg.audio.maikiwiAudio.vibrantBass.gain[i] * (app.cfg.audio.equalizer.vibrantBass / 10);
|
||||
} CiderAudio.intelliGainComp_n0_0();
|
||||
}
|
||||
catch (e) {
|
||||
CiderAudio.hierarchical_loading();
|
||||
}
|
||||
}
|
||||
|
||||
else {
|
||||
CiderAudio.hierarchical_loading();
|
||||
}
|
||||
},
|
||||
changeMix() {
|
||||
if (Math.max(...app.cfg.audio.equalizer.gain) != 0) {
|
||||
try {
|
||||
for (var i = 0; i < 10; i++) {
|
||||
CiderAudio.audioNodes.audioBands[i].gain.value = app.cfg.audio.equalizer.gain[i] * app.cfg.audio.equalizer.mix
|
||||
}
|
||||
CiderAudio.intelliGainComp_n0_0();
|
||||
} catch (e) { CiderAudio.hierarchical_loading(); }
|
||||
}
|
||||
},
|
||||
changeGain(i) {
|
||||
if (Math.max(...app.cfg.audio.equalizer.gain) != 0) {
|
||||
try {
|
||||
CiderAudio.audioNodes.audioBands[i].gain.value = app.cfg.audio.equalizer.gain[i] * app.cfg.audio.equalizer.mix
|
||||
CiderAudio.intelliGainComp_n0_0();
|
||||
}
|
||||
catch (e) { CiderAudio.hierarchical_loading(); }
|
||||
}
|
||||
else {
|
||||
CiderAudio.hierarchical_loading();
|
||||
}
|
||||
},
|
||||
changeFreq(i) {
|
||||
CiderAudio.audioNodes.audioBands[i].frequency.value = app.cfg.audio.equalizer.frequencies[i]
|
||||
},
|
||||
changeQ(i) {
|
||||
CiderAudio.audioNodes.audioBands[i].Q.value = app.cfg.audio.equalizer.Q[i]
|
||||
},
|
||||
resetGain() {
|
||||
this.applyPreset({
|
||||
'frequencies': [32, 63, 125, 250, 500, 1000, 2000, 4000, 8000, 16000],
|
||||
'gain': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
'Q': [1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
|
||||
'mix': 1,
|
||||
'vibrantBass': 0,
|
||||
})
|
||||
if (app.cfg.audio.equalizer.userGenerated) {
|
||||
this.saveSelectedPreset()
|
||||
}
|
||||
},
|
||||
addPreset() {
|
||||
let self = this
|
||||
app.prompt(app.getLz('term.newpreset.name'), (res) => {
|
||||
if (res) {
|
||||
let eqSettings = Clone(app.cfg.audio.equalizer)
|
||||
let newPreset = new self.eqPreset()
|
||||
newPreset.name = res
|
||||
newPreset.frequencies = eqSettings.frequencies
|
||||
newPreset.gain = eqSettings.gain
|
||||
newPreset.Q = eqSettings.Q
|
||||
newPreset.mix = eqSettings.mix
|
||||
newPreset.vibrantBass = eqSettings.vibrantBass
|
||||
app.cfg.audio.equalizer.presets.push(newPreset)
|
||||
notyf.success(app.getLz('term.addedpreset'))
|
||||
self.changePreset(newPreset.preset)
|
||||
}
|
||||
})
|
||||
},
|
||||
saveSelectedPreset() {
|
||||
// Save the current settings to the selected preset
|
||||
let self = this
|
||||
//let preset = app.cfg.audio.equalizer.presets[app.cfg.audio.equalizer.preset]
|
||||
// find the preset by its id (preset)
|
||||
let preset = app.cfg.audio.equalizer.presets.find(p => p.preset == app.cfg.audio.equalizer.preset)
|
||||
preset.frequencies = app.cfg.audio.equalizer.frequencies
|
||||
preset.gain = app.cfg.audio.equalizer.gain
|
||||
preset.Q = app.cfg.audio.equalizer.Q
|
||||
preset.mix = app.cfg.audio.equalizer.mix
|
||||
preset.vibrantBass = app.cfg.audio.equalizer.vibrantBass
|
||||
notyf.success("Saved Preset")
|
||||
},
|
||||
exportPreset() {
|
||||
let preset = app.cfg.audio.equalizer.presets.find(p => p.preset == app.cfg.audio.equalizer.preset)
|
||||
this.$root.copyToClipboard(btoa(JSON.stringify(preset)))
|
||||
},
|
||||
importPreset() {
|
||||
let self = this
|
||||
app.prompt("Enter preset share code", (res) => {
|
||||
if (res) {
|
||||
let preset = JSON.parse(atob(res))
|
||||
if (preset.frequencies && preset.gain && preset.Q && preset.mix && preset.vibrantBass) {
|
||||
// self.applyPreset(preset)
|
||||
app.cfg.audio.equalizer.presets.push(preset)
|
||||
notyf.success(`${preset.name} has been imported.`)
|
||||
}
|
||||
else {
|
||||
notyf.error("Invalid Preset")
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
applyPreset(preset) {
|
||||
Object.assign(this.$root.cfg.audio.equalizer, preset)
|
||||
this.changeVibrantBass()
|
||||
for (var i = 0; i < 10; i++) {
|
||||
try { CiderAudio.audioNodes.audioBands[i].gain.value = app.cfg.audio.equalizer.gain[i] * app.cfg.audio.equalizer.mix }
|
||||
catch (e) {
|
||||
CiderAudio.hierarchical_loading();
|
||||
CiderAudio.audioNodes.audioBands[i].gain.value = app.cfg.audio.equalizer.gain[i] * app.cfg.audio.equalizer.mix
|
||||
}
|
||||
|
||||
CiderAudio.audioNodes.audioBands[i].frequency.value = app.cfg.audio.equalizer.frequencies[i]
|
||||
CiderAudio.audioNodes.audioBands[i].Q.value = app.cfg.audio.equalizer.Q[i]
|
||||
}
|
||||
CiderAudio.intelliGainComp_n0_0();
|
||||
},
|
||||
changePreset(id) {
|
||||
let userPresets = app.cfg.audio.equalizer.presets
|
||||
let defaultPresets = Clone(this.defaultPresets)
|
||||
|
||||
let presets = defaultPresets.concat(userPresets)
|
||||
console.log(presets)
|
||||
let preset = presets.find(p => p.preset == id)
|
||||
|
||||
console.log(preset)
|
||||
|
||||
if (preset) {
|
||||
this.applyPreset(preset)
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<script type="text/x-template" id="eq-view">
|
||||
<div class="modal-fullscreen equalizer-panel" @click.self="close()" @contextmenu.self="close()">
|
||||
<div class="modal-window">
|
||||
<div class="modal-header">
|
||||
<div class="modal-title">{{$root.getLz('term.equalizer')}}</div>
|
||||
<button class="close-btn" @click="close()" :aria-label="$root.getLz('action.close')"></button>
|
||||
<div class="md-option-segment md-option-segment_auto">
|
||||
<select class="md-select" style="width:220px;text-align:center;margin-right:245px"
|
||||
v-model="$root.cfg.audio.equalizer.preset"
|
||||
v-on:change="changePreset($root.cfg.audio.equalizer.preset)">
|
||||
<optgroup :label="$root.getLz('term.userPresets')">
|
||||
<option v-for="preset in $root.cfg.audio.equalizer.presets" :value="preset.preset">
|
||||
{{preset.name}}
|
||||
</option>
|
||||
</optgroup>
|
||||
<optgroup :label="$root.getLz('term.defaultPresets')">
|
||||
<option v-for="preset in defaultPresets" :value="preset.preset">{{preset.name}}</option>
|
||||
</optgroup>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-content">
|
||||
<!-- BANDS = [60, 170, 310, 600, 1000, 3000, 6000, 12000, 14000, 16000]; -->
|
||||
<div class="inputs-container">
|
||||
<div class="input-container mini">
|
||||
{{$root.cfg.audio.equalizer.vibrantBass}}
|
||||
<input tabindex="0" type="range" class="eq-slider mini" orient="vertical" min="-15" max="15"
|
||||
step="1" v-model="$root.cfg.audio.equalizer.vibrantBass" @change="changeVibrantBass()">
|
||||
Vibrant Bass
|
||||
</div>
|
||||
<div class="input-container mini">
|
||||
{{$root.cfg.audio.equalizer.mix}}
|
||||
<input tabindex="0" type="range" class="eq-slider mini" orient="vertical" min="0" max="2"
|
||||
step="0.1" v-model="$root.cfg.audio.equalizer.mix" @change="changeMix()">
|
||||
Mix
|
||||
</div>
|
||||
<div class="input-container header mini">
|
||||
Gain
|
||||
<input type="range" class="eq-slider" orient="vertical" min="-12" max="12" step="0.1">
|
||||
<div class="freq-header">Freq</div>
|
||||
<div>Q</div>
|
||||
</div>
|
||||
<div class="input-container">
|
||||
<input tabindex="0" type="number" class="eq-freq" orient="vertical" min="-12" max="12"
|
||||
step="0.1" v-model="$root.cfg.audio.equalizer.gain[0]" @change="changeGain(0)">
|
||||
<input tabindex="0" type="range" class="eq-slider" orient="vertical" min="-12" max="12"
|
||||
step="0.1" v-model="$root.cfg.audio.equalizer.gain[0]" @change="changeGain(0)">
|
||||
<input type="number" class="eq-freq" orient="vertical" min="22" max="44" step="2"
|
||||
v-model="$root.cfg.audio.equalizer.frequencies[0]" @change="changeFreq(0)">
|
||||
<input type="number" class="eq-q" orient="vertical" min="0" max="5" step="0.1"
|
||||
v-model="$root.cfg.audio.equalizer.Q[0]" @change="changeQ(0)">
|
||||
</div>
|
||||
<div class="input-container">
|
||||
<input tabindex="0" type="number" class="eq-freq" orient="vertical" min="-12" max="12"
|
||||
step="0.1" v-model="$root.cfg.audio.equalizer.gain[1]" @change="changeGain(1)">
|
||||
<input tabindex="0" type="range" class="eq-slider" orient="vertical" min="-12" max="12"
|
||||
step="0.1" v-model="$root.cfg.audio.equalizer.gain[1]" @change="changeGain(1)">
|
||||
<input type="number" class="eq-freq" orient="vertical" min="44" max="88" step="4"
|
||||
v-model="$root.cfg.audio.equalizer.frequencies[1]" @change="changeFreq(1)">
|
||||
<input type="number" class="eq-q" orient="vertical" min="0" max="5" step="0.1"
|
||||
v-model="$root.cfg.audio.equalizer.Q[1]" @change="changeQ(1)">
|
||||
</div>
|
||||
<div class="input-container">
|
||||
<input tabindex="0" type="number" class="eq-freq" orient="vertical" min="-12" max="12"
|
||||
step="0.1" v-model="$root.cfg.audio.equalizer.gain[2]" @change="changeGain(2)">
|
||||
<input tabindex="0" type="range" class="eq-slider" orient="vertical" min="-12" max="12"
|
||||
step="0.1" v-model="$root.cfg.audio.equalizer.gain[2]" @change="changeGain(2)">
|
||||
<input type="number" class="eq-freq" orient="vertical" min="88" max="177" step="8"
|
||||
v-model="$root.cfg.audio.equalizer.frequencies[2]" @change="changeFreq(2)">
|
||||
<input type="number" class="eq-q" orient="vertical" min="0" max="5" step="0.1"
|
||||
v-model="$root.cfg.audio.equalizer.Q[2]" @change="changeQ(2)">
|
||||
</div>
|
||||
<div class="input-container">
|
||||
<input tabindex="0" type="number" class="eq-freq" orient="vertical" min="-12" max="12"
|
||||
step="0.1" v-model="$root.cfg.audio.equalizer.gain[3]" @change="changeGain(3)">
|
||||
<input tabindex="0" type="range" class="eq-slider" orient="vertical" min="-12" max="12"
|
||||
step="0.1" v-model="$root.cfg.audio.equalizer.gain[3]" @change="changeGain(3)">
|
||||
<input type="number" class="eq-freq" orient="vertical" min="177" max="355" step="16"
|
||||
v-model="$root.cfg.audio.equalizer.frequencies[3]" @change="changeFreq(3)">
|
||||
<input type="number" class="eq-q" orient="vertical" min="0" max="5" step="0.1"
|
||||
v-model="$root.cfg.audio.equalizer.Q[3]" @change="changeQ(3)">
|
||||
</div>
|
||||
<div class="input-container">
|
||||
<input tabindex="0" type="number" class="eq-freq" orient="vertical" min="-12" max="12"
|
||||
step="0.1" v-model="$root.cfg.audio.equalizer.gain[4]" @change="changeGain(4)">
|
||||
<input tabindex="0" type="range" class="eq-slider" orient="vertical" min="-12" max="12"
|
||||
step="0.1" v-model="$root.cfg.audio.equalizer.gain[4]" @change="changeGain(4)">
|
||||
<input type="number" class="eq-freq" orient="vertical" min="355" max="710" step="32"
|
||||
v-model="$root.cfg.audio.equalizer.frequencies[4]" @change="changeFreq(4)">
|
||||
<input type="number" class="eq-q" orient="vertical" min="0" max="5" step="0.1"
|
||||
v-model="$root.cfg.audio.equalizer.Q[4]" @change="changeQ(4)">
|
||||
</div>
|
||||
<div class="input-container">
|
||||
<input tabindex="0" type="number" class="eq-freq" orient="vertical" min="-12" max="12"
|
||||
step="0.1" v-model="$root.cfg.audio.equalizer.gain[5]" @change="changeGain(5)">
|
||||
<input tabindex="0" type="range" class="eq-slider" orient="vertical" min="-12" max="12"
|
||||
step="0.1" v-model="$root.cfg.audio.equalizer.gain[5]" @change="changeGain(5)">
|
||||
<input type="number" class="eq-freq" orient="vertical" min="710" max="1420" step="64"
|
||||
v-model="$root.cfg.audio.equalizer.frequencies[5]" @change="changeFreq(5)">
|
||||
<input type="number" class="eq-q" orient="vertical" min="0" max="5" step="0.1"
|
||||
v-model="$root.cfg.audio.equalizer.Q[5]" @change="changeQ(5)">
|
||||
</div>
|
||||
<div class="input-container">
|
||||
<input tabindex="0" type="number" class="eq-freq" orient="vertical" min="-12" max="12"
|
||||
step="0.1" v-model="$root.cfg.audio.equalizer.gain[6]" @change="changeGain(6)">
|
||||
<input tabindex="0" type="range" class="eq-slider" orient="vertical" min="-12" max="12"
|
||||
step="0.1" v-model="$root.cfg.audio.equalizer.gain[6]" @change="changeGain(6)">
|
||||
<input type="number" class="eq-freq" orient="vertical" min="1420" max="2840" step="128"
|
||||
v-model="$root.cfg.audio.equalizer.frequencies[6]" @change="changeFreq(6)">
|
||||
<input type="number" class="eq-q" orient="vertical" min="0" max="5" step="0.1"
|
||||
v-model="$root.cfg.audio.equalizer.Q[6]" @change="changeQ(6)">
|
||||
</div>
|
||||
<div class="input-container">
|
||||
<input tabindex="0" type="number" class="eq-freq" orient="vertical" min="-12" max="12"
|
||||
step="0.1" v-model="$root.cfg.audio.equalizer.gain[7]" @change="changeGain(7)">
|
||||
<input tabindex="0" type="range" class="eq-slider" orient="vertical" min="-12" max="12"
|
||||
step="0.1" v-model="$root.cfg.audio.equalizer.gain[7]" @change="changeGain(7)">
|
||||
<input type="number" class="eq-freq" orient="vertical" min="2840" max="5680" step="256"
|
||||
v-model="$root.cfg.audio.equalizer.frequencies[7]" @change="changeFreq(7)">
|
||||
<input type="number" class="eq-q" orient="vertical" min="0" max="5" step="0.1"
|
||||
v-model="$root.cfg.audio.equalizer.Q[7]" @change="changeQ(7)">
|
||||
</div>
|
||||
<div class="input-container">
|
||||
<input tabindex="0" type="number" class="eq-freq" orient="vertical" min="-12" max="12"
|
||||
step="0.1" v-model="$root.cfg.audio.equalizer.gain[8]" @change="changeGain(8)">
|
||||
<input tabindex="0" type="range" class="eq-slider" orient="vertical" min="-12" max="12"
|
||||
step="0.1" v-model="$root.cfg.audio.equalizer.gain[8]" @change="changeGain(8)">
|
||||
<input type="number" class="eq-freq" orient="vertical" min="5680" max="11360" step="512"
|
||||
v-model="$root.cfg.audio.equalizer.frequencies[8]" @change="changeFreq(8)">
|
||||
<input type="number" class="eq-q" orient="vertical" min="0" max="5" step="0.1"
|
||||
v-model="$root.cfg.audio.equalizer.Q[8]" @change="changeQ(8)">
|
||||
</div>
|
||||
<div class="input-container">
|
||||
<input tabindex="0" type="number" class="eq-freq" orient="vertical" min="-12" max="12"
|
||||
step="0.1" v-model="$root.cfg.audio.equalizer.gain[9]" @change="changeGain(9)">
|
||||
<input tabindex="0" type="range" class="eq-slider" orient="vertical" min="-12" max="12"
|
||||
step="0.1" v-model="$root.cfg.audio.equalizer.gain[9]" @change="changeGain(9)">
|
||||
<input type="number" class="eq-freq" orient="vertical" min="11360" max="22720" step="1024"
|
||||
v-model="$root.cfg.audio.equalizer.frequencies[9]" @change="changeFreq(9)">
|
||||
<input type="number" class="eq-q" orient="vertical" min="0" max="5" step="0.1"
|
||||
v-model="$root.cfg.audio.equalizer.Q[9]" @change="changeQ(9)">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="modal-lowercontent">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<button class="md-btn" style="width:100%" @click="resetGain()">{{$root.getLz('term.reset')}}
|
||||
</button>
|
||||
</div>
|
||||
<div class="col">
|
||||
<button class="md-btn" style="width:100%" @click="presetOptions($event)">
|
||||
{{$root.getLz('term.menu')}}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script>
|
||||
Vue.component('eq-view', {
|
||||
template: '#eq-view',
|
||||
data: function() {
|
||||
return {
|
||||
// app: this.$root,
|
||||
eqPreset: function() {
|
||||
this.preset = uuidv4()
|
||||
this.name = ""
|
||||
this.frequencies = []
|
||||
this.gain = []
|
||||
this.Q = []
|
||||
this.mix = 1
|
||||
this.vibrantBass = 0
|
||||
this.userGenerated = true
|
||||
},
|
||||
defaultPresets: [
|
||||
{
|
||||
'preset': 'default',
|
||||
'name': 'Default',
|
||||
'frequencies': [32, 63, 125, 250, 500, 1000, 2000, 4000, 8000, 16000],
|
||||
'gain': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
'Q': [1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
|
||||
'mix': 1,
|
||||
'vibrantBass': 0,
|
||||
'userGenerated': false
|
||||
}, {
|
||||
'preset': 'boostAiriness',
|
||||
'name': 'Boost Airiness',
|
||||
'frequencies': [1169, 1733, 5962, 8688, 14125, 18628, 18628, 19000, 19500, 20000],
|
||||
'gain': [-1.41, 0.25, 3.33, 0.22, -0.53, 0.2, 3.64, 0, 0, 0],
|
||||
'Q': [0.405, 2.102, 0.025, 2.5, 7.071, 1.768, 1.146, 1, 1, 1],
|
||||
'mix': 1,
|
||||
'vibrantBass': 0,
|
||||
'userGenerated': false
|
||||
}, {
|
||||
'preset': 'acoustic',
|
||||
'name': 'Acoustic',
|
||||
'frequencies': [32, 75, 125, 220, 700, 1000, 2000, 4000, 10000, 16000],
|
||||
'gain': [0, -8, 0, -0.1, -3, 0, 0, 0, 4, 0],
|
||||
'Q': [1, 0.2, 1, 2.0, 1.4, 1, 1, 1, 0.1, 1],
|
||||
'mix': 1,
|
||||
'vibrantBass': 0,
|
||||
'userGenerated': false
|
||||
}, {
|
||||
'preset': 'clearVocal',
|
||||
'name': 'Clear Vocal',
|
||||
'frequencies': [20, 63, 125, 250, 400, 1000, 2000, 4000, 8000, 20000],
|
||||
'gain': [-22, 0, 0, 0, -3, 0, 1.8, 0, 0, 3.5],
|
||||
'Q': [0.3, 1, 1, 1, 2.0, 1, 0.7, 1, 1, 0.8],
|
||||
'mix': 1,
|
||||
'vibrantBass': 0,
|
||||
'userGenerated': false
|
||||
}, {
|
||||
'preset': 'instrumentClarity',
|
||||
'name': 'Instrument Clarity',
|
||||
'frequencies': [20, 63, 155, 250, 500, 1000, 2000, 5000, 11000, 16000],
|
||||
'gain': [-15, 0, -3, 0, 0, 0, 0, 3.1, 0, 0],
|
||||
'Q': [0.5, 1, 2, 1, 1, 1, 1, 1.5, 0.1, 1],
|
||||
'mix': 1,
|
||||
'vibrantBass': 0,
|
||||
'userGenerated': false
|
||||
}, {
|
||||
'preset': 'reduceHarshness',
|
||||
'name': 'Reduce Harshness',
|
||||
'frequencies': [32, 63, 125, 250, 500, 1128, 2000, 4057, 8000, 16000],
|
||||
'gain': [0, 0, 0, 0, 0, 2, 0, -6.4, 0, 0],
|
||||
'Q': [1, 1, 1, 1, 1, 2, 1, 1, 1, 1],
|
||||
'mix': 1,
|
||||
'vibrantBass': 0,
|
||||
'userGenerated': false
|
||||
}, {
|
||||
'preset': 'smileyFace',
|
||||
'name': 'Smiley Face',
|
||||
'frequencies': [35, 63, 125, 250, 500, 800, 2000, 4000, 8000, 20000],
|
||||
'gain': [5, 0, 0, 0, 0, -5, 0, 0, 0, 5],
|
||||
'Q': [0.1, 1, 1, 1, 1, 0.6, 1, 1, 1, 0.2],
|
||||
'mix': 1,
|
||||
'vibrantBass': 0,
|
||||
'userGenerated': false
|
||||
},
|
||||
{
|
||||
'preset': 'bassBoostSurgical',
|
||||
'name': 'Surgical Bass Boost',
|
||||
'frequencies': [32, 63, 125, 250, 500, 1000, 2000, 4000, 8000, 16000],
|
||||
'gain': [2.7, 2.2, 1.6, 1.4, 0.6, 0, 0, 0, 0, 0],
|
||||
'Q': [1.4, 1.4, 1.4, 1.4, 1.4, 1, 1, 1, 1, 1],
|
||||
'mix': 1,
|
||||
'vibrantBass': 0,
|
||||
'userGenerated': false
|
||||
}, {
|
||||
'preset': 'bassBoostClassic',
|
||||
'name': 'Classic Bass Boost',
|
||||
'frequencies': [32, 63, 160, 250, 500, 1000, 2000, 3500, 8000, 20000],
|
||||
'gain': [2.7, 2.2, 1.6, 1.4, 0.6, 0, 0, 0, 0, 0],
|
||||
'Q': [0.7, 0.7, 0.7, 0.7, 0.7, 1, 1, 1, 1, 1],
|
||||
'mix': 1,
|
||||
'vibrantBass': 0,
|
||||
'userGenerated': false
|
||||
}]
|
||||
}
|
||||
},
|
||||
props: ["src", "url"],
|
||||
mounted() {
|
||||
},
|
||||
methods: {
|
||||
presetOptions(event) {
|
||||
let menu = {
|
||||
items: {
|
||||
"new": {
|
||||
"icon": "./assets/feather/plus.svg",
|
||||
"name": app.getLz('action.newpreset'),
|
||||
action: () => {
|
||||
this.addPreset()
|
||||
}
|
||||
},
|
||||
"delete": {
|
||||
"icon": "./assets/feather/x-circle.svg",
|
||||
"name": app.getLz('action.deletepreset'),
|
||||
action: () => {
|
||||
this.deletePreset()
|
||||
}
|
||||
},
|
||||
"import": {
|
||||
"icon": "./assets/feather/share.svg",
|
||||
"name": app.getLz('action.import'),
|
||||
action: () => {
|
||||
this.importPreset()
|
||||
}
|
||||
},
|
||||
"export": {
|
||||
"icon": "./assets/feather/share.svg",
|
||||
"name": app.getLz('action.export'),
|
||||
action: () => {
|
||||
this.exportPreset()
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
if (!this.$root.cfg.audio.equalizer.userGenerated) {
|
||||
delete menu.items.delete
|
||||
}
|
||||
|
||||
app.showMenuPanel(menu, event)
|
||||
},
|
||||
sharePreset(event) {
|
||||
let menu = {
|
||||
items: [
|
||||
{
|
||||
"icon": "./assets/feather/share.svg",
|
||||
"name": app.getLz('action.import'),
|
||||
"action": function() {
|
||||
notyf.error("Not implemented yet")
|
||||
}
|
||||
},
|
||||
{
|
||||
"icon": "./assets/feather/share.svg",
|
||||
"name": app.getLz('action.export'),
|
||||
"action": function() {
|
||||
notyf.error("Not implemented yet")
|
||||
}
|
||||
},
|
||||
]
|
||||
}
|
||||
app.showMenuPanel(menu, event)
|
||||
},
|
||||
deletePreset() {
|
||||
let presets = this.$root.cfg.audio.equalizer.presets
|
||||
app.confirm(app.getLz('term.deletepreset.warn'), (result) => {
|
||||
if (result) {
|
||||
this.changePreset("default")
|
||||
// find the preset by id (preset) and remove it
|
||||
let index = presets.findIndex(p => p.preset == this.preset)
|
||||
presets.splice(index, 1)
|
||||
notyf.success(app.getLz('term.deletedpreset'))
|
||||
}
|
||||
})
|
||||
},
|
||||
close() {
|
||||
app.modals.equalizer = false
|
||||
},
|
||||
changeVibrantBass() {
|
||||
if (app.cfg.audio.equalizer.vibrantBass !== '0') {
|
||||
try {
|
||||
for (var i = 0; i < 21; i++) {
|
||||
CiderAudio.audioNodes.vibrantbassNode[i].gain.value = app.cfg.audio.maikiwiAudio.vibrantBass.gain[i] * (app.cfg.audio.equalizer.vibrantBass / 10);
|
||||
}
|
||||
CiderAudio.intelliGainComp_n0_0();
|
||||
} catch (e) {
|
||||
CiderAudio.hierarchical_loading();
|
||||
}
|
||||
} else {
|
||||
CiderAudio.hierarchical_loading();
|
||||
}
|
||||
},
|
||||
changeMix() {
|
||||
if (Math.max(...app.cfg.audio.equalizer.gain) != 0) {
|
||||
try {
|
||||
for (var i = 0; i < 10; i++) {
|
||||
CiderAudio.audioNodes.audioBands[i].gain.value = app.cfg.audio.equalizer.gain[i] * app.cfg.audio.equalizer.mix
|
||||
}
|
||||
CiderAudio.intelliGainComp_n0_0();
|
||||
} catch (e) {
|
||||
CiderAudio.hierarchical_loading();
|
||||
}
|
||||
}
|
||||
},
|
||||
changeGain(i) {
|
||||
if (Math.max(...app.cfg.audio.equalizer.gain) != 0) {
|
||||
try {
|
||||
CiderAudio.audioNodes.audioBands[i].gain.value = app.cfg.audio.equalizer.gain[i] * app.cfg.audio.equalizer.mix
|
||||
CiderAudio.intelliGainComp_n0_0();
|
||||
} catch (e) {
|
||||
CiderAudio.hierarchical_loading();
|
||||
}
|
||||
} else {
|
||||
CiderAudio.hierarchical_loading();
|
||||
}
|
||||
},
|
||||
changeFreq(i) {
|
||||
CiderAudio.audioNodes.audioBands[i].frequency.value = app.cfg.audio.equalizer.frequencies[i]
|
||||
},
|
||||
changeQ(i) {
|
||||
CiderAudio.audioNodes.audioBands[i].Q.value = app.cfg.audio.equalizer.Q[i]
|
||||
},
|
||||
resetGain() {
|
||||
this.applyPreset({
|
||||
'frequencies': [32, 63, 125, 250, 500, 1000, 2000, 4000, 8000, 16000],
|
||||
'gain': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
'Q': [1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
|
||||
'mix': 1,
|
||||
'vibrantBass': 0,
|
||||
})
|
||||
if (app.cfg.audio.equalizer.userGenerated) {
|
||||
this.saveSelectedPreset()
|
||||
}
|
||||
},
|
||||
addPreset() {
|
||||
let self = this
|
||||
app.prompt(app.getLz('term.newpreset.name'), (res) => {
|
||||
if (res) {
|
||||
let eqSettings = Clone(app.cfg.audio.equalizer)
|
||||
let newPreset = new self.eqPreset()
|
||||
newPreset.name = res
|
||||
newPreset.frequencies = eqSettings.frequencies
|
||||
newPreset.gain = eqSettings.gain
|
||||
newPreset.Q = eqSettings.Q
|
||||
newPreset.mix = eqSettings.mix
|
||||
newPreset.vibrantBass = eqSettings.vibrantBass
|
||||
app.cfg.audio.equalizer.presets.push(newPreset)
|
||||
notyf.success(app.getLz('term.addedpreset'))
|
||||
self.changePreset(newPreset.preset)
|
||||
}
|
||||
})
|
||||
},
|
||||
saveSelectedPreset() {
|
||||
// Save the current settings to the selected preset
|
||||
let self = this
|
||||
//let preset = app.cfg.audio.equalizer.presets[app.cfg.audio.equalizer.preset]
|
||||
// find the preset by its id (preset)
|
||||
let preset = app.cfg.audio.equalizer.presets.find(p => p.preset == app.cfg.audio.equalizer.preset)
|
||||
preset.frequencies = app.cfg.audio.equalizer.frequencies
|
||||
preset.gain = app.cfg.audio.equalizer.gain
|
||||
preset.Q = app.cfg.audio.equalizer.Q
|
||||
preset.mix = app.cfg.audio.equalizer.mix
|
||||
preset.vibrantBass = app.cfg.audio.equalizer.vibrantBass
|
||||
notyf.success("Saved Preset")
|
||||
},
|
||||
exportPreset() {
|
||||
let preset = app.cfg.audio.equalizer.presets.find(p => p.preset == app.cfg.audio.equalizer.preset)
|
||||
this.$root.copyToClipboard(btoa(JSON.stringify(preset)))
|
||||
},
|
||||
importPreset() {
|
||||
let self = this
|
||||
app.prompt("Enter preset share code", (res) => {
|
||||
if (res) {
|
||||
let preset = JSON.parse(atob(res))
|
||||
if (preset.frequencies && preset.gain && preset.Q && preset.mix && preset.vibrantBass) {
|
||||
// self.applyPreset(preset)
|
||||
app.cfg.audio.equalizer.presets.push(preset)
|
||||
notyf.success(`${preset.name} has been imported.`)
|
||||
} else {
|
||||
notyf.error("Invalid Preset")
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
applyPreset(preset) {
|
||||
Object.assign(this.$root.cfg.audio.equalizer, preset)
|
||||
this.changeVibrantBass()
|
||||
for (var i = 0; i < 10; i++) {
|
||||
try {
|
||||
CiderAudio.audioNodes.audioBands[i].gain.value = app.cfg.audio.equalizer.gain[i] * app.cfg.audio.equalizer.mix
|
||||
} catch (e) {
|
||||
CiderAudio.hierarchical_loading();
|
||||
CiderAudio.audioNodes.audioBands[i].gain.value = app.cfg.audio.equalizer.gain[i] * app.cfg.audio.equalizer.mix
|
||||
}
|
||||
|
||||
CiderAudio.audioNodes.audioBands[i].frequency.value = app.cfg.audio.equalizer.frequencies[i]
|
||||
CiderAudio.audioNodes.audioBands[i].Q.value = app.cfg.audio.equalizer.Q[i]
|
||||
}
|
||||
CiderAudio.intelliGainComp_n0_0();
|
||||
},
|
||||
changePreset(id) {
|
||||
let userPresets = app.cfg.audio.equalizer.presets
|
||||
let defaultPresets = Clone(this.defaultPresets)
|
||||
|
||||
let presets = defaultPresets.concat(userPresets)
|
||||
console.log(presets)
|
||||
let preset = presets.find(p => p.preset == id)
|
||||
|
||||
console.log(preset)
|
||||
|
||||
if (preset) {
|
||||
this.applyPreset(preset)
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -14,19 +14,26 @@
|
|||
</div>
|
||||
<div class="fs-header" v-if="immersiveEnabled">
|
||||
<div class="top-nav-group">
|
||||
<sidebar-library-item @click.native="tabMode = 'catalog'" :name="$root.getLz('home.title')" svg-icon="./assets/feather/home.svg" svg-icon-name="home" page="home">
|
||||
<sidebar-library-item @click.native="tabMode = 'catalog'" :name="$root.getLz('home.title')"
|
||||
svg-icon="./assets/feather/home.svg" svg-icon-name="home" page="home">
|
||||
</sidebar-library-item>
|
||||
<sidebar-library-item @click.native="tabMode = 'catalog'" :name="$root.getLz('term.listenNow')" svg-icon="./assets/feather/play-circle.svg" svg-icon-name="listenNow"
|
||||
<sidebar-library-item @click.native="tabMode = 'catalog'" :name="$root.getLz('term.listenNow')"
|
||||
svg-icon="./assets/feather/play-circle.svg" svg-icon-name="listenNow"
|
||||
page="listen_now"></sidebar-library-item>
|
||||
<sidebar-library-item @click.native="tabMode = 'catalog'" :name="$root.getLz('term.browse')" svg-icon="./assets/feather/globe.svg" svg-icon-name="browse" page="browse">
|
||||
<sidebar-library-item @click.native="tabMode = 'catalog'" :name="$root.getLz('term.browse')"
|
||||
svg-icon="./assets/feather/globe.svg" svg-icon-name="browse" page="browse">
|
||||
</sidebar-library-item>
|
||||
<sidebar-library-item @click.native="tabMode = 'catalog'" :name="$root.getLz('term.radio')" svg-icon="./assets/feather/radio.svg" svg-icon-name="radio" page="radio">
|
||||
<sidebar-library-item @click.native="tabMode = 'catalog'" :name="$root.getLz('term.radio')"
|
||||
svg-icon="./assets/feather/radio.svg" svg-icon-name="radio" page="radio">
|
||||
</sidebar-library-item>
|
||||
<sidebar-library-item @click.native="tabMode = 'catalog'" :name="$root.getLz('term.library')" svg-icon="./assets/feather/radio.svg" svg-icon-name="library" page="library">
|
||||
<sidebar-library-item @click.native="tabMode = 'catalog'" :name="$root.getLz('term.library')"
|
||||
svg-icon="./assets/feather/radio.svg" svg-icon-name="library" page="library">
|
||||
</sidebar-library-item>
|
||||
<sidebar-library-item @click.native="tabMode = ''" :name="$root.getLz('term.nowPlaying')" svg-icon="./assets/play.svg" svg-icon-name="nowPlaying" page="nowPlaying">
|
||||
<sidebar-library-item @click.native="tabMode = ''" :name="$root.getLz('term.nowPlaying')"
|
||||
svg-icon="./assets/play.svg" svg-icon-name="nowPlaying" page="nowPlaying">
|
||||
</sidebar-library-item>
|
||||
<sidebar-library-item @click.native="tabMode = 'catalog'" name="" svg-icon="./assets/search.svg" svg-icon-name="search" page="search">
|
||||
<sidebar-library-item @click.native="tabMode = 'catalog'" name="" svg-icon="./assets/search.svg"
|
||||
svg-icon-name="search" page="search">
|
||||
</sidebar-library-item>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -59,7 +66,8 @@
|
|||
</div>
|
||||
<div class="song-artist item-navigate" style="display: inline-block;"
|
||||
@click="app.getNowPlayingItemDetailed('album') && app.fullscreen(false)">
|
||||
{{ (app.mk.nowPlayingItem["attributes"]["albumName"]) ? (app.mk.nowPlayingItem["attributes"]["albumName"]) : "" }}
|
||||
{{ (app.mk.nowPlayingItem["attributes"]["albumName"]) ?
|
||||
(app.mk.nowPlayingItem["attributes"]["albumName"]) : "" }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -139,7 +147,7 @@
|
|||
v-b-tooltip.hover :title="$root.formatVolumeTooltip()">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
<div class="col right-col" v-if="tabMode != ''">
|
||||
|
@ -175,77 +183,77 @@
|
|||
</script>
|
||||
|
||||
<script>
|
||||
Vue.component('fullscreen-view', {
|
||||
template: '#fullscreen-view',
|
||||
props: {
|
||||
time: {
|
||||
type: Number,
|
||||
required: false
|
||||
},
|
||||
lyrics: {
|
||||
type: Array,
|
||||
required: false
|
||||
},
|
||||
richlyrics: {
|
||||
type: Array,
|
||||
required: false
|
||||
},
|
||||
image: {
|
||||
type: String,
|
||||
required: false
|
||||
},
|
||||
},
|
||||
data: function () {
|
||||
return {
|
||||
app: this.$root,
|
||||
tabMode: "lyrics",
|
||||
video: null,
|
||||
immersiveEnabled: app.cfg.advanced.experiments.includes("immersive-preview")
|
||||
}
|
||||
},
|
||||
async mounted() {
|
||||
if (app.mk.nowPlayingItem._container.type == "albums") {
|
||||
try {
|
||||
const result = (await app.mk.api.v3.music(`/v1/catalog/${app.mk.storefrontId}/${app.mk.nowPlayingItem._container.type}/${app.mk.nowPlayingItem._container.id}`, {
|
||||
"fields": "editorialArtwork,editorialVideo",
|
||||
})).data.data[0].attributes?.editorialVideo?.motionDetailSquare?.video
|
||||
if (result) {
|
||||
this.video = result
|
||||
} else {
|
||||
this.video = null
|
||||
}
|
||||
} catch (e) {
|
||||
this.video = null
|
||||
e = null
|
||||
}
|
||||
} else if (app.mk.nowPlayingItem._container.type == "library-albums") {
|
||||
try {
|
||||
const result = (await app.mk.api.v3.music(`/v1/me/library/albums/${app.mk.nowPlayingItem._container.id}/catalog`
|
||||
, {"fields": "editorialArtwork,editorialVideo"})).data.data[0].attributes?.editorialVideo?.motionDetailSquare?.video
|
||||
if (result) {
|
||||
this.video = result
|
||||
} else {
|
||||
this.video = null
|
||||
}
|
||||
} catch (e) {
|
||||
e = null
|
||||
this.video = null
|
||||
}
|
||||
}
|
||||
},
|
||||
beforeMount() {
|
||||
window.addEventListener('keyup', this.onEscapeKeyUp);
|
||||
},
|
||||
beforeDestroy() {
|
||||
window.removeEventListener('keyup', this.onEscapeKeyUp)
|
||||
},
|
||||
methods: {
|
||||
onEscapeKeyUp(event) {
|
||||
if (event.which === 27) {
|
||||
app.fullscreen(false);
|
||||
console.log('js')
|
||||
}
|
||||
},
|
||||
Vue.component('fullscreen-view', {
|
||||
template: '#fullscreen-view',
|
||||
props: {
|
||||
time: {
|
||||
type: Number,
|
||||
required: false
|
||||
},
|
||||
lyrics: {
|
||||
type: Array,
|
||||
required: false
|
||||
},
|
||||
richlyrics: {
|
||||
type: Array,
|
||||
required: false
|
||||
},
|
||||
image: {
|
||||
type: String,
|
||||
required: false
|
||||
},
|
||||
},
|
||||
data: function() {
|
||||
return {
|
||||
app: this.$root,
|
||||
tabMode: "lyrics",
|
||||
video: null,
|
||||
immersiveEnabled: app.cfg.advanced.experiments.includes("immersive-preview")
|
||||
}
|
||||
},
|
||||
async mounted() {
|
||||
if (app.mk.nowPlayingItem._container.type == "albums") {
|
||||
try {
|
||||
const result = (await app.mk.api.v3.music(`/v1/catalog/${app.mk.storefrontId}/${app.mk.nowPlayingItem._container.type}/${app.mk.nowPlayingItem._container.id}`, {
|
||||
"fields": "editorialArtwork,editorialVideo",
|
||||
})).data.data[0].attributes?.editorialVideo?.motionDetailSquare?.video
|
||||
if (result) {
|
||||
this.video = result
|
||||
} else {
|
||||
this.video = null
|
||||
}
|
||||
} catch (e) {
|
||||
this.video = null
|
||||
e = null
|
||||
}
|
||||
});
|
||||
</script>
|
||||
} else if (app.mk.nowPlayingItem._container.type == "library-albums") {
|
||||
try {
|
||||
const result = (await app.mk.api.v3.music(`/v1/me/library/albums/${app.mk.nowPlayingItem._container.id}/catalog`
|
||||
, { "fields": "editorialArtwork,editorialVideo" })).data.data[0].attributes?.editorialVideo?.motionDetailSquare?.video
|
||||
if (result) {
|
||||
this.video = result
|
||||
} else {
|
||||
this.video = null
|
||||
}
|
||||
} catch (e) {
|
||||
e = null
|
||||
this.video = null
|
||||
}
|
||||
}
|
||||
},
|
||||
beforeMount() {
|
||||
window.addEventListener('keyup', this.onEscapeKeyUp);
|
||||
},
|
||||
beforeDestroy() {
|
||||
window.removeEventListener('keyup', this.onEscapeKeyUp)
|
||||
},
|
||||
methods: {
|
||||
onEscapeKeyUp(event) {
|
||||
if (event.which === 27) {
|
||||
app.fullscreen(false);
|
||||
console.log('js')
|
||||
}
|
||||
},
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -3,12 +3,12 @@
|
|||
</script>
|
||||
|
||||
<script>
|
||||
var hw = Vue.component('hello-world', {
|
||||
template: '#hello-world',
|
||||
methods: {
|
||||
sayHello: function () {
|
||||
alert('Hello world!');
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
var hw = Vue.component('hello-world', {
|
||||
template: '#hello-world',
|
||||
methods: {
|
||||
sayHello: function() {
|
||||
alert('Hello world!');
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<template v-if="item.type == 'artists'">
|
||||
<mediaitem-square :item="item"></mediaitem-square>
|
||||
</template>
|
||||
<template v-else>
|
||||
<template v-else>
|
||||
<mediaitem-list-item
|
||||
v-if="getKind(item) == 'song'"
|
||||
:index="key"
|
||||
|
@ -14,11 +14,13 @@
|
|||
<mediaitem-square v-else :item="item" :type="getKind(item)"></mediaitem-square>
|
||||
</template>
|
||||
</template>
|
||||
<button v-if="triggerEnabled" style="opacity:0;height: 32px;" v-observe-visibility="{callback: visibilityChanged}">{{this.app.getLz('term.showMore')}}
|
||||
<button v-if="triggerEnabled" style="opacity:0;height: 32px;"
|
||||
v-observe-visibility="{callback: visibilityChanged}">{{this.app.getLz('term.showMore')}}
|
||||
</button>
|
||||
</div>
|
||||
<transition name="fabfade">
|
||||
<button class="top-fab" v-show="showFab" @click="scrollToTop()" :aria-label="app.getLz('action.scrollToTop')">
|
||||
<button class="top-fab" v-show="showFab" @click="scrollToTop()"
|
||||
:aria-label="app.getLz('action.scrollToTop')">
|
||||
<%- include("../svg/arrow-up.svg") %>
|
||||
</button>
|
||||
</transition>
|
||||
|
@ -28,104 +30,104 @@
|
|||
</div>
|
||||
</script>
|
||||
<script>
|
||||
Vue.component('inline-collection-list', {
|
||||
template: "#inline-collection-list",
|
||||
props: {
|
||||
data: {
|
||||
required: true
|
||||
},
|
||||
title: {
|
||||
type: String,
|
||||
required: false
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: "artists"
|
||||
},
|
||||
parentSelector: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: null
|
||||
},
|
||||
},
|
||||
data: function() {
|
||||
return {
|
||||
triggerEnabled: true,
|
||||
canSeeTrigger: false,
|
||||
showFab: false,
|
||||
commonKind: "song",
|
||||
api: this.$root.mk.api,
|
||||
loading: false,
|
||||
app: this.$root,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getKind(item) {
|
||||
if (typeof item.kind != "undefined") {
|
||||
this.commonKind = item.kind;
|
||||
return item.kind
|
||||
}
|
||||
if (typeof item.attributes.playParams != "undefined") {
|
||||
this.commonKind = item.attributes.playParams.kind
|
||||
return item.attributes.playParams.kind
|
||||
}
|
||||
return this.commonKind
|
||||
},
|
||||
scrollToTop() {
|
||||
let target = document.querySelector(".header-text")
|
||||
document.querySelector(this.parentSelector ?? ".collection-page").scrollTo({
|
||||
top: 0,
|
||||
left: 0,
|
||||
behavior: 'smooth'
|
||||
})
|
||||
},
|
||||
getNext() {
|
||||
let self = this
|
||||
this.triggerEnabled = false;
|
||||
if (typeof this.data.next == "undefined") {
|
||||
return
|
||||
}
|
||||
this.loading = true
|
||||
|
||||
this.api.v3.music(this.data.next, app.collectionList.requestBody).then((response) => {
|
||||
console.log(response)
|
||||
if (!app.collectionList.response.groups) {
|
||||
this.data.data = this.data.data.concat(response.data.data);
|
||||
if (response.data.next) {
|
||||
this.data.next = response.data.next;
|
||||
this.triggerEnabled = true;
|
||||
}
|
||||
this.loading = false
|
||||
} else {
|
||||
if (!response.data.results[app.collectionList.response.groups]) {
|
||||
this.loading = false
|
||||
return
|
||||
}
|
||||
this.data.data = this.data.data.concat(response.data.results[app.collectionList.response.groups].data);
|
||||
if (response.data.results[app.collectionList.response.groups].next) {
|
||||
this.data.next = response.data.results[app.collectionList.response.groups].next;
|
||||
this.triggerEnabled = true;
|
||||
this.loading = false
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
headerVisibility: function(isVisible, entry) {
|
||||
if (isVisible) {
|
||||
this.showFab = false;
|
||||
} else {
|
||||
this.showFab = true;
|
||||
}
|
||||
},
|
||||
visibilityChanged: function(isVisible, entry) {
|
||||
if (isVisible) {
|
||||
this.canSeeTrigger = true;
|
||||
this.getNext();
|
||||
} else {
|
||||
this.canSeeTrigger = false;
|
||||
}
|
||||
}
|
||||
Vue.component('inline-collection-list', {
|
||||
template: "#inline-collection-list",
|
||||
props: {
|
||||
data: {
|
||||
required: true
|
||||
},
|
||||
title: {
|
||||
type: String,
|
||||
required: false
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: "artists"
|
||||
},
|
||||
parentSelector: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: null
|
||||
},
|
||||
},
|
||||
data: function() {
|
||||
return {
|
||||
triggerEnabled: true,
|
||||
canSeeTrigger: false,
|
||||
showFab: false,
|
||||
commonKind: "song",
|
||||
api: this.$root.mk.api,
|
||||
loading: false,
|
||||
app: this.$root,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getKind(item) {
|
||||
if (typeof item.kind != "undefined") {
|
||||
this.commonKind = item.kind;
|
||||
return item.kind
|
||||
}
|
||||
})
|
||||
</script>
|
||||
if (typeof item.attributes.playParams != "undefined") {
|
||||
this.commonKind = item.attributes.playParams.kind
|
||||
return item.attributes.playParams.kind
|
||||
}
|
||||
return this.commonKind
|
||||
},
|
||||
scrollToTop() {
|
||||
let target = document.querySelector(".header-text")
|
||||
document.querySelector(this.parentSelector ?? ".collection-page").scrollTo({
|
||||
top: 0,
|
||||
left: 0,
|
||||
behavior: 'smooth'
|
||||
})
|
||||
},
|
||||
getNext() {
|
||||
let self = this
|
||||
this.triggerEnabled = false;
|
||||
if (typeof this.data.next == "undefined") {
|
||||
return
|
||||
}
|
||||
this.loading = true
|
||||
|
||||
this.api.v3.music(this.data.next, app.collectionList.requestBody).then((response) => {
|
||||
console.log(response)
|
||||
if (!app.collectionList.response.groups) {
|
||||
this.data.data = this.data.data.concat(response.data.data);
|
||||
if (response.data.next) {
|
||||
this.data.next = response.data.next;
|
||||
this.triggerEnabled = true;
|
||||
}
|
||||
this.loading = false
|
||||
} else {
|
||||
if (!response.data.results[app.collectionList.response.groups]) {
|
||||
this.loading = false
|
||||
return
|
||||
}
|
||||
this.data.data = this.data.data.concat(response.data.results[app.collectionList.response.groups].data);
|
||||
if (response.data.results[app.collectionList.response.groups].next) {
|
||||
this.data.next = response.data.results[app.collectionList.response.groups].next;
|
||||
this.triggerEnabled = true;
|
||||
this.loading = false
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
headerVisibility: function(isVisible, entry) {
|
||||
if (isVisible) {
|
||||
this.showFab = false;
|
||||
} else {
|
||||
this.showFab = true;
|
||||
}
|
||||
},
|
||||
visibilityChanged: function(isVisible, entry) {
|
||||
if (isVisible) {
|
||||
this.canSeeTrigger = true;
|
||||
this.getNext();
|
||||
} else {
|
||||
this.canSeeTrigger = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<template v-for="segment in lyrics" v-if="segmentInRange(segment.ts, segment.te, segment.x)">
|
||||
<div class="verse-group active">
|
||||
<template v-for="(verse, verseIndex) in segment.l"
|
||||
v-if="verseInRange(segment.ts, segment.te, verse.o)">
|
||||
v-if="verseInRange(segment.ts, segment.te, verse.o)">
|
||||
<span class="verse verse-active">{{ verse.c }}</span>
|
||||
</template>
|
||||
<template v-else>
|
||||
|
@ -17,4 +17,4 @@
|
|||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
</script>
|
||||
|
|
|
@ -1,192 +1,197 @@
|
|||
<script type="text/x-template" id="libraryartist-item">
|
||||
<div v-observe-visibility="{callback: visibilityChanged}"
|
||||
<div v-observe-visibility="{callback: visibilityChanged}"
|
||||
@click="select"
|
||||
class="cd-mediaitem-list-item"
|
||||
:class="{'mediaitem-selected': app.select_hasMediaItem(guid)}"
|
||||
@contextmenu="contextMenu">
|
||||
<div class="artwork" v-show="isVisible" v-if="showArtwork == true">
|
||||
<mediaitem-artwork
|
||||
:url="getArtwork()"
|
||||
size="50"
|
||||
:type="item.type"></mediaitem-artwork>
|
||||
</div>
|
||||
<div class="info-rect" :style="{'padding-left': (showArtwork ? '' : '16px')}"
|
||||
@dblclick="app.routeView(item)">
|
||||
<div class="title text-overflow-elipsis">
|
||||
{{ item.attributes.name }}
|
||||
</div>
|
||||
<div class="artwork" v-show="isVisible" v-if="showArtwork == true">
|
||||
<mediaitem-artwork
|
||||
:url="getArtwork()"
|
||||
size="50"
|
||||
:type="item.type"></mediaitem-artwork>
|
||||
</div>
|
||||
<div class="info-rect" :style="{'padding-left': (showArtwork ? '' : '16px')}"
|
||||
@dblclick="app.routeView(item)">
|
||||
<div class="title text-overflow-elipsis">
|
||||
{{ item.attributes.name }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script>
|
||||
Vue.component('libraryartist-item', {
|
||||
template: '#libraryartist-item',
|
||||
data: function () {
|
||||
return {
|
||||
isVisible: false,
|
||||
addedToLibrary: false,
|
||||
guid: this.uuidv4(),
|
||||
app: this.$root
|
||||
}
|
||||
},
|
||||
props: {
|
||||
'item': {type: Object, required: true},
|
||||
'parent': {type: String, required: false},
|
||||
'index': {type: Number, required: false, default: -1},
|
||||
'show-artwork': {type: Boolean, default: true},
|
||||
'show-library-status': {type: Boolean, default: true},
|
||||
'show-meta-data': {type: Boolean, default: false},
|
||||
'show-duration': {type: Boolean, default: true},
|
||||
'contextExt': {type: Object, required: false},
|
||||
},
|
||||
methods: {
|
||||
uuidv4() {
|
||||
return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, c =>
|
||||
(c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16)
|
||||
);
|
||||
},
|
||||
msToMinSec(ms) {
|
||||
var minutes = Math.floor(ms / 60000);
|
||||
var seconds = ((ms % 60000) / 1000).toFixed(0);
|
||||
return minutes + ":" + (seconds < 10 ? '0' : '') + seconds;
|
||||
},
|
||||
getDataType() {
|
||||
return this.item.type
|
||||
},
|
||||
async select(e) {
|
||||
let u = this.item
|
||||
let u1 = await app.mk.api.v3.music(`/v1/me/library/artists/${u.id}/albums`, {
|
||||
"platform": "web",
|
||||
"include[library-albums]": "artists,tracks",
|
||||
"include[library-artists]": "catalog",
|
||||
"fields[artists]": "url",
|
||||
"includeOnly": "catalog,artists"
|
||||
})
|
||||
app.showCollection({data : Object.assign({},u1.data.data)}, u.attributes.name?? '', '');
|
||||
app.select_selectMediaItem(u.id, this.getDataType(), this.index, this.guid, true)
|
||||
},
|
||||
getArtwork(){
|
||||
let u = ""
|
||||
try{
|
||||
u = this.item.relationships.catalog.data[0].attributes.artwork.url}
|
||||
catch (e){};
|
||||
return u;
|
||||
},
|
||||
contextMenu(event) {
|
||||
|
||||
let self = this
|
||||
let data_type = this.getDataType()
|
||||
|
||||
let item = self.item
|
||||
item.attributes.artistName = item.attributes.name;
|
||||
|
||||
let useMenu = "normal"
|
||||
if (app.selectedMediaItems.length <= 1) {
|
||||
app.selectedMediaItems = []
|
||||
app.select_selectMediaItem(this.item.id, data_type, this.index, this.guid, true)
|
||||
} else {
|
||||
useMenu = "multiple"
|
||||
}
|
||||
|
||||
let menus = {
|
||||
multiple: {
|
||||
items: [] //
|
||||
},
|
||||
normal: {
|
||||
items: [
|
||||
{
|
||||
"name": app.getLz('action.goToArtist'),
|
||||
"icon": "./assets/feather/user.svg",
|
||||
"action": function () {
|
||||
app.searchAndNavigate(self.item, 'artist')
|
||||
console.log(self.item)
|
||||
}
|
||||
},
|
||||
{
|
||||
"icon": "./assets/feather/radio.svg",
|
||||
"name": app.getLz('action.startRadio'),
|
||||
"action": function () {
|
||||
app.mk.setStationQueue({song: self.item.attributes.playParams.id ?? self.item.id}).then(() => {
|
||||
app.mk.play()
|
||||
app.selectedMediaItems = []
|
||||
})
|
||||
}
|
||||
},
|
||||
{
|
||||
"icon": "./assets/feather/share.svg",
|
||||
"name": app.getLz('action.share'),
|
||||
"action": function () {
|
||||
if (!self.item.attributes.url && self.item.relationships){
|
||||
if (self.item.relationships.catalog){
|
||||
app.mkapi(self.item.attributes.playParams.kind, false, self.item.relationships.catalog.data[0].id).then(u => {self.app.copyToClipboard((u.data.data.length && u.data.data.length > 0)? u.data.data[0].attributes.url : u.data.data.attributes.url)})
|
||||
}
|
||||
} else {
|
||||
self.app.copyToClipboard(self.item.attributes.url)}
|
||||
}
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
if (this.contextExt) {
|
||||
// if this.context-ext.normal is true append all options to the 'normal' menu which is a kvp of arrays
|
||||
if (this.contextExt.normal) {
|
||||
menus.normal.items = menus.normal.items.concat(this.contextExt.normal)
|
||||
}
|
||||
if (this.contextExt.multiple) {
|
||||
menus.multiple.items = menus.multiple.items.concat(this.contextExt.multiple)
|
||||
}
|
||||
}
|
||||
//CiderContextMenu.Create(event, menus[useMenu]); // Depreciated Context Menu
|
||||
app.showMenuPanel(menus[useMenu], event);
|
||||
|
||||
},
|
||||
visibilityChanged: function (isVisible, entry) {
|
||||
this.isVisible = isVisible
|
||||
},
|
||||
addToLibrary() {
|
||||
let item = this.item
|
||||
if (item.attributes.playParams.id) {
|
||||
console.log('adding to library', item.attributes.playParams.id)
|
||||
app.addToLibrary(item.attributes.playParams.id.toString())
|
||||
this.addedToLibrary = true
|
||||
} else if (item.id) {
|
||||
console.log('adding to library', item.id)
|
||||
app.addToLibrary(item.id.toString())
|
||||
this.addedToLibrary = true
|
||||
}
|
||||
},
|
||||
async removeFromLibrary() {
|
||||
let item = this.item
|
||||
let params = {"fields[songs]": "inLibrary", "fields[albums]": "inLibrary", "relate": "library"}
|
||||
let id = item.id ?? item.attributes.playParams.id
|
||||
let res = await app.mkapi(item.attributes.playParams.kind ?? item.type, item.attributes.playParams.isLibrary ?? false, item.attributes.playParams.id ?? item.id, params);
|
||||
if (res && res.relationships && res.relationships.library && res.relationships.library.data && res.relationships.library.data.length > 0) {
|
||||
id = res.relationships.library.data[0].id
|
||||
}
|
||||
let kind = this.item.attributes.playParams.kind ?? this.data.item ?? '';
|
||||
let truekind = (!kind.endsWith("s")) ? (kind + "s") : kind;
|
||||
if (item.attributes.playParams.id) {
|
||||
console.log('remove from library', id)
|
||||
app.removeFromLibrary(truekind, id)
|
||||
this.addedToLibrary = false
|
||||
} else if (item.id) {
|
||||
console.log('remove from library', id)
|
||||
app.removeFromLibrary(truekind, id)
|
||||
this.addedToLibrary = false
|
||||
}
|
||||
},
|
||||
playTrack() {
|
||||
let item = this.item
|
||||
let parent = this.parent
|
||||
let childIndex = this.index
|
||||
console.log(item, parent, childIndex)
|
||||
if (parent != null && childIndex != null) {
|
||||
app.queueParentandplayChild(parent, childIndex, item);
|
||||
} else {
|
||||
app.playMediaItemById(item.attributes.playParams.id ?? item.id, item.attributes.playParams.kind ?? item.type, item.attributes.playParams.isLibrary ?? false, item.attributes.url)
|
||||
}
|
||||
}
|
||||
Vue.component('libraryartist-item', {
|
||||
template: '#libraryartist-item',
|
||||
data: function() {
|
||||
return {
|
||||
isVisible: false,
|
||||
addedToLibrary: false,
|
||||
guid: this.uuidv4(),
|
||||
app: this.$root
|
||||
}
|
||||
},
|
||||
props: {
|
||||
'item': { type: Object, required: true },
|
||||
'parent': { type: String, required: false },
|
||||
'index': { type: Number, required: false, default: -1 },
|
||||
'show-artwork': { type: Boolean, default: true },
|
||||
'show-library-status': { type: Boolean, default: true },
|
||||
'show-meta-data': { type: Boolean, default: false },
|
||||
'show-duration': { type: Boolean, default: true },
|
||||
'contextExt': { type: Object, required: false },
|
||||
},
|
||||
methods: {
|
||||
uuidv4() {
|
||||
return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, c =>
|
||||
(c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16)
|
||||
);
|
||||
},
|
||||
msToMinSec(ms) {
|
||||
var minutes = Math.floor(ms / 60000);
|
||||
var seconds = ((ms % 60000) / 1000).toFixed(0);
|
||||
return minutes + ":" + (seconds < 10 ? '0' : '') + seconds;
|
||||
},
|
||||
getDataType() {
|
||||
return this.item.type
|
||||
},
|
||||
async select(e) {
|
||||
let u = this.item
|
||||
let u1 = await app.mk.api.v3.music(`/v1/me/library/artists/${u.id}/albums`, {
|
||||
"platform": "web",
|
||||
"include[library-albums]": "artists,tracks",
|
||||
"include[library-artists]": "catalog",
|
||||
"fields[artists]": "url",
|
||||
"includeOnly": "catalog,artists"
|
||||
})
|
||||
app.showCollection({ data: Object.assign({}, u1.data.data) }, u.attributes.name ?? '', '');
|
||||
app.select_selectMediaItem(u.id, this.getDataType(), this.index, this.guid, true)
|
||||
},
|
||||
getArtwork() {
|
||||
let u = ""
|
||||
try {
|
||||
u = this.item.relationships.catalog.data[0].attributes.artwork.url
|
||||
} catch (e) {
|
||||
}
|
||||
});
|
||||
</script>
|
||||
;
|
||||
return u;
|
||||
},
|
||||
contextMenu(event) {
|
||||
|
||||
let self = this
|
||||
let data_type = this.getDataType()
|
||||
|
||||
let item = self.item
|
||||
item.attributes.artistName = item.attributes.name;
|
||||
|
||||
let useMenu = "normal"
|
||||
if (app.selectedMediaItems.length <= 1) {
|
||||
app.selectedMediaItems = []
|
||||
app.select_selectMediaItem(this.item.id, data_type, this.index, this.guid, true)
|
||||
} else {
|
||||
useMenu = "multiple"
|
||||
}
|
||||
|
||||
let menus = {
|
||||
multiple: {
|
||||
items: [] //
|
||||
},
|
||||
normal: {
|
||||
items: [
|
||||
{
|
||||
"name": app.getLz('action.goToArtist'),
|
||||
"icon": "./assets/feather/user.svg",
|
||||
"action": function() {
|
||||
app.searchAndNavigate(self.item, 'artist')
|
||||
console.log(self.item)
|
||||
}
|
||||
},
|
||||
{
|
||||
"icon": "./assets/feather/radio.svg",
|
||||
"name": app.getLz('action.startRadio'),
|
||||
"action": function() {
|
||||
app.mk.setStationQueue({ song: self.item.attributes.playParams.id ?? self.item.id }).then(() => {
|
||||
app.mk.play()
|
||||
app.selectedMediaItems = []
|
||||
})
|
||||
}
|
||||
},
|
||||
{
|
||||
"icon": "./assets/feather/share.svg",
|
||||
"name": app.getLz('action.share'),
|
||||
"action": function() {
|
||||
if (!self.item.attributes.url && self.item.relationships) {
|
||||
if (self.item.relationships.catalog) {
|
||||
app.mkapi(self.item.attributes.playParams.kind, false, self.item.relationships.catalog.data[0].id).then(u => {
|
||||
self.app.copyToClipboard((u.data.data.length && u.data.data.length > 0) ? u.data.data[0].attributes.url : u.data.data.attributes.url)
|
||||
})
|
||||
}
|
||||
} else {
|
||||
self.app.copyToClipboard(self.item.attributes.url)
|
||||
}
|
||||
}
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
if (this.contextExt) {
|
||||
// if this.context-ext.normal is true append all options to the 'normal' menu which is a kvp of arrays
|
||||
if (this.contextExt.normal) {
|
||||
menus.normal.items = menus.normal.items.concat(this.contextExt.normal)
|
||||
}
|
||||
if (this.contextExt.multiple) {
|
||||
menus.multiple.items = menus.multiple.items.concat(this.contextExt.multiple)
|
||||
}
|
||||
}
|
||||
//CiderContextMenu.Create(event, menus[useMenu]); // Depreciated Context Menu
|
||||
app.showMenuPanel(menus[useMenu], event);
|
||||
|
||||
},
|
||||
visibilityChanged: function(isVisible, entry) {
|
||||
this.isVisible = isVisible
|
||||
},
|
||||
addToLibrary() {
|
||||
let item = this.item
|
||||
if (item.attributes.playParams.id) {
|
||||
console.log('adding to library', item.attributes.playParams.id)
|
||||
app.addToLibrary(item.attributes.playParams.id.toString())
|
||||
this.addedToLibrary = true
|
||||
} else if (item.id) {
|
||||
console.log('adding to library', item.id)
|
||||
app.addToLibrary(item.id.toString())
|
||||
this.addedToLibrary = true
|
||||
}
|
||||
},
|
||||
async removeFromLibrary() {
|
||||
let item = this.item
|
||||
let params = { "fields[songs]": "inLibrary", "fields[albums]": "inLibrary", "relate": "library" }
|
||||
let id = item.id ?? item.attributes.playParams.id
|
||||
let res = await app.mkapi(item.attributes.playParams.kind ?? item.type, item.attributes.playParams.isLibrary ?? false, item.attributes.playParams.id ?? item.id, params);
|
||||
if (res && res.relationships && res.relationships.library && res.relationships.library.data && res.relationships.library.data.length > 0) {
|
||||
id = res.relationships.library.data[0].id
|
||||
}
|
||||
let kind = this.item.attributes.playParams.kind ?? this.data.item ?? '';
|
||||
let truekind = (!kind.endsWith("s")) ? (kind + "s") : kind;
|
||||
if (item.attributes.playParams.id) {
|
||||
console.log('remove from library', id)
|
||||
app.removeFromLibrary(truekind, id)
|
||||
this.addedToLibrary = false
|
||||
} else if (item.id) {
|
||||
console.log('remove from library', id)
|
||||
app.removeFromLibrary(truekind, id)
|
||||
this.addedToLibrary = false
|
||||
}
|
||||
},
|
||||
playTrack() {
|
||||
let item = this.item
|
||||
let parent = this.parent
|
||||
let childIndex = this.index
|
||||
console.log(item, parent, childIndex)
|
||||
if (parent != null && childIndex != null) {
|
||||
app.queueParentandplayChild(parent, childIndex, item);
|
||||
} else {
|
||||
app.playMediaItemById(item.attributes.playParams.id ?? item.id, item.attributes.playParams.kind ?? item.type, item.attributes.playParams.isLibrary ?? false, item.attributes.url)
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -1,92 +1,106 @@
|
|||
<script type="text/x-template" id="listennow-child">
|
||||
<div v-observe-visibility="{callback: visibilityChanged}">
|
||||
<template v-if="isVisible && recom.attributes.display.kind != 'MusicSuperHeroShelf'">
|
||||
<div class="row">
|
||||
<div class="col" v-if="recom?.relationships['primary-content']?.data?.length > 0" style="display: flex; margin-block:1rem;">
|
||||
<div @click="navigateContent(recom?.relationships['primary-content']?.data[0] ?? recom?.attributes?.title?.contentIds[0] ?? '')" class="listennow-chip" style="height: 40px;width: 40px;align-self: center;margin-right: 10px;" :class="{ 'circle': recom?.relationships['primary-content']?.data[0]?.type == 'artists' }">
|
||||
<mediaitem-artwork v-if="recom?.relationships['primary-content']?.data[0]?.attributes?.artwork != null" :url="recom?.relationships['primary-content']?.data[0]?.attributes?.artwork?.url" :size="100"></mediaitem-artwork>
|
||||
</div>
|
||||
<div @click="navigateContent(recom?.relationships['primary-content']?.data[0] ?? recom?.attributes?.title?.contentIds[0] ?? '')" style="width: fit-content;" :class="{'item-navigate' : (recom?.attributes?.title?.contentIds?.length ?? 0) > 0 | recom?.relationships['primary-content']?.data?.length > 0}">
|
||||
<span style="opacity: 0.5; font-weight: bold;"> {{ recom.attributes.titleWithoutName.stringForDisplay }} </span>
|
||||
<h3 style="margin-block: 0"> {{ recom?.relationships['primary-content']?.data[0].attributes?.name ?? recom.attributes.title.stringForDisplay.replace(recom.attributes.titleWithoutName.stringForDisplay, '') }}</h3>
|
||||
<template v-if="isVisible && recom.attributes.display.kind != 'MusicSuperHeroShelf'">
|
||||
<div class="row">
|
||||
<div class="col" v-if="recom?.relationships['primary-content']?.data?.length > 0"
|
||||
style="display: flex; margin-block:1rem;">
|
||||
<div @click="navigateContent(recom?.relationships['primary-content']?.data[0] ?? recom?.attributes?.title?.contentIds[0] ?? '')"
|
||||
class="listennow-chip" style="height: 40px;width: 40px;align-self: center;margin-right: 10px;"
|
||||
:class="{ 'circle': recom?.relationships['primary-content']?.data[0]?.type == 'artists' }">
|
||||
<mediaitem-artwork
|
||||
v-if="recom?.relationships['primary-content']?.data[0]?.attributes?.artwork != null"
|
||||
:url="recom?.relationships['primary-content']?.data[0]?.attributes?.artwork?.url"
|
||||
:size="100"></mediaitem-artwork>
|
||||
</div>
|
||||
<div @click="navigateContent(recom?.relationships['primary-content']?.data[0] ?? recom?.attributes?.title?.contentIds[0] ?? '')"
|
||||
style="width: fit-content;"
|
||||
:class="{'item-navigate' : (recom?.attributes?.title?.contentIds?.length ?? 0) > 0 | recom?.relationships['primary-content']?.data?.length > 0}">
|
||||
<span style="opacity: 0.5; font-weight: bold;"> {{ recom.attributes.titleWithoutName.stringForDisplay }} </span>
|
||||
<h3 style="margin-block: 0"> {{
|
||||
recom?.relationships['primary-content']?.data[0].attributes?.name ??
|
||||
recom.attributes.title.stringForDisplay.replace(recom.attributes.titleWithoutName.stringForDisplay,
|
||||
'') }}</h3>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="col" v-else style="display: flex; margin-block:1rem;">
|
||||
<h3 @click="navigateContent(recom?.relationships['primary-content']?.data[0] ?? recom?.attributes?.title?.contentIds[0] ?? '')"
|
||||
style="width: fit-content; margin-block:0;"
|
||||
:class="{'item-navigate' : (recom?.attributes?.title?.contentIds?.length ?? 0) > 0 | recom?.relationships['primary-content']?.data?.length > 0}">
|
||||
{{ recom.attributes.title ? recom.attributes.title.stringForDisplay : " "}}</h3>
|
||||
</div>
|
||||
<div class="col-auto cider-flex-center" v-if="recom.relationships.contents.data.length >= 10">
|
||||
<button class="cd-btn-seeall" @click="showCollection(recom)">{{app.getLz('term.seeAll')}}</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col" v-else style="display: flex; margin-block:1rem;">
|
||||
<h3 @click="navigateContent(recom?.relationships['primary-content']?.data[0] ?? recom?.attributes?.title?.contentIds[0] ?? '')" style="width: fit-content; margin-block:0;" :class="{'item-navigate' : (recom?.attributes?.title?.contentIds?.length ?? 0) > 0 | recom?.relationships['primary-content']?.data?.length > 0}">
|
||||
{{ recom.attributes.title ? recom.attributes.title.stringForDisplay : " "}}</h3>
|
||||
</div>
|
||||
<div class="col-auto cider-flex-center" v-if="recom.relationships.contents.data.length >= 10">
|
||||
<button class="cd-btn-seeall" @click="showCollection(recom)" >{{app.getLz('term.seeAll')}}</button>
|
||||
</div>
|
||||
</div>
|
||||
<template v-if="recom.attributes.display.kind == 'MusicCoverShelf' || recom.attributes.display.kind == 'MusicCircleCoverShelf'">
|
||||
<mediaitem-scroller-horizontal-large
|
||||
:items="recom.relationships.contents.data.limit(10)"></mediaitem-scroller-horizontal-large>
|
||||
<template
|
||||
v-if="recom.attributes.display.kind == 'MusicCoverShelf' || recom.attributes.display.kind == 'MusicCircleCoverShelf'">
|
||||
<mediaitem-scroller-horizontal-large
|
||||
:items="recom.relationships.contents.data.limit(10)"></mediaitem-scroller-horizontal-large>
|
||||
</template>
|
||||
<template v-else>
|
||||
<mediaitem-scroller-horizontal-sp
|
||||
:withReason="index==0"
|
||||
:items="recom.relationships.contents.data.limit(10)"></mediaitem-scroller-horizontal-sp>
|
||||
</template>
|
||||
</template>
|
||||
<template v-else>
|
||||
<mediaitem-scroller-horizontal-sp
|
||||
:withReason="index==0"
|
||||
:items="recom.relationships.contents.data.limit(10)"></mediaitem-scroller-horizontal-sp>
|
||||
<template v-else-if="recom.attributes.display.kind != 'MusicSuperHeroShelf'">
|
||||
<div style="height:330px"></div>
|
||||
</template>
|
||||
</template>
|
||||
<template v-else-if="recom.attributes.display.kind != 'MusicSuperHeroShelf'">
|
||||
<div style="height:330px"> </div>
|
||||
</template>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
<script>
|
||||
Vue.component('listennow-child', {
|
||||
template: "#listennow-child",
|
||||
props: ["recom","index"],
|
||||
data: function () {
|
||||
return {
|
||||
isVisible: true,
|
||||
app: this.$root
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
visibilityChanged: function (isVisible, entry) {
|
||||
// this.isVisible = isVisible
|
||||
},
|
||||
showCollection: function (recom) {
|
||||
console.debug(recom)
|
||||
app.showCollection(recom.relationships.contents, recom.attributes.title ? recom.attributes.title.stringForDisplay : '', 'listen_now')
|
||||
},
|
||||
navigateContent: async function (id) {
|
||||
Vue.component('listennow-child', {
|
||||
template: "#listennow-child",
|
||||
props: ["recom", "index"],
|
||||
data: function() {
|
||||
return {
|
||||
isVisible: true,
|
||||
app: this.$root
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
visibilityChanged: function(isVisible, entry) {
|
||||
// this.isVisible = isVisible
|
||||
},
|
||||
showCollection: function(recom) {
|
||||
console.debug(recom)
|
||||
app.showCollection(recom.relationships.contents, recom.attributes.title ? recom.attributes.title.stringForDisplay : '', 'listen_now')
|
||||
},
|
||||
navigateContent: async function(id) {
|
||||
|
||||
if (typeof id != "string") {
|
||||
app.routeView(id)
|
||||
} else {
|
||||
try{
|
||||
let a = await app.mk.api.v3.music(`/v1/catalog/${app.mk.storefrontId}?ids[albums]=${id}`)
|
||||
let q1 = a.data?.data[0]
|
||||
if (q1) {
|
||||
app.routeView(q1)
|
||||
} else {
|
||||
let b = await app.mk.api.v3.music(`/v1/catalog/${app.mk.storefrontId}?ids[artists]=${id}`)
|
||||
let q2 = b.data?.data[0]
|
||||
if (q2) {
|
||||
app.routeView(q2)
|
||||
} else {
|
||||
let c = await app.mk.api.v3.music(`/v1/catalog/${app.mk.storefrontId}?ids[playlists]=${id}`)
|
||||
let q3 = c.data?.data[0]
|
||||
if (q3) {
|
||||
app.routeView(q3)
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
let b = await app.mk.api.v3.music(`/v1/catalog/${app.mk.storefrontId}?ids[artists]=${id}`)
|
||||
let q2 = b.data?.data[0]
|
||||
if (q2) {
|
||||
app.routeView(q2)
|
||||
}
|
||||
}
|
||||
if (typeof id != "string") {
|
||||
app.routeView(id)
|
||||
} else {
|
||||
try {
|
||||
let a = await app.mk.api.v3.music(`/v1/catalog/${app.mk.storefrontId}?ids[albums]=${id}`)
|
||||
let q1 = a.data?.data[0]
|
||||
if (q1) {
|
||||
app.routeView(q1)
|
||||
} else {
|
||||
let b = await app.mk.api.v3.music(`/v1/catalog/${app.mk.storefrontId}?ids[artists]=${id}`)
|
||||
let q2 = b.data?.data[0]
|
||||
if (q2) {
|
||||
app.routeView(q2)
|
||||
} else {
|
||||
let c = await app.mk.api.v3.music(`/v1/catalog/${app.mk.storefrontId}?ids[playlists]=${id}`)
|
||||
let q3 = c.data?.data[0]
|
||||
if (q3) {
|
||||
app.routeView(q3)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
let b = await app.mk.api.v3.music(`/v1/catalog/${app.mk.storefrontId}?ids[artists]=${id}`)
|
||||
let q2 = b.data?.data[0]
|
||||
if (q2) {
|
||||
app.routeView(q2)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
|
|
@ -1,69 +1,74 @@
|
|||
<script type="text/x-template" id="listitem-horizontal">
|
||||
<div class="listitem-horizontal">
|
||||
<vue-horizontal>
|
||||
<div v-for="items in itemPages">
|
||||
<mediaitem-list-item
|
||||
v-for="(song, index) in items" :show-library-status="showLibraryStatus" :parent="'listitem-hr' + simplifiedParent"
|
||||
:index="song.index"
|
||||
:item="song"></mediaitem-list-item>
|
||||
</div>
|
||||
</vue-horizontal>
|
||||
</div>
|
||||
<div class="listitem-horizontal">
|
||||
<vue-horizontal>
|
||||
<div v-for="items in itemPages">
|
||||
<mediaitem-list-item
|
||||
v-for="(song, index) in items" :show-library-status="showLibraryStatus"
|
||||
:parent="'listitem-hr' + simplifiedParent"
|
||||
:index="song.index"
|
||||
:item="song"></mediaitem-list-item>
|
||||
</div>
|
||||
</vue-horizontal>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script>
|
||||
Vue.component('listitem-horizontal', {
|
||||
template: '#listitem-horizontal',
|
||||
name: "listitem-horizontal",
|
||||
props: {
|
||||
items: {
|
||||
type: Array,
|
||||
required: true
|
||||
},
|
||||
showLibraryStatus: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
},
|
||||
data: function () {
|
||||
return {
|
||||
itemPages: [],
|
||||
simplifiedParent : []
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
// give every item an id
|
||||
this.items.forEach(function (item, index) {
|
||||
item.id = index;
|
||||
});
|
||||
// split items into pages
|
||||
this.itemPages = app.arrayToChunk(this.items, 4);
|
||||
try{
|
||||
this.simplifiedParent = JSON.stringify(this.items.map ( function(x){return x.attributes.playParams}));
|
||||
console.debug("simplifiedParent: " + this.simplifiedParent);
|
||||
}
|
||||
catch (e){}
|
||||
|
||||
},
|
||||
watch: {
|
||||
items: function (items) {
|
||||
// give every item an id
|
||||
this.items.forEach(function (item, index) {
|
||||
item.id = index;
|
||||
});
|
||||
// split items into pages
|
||||
this.itemPages = app.arrayToChunk(this.items, 4);
|
||||
try{
|
||||
this.simplifiedParent = JSON.stringify(this.items.map ( function(x){return x.attributes.playParams}));
|
||||
console.log("simplifiedParent: " + this.simplifiedParent);
|
||||
}
|
||||
catch (e){}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
sayHello: function () {
|
||||
alert('Hello world!');
|
||||
}
|
||||
Vue.component('listitem-horizontal', {
|
||||
template: '#listitem-horizontal',
|
||||
name: "listitem-horizontal",
|
||||
props: {
|
||||
items: {
|
||||
type: Array,
|
||||
required: true
|
||||
},
|
||||
showLibraryStatus: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
},
|
||||
data: function() {
|
||||
return {
|
||||
itemPages: [],
|
||||
simplifiedParent: []
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
// give every item an id
|
||||
this.items.forEach(function(item, index) {
|
||||
item.id = index;
|
||||
});
|
||||
// split items into pages
|
||||
this.itemPages = app.arrayToChunk(this.items, 4);
|
||||
try {
|
||||
this.simplifiedParent = JSON.stringify(this.items.map(function(x) {
|
||||
return x.attributes.playParams
|
||||
}));
|
||||
console.debug("simplifiedParent: " + this.simplifiedParent);
|
||||
} catch (e) {
|
||||
}
|
||||
|
||||
},
|
||||
watch: {
|
||||
items: function(items) {
|
||||
// give every item an id
|
||||
this.items.forEach(function(item, index) {
|
||||
item.id = index;
|
||||
});
|
||||
// split items into pages
|
||||
this.itemPages = app.arrayToChunk(this.items, 4);
|
||||
try {
|
||||
this.simplifiedParent = JSON.stringify(this.items.map(function(x) {
|
||||
return x.attributes.playParams
|
||||
}));
|
||||
console.log("simplifiedParent: " + this.simplifiedParent);
|
||||
} catch (e) {
|
||||
}
|
||||
});
|
||||
</script>
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
sayHello: function() {
|
||||
alert('Hello world!');
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -5,16 +5,17 @@
|
|||
<h3 class="lyric-line" @click="seekTo(lyric.startTime)" :class="{unsynced : lyric.startTime == 9999999}"
|
||||
v-bind:line-index="index.toString()">
|
||||
<template v-if="richlyrics && richlyrics != [] && richlyrics.length > 0">
|
||||
<div class="richl" >
|
||||
<template v-for="verse in getVerseLine(index-1)" >
|
||||
<span class="verse" :lyricstart="lyric.startTime" :versestart="verse.o" >{{ verse.c }}</span>
|
||||
<div class="richl">
|
||||
<template v-for="verse in getVerseLine(index-1)">
|
||||
<span class="verse" :lyricstart="lyric.startTime"
|
||||
:versestart="verse.o">{{ verse.c }}</span>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div class="norm" >
|
||||
{{ lyric.line }}
|
||||
</div>
|
||||
<div class="norm">
|
||||
{{ lyric.line }}
|
||||
</div>
|
||||
</template>
|
||||
<div class="lyrics-translation" v-if="lyric.translation && lyric.translation != ''">
|
||||
{{ lyric.translation }}
|
||||
|
@ -35,173 +36,182 @@
|
|||
</template>
|
||||
<template v-else>
|
||||
<div class="no-lyrics">
|
||||
{{app.getLz('term.noLyrics')}}</div>
|
||||
{{app.getLz('term.noLyrics')}}
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</script>
|
||||
<script>
|
||||
Vue.component('lyrics-view', {
|
||||
template: '#lyrics-view',
|
||||
props: ["time", "lyrics", "richlyrics", "translation", "onindex", "yoffset"],
|
||||
data: function () {
|
||||
return {
|
||||
app: this.$root,
|
||||
Vue.component('lyrics-view', {
|
||||
template: '#lyrics-view',
|
||||
props: ["time", "lyrics", "richlyrics", "translation", "onindex", "yoffset"],
|
||||
data: function() {
|
||||
return {
|
||||
app: this.$root,
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
time: function() {
|
||||
if (((app.lyricon && app.drawer.open) || app.appMode == 'fullscreen') && this.$refs.lyricsview) {
|
||||
let currentLine = this.$refs.lyricsview.querySelector(`.lyric-line.active`)
|
||||
if (currentLine && currentLine.getElementsByClassName('lyricWaiting').length > 0) {
|
||||
let duration = currentLine.getAttribute("end") - currentLine.getAttribute("start");
|
||||
let u = (this.time - currentLine.getAttribute("start")) / duration;
|
||||
if (u < 0.25 && !currentLine.classList.contains('mode1')) {
|
||||
try {
|
||||
currentLine.classList.add('mode1');
|
||||
currentLine.classList.remove('mode3');
|
||||
currentLine.classList.remove('mode2');
|
||||
} catch (e) {
|
||||
}
|
||||
currentLine.getElementsByClassName('WaitingDot1')[0].style.animation = `dotOpacity ${0.25 * duration}s cubic-bezier(0.42, 0, 0.58, 1) forwards`;
|
||||
currentLine.getElementsByClassName('WaitingDot2')[0].style.animation = ``;
|
||||
currentLine.getElementsByClassName('WaitingDot3')[0].style.animation = ``;
|
||||
currentLine.getElementsByClassName('WaitingDot2')[0].style.opacity = 0.25;
|
||||
currentLine.getElementsByClassName('WaitingDot3')[0].style.opacity = 0.25;
|
||||
|
||||
} else if (u >= 0.25 && u < 0.5 && !currentLine.classList.contains('mode2')) {
|
||||
try {
|
||||
currentLine.classList.add('mode2');
|
||||
currentLine.classList.remove('mode1');
|
||||
currentLine.classList.remove('mode3');
|
||||
} catch (e) {
|
||||
}
|
||||
currentLine.getElementsByClassName('WaitingDot2')[0].style.animation = `dotOpacity ${0.25 * duration}s cubic-bezier(0.42, 0, 0.58, 1) forwards`;
|
||||
currentLine.getElementsByClassName('WaitingDot1')[0].style.animation = ``;
|
||||
currentLine.getElementsByClassName('WaitingDot3')[0].style.animation = ``;
|
||||
currentLine.getElementsByClassName('WaitingDot1')[0].style.opacity = 1;
|
||||
currentLine.getElementsByClassName('WaitingDot3')[0].style.opacity = 0.25;
|
||||
} else if (u >= 0.5 && u < 0.75 && !currentLine.classList.contains('mode3')) {
|
||||
try {
|
||||
currentLine.classList.add('mode3');
|
||||
currentLine.classList.remove('mode1');
|
||||
currentLine.classList.remove('mode2');
|
||||
} catch (e) {
|
||||
}
|
||||
currentLine.getElementsByClassName('WaitingDot3')[0].style.animation = `dotOpacity ${0.25 * duration}s cubic-bezier(0.42, 0, 0.58, 1) forwards`;
|
||||
currentLine.getElementsByClassName('WaitingDot1')[0].style.animation = ``;
|
||||
currentLine.getElementsByClassName('WaitingDot2')[0].style.animation = ``;
|
||||
currentLine.getElementsByClassName('WaitingDot1')[0].style.opacity = 1;
|
||||
currentLine.getElementsByClassName('WaitingDot2')[0].style.opacity = 1;
|
||||
} else if (u >= 0.75 && currentLine.classList.contains('mode3')) {
|
||||
try {
|
||||
currentLine.classList.remove('mode1');
|
||||
currentLine.classList.remove('mode2');
|
||||
currentLine.classList.remove('mode3');
|
||||
} catch (e) {
|
||||
}
|
||||
currentLine.getElementsByClassName('WaitingDot1')[0].style.animation = ``;
|
||||
currentLine.getElementsByClassName('WaitingDot2')[0].style.animation = ``;
|
||||
currentLine.getElementsByClassName('WaitingDot1')[0].style.opacity = 1;
|
||||
currentLine.getElementsByClassName('WaitingDot2')[0].style.opacity = 1;
|
||||
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
time: function () {
|
||||
if (((app.lyricon && app.drawer.open) || app.appMode == 'fullscreen') && this.$refs.lyricsview) {
|
||||
let currentLine = this.$refs.lyricsview.querySelector(`.lyric-line.active`)
|
||||
if (currentLine && currentLine.getElementsByClassName('lyricWaiting').length > 0) {
|
||||
let duration = currentLine.getAttribute("end") - currentLine.getAttribute("start");
|
||||
let u = (this.time - currentLine.getAttribute("start")) / duration;
|
||||
if (u < 0.25 && !currentLine.classList.contains('mode1')) {
|
||||
try {
|
||||
currentLine.classList.add('mode1');
|
||||
currentLine.classList.remove('mode3');
|
||||
currentLine.classList.remove('mode2');
|
||||
} catch (e) {
|
||||
}
|
||||
currentLine.getElementsByClassName('WaitingDot1')[0].style.animation = `dotOpacity ${0.25 * duration}s cubic-bezier(0.42, 0, 0.58, 1) forwards`;
|
||||
currentLine.getElementsByClassName('WaitingDot2')[0].style.animation = ``;
|
||||
currentLine.getElementsByClassName('WaitingDot3')[0].style.animation = ``;
|
||||
currentLine.getElementsByClassName('WaitingDot2')[0].style.opacity = 0.25;
|
||||
currentLine.getElementsByClassName('WaitingDot3')[0].style.opacity = 0.25;
|
||||
|
||||
} else if (u >= 0.25 && u < 0.5 && !currentLine.classList.contains('mode2')) {
|
||||
try {
|
||||
currentLine.classList.add('mode2');
|
||||
currentLine.classList.remove('mode1');
|
||||
currentLine.classList.remove('mode3');
|
||||
} catch (e) {
|
||||
}
|
||||
currentLine.getElementsByClassName('WaitingDot2')[0].style.animation = `dotOpacity ${0.25 * duration}s cubic-bezier(0.42, 0, 0.58, 1) forwards`;
|
||||
currentLine.getElementsByClassName('WaitingDot1')[0].style.animation = ``;
|
||||
currentLine.getElementsByClassName('WaitingDot3')[0].style.animation = ``;
|
||||
currentLine.getElementsByClassName('WaitingDot1')[0].style.opacity = 1;
|
||||
currentLine.getElementsByClassName('WaitingDot3')[0].style.opacity = 0.25;
|
||||
} else if (u >= 0.5 && u < 0.75 && !currentLine.classList.contains('mode3')) {
|
||||
try {
|
||||
currentLine.classList.add('mode3');
|
||||
currentLine.classList.remove('mode1');
|
||||
currentLine.classList.remove('mode2');
|
||||
} catch (e) {
|
||||
}
|
||||
currentLine.getElementsByClassName('WaitingDot3')[0].style.animation = `dotOpacity ${0.25 * duration}s cubic-bezier(0.42, 0, 0.58, 1) forwards`;
|
||||
currentLine.getElementsByClassName('WaitingDot1')[0].style.animation = ``;
|
||||
currentLine.getElementsByClassName('WaitingDot2')[0].style.animation = ``;
|
||||
currentLine.getElementsByClassName('WaitingDot1')[0].style.opacity = 1;
|
||||
currentLine.getElementsByClassName('WaitingDot2')[0].style.opacity = 1;
|
||||
} else if (u >= 0.75 && currentLine.classList.contains('mode3')) {
|
||||
try {
|
||||
currentLine.classList.remove('mode1');
|
||||
currentLine.classList.remove('mode2');
|
||||
currentLine.classList.remove('mode3');
|
||||
} catch (e) {
|
||||
}
|
||||
currentLine.getElementsByClassName('WaitingDot1')[0].style.animation = ``;
|
||||
currentLine.getElementsByClassName('WaitingDot2')[0].style.animation = ``;
|
||||
currentLine.getElementsByClassName('WaitingDot1')[0].style.opacity = 1;
|
||||
currentLine.getElementsByClassName('WaitingDot2')[0].style.opacity = 1;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
this.getActiveLyric();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
},
|
||||
methods: {
|
||||
seekTo(startTime) {
|
||||
if (startTime != 9999999) this.app.seekTo(startTime, false);
|
||||
},
|
||||
getActiveLyric() {
|
||||
const delayfix = 0.1
|
||||
const prevLine = app.currentLyricsLine;
|
||||
for (var i = 0; i < this.lyrics.length; i++) {
|
||||
if (this.time + delayfix >= this.lyrics[i].startTime && this.time + delayfix <= app.lyrics[i].endTime) {
|
||||
if (app.currentLyricsLine != i) {
|
||||
app.currentLyricsLine = i;
|
||||
if (((app.lyricon && app.drawer.open) || app.appMode == 'fullscreen') && this.$refs.lyricsview.querySelector(`.lyric-line[line-index="${i}"]`)) {
|
||||
if (this.$refs.lyricsview.querySelector(`.lyric-line[line-index="${prevLine}"]`)) {
|
||||
this.$refs.lyricsview.querySelector(`.lyric-line[line-index="${prevLine}"]`).classList.remove("active");
|
||||
}
|
||||
this.getActiveLyric();
|
||||
this.$refs.lyricsview.querySelector(`.lyric-line[line-index="${i}"]`).classList.add("active")
|
||||
if (this.checkIfScrollIsStatic) {
|
||||
let lyricElement = this.$refs.lyricsview.querySelector(`.lyric-line[line-index="${i}"]`)
|
||||
// this.$refs.lyricsview.querySelector(`.lyric-line[line-index="${i}"]`).scrollIntoView({
|
||||
// behavior: "smooth",
|
||||
// block: "nearest", inline: 'start'
|
||||
// })
|
||||
let parent = lyricElement.parentElement
|
||||
let parentRect = parent.getBoundingClientRect()
|
||||
let lyricElementRect = lyricElement.getBoundingClientRect()
|
||||
let parentScrollTop = parent.scrollTop
|
||||
let parentScrollLeft = parent.scrollLeft
|
||||
let parentScrollTopDiff = parentScrollTop - parentRect.top
|
||||
let parentScrollLeftDiff = parentScrollLeft - parentRect.left
|
||||
let lyricElementScrollTop = lyricElementRect.top + parentScrollTopDiff
|
||||
let lyricElementScrollLeft = lyricElementRect.left + parentScrollLeftDiff
|
||||
let scrollTopDiff = lyricElementScrollTop - parentScrollTop
|
||||
let scrollLeftDiff = lyricElementScrollLeft - parentScrollLeft
|
||||
let scrollTop = parent.scrollTop + scrollTopDiff
|
||||
let scrollLeft = parent.scrollLeft + scrollLeftDiff
|
||||
parent.scrollTo({
|
||||
top: scrollTop - (this.yoffset ?? 128),
|
||||
left: scrollLeft,
|
||||
behavior: 'smooth'
|
||||
})
|
||||
|
||||
}
|
||||
}
|
||||
} else if (app.currentLyricsLine == 0 && app.drawer.open) {
|
||||
if (this.$refs.lyricsview.querySelector(`.lyric-line[line-index="0"]`) && !this.$refs.lyricsview.querySelector(`.lyric-line[line-index="0"]`).classList.contains("active"))
|
||||
this.$refs.lyricsview.querySelector(`.lyric-line[line-index="0"]`).classList.add("active");
|
||||
}
|
||||
|
||||
},
|
||||
methods: {
|
||||
seekTo(startTime) {
|
||||
if (startTime != 9999999) this.app.seekTo(startTime, false);
|
||||
},
|
||||
getActiveLyric() {
|
||||
const delayfix = 0.1
|
||||
const prevLine = app.currentLyricsLine;
|
||||
for (var i = 0; i < this.lyrics.length; i++) {
|
||||
if (this.time + delayfix >= this.lyrics[i].startTime && this.time + delayfix <= app.lyrics[i].endTime) {
|
||||
if (app.currentLyricsLine != i) {
|
||||
app.currentLyricsLine = i;
|
||||
if (((app.lyricon && app.drawer.open) || app.appMode == 'fullscreen') && this.$refs.lyricsview.querySelector(`.lyric-line[line-index="${i}"]`)) {
|
||||
if (this.$refs.lyricsview.querySelector(`.lyric-line[line-index="${prevLine}"]`)) {this.$refs.lyricsview.querySelector(`.lyric-line[line-index="${prevLine}"]`).classList.remove("active");}
|
||||
this.$refs.lyricsview.querySelector(`.lyric-line[line-index="${i}"]`).classList.add("active")
|
||||
if (this.checkIfScrollIsStatic) {
|
||||
let lyricElement = this.$refs.lyricsview.querySelector(`.lyric-line[line-index="${i}"]`)
|
||||
// this.$refs.lyricsview.querySelector(`.lyric-line[line-index="${i}"]`).scrollIntoView({
|
||||
// behavior: "smooth",
|
||||
// block: "nearest", inline: 'start'
|
||||
// })
|
||||
let parent = lyricElement.parentElement
|
||||
let parentRect = parent.getBoundingClientRect()
|
||||
let lyricElementRect = lyricElement.getBoundingClientRect()
|
||||
let parentScrollTop = parent.scrollTop
|
||||
let parentScrollLeft = parent.scrollLeft
|
||||
let parentScrollTopDiff = parentScrollTop - parentRect.top
|
||||
let parentScrollLeftDiff = parentScrollLeft - parentRect.left
|
||||
let lyricElementScrollTop = lyricElementRect.top + parentScrollTopDiff
|
||||
let lyricElementScrollLeft = lyricElementRect.left + parentScrollLeftDiff
|
||||
let scrollTopDiff = lyricElementScrollTop - parentScrollTop
|
||||
let scrollLeftDiff = lyricElementScrollLeft - parentScrollLeft
|
||||
let scrollTop = parent.scrollTop + scrollTopDiff
|
||||
let scrollLeft = parent.scrollLeft + scrollLeftDiff
|
||||
parent.scrollTo({
|
||||
top: scrollTop - (this.yoffset ?? 128),
|
||||
left: scrollLeft,
|
||||
behavior: 'smooth'
|
||||
})
|
||||
|
||||
}
|
||||
}
|
||||
} else if (app.currentLyricsLine == 0 && app.drawer.open) {
|
||||
if (this.$refs.lyricsview.querySelector(`.lyric-line[line-index="0"]`) && !this.$refs.lyricsview.querySelector(`.lyric-line[line-index="0"]`).classList.contains("active"))
|
||||
this.$refs.lyricsview.querySelector(`.lyric-line[line-index="0"]`).classList.add("active");
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
try{
|
||||
if ((app.drawer.open) || app.appMode == 'fullscreen'){
|
||||
try{this.$refs.lyricsview.querySelector(`.lyric-line[line-index="${prevLine}"]`).childNodes.classList.remove("verse-active");} catch(e){}
|
||||
for (child of this.$refs.lyricsview.querySelector(`.lyric-line[line-index="${app.currentLyricsLine}"]`).querySelectorAll(".verse")){
|
||||
if (this.time + 0.1 >= child.getAttribute("lyricstart") * 1 + child.getAttribute("versestart") * 1){
|
||||
child.classList.add("verse-active");
|
||||
} else {child.classList.remove("verse-active");}}
|
||||
}
|
||||
} catch(e){}
|
||||
|
||||
},
|
||||
getActiveVerse(timeStart, timeEnd, verseTime) {
|
||||
let relativeTime = this.time - timeStart
|
||||
console.log(this.time,timeEnd,timeStart,relativeTime >= verseTime && relativeTime <= timeEnd - timeStart)
|
||||
return relativeTime >= verseTime && relativeTime <= timeEnd - timeStart
|
||||
},
|
||||
getVerseLine(index) {
|
||||
if (this.richlyrics[index] != null && this.richlyrics[index].l != null) {
|
||||
return this.richlyrics[index].l
|
||||
}
|
||||
else return []
|
||||
},
|
||||
qqInstrumental(lyrics) {
|
||||
for(lyric of lyrics){
|
||||
if (lyric.line.includes("纯音乐") && lyric.line.includes("欣赏")){
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
},
|
||||
checkIfScrollIsStatic : setInterval(() => {
|
||||
break;
|
||||
}
|
||||
}
|
||||
try {
|
||||
if ((app.drawer.open) || app.appMode == 'fullscreen') {
|
||||
try {
|
||||
if (position === this.$refs.lyricsview.scrollTop) {
|
||||
clearInterval(checkIfScrollIsStatic)
|
||||
// do something
|
||||
}
|
||||
position = this.$refs.lyricsview.scrollTop
|
||||
this.$refs.lyricsview.querySelector(`.lyric-line[line-index="${prevLine}"]`).childNodes.classList.remove("verse-active");
|
||||
} catch (e) {
|
||||
}
|
||||
}, 50)
|
||||
,
|
||||
for (child of this.$refs.lyricsview.querySelector(`.lyric-line[line-index="${app.currentLyricsLine}"]`).querySelectorAll(".verse")) {
|
||||
if (this.time + 0.1 >= child.getAttribute("lyricstart") * 1 + child.getAttribute("versestart") * 1) {
|
||||
child.classList.add("verse-active");
|
||||
} else {
|
||||
child.classList.remove("verse-active");
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
},
|
||||
getActiveVerse(timeStart, timeEnd, verseTime) {
|
||||
let relativeTime = this.time - timeStart
|
||||
console.log(this.time, timeEnd, timeStart, relativeTime >= verseTime && relativeTime <= timeEnd - timeStart)
|
||||
return relativeTime >= verseTime && relativeTime <= timeEnd - timeStart
|
||||
},
|
||||
getVerseLine(index) {
|
||||
if (this.richlyrics[index] != null && this.richlyrics[index].l != null) {
|
||||
return this.richlyrics[index].l
|
||||
} else return []
|
||||
},
|
||||
qqInstrumental(lyrics) {
|
||||
for (lyric of lyrics) {
|
||||
if (lyric.line.includes("纯音乐") && lyric.line.includes("欣赏")) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
},
|
||||
checkIfScrollIsStatic: setInterval(() => {
|
||||
try {
|
||||
if (position === this.$refs.lyricsview.scrollTop) {
|
||||
clearInterval(checkIfScrollIsStatic)
|
||||
// do something
|
||||
}
|
||||
position = this.$refs.lyricsview.scrollTop
|
||||
} catch (e) {
|
||||
}
|
||||
}, 50)
|
||||
,
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
<script type="text/x-template" id="mediaitem-artwork">
|
||||
<div class="mediaitem-artwork" :style="awStyle" @contextmenu="contextMenu" :class="[{'rounded': (type == 'artists')}, classes]" :key="url">
|
||||
<div class="mediaitem-artwork" :style="awStyle" @contextmenu="contextMenu"
|
||||
:class="[{'rounded': (type == 'artists')}, classes]" :key="url">
|
||||
<img :src="imgSrc"
|
||||
ref="image"
|
||||
decoding="async"
|
||||
|
@ -14,138 +15,138 @@
|
|||
</script>
|
||||
|
||||
<script>
|
||||
Vue.component('mediaitem-artwork', {
|
||||
template: '#mediaitem-artwork',
|
||||
props: {
|
||||
size: {
|
||||
type: [String, Number],
|
||||
default: '120'
|
||||
},
|
||||
width: {
|
||||
type: [String, Number],
|
||||
required: false
|
||||
},
|
||||
bgcolor: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
url: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
video: {
|
||||
type: String,
|
||||
required: false
|
||||
},
|
||||
videoPriority: {
|
||||
type: Boolean,
|
||||
required: false
|
||||
},
|
||||
shadow: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
upscaling: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
Vue.component('mediaitem-artwork', {
|
||||
template: '#mediaitem-artwork',
|
||||
props: {
|
||||
size: {
|
||||
type: [String, Number],
|
||||
default: '120'
|
||||
},
|
||||
width: {
|
||||
type: [String, Number],
|
||||
required: false
|
||||
},
|
||||
bgcolor: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
url: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
video: {
|
||||
type: String,
|
||||
required: false
|
||||
},
|
||||
videoPriority: {
|
||||
type: Boolean,
|
||||
required: false
|
||||
},
|
||||
shadow: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
upscaling: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data: function() {
|
||||
return {
|
||||
app: this.$root,
|
||||
isVisible: false,
|
||||
style: {
|
||||
"box-shadow": ""
|
||||
},
|
||||
data: function () {
|
||||
return {
|
||||
app: this.$root,
|
||||
isVisible: false,
|
||||
style: {
|
||||
"box-shadow": ""
|
||||
},
|
||||
awStyle: {
|
||||
background: this.bgcolor
|
||||
},
|
||||
imgStyle: {
|
||||
opacity: 0,
|
||||
transition: "opacity .25s linear"
|
||||
},
|
||||
classes: [],
|
||||
imgSrc: ""
|
||||
}
|
||||
awStyle: {
|
||||
background: this.bgcolor
|
||||
},
|
||||
computed: {
|
||||
windowRelativeScale: function () {
|
||||
return app.$store.state.windowRelativeScale;
|
||||
}
|
||||
imgStyle: {
|
||||
opacity: 0,
|
||||
transition: "opacity .25s linear"
|
||||
},
|
||||
watch: {
|
||||
windowRelativeScale: function (newValue, oldValue) {
|
||||
this.swapImage(newValue)
|
||||
},
|
||||
url: function (newValue, oldValue) {
|
||||
this.imgSrc = app.getMediaItemArtwork(this.url, this.size, this.width)
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.getClasses()
|
||||
this.imgSrc = app.getMediaItemArtwork(this.url, this.size, this.width)
|
||||
},
|
||||
methods: {
|
||||
swapImage(newValue) {
|
||||
if(!this.upscaling || window.devicePixelRatio !== 1) return
|
||||
if (newValue > 1.5) {
|
||||
this.imgSrc = app.getMediaItemArtwork(this.url, parseInt(this.size * 2.0), parseInt(this.size * 2.0));
|
||||
}
|
||||
},
|
||||
imgLoaded() {
|
||||
this.imgStyle.opacity = 1
|
||||
this.swapImage(app.$store.state.windowRelativeScale)
|
||||
// this.awStyle.background = ""
|
||||
},
|
||||
contextMenu(event) {
|
||||
let self = this
|
||||
app.showMenuPanel({
|
||||
items: {
|
||||
"save": {
|
||||
name: app.getLz('action.openArtworkInBrowser'),
|
||||
action: () => {
|
||||
window.open(app.getMediaItemArtwork(self.url, 1024, 1024))
|
||||
}
|
||||
}
|
||||
}
|
||||
}, event)
|
||||
},
|
||||
getVideoPriority() {
|
||||
if (app.cfg.visual.animated_artwork == "always") {
|
||||
return true;
|
||||
} else if (this.videoPriority && app.cfg.visual.animated_artwork == "limited") {
|
||||
return true
|
||||
} else if (app.cfg.visual.animated_artwork == "disabled") {
|
||||
return false
|
||||
}
|
||||
return this.videoPriority
|
||||
},
|
||||
getClasses() {
|
||||
switch (this.shadow) {
|
||||
case "none":
|
||||
this.classes.push("no-shadow")
|
||||
break;
|
||||
case "large":
|
||||
this.classes.push("shadow")
|
||||
break;
|
||||
case "subtle":
|
||||
this.classes.push("subtle-shadow")
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return this.classes;
|
||||
},
|
||||
getArtworkStyle() {
|
||||
return {
|
||||
width: this.size + 'px',
|
||||
height: this.size + 'px'
|
||||
};
|
||||
}
|
||||
classes: [],
|
||||
imgSrc: ""
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
windowRelativeScale: function() {
|
||||
return app.$store.state.windowRelativeScale;
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
windowRelativeScale: function(newValue, oldValue) {
|
||||
this.swapImage(newValue)
|
||||
},
|
||||
url: function(newValue, oldValue) {
|
||||
this.imgSrc = app.getMediaItemArtwork(this.url, this.size, this.width)
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.getClasses()
|
||||
this.imgSrc = app.getMediaItemArtwork(this.url, this.size, this.width)
|
||||
},
|
||||
methods: {
|
||||
swapImage(newValue) {
|
||||
if (!this.upscaling || window.devicePixelRatio !== 1) return
|
||||
if (newValue > 1.5) {
|
||||
this.imgSrc = app.getMediaItemArtwork(this.url, parseInt(this.size * 2.0), parseInt(this.size * 2.0));
|
||||
}
|
||||
});
|
||||
</script>
|
||||
},
|
||||
imgLoaded() {
|
||||
this.imgStyle.opacity = 1
|
||||
this.swapImage(app.$store.state.windowRelativeScale)
|
||||
// this.awStyle.background = ""
|
||||
},
|
||||
contextMenu(event) {
|
||||
let self = this
|
||||
app.showMenuPanel({
|
||||
items: {
|
||||
"save": {
|
||||
name: app.getLz('action.openArtworkInBrowser'),
|
||||
action: () => {
|
||||
window.open(app.getMediaItemArtwork(self.url, 1024, 1024))
|
||||
}
|
||||
}
|
||||
}
|
||||
}, event)
|
||||
},
|
||||
getVideoPriority() {
|
||||
if (app.cfg.visual.animated_artwork == "always") {
|
||||
return true;
|
||||
} else if (this.videoPriority && app.cfg.visual.animated_artwork == "limited") {
|
||||
return true
|
||||
} else if (app.cfg.visual.animated_artwork == "disabled") {
|
||||
return false
|
||||
}
|
||||
return this.videoPriority
|
||||
},
|
||||
getClasses() {
|
||||
switch (this.shadow) {
|
||||
case "none":
|
||||
this.classes.push("no-shadow")
|
||||
break;
|
||||
case "large":
|
||||
this.classes.push("shadow")
|
||||
break;
|
||||
case "subtle":
|
||||
this.classes.push("subtle-shadow")
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return this.classes;
|
||||
},
|
||||
getArtworkStyle() {
|
||||
return {
|
||||
width: this.size + 'px',
|
||||
height: this.size + 'px'
|
||||
};
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -24,14 +24,14 @@
|
|||
</script>
|
||||
|
||||
<script>
|
||||
Vue.component('mediaitem-hrect', {
|
||||
template: '#mediaitem-hrect',
|
||||
props: ['item'],
|
||||
data: function () {
|
||||
return {
|
||||
app: this.$root,
|
||||
}
|
||||
},
|
||||
methods: {}
|
||||
});
|
||||
</script>
|
||||
Vue.component('mediaitem-hrect', {
|
||||
template: '#mediaitem-hrect',
|
||||
props: ['item'],
|
||||
data: function() {
|
||||
return {
|
||||
app: this.$root,
|
||||
}
|
||||
},
|
||||
methods: {}
|
||||
});
|
||||
</script>
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -24,7 +24,7 @@
|
|||
<div class="button" style="
|
||||
border-radius: 50%;
|
||||
background: rgba(50,50,50,0.7);"
|
||||
:style="[(!(item.attributes?.playParams ? (item.attributes?.playParams?.kind ?? (item.type ?? '')): (item.type ?? '')).includes('radioStation') && !(item.attributes?.playParams ? (item.attributes?.playParams?.kind ?? (item.type ?? '')): (item.type ?? '')).includes('song')) ?
|
||||
:style="[(!(item.attributes?.playParams ? (item.attributes?.playParams?.kind ?? (item.type ?? '')): (item.type ?? '')).includes('radioStation') && !(item.attributes?.playParams ? (item.attributes?.playParams?.kind ?? (item.type ?? '')): (item.type ?? '')).includes('song')) ?
|
||||
{'margin': '205px',
|
||||
'margin-left': '260px', 'margin-bottom': '140px',
|
||||
width: '30px',
|
||||
|
@ -57,18 +57,18 @@
|
|||
</script>
|
||||
|
||||
<script>
|
||||
Vue.component('mediaitem-mvview-sp', {
|
||||
template: '#mediaitem-mvview-sp',
|
||||
props: ['item', "imagesize", "badge"],
|
||||
data: function () {
|
||||
return {
|
||||
app: this.$root,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
log(item) {
|
||||
console.log(item);
|
||||
},
|
||||
}
|
||||
});
|
||||
</script>
|
||||
Vue.component('mediaitem-mvview-sp', {
|
||||
template: '#mediaitem-mvview-sp',
|
||||
props: ['item', "imagesize", "badge"],
|
||||
data: function() {
|
||||
return {
|
||||
app: this.$root,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
log(item) {
|
||||
console.log(item);
|
||||
},
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -27,7 +27,9 @@
|
|||
<div class="title text-overflow-elipsis" @click='app.routeView(item)'>
|
||||
{{ item.attributes.name ?? '' }}
|
||||
</div>
|
||||
<div class="subtitle text-overflow-elipsis item-navigate" v-if="item.attributes.artistName" :style = "{'z-index': ((item.attributes.editorialNotes == null) && item.attributes.artistName) ? '4' : ''}" @click="if (item.attributes.artistName)app.searchAndNavigate(item,'artist')">
|
||||
<div class="subtitle text-overflow-elipsis item-navigate" v-if="item.attributes.artistName"
|
||||
:style="{'z-index': ((item.attributes.editorialNotes == null) && item.attributes.artistName) ? '4' : ''}"
|
||||
@click="if (item.attributes.artistName)app.searchAndNavigate(item,'artist')">
|
||||
{{ item.attributes.artistName ?? '' }}
|
||||
</div>
|
||||
|
||||
|
@ -51,14 +53,14 @@
|
|||
</script>
|
||||
|
||||
<script>
|
||||
Vue.component('mediaitem-mvview', {
|
||||
template: '#mediaitem-mvview',
|
||||
props: ['item', "imagesize"],
|
||||
data: function () {
|
||||
return {
|
||||
app: this.$root,
|
||||
}
|
||||
},
|
||||
methods: {}
|
||||
});
|
||||
</script>
|
||||
Vue.component('mediaitem-mvview', {
|
||||
template: '#mediaitem-mvview',
|
||||
props: ['item', "imagesize"],
|
||||
data: function() {
|
||||
return {
|
||||
app: this.$root,
|
||||
}
|
||||
},
|
||||
methods: {}
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
<script type="text/x-template" id="mediaitem-scroller-horizontal-large">
|
||||
<vue-horizontal>
|
||||
<mediaitem-square :item="item" :key="item?.id ?? ''"
|
||||
v-for="item in items"></mediaitem-square>
|
||||
v-for="item in items"></mediaitem-square>
|
||||
</vue-horizontal>
|
||||
</script>
|
||||
|
||||
|
||||
<script>
|
||||
Vue.component('mediaitem-scroller-horizontal-large', {
|
||||
template: '#mediaitem-scroller-horizontal-large',
|
||||
props: ['items']
|
||||
});
|
||||
</script>
|
||||
Vue.component('mediaitem-scroller-horizontal-large', {
|
||||
template: '#mediaitem-scroller-horizontal-large',
|
||||
props: ['items']
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -2,15 +2,15 @@
|
|||
<vue-horizontal>
|
||||
<template v-if="browsesp">
|
||||
<mediaitem-mvview-sp
|
||||
:item="
|
||||
:item="
|
||||
((item?.attributes?.kind != null || item?.attributes?.type == 'editorial-elements')
|
||||
? item :
|
||||
? item :
|
||||
((item.relationships && item.relationships.contents ) ? item.relationships.contents.data[0] : item)) ?? (item)"
|
||||
:imagesize="imagesize"
|
||||
:badge="item.attributes ?? [] " v-for="item in items"></mediaitem-mvview-sp>
|
||||
</template>
|
||||
<template v-else>
|
||||
<mediaitem-square :kind="kind" size="600" :key="item?.id ?? ''"
|
||||
<mediaitem-square :kind="kind" size="600" :key="item?.id ?? ''"
|
||||
:item="item ? ((item.attributes?.kind != null || item.type == 'editorial-elements') ? item : ((item.relationships && item.relationships.contents ) ? item.relationships.contents.data[0] : item)) : []"
|
||||
:imagesize="imagesize"
|
||||
v-for="item in items"></mediaitem-square>
|
||||
|
@ -20,34 +20,34 @@
|
|||
|
||||
|
||||
<script>
|
||||
Vue.component('mediaitem-scroller-horizontal-mvview', {
|
||||
template: '#mediaitem-scroller-horizontal-mvview',
|
||||
props: {
|
||||
items: {
|
||||
type: Array,
|
||||
required: true
|
||||
},
|
||||
imagesize: {
|
||||
type: Number,
|
||||
required: false
|
||||
},
|
||||
browsesp: {
|
||||
type: Boolean,
|
||||
required: false
|
||||
},
|
||||
kind: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: ""
|
||||
}
|
||||
},
|
||||
data: function () {
|
||||
return {
|
||||
app: this.$root,
|
||||
}
|
||||
},
|
||||
// mounted(){
|
||||
// console.log('hes',this.items)
|
||||
// }
|
||||
});
|
||||
</script>
|
||||
Vue.component('mediaitem-scroller-horizontal-mvview', {
|
||||
template: '#mediaitem-scroller-horizontal-mvview',
|
||||
props: {
|
||||
items: {
|
||||
type: Array,
|
||||
required: true
|
||||
},
|
||||
imagesize: {
|
||||
type: Number,
|
||||
required: false
|
||||
},
|
||||
browsesp: {
|
||||
type: Boolean,
|
||||
required: false
|
||||
},
|
||||
kind: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: ""
|
||||
}
|
||||
},
|
||||
data: function() {
|
||||
return {
|
||||
app: this.$root,
|
||||
}
|
||||
},
|
||||
// mounted(){
|
||||
// console.log('hes',this.items)
|
||||
// }
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -1,26 +1,26 @@
|
|||
<script type="text/x-template" id="mediaitem-scroller-horizontal-sp">
|
||||
<div class="cd-hmedia-scroller hmedia-scroller-card">
|
||||
<vue-horizontal>
|
||||
<template>
|
||||
<mediaitem-square kind="card" :item="item" size="300" :reasonShown="withReason"
|
||||
v-for="item in items"></mediaitem-square>
|
||||
</template>
|
||||
</vue-horizontal>
|
||||
</div>
|
||||
<div class="cd-hmedia-scroller hmedia-scroller-card">
|
||||
<vue-horizontal>
|
||||
<template>
|
||||
<mediaitem-square kind="card" :item="item" size="300" :reasonShown="withReason"
|
||||
v-for="item in items"></mediaitem-square>
|
||||
</template>
|
||||
</vue-horizontal>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script>
|
||||
Vue.component('mediaitem-scroller-horizontal-sp', {
|
||||
template: '#mediaitem-scroller-horizontal-sp',
|
||||
props: {
|
||||
'items': { type: Array , required: false },
|
||||
'withReason': { type: Boolean, required: false, default: false },
|
||||
},
|
||||
data: function () {
|
||||
return {
|
||||
app: this.$root,
|
||||
}
|
||||
},
|
||||
methods: {}
|
||||
});
|
||||
Vue.component('mediaitem-scroller-horizontal-sp', {
|
||||
template: '#mediaitem-scroller-horizontal-sp',
|
||||
props: {
|
||||
'items': { type: Array, required: false },
|
||||
'withReason': { type: Boolean, required: false, default: false },
|
||||
},
|
||||
data: function() {
|
||||
return {
|
||||
app: this.$root,
|
||||
}
|
||||
},
|
||||
methods: {}
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -6,27 +6,27 @@
|
|||
</script>
|
||||
|
||||
<script>
|
||||
Vue.component('mediaitem-scroller-horizontal', {
|
||||
template: '#mediaitem-scroller-horizontal',
|
||||
props: {
|
||||
'items': {
|
||||
type: Array,
|
||||
required: false
|
||||
},
|
||||
'kind': {
|
||||
type: String,
|
||||
required: false,
|
||||
defualt: ""
|
||||
}
|
||||
},
|
||||
data: function() {
|
||||
return {
|
||||
app: this.$root,
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
// this.$refs.horizontal.refresh()
|
||||
},
|
||||
methods: {}
|
||||
});
|
||||
</script>
|
||||
Vue.component('mediaitem-scroller-horizontal', {
|
||||
template: '#mediaitem-scroller-horizontal',
|
||||
props: {
|
||||
'items': {
|
||||
type: Array,
|
||||
required: false
|
||||
},
|
||||
'kind': {
|
||||
type: String,
|
||||
required: false,
|
||||
defualt: ""
|
||||
}
|
||||
},
|
||||
data: function() {
|
||||
return {
|
||||
app: this.$root,
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
// this.$refs.horizontal.refresh()
|
||||
},
|
||||
methods: {}
|
||||
});
|
||||
</script>
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -36,105 +36,105 @@
|
|||
|
||||
|
||||
<script>
|
||||
Vue.component('cider-menu-panel', {
|
||||
template: '#cider-menu-panel',
|
||||
data: function () {
|
||||
return {
|
||||
app: this.$root,
|
||||
menuPanel: this.$root.menuPanel,
|
||||
content: this.$root.menuPanel.content,
|
||||
getSvgIcon: this.$root.getSvgIcon,
|
||||
position: [0, 0],
|
||||
size: [0, 0],
|
||||
event: this.$root.menuPanel.event,
|
||||
direction: "down",
|
||||
elStyle: {
|
||||
opacity: 0
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
if (this.event) {
|
||||
this.position = [this.event.clientX, this.event.clientY];
|
||||
}
|
||||
this.$nextTick(() => {
|
||||
// this.size = [document.querySelector(".menu-panel-body").offsetWidth, document.querySelector(".menu-panel-body").offsetHeight];
|
||||
// ugly hack
|
||||
setTimeout(this.getStyle, 1)
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
getBodyClasses() {
|
||||
if (this.direction == "down") {
|
||||
return ["menu-panel-body-down"]
|
||||
} else if (this.direction == "up") {
|
||||
return ["menu-panel-body-up"]
|
||||
} else {
|
||||
return ["foo"]
|
||||
}
|
||||
},
|
||||
getClasses(item) {
|
||||
if (item["active"]) {
|
||||
return "active";
|
||||
}
|
||||
},
|
||||
getStyle() {
|
||||
let style = {}
|
||||
this.size = [this.$refs.menubody.offsetWidth, this.$refs.menubody.offsetHeight];
|
||||
if (this.event) {
|
||||
style["position"] = "absolute";
|
||||
style["left"] = this.event.clientX + "px";
|
||||
style["top"] = this.event.clientY + "px";
|
||||
// make sure the menu panel isnt off the screen
|
||||
if (this.event.clientX + this.size[0] > window.innerWidth) {
|
||||
style["left"] = (this.event.clientX - this.size[0]) + "px";
|
||||
}
|
||||
if (this.event.clientY + this.size[1] > window.innerHeight) {
|
||||
style["top"] = (this.event.clientY - this.size[1]) + "px";
|
||||
}
|
||||
|
||||
|
||||
// if the panel is above the mouse, set the direction to up
|
||||
if (this.event.clientY < this.size[1]) {
|
||||
this.direction = "up";
|
||||
} else {
|
||||
this.direction = "down";
|
||||
}
|
||||
// check if the panel is too long and goes off the screen vertically,
|
||||
// if so move it upwards
|
||||
if (this.event.clientY + this.size[1] > window.innerHeight) {
|
||||
style["top"] = (this.event.clientY - this.size[1]) + "px";
|
||||
}
|
||||
}
|
||||
style["opacity"] = 1
|
||||
this.elStyle = style;
|
||||
},
|
||||
getItemStyle(item) {
|
||||
let style = {}
|
||||
if (item["disabled"]) {
|
||||
style = Object.assign(style, {
|
||||
"pointer-events": "none",
|
||||
"opacity": "0.5",
|
||||
});
|
||||
}
|
||||
return style
|
||||
},
|
||||
canDisplay(item) {
|
||||
if (!item["hidden"]) {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
},
|
||||
async getActions() {
|
||||
return this.content.items;
|
||||
},
|
||||
action(item) {
|
||||
item.action()
|
||||
if (!item["keepOpen"]) {
|
||||
this.menuPanel.visible = false
|
||||
}
|
||||
}
|
||||
Vue.component('cider-menu-panel', {
|
||||
template: '#cider-menu-panel',
|
||||
data: function() {
|
||||
return {
|
||||
app: this.$root,
|
||||
menuPanel: this.$root.menuPanel,
|
||||
content: this.$root.menuPanel.content,
|
||||
getSvgIcon: this.$root.getSvgIcon,
|
||||
position: [0, 0],
|
||||
size: [0, 0],
|
||||
event: this.$root.menuPanel.event,
|
||||
direction: "down",
|
||||
elStyle: {
|
||||
opacity: 0
|
||||
}
|
||||
});
|
||||
</script>
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
if (this.event) {
|
||||
this.position = [this.event.clientX, this.event.clientY];
|
||||
}
|
||||
this.$nextTick(() => {
|
||||
// this.size = [document.querySelector(".menu-panel-body").offsetWidth, document.querySelector(".menu-panel-body").offsetHeight];
|
||||
// ugly hack
|
||||
setTimeout(this.getStyle, 1)
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
getBodyClasses() {
|
||||
if (this.direction == "down") {
|
||||
return ["menu-panel-body-down"]
|
||||
} else if (this.direction == "up") {
|
||||
return ["menu-panel-body-up"]
|
||||
} else {
|
||||
return ["foo"]
|
||||
}
|
||||
},
|
||||
getClasses(item) {
|
||||
if (item["active"]) {
|
||||
return "active";
|
||||
}
|
||||
},
|
||||
getStyle() {
|
||||
let style = {}
|
||||
this.size = [this.$refs.menubody.offsetWidth, this.$refs.menubody.offsetHeight];
|
||||
if (this.event) {
|
||||
style["position"] = "absolute";
|
||||
style["left"] = this.event.clientX + "px";
|
||||
style["top"] = this.event.clientY + "px";
|
||||
// make sure the menu panel isnt off the screen
|
||||
if (this.event.clientX + this.size[0] > window.innerWidth) {
|
||||
style["left"] = (this.event.clientX - this.size[0]) + "px";
|
||||
}
|
||||
if (this.event.clientY + this.size[1] > window.innerHeight) {
|
||||
style["top"] = (this.event.clientY - this.size[1]) + "px";
|
||||
}
|
||||
|
||||
|
||||
// if the panel is above the mouse, set the direction to up
|
||||
if (this.event.clientY < this.size[1]) {
|
||||
this.direction = "up";
|
||||
} else {
|
||||
this.direction = "down";
|
||||
}
|
||||
// check if the panel is too long and goes off the screen vertically,
|
||||
// if so move it upwards
|
||||
if (this.event.clientY + this.size[1] > window.innerHeight) {
|
||||
style["top"] = (this.event.clientY - this.size[1]) + "px";
|
||||
}
|
||||
}
|
||||
style["opacity"] = 1
|
||||
this.elStyle = style;
|
||||
},
|
||||
getItemStyle(item) {
|
||||
let style = {}
|
||||
if (item["disabled"]) {
|
||||
style = Object.assign(style, {
|
||||
"pointer-events": "none",
|
||||
"opacity": "0.5",
|
||||
});
|
||||
}
|
||||
return style
|
||||
},
|
||||
canDisplay(item) {
|
||||
if (!item["hidden"]) {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
},
|
||||
async getActions() {
|
||||
return this.content.items;
|
||||
},
|
||||
action(item) {
|
||||
item.action()
|
||||
if (!item["keepOpen"]) {
|
||||
this.menuPanel.visible = false
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -2,186 +2,206 @@
|
|||
<div class="mini-view" tabindex="0">
|
||||
<div class="background">
|
||||
</div>
|
||||
<div class="player-pin" title="Pin to Top" v-if="app.cfg.visual.miniplayer_top_toggle === false" @click="app.pinMiniPlayer()">
|
||||
<div class="player-pin" title="Pin to Top" v-if="app.cfg.visual.miniplayer_top_toggle === false"
|
||||
@click="app.pinMiniPlayer()">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 28 28" fill="none" class="feather feather-pin">
|
||||
<path d="M7.05664 16.3613C7.05664 17.1523 7.59277 17.6797 8.42773 17.6797H13.1299V21.8369C13.1299 23.0762 13.7539 24.3242 14 24.3242C14.2373 24.3242 14.8613 23.0762 14.8613 21.8369V17.6797H19.5635C20.3984 17.6797 20.9346 17.1523 20.9346 16.3613C20.9346 14.4717 19.4316 12.5293 16.9531 11.6152L16.6631 7.52832C17.9727 6.78125 19.0098 5.96387 19.4668 5.38379C19.7041 5.06738 19.8271 4.75098 19.8271 4.46973C19.8271 3.88965 19.3789 3.45898 18.7197 3.45898H9.27148C8.6123 3.45898 8.16406 3.88965 8.16406 4.46973C8.16406 4.75098 8.28711 5.06738 8.52441 5.38379C8.98145 5.96387 10.0186 6.78125 11.3281 7.52832L11.0469 11.6152C8.55957 12.5293 7.05664 14.4717 7.05664 16.3613Z" fill="#ff2654"/>
|
||||
<path d="M7.05664 16.3613C7.05664 17.1523 7.59277 17.6797 8.42773 17.6797H13.1299V21.8369C13.1299 23.0762 13.7539 24.3242 14 24.3242C14.2373 24.3242 14.8613 23.0762 14.8613 21.8369V17.6797H19.5635C20.3984 17.6797 20.9346 17.1523 20.9346 16.3613C20.9346 14.4717 19.4316 12.5293 16.9531 11.6152L16.6631 7.52832C17.9727 6.78125 19.0098 5.96387 19.4668 5.38379C19.7041 5.06738 19.8271 4.75098 19.8271 4.46973C19.8271 3.88965 19.3789 3.45898 18.7197 3.45898H9.27148C8.6123 3.45898 8.16406 3.88965 8.16406 4.46973C8.16406 4.75098 8.28711 5.06738 8.52441 5.38379C8.98145 5.96387 10.0186 6.78125 11.3281 7.52832L11.0469 11.6152C8.55957 12.5293 7.05664 14.4717 7.05664 16.3613Z"
|
||||
fill="#ff2654" />
|
||||
</svg>
|
||||
</div>
|
||||
<div class="player-pin" title="Unpin to Top" v-if="app.cfg.visual.miniplayer_top_toggle === true" @click="app.pinMiniPlayer(false)">
|
||||
<div class="player-pin" title="Unpin to Top" v-if="app.cfg.visual.miniplayer_top_toggle === true"
|
||||
@click="app.pinMiniPlayer(false)">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 28 28" fill="none" class="feather feather-pin-slashed">
|
||||
<path d="M9.271 3.459c-.659 0-1.107.43-1.107 1.01 0 .282.114.59.352.897.448.59 1.494 1.415 2.777 2.162l-.07 1.02 8.99 8.991c.458-.202.722-.615.722-1.178 0-1.89-1.503-3.832-3.947-4.746l-.29-4.087c1.275-.747 2.312-1.555 2.76-2.144.246-.308.37-.633.37-.914 0-.58-.45-1.011-1.108-1.011H9.27ZM5.15 6.061l16.076 16.057c.272.281.73.273.993 0a.703.703 0 0 0 0-.984L6.15 5.076a.716.716 0 0 0-1.002 0 .711.711 0 0 0 0 .985Zm1.908 10.3c0 .791.536 1.319 1.37 1.319h4.703v4.157c0 1.24.624 2.487.861 2.487.246 0 .87-1.248.87-2.487V17.81h.413l-5.537-5.545c-1.678 1.002-2.68 2.557-2.68 4.095Z" fill="#ff2654"/>
|
||||
<path d="M9.271 3.459c-.659 0-1.107.43-1.107 1.01 0 .282.114.59.352.897.448.59 1.494 1.415 2.777 2.162l-.07 1.02 8.99 8.991c.458-.202.722-.615.722-1.178 0-1.89-1.503-3.832-3.947-4.746l-.29-4.087c1.275-.747 2.312-1.555 2.76-2.144.246-.308.37-.633.37-.914 0-.58-.45-1.011-1.108-1.011H9.27ZM5.15 6.061l16.076 16.057c.272.281.73.273.993 0a.703.703 0 0 0 0-.984L6.15 5.076a.716.716 0 0 0-1.002 0 .711.711 0 0 0 0 .985Zm1.908 10.3c0 .791.536 1.319 1.37 1.319h4.703v4.157c0 1.24.624 2.487.861 2.487.246 0 .87-1.248.87-2.487V17.81h.413l-5.537-5.545c-1.678 1.002-2.68 2.557-2.68 4.095Z"
|
||||
fill="#ff2654" />
|
||||
</svg>
|
||||
</div>
|
||||
<div class="player-exit" title="Close" @click="app.miniPlayer(false)">
|
||||
<svg fill="#323232e3" width="21" height="21" viewBox="0 0 21 21" aria-role="presentation" focusable="false" xmlns="http://www.w3.org/2000/svg">
|
||||
<svg fill="#323232e3" width="21" height="21" viewBox="0 0 21 21" aria-role="presentation" focusable="false"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<defs>
|
||||
<radialGradient gradientUnits="userSpaceOnUse" cx="10.5" cy="10.5" r="10.5" id="gradient-0">
|
||||
<stop offset="0" style="stop-color: rgba(168, 163, 163, 1)"/>
|
||||
<stop offset="1" style="stop-color: rgba(118, 111, 111, 1)"/>
|
||||
<stop offset="0" style="stop-color: rgba(168, 163, 163, 1)" />
|
||||
<stop offset="1" style="stop-color: rgba(118, 111, 111, 1)" />
|
||||
</radialGradient>
|
||||
</defs>
|
||||
<path d="M10.5 21C4.724 21 0 16.275 0 10.5S4.724 0 10.5 0 21 4.725 21 10.5 16.276 21 10.5 21zm-3.543-5.967a.96.96 0 00.693-.295l2.837-2.842 2.85 2.842c.167.167.41.295.693.295.552 0 1.001-.461 1.001-1.012 0-.281-.115-.512-.295-.704L11.899 10.5l2.85-2.855a.875.875 0 00.295-.68c0-.55-.45-.998-1.001-.998a.871.871 0 00-.668.295l-2.888 2.855-2.862-2.843a.891.891 0 00-.668-.281.99.99 0 00-1.001.986c0 .269.116.512.295.678L9.088 10.5l-2.837 2.843a.926.926 0 00-.295.678c0 .551.45 1.012 1.001 1.012z"
|
||||
fill-rule="nonzero" style="stroke-miterlimit: 11; vector-effect: non-scaling-stroke; stroke-width: 31px; fill: url(#gradient-0);"/>
|
||||
fill-rule="nonzero"
|
||||
style="stroke-miterlimit: 11; vector-effect: non-scaling-stroke; stroke-width: 31px; fill: url(#gradient-0);" />
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col artwork-col">
|
||||
<div class="artwork" @click="app.miniPlayer(false)">
|
||||
<div class="artwork" @click="app.miniPlayer(false)">
|
||||
<mediaitem-artwork
|
||||
:size="600"
|
||||
:url="image ?? ''"
|
||||
></mediaitem-artwork>
|
||||
</div>
|
||||
<div class="controls-parents">
|
||||
<template v-if="app.mkReady()">
|
||||
<div class="app-playback-controls" @mouseover="app.chrome.progresshover = true"
|
||||
@mouseleave="app.chrome.progresshover = false" @contextmenu="app.nowPlayingContextMenu">
|
||||
<div class="playback-info">
|
||||
<div class="song-name">
|
||||
{{ app.mk.nowPlayingItem["attributes"]["name"] }}
|
||||
</div>
|
||||
<div
|
||||
style="display: inline-block; -webkit-box-orient: horizontal; white-space: nowrap; margin-top: 0.25vh; overflow: hidden; margin-bottom: 5px;">
|
||||
<div class="item-navigate song-artist" style="display: inline-block;"
|
||||
@click="app.getNowPlayingItemDetailed(`artist`)">
|
||||
{{ app.mk.nowPlayingItem["attributes"]["artistName"] }}
|
||||
<template v-if="app.mkReady()">
|
||||
<div class="app-playback-controls" @mouseover="app.chrome.progresshover = true"
|
||||
@mouseleave="app.chrome.progresshover = false" @contextmenu="app.nowPlayingContextMenu">
|
||||
<div class="playback-info">
|
||||
<div class="song-name">
|
||||
{{ app.mk.nowPlayingItem["attributes"]["name"] }}
|
||||
</div>
|
||||
<div class="song-artist item-navigate" style="display: inline-block;"
|
||||
@click="app.getNowPlayingItemDetailed('album')">
|
||||
{{ (app.mk.nowPlayingItem["attributes"]["albumName"]) ? (" — " +
|
||||
app.mk.nowPlayingItem["attributes"]["albumName"]) : "" }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="song-progress">
|
||||
<div class="song-duration" style="justify-content: space-between; height: 1px; margin-bottom: 1px;"
|
||||
:style="[app.chrome.progresshover ? {'display': 'flex'} : {'display' : 'none'} ]">
|
||||
<p style="width: auto">{{ app.convertTime(app.getSongProgress()) }}</p>
|
||||
<p style="width: auto">{{ app.convertTime(app.mk.currentPlaybackDuration) }}</p>
|
||||
<div
|
||||
style="display: inline-block; -webkit-box-orient: horizontal; white-space: nowrap; margin-top: 0.25vh; overflow: hidden; margin-bottom: 5px;">
|
||||
<div class="item-navigate song-artist" style="display: inline-block;"
|
||||
@click="app.getNowPlayingItemDetailed(`artist`)">
|
||||
{{ app.mk.nowPlayingItem["attributes"]["artistName"] }}
|
||||
</div>
|
||||
<div class="song-artist item-navigate" style="display: inline-block;"
|
||||
@click="app.getNowPlayingItemDetailed('album')">
|
||||
{{ (app.mk.nowPlayingItem["attributes"]["albumName"]) ? (" — " +
|
||||
app.mk.nowPlayingItem["attributes"]["albumName"]) : "" }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<input type="range" step="0.01" min="0" :style="app.progressBarStyle()"
|
||||
@input="app.playerLCD.desiredDuration = $event.target.value;app.playerLCD.userInteraction = true"
|
||||
@mouseup="app.mk.seekToTime($event.target.value);app.playerLCD.desiredDuration = 0;app.playerLCD.userInteraction = false"
|
||||
:max="app.mk.currentPlaybackDuration" :value="app.getSongProgress()">
|
||||
<div class="song-progress">
|
||||
<div class="song-duration"
|
||||
style="justify-content: space-between; height: 1px; margin-bottom: 1px;"
|
||||
:style="[app.chrome.progresshover ? {'display': 'flex'} : {'display' : 'none'} ]">
|
||||
<p style="width: auto">{{ app.convertTime(app.getSongProgress()) }}</p>
|
||||
<p style="width: auto">{{ app.convertTime(app.mk.currentPlaybackDuration) }}</p>
|
||||
</div>
|
||||
|
||||
<input type="range" step="0.01" min="0" :style="app.progressBarStyle()"
|
||||
@input="app.playerLCD.desiredDuration = $event.target.value;app.playerLCD.userInteraction = true"
|
||||
@mouseup="app.mk.seekToTime($event.target.value);app.playerLCD.desiredDuration = 0;app.playerLCD.userInteraction = false"
|
||||
:max="app.mk.currentPlaybackDuration" :value="app.getSongProgress()">
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-buttons">
|
||||
<div class="app-chrome-item display--large">
|
||||
<button class="playback-button--small shuffle" v-if="$root.mk.shuffleMode == 0"
|
||||
:class="$root.isDisabled() && 'disabled'"
|
||||
@click="$root.mk.shuffleMode = 1" :title="$root.getLz('term.enableShuffle')"
|
||||
v-b-tooltip.hover></button>
|
||||
<button class="playback-button--small shuffle active" v-else
|
||||
:class="$root.isDisabled() && 'disabled'"
|
||||
@click="$root.mk.shuffleMode = 0" :title="$root.getLz('term.disableShuffle')"
|
||||
v-b-tooltip.hover></button>
|
||||
</div>
|
||||
<div class="app-chrome-item display--large">
|
||||
<button class="playback-button previous" @click="$root.prevButton()"
|
||||
:class="$root.isPrevDisabled() && 'disabled'"
|
||||
:title="$root.getLz('term.previous')" v-b-tooltip.hover></button>
|
||||
</div>
|
||||
<div class="app-chrome-item display--large">
|
||||
<button class="playback-button stop" @click="$root.mk.stop()"
|
||||
v-if="$root.mk.isPlaying && $root.mk.nowPlayingItem.attributes.playParams.kind == 'radioStation'"
|
||||
:title="$root.getLz('term.stop')" v-b-tooltip.hover></button>
|
||||
<button class="playback-button pause" @click="$root.mk.pause()"
|
||||
v-else-if="$root.mk.isPlaying"
|
||||
:title="$root.getLz('term.pause')" v-b-tooltip.hover></button>
|
||||
<button class="playback-button play" @click="$root.mk.play()" v-else
|
||||
:title="$root.getLz('term.play')"
|
||||
v-b-tooltip.hover></button>
|
||||
</div>
|
||||
<div class="app-chrome-item display--large">
|
||||
<button class="playback-button next" @click="$root.skipToNextItem()"
|
||||
:class="$root.isNextDisabled() && 'disabled'"
|
||||
:title="$root.getLz('term.next')" v-b-tooltip.hover></button>
|
||||
</div>
|
||||
<div class="app-chrome-item display--large">
|
||||
<button class="playback-button--small repeat" v-if="$root.mk.repeatMode == 0"
|
||||
:class="$root.isDisabled() && 'disabled'"
|
||||
@click="$root.mk.repeatMode = 1" :title="$root.getLz('term.enableRepeatOne')"
|
||||
v-b-tooltip.hover></button>
|
||||
<button class="playback-button--small repeat repeatOne" @click="mk.repeatMode = 2"
|
||||
:class="$root.isDisabled() && 'disabled'" v-else-if="$root.mk.repeatMode == 1"
|
||||
:title="$root.getLz('term.disableRepeatOne')" v-b-tooltip.hover></button>
|
||||
<button class="playback-button--small repeat active" @click="$root.mk.repeatMode = 0"
|
||||
:class="$root.isDisabled() && 'disabled'" v-else-if="$root.mk.repeatMode == 2"
|
||||
:title="$root.getLz('term.disableRepeat')"
|
||||
v-b-tooltip.hover></button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="app-chrome-item volume display--large">
|
||||
<div class="input-container">
|
||||
<button class="volume-button--small volume" @click="app.muteButtonPressed()"
|
||||
:class="{'active': app.cfg.audio.volume == 0}"></button>
|
||||
<input type="range" class="slider" @wheel="app.volumeWheel"
|
||||
:step="app.cfg.audio.volumeStep" min="0" :max="app.cfg.audio.maxVolume"
|
||||
v-model="app.mk.volume"
|
||||
v-if="typeof app.mk.volume != 'undefined'" @change="app.checkMuteChange()">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-buttons">
|
||||
<div class="app-chrome-item display--large">
|
||||
<button class="playback-button--small shuffle" v-if="$root.mk.shuffleMode == 0" :class="$root.isDisabled() && 'disabled'"
|
||||
@click="$root.mk.shuffleMode = 1" :title="$root.getLz('term.enableShuffle')" v-b-tooltip.hover></button>
|
||||
<button class="playback-button--small shuffle active" v-else :class="$root.isDisabled() && 'disabled'"
|
||||
@click="$root.mk.shuffleMode = 0" :title="$root.getLz('term.disableShuffle')" v-b-tooltip.hover></button>
|
||||
</div>
|
||||
<div class="app-chrome-item display--large">
|
||||
<button class="playback-button previous" @click="$root.prevButton()" :class="$root.isPrevDisabled() && 'disabled'"
|
||||
:title="$root.getLz('term.previous')" v-b-tooltip.hover></button>
|
||||
</div>
|
||||
<div class="app-chrome-item display--large">
|
||||
<button class="playback-button stop" @click="$root.mk.stop()"
|
||||
v-if="$root.mk.isPlaying && $root.mk.nowPlayingItem.attributes.playParams.kind == 'radioStation'"
|
||||
:title="$root.getLz('term.stop')" v-b-tooltip.hover></button>
|
||||
<button class="playback-button pause" @click="$root.mk.pause()" v-else-if="$root.mk.isPlaying"
|
||||
:title="$root.getLz('term.pause')" v-b-tooltip.hover></button>
|
||||
<button class="playback-button play" @click="$root.mk.play()" v-else :title="$root.getLz('term.play')"
|
||||
v-b-tooltip.hover></button>
|
||||
</div>
|
||||
<div class="app-chrome-item display--large">
|
||||
<button class="playback-button next" @click="$root.skipToNextItem()" :class="$root.isNextDisabled() && 'disabled'"
|
||||
:title="$root.getLz('term.next')" v-b-tooltip.hover></button>
|
||||
</div>
|
||||
<div class="app-chrome-item display--large">
|
||||
<button class="playback-button--small repeat" v-if="$root.mk.repeatMode == 0" :class="$root.isDisabled() && 'disabled'"
|
||||
@click="$root.mk.repeatMode = 1" :title="$root.getLz('term.enableRepeatOne')" v-b-tooltip.hover></button>
|
||||
<button class="playback-button--small repeat repeatOne" @click="mk.repeatMode = 2"
|
||||
:class="$root.isDisabled() && 'disabled'" v-else-if="$root.mk.repeatMode == 1"
|
||||
:title="$root.getLz('term.disableRepeatOne')" v-b-tooltip.hover></button>
|
||||
<button class="playback-button--small repeat active" @click="$root.mk.repeatMode = 0"
|
||||
:class="$root.isDisabled() && 'disabled'" v-else-if="$root.mk.repeatMode == 2" :title="$root.getLz('term.disableRepeat')"
|
||||
v-b-tooltip.hover></button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="app-chrome-item volume display--large">
|
||||
<div class="input-container">
|
||||
<button class="volume-button--small volume" @click="app.muteButtonPressed()" :class="{'active': app.cfg.audio.volume == 0}"></button>
|
||||
<input type="range" class="slider" @wheel="app.volumeWheel" :step="app.cfg.audio.volumeStep" min="0" :max="app.cfg.audio.maxVolume" v-model="app.mk.volume"
|
||||
v-if="typeof app.mk.volume != 'undefined'" @change="app.checkMuteChange()">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
<!-- <div class="row fs-row">
|
||||
|
||||
<div class="col right-col" v-if="tabMode != ''">
|
||||
<div class="fs-info">
|
||||
<div>Name</div>
|
||||
<div>Name</div>
|
||||
<div>Name</div>
|
||||
</div>
|
||||
<div class="lyrics-col" v-if="tabMode == 'lyrics'">
|
||||
<lyrics-view :yoffset="120" :time="time" :lyrics="lyrics"
|
||||
:richlyrics="richlyrics"></lyrics-view>
|
||||
</div>
|
||||
<div class="queue-col" v-if="tabMode == 'queue'">
|
||||
<cider-queue v-if="tabMode == 'queue'" ref="queue" ></cider-queue>
|
||||
</div>
|
||||
</div>
|
||||
<!-- <div class="row fs-row">
|
||||
|
||||
<div class="col right-col" v-if="tabMode != ''">
|
||||
<div class="fs-info">
|
||||
<div>Name</div>
|
||||
<div>Name</div>
|
||||
<div>Name</div>
|
||||
</div>
|
||||
<div class="lyrics-col" v-if="tabMode == 'lyrics'">
|
||||
<lyrics-view :yoffset="120" :time="time" :lyrics="lyrics"
|
||||
:richlyrics="richlyrics"></lyrics-view>
|
||||
</div>
|
||||
<div class="queue-col" v-if="tabMode == 'queue'">
|
||||
<cider-queue v-if="tabMode == 'queue'" ref="queue" ></cider-queue>
|
||||
</div>
|
||||
</div>
|
||||
</div> -->
|
||||
<!-- <div class="tab-toggles">
|
||||
<div class="lyrics" :class="{active: tabMode == 'lyrics'}" @click="tabMode = (tabMode == 'lyrics') ? '' : 'lyrics'"></div>
|
||||
<div class="queue" :class="{active: tabMode == 'queue'}" @click="tabMode = (tabMode == 'queue') ? '' :'queue'"></div>
|
||||
</div> -->
|
||||
</div> -->
|
||||
<!-- <div class="tab-toggles">
|
||||
<div class="lyrics" :class="{active: tabMode == 'lyrics'}" @click="tabMode = (tabMode == 'lyrics') ? '' : 'lyrics'"></div>
|
||||
<div class="queue" :class="{active: tabMode == 'queue'}" @click="tabMode = (tabMode == 'queue') ? '' :'queue'"></div>
|
||||
</div> -->
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<script>
|
||||
Vue.component('mini-view', {
|
||||
template: '#mini-view',
|
||||
props: {
|
||||
time: {
|
||||
type: Number,
|
||||
required: false
|
||||
},
|
||||
lyrics: {
|
||||
type: Array,
|
||||
required: false
|
||||
},
|
||||
richlyrics: {
|
||||
type: Array,
|
||||
required: false
|
||||
},
|
||||
image: {
|
||||
type: String,
|
||||
required: false
|
||||
},
|
||||
},
|
||||
data: function () {
|
||||
return {
|
||||
app: this.$root,
|
||||
tabMode: "",
|
||||
}
|
||||
},
|
||||
beforeMount() {
|
||||
window.addEventListener('keyup', this.onEscapeKeyUp);
|
||||
},
|
||||
beforeDestroy() {
|
||||
window.removeEventListener('keyup', this.onEscapeKeyUp)
|
||||
},
|
||||
mounted() {
|
||||
app.pinMiniPlayer(true)
|
||||
},
|
||||
methods: {
|
||||
onEscapeKeyUp(event) {
|
||||
if (event.which === 27) {
|
||||
app.miniPlayer(false);
|
||||
console.log('js')
|
||||
}
|
||||
},
|
||||
Vue.component('mini-view', {
|
||||
template: '#mini-view',
|
||||
props: {
|
||||
time: {
|
||||
type: Number,
|
||||
required: false
|
||||
},
|
||||
lyrics: {
|
||||
type: Array,
|
||||
required: false
|
||||
},
|
||||
richlyrics: {
|
||||
type: Array,
|
||||
required: false
|
||||
},
|
||||
image: {
|
||||
type: String,
|
||||
required: false
|
||||
},
|
||||
},
|
||||
data: function() {
|
||||
return {
|
||||
app: this.$root,
|
||||
tabMode: "",
|
||||
}
|
||||
},
|
||||
beforeMount() {
|
||||
window.addEventListener('keyup', this.onEscapeKeyUp);
|
||||
},
|
||||
beforeDestroy() {
|
||||
window.removeEventListener('keyup', this.onEscapeKeyUp)
|
||||
},
|
||||
mounted() {
|
||||
app.pinMiniPlayer(true)
|
||||
},
|
||||
methods: {
|
||||
onEscapeKeyUp(event) {
|
||||
if (event.which === 27) {
|
||||
app.miniPlayer(false);
|
||||
console.log('js')
|
||||
}
|
||||
});
|
||||
</script>
|
||||
},
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<script type="text/x-template" id="moreinfo-modal">
|
||||
<div class="modal-fullscreen spatialproperties-panel moreinfo-modal" @click.self="if(timedelay) close()">
|
||||
<div class="modal-window" >
|
||||
<div class="modal-window">
|
||||
<div class="modal-header">
|
||||
<div class="modal-title">{{data.title}}</div>
|
||||
<div class="modal-subtitle modal-title">{{data.subtitle ?? ""}}</div>
|
||||
|
@ -15,28 +15,28 @@
|
|||
</script>
|
||||
|
||||
<script>
|
||||
Vue.component('moreinfo-modal', {
|
||||
template: '#moreinfo-modal',
|
||||
data: function () {
|
||||
return {
|
||||
app: this.$root,
|
||||
timedelay: false,
|
||||
}
|
||||
},
|
||||
props: ["data"],
|
||||
mounted() {
|
||||
let self = this;
|
||||
this.$nextTick(()=>{
|
||||
setTimeout(function(){
|
||||
self.timedelay = true
|
||||
}, 1000);
|
||||
})
|
||||
Vue.component('moreinfo-modal', {
|
||||
template: '#moreinfo-modal',
|
||||
data: function() {
|
||||
return {
|
||||
app: this.$root,
|
||||
timedelay: false,
|
||||
}
|
||||
},
|
||||
props: ["data"],
|
||||
mounted() {
|
||||
let self = this;
|
||||
this.$nextTick(() => {
|
||||
setTimeout(function() {
|
||||
self.timedelay = true
|
||||
}, 1000);
|
||||
})
|
||||
|
||||
},
|
||||
methods: {
|
||||
close() {
|
||||
app.modals.moreInfo = false;
|
||||
},
|
||||
}
|
||||
});
|
||||
</script>
|
||||
},
|
||||
methods: {
|
||||
close() {
|
||||
app.modals.moreInfo = false;
|
||||
},
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -1,37 +1,38 @@
|
|||
<script type="text/x-template" id="pagination">
|
||||
<div class="pagination-container" v-if="!isInfinite">
|
||||
<button
|
||||
class="md-btn page-btn"
|
||||
:disabled="effectivePage === 1"
|
||||
@click="goToPage(1)"
|
||||
class="md-btn page-btn"
|
||||
:disabled="effectivePage === 1"
|
||||
@click="goToPage(1)"
|
||||
>
|
||||
<img class="md-ico-first"/>
|
||||
<img class="md-ico-first" />
|
||||
</button>
|
||||
<button
|
||||
class="md-btn page-btn prev"
|
||||
:disabled="effectivePage === 1"
|
||||
@click="goToPrevious()"
|
||||
class="md-btn page-btn prev"
|
||||
:disabled="effectivePage === 1"
|
||||
@click="goToPrevious()"
|
||||
>
|
||||
<img class="md-ico-prev"/>
|
||||
<img class="md-ico-prev" />
|
||||
</button>
|
||||
<button
|
||||
:class="`md-btn page-btn${ isCurrentPage(page) ? ' md-btn-primary': ''}`"
|
||||
@click="goToPage(page)"
|
||||
v-for="page in pagesToShow"
|
||||
>{{ page }}</button>
|
||||
<button
|
||||
class="md-btn page-btn next"
|
||||
:disabled="effectivePage === numPages"
|
||||
@click="goToNext()"
|
||||
>
|
||||
<img class="md-ico-next"/>
|
||||
:class="`md-btn page-btn${ isCurrentPage(page) ? ' md-btn-primary': ''}`"
|
||||
@click="goToPage(page)"
|
||||
v-for="page in pagesToShow"
|
||||
>{{ page }}
|
||||
</button>
|
||||
<button
|
||||
class="md-btn page-btn last"
|
||||
:disabled="effectivePage === numPages"
|
||||
@click="goToEnd()"
|
||||
class="md-btn page-btn next"
|
||||
:disabled="effectivePage === numPages"
|
||||
@click="goToNext()"
|
||||
>
|
||||
<img class="md-ico-last"/>
|
||||
<img class="md-ico-next" />
|
||||
</button>
|
||||
<button
|
||||
class="md-btn page-btn last"
|
||||
:disabled="effectivePage === numPages"
|
||||
@click="goToEnd()"
|
||||
>
|
||||
<img class="md-ico-last" />
|
||||
</button>
|
||||
<div class="page-btn md-input-number">
|
||||
<input type="number" min="1" :max="numPages" :value="effectivePage" @change="changePage" />
|
||||
|
@ -41,135 +42,135 @@
|
|||
</script>
|
||||
|
||||
<script>
|
||||
Vue.component('pagination', {
|
||||
template: "#pagination",
|
||||
props: {
|
||||
'length': { type: Number, required: true },
|
||||
'pageSize': { type: Number, required: true },
|
||||
'scroll': { type: String, required: true },
|
||||
'scrollSelector': { type: String, required: true }
|
||||
},
|
||||
data: function () {
|
||||
return { currentPage: 1 }
|
||||
},
|
||||
mounted() {
|
||||
document.querySelector(this.scrollSelector)
|
||||
.addEventListener("scroll", this.handleScroll)
|
||||
},
|
||||
destroyed() {
|
||||
document.querySelector(this.scrollSelector)
|
||||
.removeEventListener("scroll", this.handleScroll)
|
||||
},
|
||||
watch: {
|
||||
'length': function () {
|
||||
if (this.isInfinite) {
|
||||
// If a search reduces the number of things to show, we want to limit
|
||||
// the number of songs shown as well. This is to prevent you scrolling
|
||||
// to load your entire library, searching for one song, and then having
|
||||
// th re-render the entire library
|
||||
if (this.currentPage > this.numPages) {
|
||||
this.currentPage = this.numPages;
|
||||
this.$emit("onRangeChange", this.currentRange);
|
||||
}
|
||||
} else {
|
||||
this.$emit("onRangeChange", this.currentRange);
|
||||
}
|
||||
},
|
||||
'scroll': function () {
|
||||
// When changing modes, set the page to 1. This is primarily to
|
||||
// prevent going to a high page (e.g., 50) and then switching to infinite
|
||||
// and showing 12.5k songs
|
||||
this.currentPage = 1;
|
||||
this.$emit("onRangeChange", this.currentRange);
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
isInfinite: function () {
|
||||
return this.scroll === "infinite"
|
||||
},
|
||||
currentRange: function () {
|
||||
if (this.isInfinite) {
|
||||
return [0, this.currentPage * this.pageSize];
|
||||
} else {
|
||||
const startingPage = Math.min(this.numPages, this.currentPage);
|
||||
|
||||
return [
|
||||
(startingPage - 1) * this.pageSize,
|
||||
startingPage * this.pageSize
|
||||
];
|
||||
}
|
||||
},
|
||||
effectivePage: function () {
|
||||
return Math.min(this.currentPage, this.numPages)
|
||||
},
|
||||
numPages: function () {
|
||||
return Math.ceil(this.length / this.pageSize) || 1;
|
||||
},
|
||||
pagesToShow: function () {
|
||||
let start = this.currentPage - 2;
|
||||
let end = this.currentPage + 2;
|
||||
|
||||
if (start < 1) {
|
||||
end += (1 - start);
|
||||
start = 1;
|
||||
}
|
||||
|
||||
const endDifference = end - this.numPages;
|
||||
if (endDifference > 0) {
|
||||
end = this.numPages;
|
||||
start = Math.max(1, start - endDifference);
|
||||
}
|
||||
|
||||
const array = [];
|
||||
for (let idx = start; idx <= end; idx++) {
|
||||
array.push(idx);
|
||||
}
|
||||
return array;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// Infinite Scrolling
|
||||
handleScroll: function (event) {
|
||||
if (this.isInfinite &&
|
||||
this.currentPage < this.numPages &&
|
||||
event.target.scrollTop >= event.target.scrollHeight - event.target.clientHeight) {
|
||||
this.currentPage += 1;
|
||||
this.$emit("onRangeChange", this.currentRange);
|
||||
}
|
||||
},
|
||||
// Pagination
|
||||
isCurrentPage: function (idx) {
|
||||
return idx === this.currentPage ||
|
||||
(idx === this.numPages && this.currentPage > this.numPages);
|
||||
},
|
||||
changePage: function (event) {
|
||||
const value = event.target.valueAsNumber;
|
||||
|
||||
if (!isNaN(value) && value >= 1 && value <= this.numPages) {
|
||||
this.currentPage = value;
|
||||
this.$emit("onRangeChange", this.currentRange);
|
||||
}
|
||||
},
|
||||
goToPage: function (page) {
|
||||
this.currentPage = page;
|
||||
this.$emit("onRangeChange", this.currentRange);
|
||||
},
|
||||
goToPrevious: function () {
|
||||
if (this.currentPage > 1) {
|
||||
this.currentPage -= 1;
|
||||
this.$emit("onRangeChange", this.currentRange);
|
||||
}
|
||||
},
|
||||
goToNext: function () {
|
||||
if (this.currentPage < this.numPages) {
|
||||
this.currentPage += 1;
|
||||
this.$emit("onRangeChange", this.currentRange);
|
||||
}
|
||||
},
|
||||
goToEnd: function () {
|
||||
this.currentPage = this.numPages;
|
||||
this.$emit("onRangeChange", this.currentRange);
|
||||
}
|
||||
Vue.component('pagination', {
|
||||
template: "#pagination",
|
||||
props: {
|
||||
'length': { type: Number, required: true },
|
||||
'pageSize': { type: Number, required: true },
|
||||
'scroll': { type: String, required: true },
|
||||
'scrollSelector': { type: String, required: true }
|
||||
},
|
||||
data: function() {
|
||||
return { currentPage: 1 }
|
||||
},
|
||||
mounted() {
|
||||
document.querySelector(this.scrollSelector)
|
||||
.addEventListener("scroll", this.handleScroll)
|
||||
},
|
||||
destroyed() {
|
||||
document.querySelector(this.scrollSelector)
|
||||
.removeEventListener("scroll", this.handleScroll)
|
||||
},
|
||||
watch: {
|
||||
'length': function() {
|
||||
if (this.isInfinite) {
|
||||
// If a search reduces the number of things to show, we want to limit
|
||||
// the number of songs shown as well. This is to prevent you scrolling
|
||||
// to load your entire library, searching for one song, and then having
|
||||
// th re-render the entire library
|
||||
if (this.currentPage > this.numPages) {
|
||||
this.currentPage = this.numPages;
|
||||
this.$emit("onRangeChange", this.currentRange);
|
||||
}
|
||||
} else {
|
||||
this.$emit("onRangeChange", this.currentRange);
|
||||
}
|
||||
})
|
||||
</script>
|
||||
},
|
||||
'scroll': function() {
|
||||
// When changing modes, set the page to 1. This is primarily to
|
||||
// prevent going to a high page (e.g., 50) and then switching to infinite
|
||||
// and showing 12.5k songs
|
||||
this.currentPage = 1;
|
||||
this.$emit("onRangeChange", this.currentRange);
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
isInfinite: function() {
|
||||
return this.scroll === "infinite"
|
||||
},
|
||||
currentRange: function() {
|
||||
if (this.isInfinite) {
|
||||
return [0, this.currentPage * this.pageSize];
|
||||
} else {
|
||||
const startingPage = Math.min(this.numPages, this.currentPage);
|
||||
|
||||
return [
|
||||
(startingPage - 1) * this.pageSize,
|
||||
startingPage * this.pageSize
|
||||
];
|
||||
}
|
||||
},
|
||||
effectivePage: function() {
|
||||
return Math.min(this.currentPage, this.numPages)
|
||||
},
|
||||
numPages: function() {
|
||||
return Math.ceil(this.length / this.pageSize) || 1;
|
||||
},
|
||||
pagesToShow: function() {
|
||||
let start = this.currentPage - 2;
|
||||
let end = this.currentPage + 2;
|
||||
|
||||
if (start < 1) {
|
||||
end += (1 - start);
|
||||
start = 1;
|
||||
}
|
||||
|
||||
const endDifference = end - this.numPages;
|
||||
if (endDifference > 0) {
|
||||
end = this.numPages;
|
||||
start = Math.max(1, start - endDifference);
|
||||
}
|
||||
|
||||
const array = [];
|
||||
for (let idx = start; idx <= end; idx++) {
|
||||
array.push(idx);
|
||||
}
|
||||
return array;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// Infinite Scrolling
|
||||
handleScroll: function(event) {
|
||||
if (this.isInfinite &&
|
||||
this.currentPage < this.numPages &&
|
||||
event.target.scrollTop >= event.target.scrollHeight - event.target.clientHeight) {
|
||||
this.currentPage += 1;
|
||||
this.$emit("onRangeChange", this.currentRange);
|
||||
}
|
||||
},
|
||||
// Pagination
|
||||
isCurrentPage: function(idx) {
|
||||
return idx === this.currentPage ||
|
||||
(idx === this.numPages && this.currentPage > this.numPages);
|
||||
},
|
||||
changePage: function(event) {
|
||||
const value = event.target.valueAsNumber;
|
||||
|
||||
if (!isNaN(value) && value >= 1 && value <= this.numPages) {
|
||||
this.currentPage = value;
|
||||
this.$emit("onRangeChange", this.currentRange);
|
||||
}
|
||||
},
|
||||
goToPage: function(page) {
|
||||
this.currentPage = page;
|
||||
this.$emit("onRangeChange", this.currentRange);
|
||||
},
|
||||
goToPrevious: function() {
|
||||
if (this.currentPage > 1) {
|
||||
this.currentPage -= 1;
|
||||
this.$emit("onRangeChange", this.currentRange);
|
||||
}
|
||||
},
|
||||
goToNext: function() {
|
||||
if (this.currentPage < this.numPages) {
|
||||
this.currentPage += 1;
|
||||
this.$emit("onRangeChange", this.currentRange);
|
||||
}
|
||||
},
|
||||
goToEnd: function() {
|
||||
this.currentPage = this.numPages;
|
||||
this.$emit("onRangeChange", this.currentRange);
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
|
|
@ -1,65 +1,66 @@
|
|||
<script type="text/x-template" id="pathmenu">
|
||||
<div class="spatialproperties-panel castmenu pathmenu modal-fullscreen" @click.self="close()" @contextmenu.self="close()">
|
||||
<div class="modal-window">
|
||||
<div class="modal-header">
|
||||
<div class="modal-title">{{'Edit Paths'}}</div>
|
||||
<button class="close-btn" @click="close()" :aria-label="$root.getLz('action.close')"></button>
|
||||
</div>
|
||||
<div class="modal-content">
|
||||
<template v-for="folder of folders">
|
||||
<div class="md-option-line">
|
||||
<div class="md-option-segment">
|
||||
{{folder}}
|
||||
<div class="spatialproperties-panel castmenu pathmenu modal-fullscreen" @click.self="close()"
|
||||
@contextmenu.self="close()">
|
||||
<div class="modal-window">
|
||||
<div class="modal-header">
|
||||
<div class="modal-title">{{'Edit Paths'}}</div>
|
||||
<button class="close-btn" @click="close()" :aria-label="$root.getLz('action.close')"></button>
|
||||
</div>
|
||||
<div class="modal-content">
|
||||
<template v-for="folder of folders">
|
||||
<div class="md-option-line">
|
||||
<div class="md-option-segment">
|
||||
{{folder}}
|
||||
</div>
|
||||
<div class="md-option-segment md-option-segment_auto">
|
||||
<button class="md-btn" @click="remove(folder)">
|
||||
{{'Remove'}}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<div class="md-option-line">
|
||||
<div class="md-option-segment md-option-segment_auto">
|
||||
<button class="md-btn" @click="remove(folder)">
|
||||
{{'Remove'}}
|
||||
<button class="md-btn" @click="add()">
|
||||
{{'Add Path'}}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<div class="md-option-line">
|
||||
<div class="md-option-segment md-option-segment_auto">
|
||||
<button class="md-btn" @click="add()">
|
||||
{{'Add Path'}}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
<script>
|
||||
Vue.component('pathmenu', {
|
||||
template: '#pathmenu',
|
||||
data: function () {
|
||||
return {
|
||||
folders: [],
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.folders = this.$root.cfg.libraryPrefs.localPaths;
|
||||
},
|
||||
watch:{},
|
||||
methods: {
|
||||
close() {
|
||||
this.$root.modals.pathMenu = false
|
||||
},
|
||||
async add(){
|
||||
const result = await ipcRenderer.invoke('folderSelector')
|
||||
for (i of result){
|
||||
if (this.folders.findIndex(x => x.startsWith(i)) == -1){
|
||||
this.folders.push(i)
|
||||
}
|
||||
}
|
||||
this.$root.cfg.libraryPrefs.localPaths = this.folders;
|
||||
ipcRenderer.invoke("scanLibrary")
|
||||
},
|
||||
remove(dir){
|
||||
this.folders = this.folders.filter(item => item !== dir)
|
||||
this.$root.cfg.libraryPrefs.localPaths = this.folders;
|
||||
ipcRenderer.invoke("scanLibrary")
|
||||
}
|
||||
Vue.component('pathmenu', {
|
||||
template: '#pathmenu',
|
||||
data: function() {
|
||||
return {
|
||||
folders: [],
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.folders = this.$root.cfg.libraryPrefs.localPaths;
|
||||
},
|
||||
watch: {},
|
||||
methods: {
|
||||
close() {
|
||||
this.$root.modals.pathMenu = false
|
||||
},
|
||||
async add() {
|
||||
const result = await ipcRenderer.invoke('folderSelector')
|
||||
for (i of result) {
|
||||
if (this.folders.findIndex(x => x.startsWith(i)) == -1) {
|
||||
this.folders.push(i)
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
this.$root.cfg.libraryPrefs.localPaths = this.folders;
|
||||
ipcRenderer.invoke("scanLibrary")
|
||||
},
|
||||
remove(dir) {
|
||||
this.folders = this.folders.filter(item => item !== dir)
|
||||
this.$root.cfg.libraryPrefs.localPaths = this.folders;
|
||||
ipcRenderer.invoke("scanLibrary")
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
<script type="text/x-template" id="plugin-menu">
|
||||
<div class="modal-fullscreen addtoplaylist-panel" @click.self="app.resetState()" @contextmenu.self="app.resetState()">
|
||||
<div class="modal-fullscreen addtoplaylist-panel" @click.self="app.resetState()"
|
||||
@contextmenu.self="app.resetState()">
|
||||
<div class="modal-window">
|
||||
<div class="modal-header">
|
||||
<div class="modal-title">{{$root.getLz('term.pluginMenu')}}</div>
|
||||
|
@ -10,30 +11,32 @@
|
|||
<span class="icon"><%- include("../svg/x.svg") %></span>
|
||||
<span class="name" style="top: 0.5px;">{{$root.getLz('term.pluginMenu.none')}}</span>
|
||||
</span>
|
||||
<button class="playlist-item" @click="entry.onClick(); closeMenu();" v-for="entry in app.pluginMenuEntries">
|
||||
<span class="icon"><%- include("../svg/grid.svg") %></span>
|
||||
<span class="name" style="top: 0.5px;">{{ entry.name }}</span>
|
||||
</button>
|
||||
<button class="playlist-item" @click="entry.onClick(); closeMenu();"
|
||||
v-for="entry in app.pluginMenuEntries">
|
||||
<span class="icon"><%- include("../svg/grid.svg") %></span>
|
||||
<span class="name" style="top: 0.5px;">{{ entry.name }}</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script>
|
||||
Vue.component('plugin-menu', {
|
||||
template: '#plugin-menu',
|
||||
data: function () {
|
||||
return {
|
||||
app: this.$root,
|
||||
}
|
||||
},
|
||||
props: {},
|
||||
mounted() {},
|
||||
methods: {
|
||||
closeMenu() {
|
||||
app.modals.pluginMenu = false
|
||||
},
|
||||
},
|
||||
Vue.component('plugin-menu', {
|
||||
template: '#plugin-menu',
|
||||
data: function() {
|
||||
return {
|
||||
app: this.$root,
|
||||
}
|
||||
);
|
||||
</script>
|
||||
},
|
||||
props: {},
|
||||
mounted() {
|
||||
},
|
||||
methods: {
|
||||
closeMenu() {
|
||||
app.modals.pluginMenu = false
|
||||
},
|
||||
},
|
||||
}
|
||||
);
|
||||
</script>
|
||||
|
|
|
@ -1,34 +1,34 @@
|
|||
<script type="text/x-template" id="qrcode-modal">
|
||||
<div class="modal-fullscreen spatialproperties-panel">
|
||||
<div class="modal-window" >
|
||||
<div class="modal-window">
|
||||
<div class="modal-header">
|
||||
<div class="modal-title">{{`Web Remote QR : ` + url }}</div>
|
||||
<button class="close-btn" @click="close()" :aria-label="app.getLz('action.close')"></button>
|
||||
</div>
|
||||
<div class="modal-content">
|
||||
<img class="qrimg" :src="src"/>
|
||||
<img class="qrimg" :src="src" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script>
|
||||
Vue.component('qrcode-modal', {
|
||||
template: '#qrcode-modal',
|
||||
data: function () {
|
||||
return {
|
||||
app: this.$root,
|
||||
Vue.component('qrcode-modal', {
|
||||
template: '#qrcode-modal',
|
||||
data: function() {
|
||||
return {
|
||||
app: this.$root,
|
||||
|
||||
}
|
||||
},
|
||||
props: ["src","url"],
|
||||
mounted() {
|
||||
}
|
||||
},
|
||||
props: ["src", "url"],
|
||||
mounted() {
|
||||
|
||||
},
|
||||
methods: {
|
||||
close() {
|
||||
app.resetState()
|
||||
},
|
||||
}
|
||||
});
|
||||
</script>
|
||||
},
|
||||
methods: {
|
||||
close() {
|
||||
app.resetState()
|
||||
},
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -14,7 +14,8 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="queue-body" v-if="page == 'history'">
|
||||
<mediaitem-list-item :show-library-status="false" v-for="item in history" :item="item"></mediaitem-list-item>
|
||||
<mediaitem-list-item :show-library-status="false" v-for="item in history"
|
||||
:item="item"></mediaitem-list-item>
|
||||
</div>
|
||||
<div class="queue-body" v-if="page == 'queue'">
|
||||
<draggable v-model="queueItems" @start="drag=true" @end="drag=false;move()">
|
||||
|
@ -27,18 +28,26 @@
|
|||
<div class="row">
|
||||
<div class="col-auto cider-flex-center">
|
||||
<div class="artwork">
|
||||
<mediaitem-artwork :url="queueItem.item.attributes.artwork ? queueItem.item.attributes.artwork.url : ''" :size="32"></mediaitem-artwork>
|
||||
<mediaitem-artwork
|
||||
:url="queueItem.item.attributes.artwork ? queueItem.item.attributes.artwork.url : ''"
|
||||
:size="32"></mediaitem-artwork>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col queue-info">
|
||||
<div class="queue-title text-overflow-elipsis">{{ queueItem.item.attributes.name }}</div>
|
||||
<div class="queue-subtitle text-overflow-elipsis">{{ queueItem.item.attributes.artistName }} — {{ queueItem.item.attributes.albumName }}</div>
|
||||
<div class="queue-title text-overflow-elipsis">{{ queueItem.item.attributes.name }}
|
||||
</div>
|
||||
<div class="queue-subtitle text-overflow-elipsis">{{
|
||||
queueItem.item.attributes.artistName }} — {{ queueItem.item.attributes.albumName }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="queue-explicit-icon cider-flex-center" v-if="queueItem.item.attributes.contentRating == 'explicit'">
|
||||
<div class="queue-explicit-icon cider-flex-center"
|
||||
v-if="queueItem.item.attributes.contentRating == 'explicit'">
|
||||
<div class="explicit-icon"></div>
|
||||
</div>
|
||||
<div class="col queue-duration-info">
|
||||
<div class="queue-duration cider-flex-center">{{convertTimeToString(queueItem.item.attributes.durationInMillis)}}</div>
|
||||
<div class="queue-duration cider-flex-center">
|
||||
{{convertTimeToString(queueItem.item.attributes.durationInMillis)}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -47,138 +56,144 @@
|
|||
</div>
|
||||
<div class="queue-footer">
|
||||
<div class="btn-group" style="width:100%;">
|
||||
<button class="md-btn md-btn-small" :class="{'md-btn-primary': (page == 'queue')}" @click="page = 'queue'">{{app.getLz('term.queue')}}</button>
|
||||
<button class="md-btn md-btn-small" :class="{'md-btn-primary': (page == 'history')}" @click="getHistory();page = 'history'">{{app.getLz('term.history')}}</button>
|
||||
<button class="md-btn md-btn-small" :class="{'md-btn-primary': (page == 'queue')}"
|
||||
@click="page = 'queue'">{{app.getLz('term.queue')}}
|
||||
</button>
|
||||
<button class="md-btn md-btn-small" :class="{'md-btn-primary': (page == 'history')}"
|
||||
@click="getHistory();page = 'history'">{{app.getLz('term.history')}}
|
||||
</button>
|
||||
</div>
|
||||
<button class="md-btn md-btn-small" style="width:100%;margin-top:6px;" v-if="queueItems.length > 1" @click="app.mk.clearQueue();updateQueue()">{{app.getLz('term.clearAll')}}</button>
|
||||
<button class="md-btn md-btn-small" style="width:100%;margin-top:6px;" v-if="queueItems.length > 1"
|
||||
@click="app.mk.clearQueue();updateQueue()">{{app.getLz('term.clearAll')}}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
|
||||
<script>
|
||||
Vue.component('cider-queue', {
|
||||
template: '#cider-queue',
|
||||
data: function () {
|
||||
return {
|
||||
drag: false,
|
||||
queuePosition: 0,
|
||||
queueItems: [],
|
||||
selected: -1,
|
||||
selectedItems: [],
|
||||
history: [],
|
||||
page: "queue",
|
||||
app: this.$root
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
displayQueueItems() {
|
||||
const displayLimit = 50;
|
||||
const lastDisplayPosition = Math.min(displayLimit + this.queuePosition, this.queueItems.length);
|
||||
return this.queueItems.slice(this.queuePosition, lastDisplayPosition);
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.updateQueue()
|
||||
},
|
||||
methods: {
|
||||
async getHistory() {
|
||||
let history = await app.mk.api.v3.music(`/v1/me/recent/played/tracks`, { l : this.$root.mklang})
|
||||
this.history = history.data.data
|
||||
},
|
||||
select(e, position) {
|
||||
if (e.ctrlKey || e.shiftKey) {
|
||||
if (this.selectedItems.indexOf(position) == -1) {
|
||||
this.selectedItems.push(position)
|
||||
} else {
|
||||
this.selectedItems.splice(this.selectedItems.indexOf(position), 1)
|
||||
}
|
||||
} else {
|
||||
this.selectedItems = [position]
|
||||
}
|
||||
},
|
||||
queueContext(event, item, position) {
|
||||
let self = this
|
||||
let useMenu = "single"
|
||||
if (this.selectedItems.length > 1) {
|
||||
useMenu = "multiple"
|
||||
}
|
||||
let menus = {
|
||||
single: {
|
||||
items: [{
|
||||
"name": app.getLz('action.removeFromQueue'),
|
||||
"action": function () {
|
||||
self.queueItems.splice(position, 1)
|
||||
app.mk.queue._queueItems = self.queueItems;
|
||||
app.mk.queue._reindex()
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": app.getLz('action.startRadio'),
|
||||
"action": function () {
|
||||
app.mk.setStationQueue({
|
||||
song: item.attributes.playParams.id ?? item.id
|
||||
}).then(() => {
|
||||
app.mk.play()
|
||||
})
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": app.getLz('action.goToArtist'),
|
||||
"action": function () {
|
||||
app.searchAndNavigate(item,'artist')
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": app.getLz('action.goToAlbum'),
|
||||
"action": function () {
|
||||
app.searchAndNavigate(item,'album')
|
||||
}
|
||||
},
|
||||
]
|
||||
},
|
||||
multiple: {
|
||||
items: [{
|
||||
"name": app.getLz('action.removeTracks').replace('${self.selectedItems.length}', self.selectedItems.length.toString()),
|
||||
"action": function () {
|
||||
// add property to items to be removed
|
||||
self.selectedItems.forEach(function (item) {
|
||||
self.queueItems[item].remove = true
|
||||
})
|
||||
// remove items
|
||||
self.queueItems = self.queueItems.filter(function (item) {
|
||||
return !item.remove
|
||||
})
|
||||
app.mk.queue._reindex()
|
||||
self.selectedItems = []
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
app.showMenuPanel(menus[useMenu], event);
|
||||
},
|
||||
playQueueItem(id) {
|
||||
app.mk.changeToMediaAtIndex(app.mk.queue._itemIDs.indexOf(id))
|
||||
},
|
||||
updateQueue() {
|
||||
this.selected = -1
|
||||
if (app.mk.queue) {
|
||||
this.queuePosition = app.mk.queue.position;
|
||||
this.queueItems = app.mk.queue._queueItems;
|
||||
} else {
|
||||
this.queuePosition = 0;
|
||||
this.queueItems = [];
|
||||
}
|
||||
},
|
||||
move() {
|
||||
this.selected = -1
|
||||
app.mk.queue._queueItems = this.queueItems;
|
||||
app.mk.queue._reindex()
|
||||
},
|
||||
convertTimeToString(timeInMilliseconds) {
|
||||
var seconds = ((timeInMilliseconds % 60000) / 1000).toFixed(0);
|
||||
return Math.floor(timeInMilliseconds/60000) + ":" + (seconds < 10 ? '0' : '') + seconds;
|
||||
}
|
||||
Vue.component('cider-queue', {
|
||||
template: '#cider-queue',
|
||||
data: function() {
|
||||
return {
|
||||
drag: false,
|
||||
queuePosition: 0,
|
||||
queueItems: [],
|
||||
selected: -1,
|
||||
selectedItems: [],
|
||||
history: [],
|
||||
page: "queue",
|
||||
app: this.$root
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
displayQueueItems() {
|
||||
const displayLimit = 50;
|
||||
const lastDisplayPosition = Math.min(displayLimit + this.queuePosition, this.queueItems.length);
|
||||
return this.queueItems.slice(this.queuePosition, lastDisplayPosition);
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.updateQueue()
|
||||
},
|
||||
methods: {
|
||||
async getHistory() {
|
||||
let history = await app.mk.api.v3.music(`/v1/me/recent/played/tracks`, { l: this.$root.mklang })
|
||||
this.history = history.data.data
|
||||
},
|
||||
select(e, position) {
|
||||
if (e.ctrlKey || e.shiftKey) {
|
||||
if (this.selectedItems.indexOf(position) == -1) {
|
||||
this.selectedItems.push(position)
|
||||
} else {
|
||||
this.selectedItems.splice(this.selectedItems.indexOf(position), 1)
|
||||
}
|
||||
} else {
|
||||
this.selectedItems = [position]
|
||||
}
|
||||
});
|
||||
</script>
|
||||
},
|
||||
queueContext(event, item, position) {
|
||||
let self = this
|
||||
let useMenu = "single"
|
||||
if (this.selectedItems.length > 1) {
|
||||
useMenu = "multiple"
|
||||
}
|
||||
let menus = {
|
||||
single: {
|
||||
items: [{
|
||||
"name": app.getLz('action.removeFromQueue'),
|
||||
"action": function() {
|
||||
self.queueItems.splice(position, 1)
|
||||
app.mk.queue._queueItems = self.queueItems;
|
||||
app.mk.queue._reindex()
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": app.getLz('action.startRadio'),
|
||||
"action": function() {
|
||||
app.mk.setStationQueue({
|
||||
song: item.attributes.playParams.id ?? item.id
|
||||
}).then(() => {
|
||||
app.mk.play()
|
||||
})
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": app.getLz('action.goToArtist'),
|
||||
"action": function() {
|
||||
app.searchAndNavigate(item, 'artist')
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": app.getLz('action.goToAlbum'),
|
||||
"action": function() {
|
||||
app.searchAndNavigate(item, 'album')
|
||||
}
|
||||
},
|
||||
]
|
||||
},
|
||||
multiple: {
|
||||
items: [{
|
||||
"name": app.getLz('action.removeTracks').replace('${self.selectedItems.length}', self.selectedItems.length.toString()),
|
||||
"action": function() {
|
||||
// add property to items to be removed
|
||||
self.selectedItems.forEach(function(item) {
|
||||
self.queueItems[item].remove = true
|
||||
})
|
||||
// remove items
|
||||
self.queueItems = self.queueItems.filter(function(item) {
|
||||
return !item.remove
|
||||
})
|
||||
app.mk.queue._reindex()
|
||||
self.selectedItems = []
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
app.showMenuPanel(menus[useMenu], event);
|
||||
},
|
||||
playQueueItem(id) {
|
||||
app.mk.changeToMediaAtIndex(app.mk.queue._itemIDs.indexOf(id))
|
||||
},
|
||||
updateQueue() {
|
||||
this.selected = -1
|
||||
if (app.mk.queue) {
|
||||
this.queuePosition = app.mk.queue.position;
|
||||
this.queueItems = app.mk.queue._queueItems;
|
||||
} else {
|
||||
this.queuePosition = 0;
|
||||
this.queueItems = [];
|
||||
}
|
||||
},
|
||||
move() {
|
||||
this.selected = -1
|
||||
app.mk.queue._queueItems = this.queueItems;
|
||||
app.mk.queue._reindex()
|
||||
},
|
||||
convertTimeToString(timeInMilliseconds) {
|
||||
var seconds = ((timeInMilliseconds % 60000) / 1000).toFixed(0);
|
||||
return Math.floor(timeInMilliseconds / 60000) + ":" + (seconds < 10 ? '0' : '') + seconds;
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
<script type="text/x-template" id="keybinds-settings">
|
||||
<div class="keybinds-page">
|
||||
<div class="md-option-header">
|
||||
<span>{{$root.getLz('settings.option.general.keybindings')}}</span>
|
||||
</div>
|
||||
<div class="md-option-header">
|
||||
<span>{{$root.getLz('settings.option.general.keybindings')}}</span>
|
||||
</div>
|
||||
<div class="settings-option-body">
|
||||
<div class="md-option-header-sub">
|
||||
<span>{{$root.getLz('settings.option.general.keybindings.library')}}</span>
|
||||
|
@ -207,7 +207,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<button class="md-btn md-btn-large md-btn-block" @click="keyBindReset()">
|
||||
{{$root.getLz('term.reset')}}
|
||||
{{$root.getLz('term.reset')}}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
|
@ -215,109 +215,109 @@
|
|||
</script>
|
||||
|
||||
<script>
|
||||
Vue.component('keybinds-settings', {
|
||||
template: "#keybinds-settings",
|
||||
props: [],
|
||||
data: function () {
|
||||
return {
|
||||
app: this.$root
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
keyBindUpdate: function (action) {
|
||||
const blur = document.createElement('div');
|
||||
blur.className = 'blur';
|
||||
blur.style.backgroundColor = 'rgba(0,0,0,0.25)';
|
||||
blur.style.position = 'fixed';
|
||||
blur.style.top = '0';
|
||||
blur.style.left = '0';
|
||||
blur.style.width = '100%';
|
||||
blur.style.height = '100%';
|
||||
blur.style.zIndex = '9999';
|
||||
blur.style.display = 'flex';
|
||||
blur.style.alignItems = 'center';
|
||||
blur.style.justifyContent = 'center';
|
||||
blur.style.fontSize = '2em';
|
||||
blur.style.color = 'white';
|
||||
blur.innerHTML = `<center>${app.getLz('settings.option.general.keybindings.pressCombination')}<br />${app.getLz('settings.option.general.keybindings.pressEscape')}</center>`
|
||||
document.body.appendChild(blur);
|
||||
Vue.component('keybinds-settings', {
|
||||
template: "#keybinds-settings",
|
||||
props: [],
|
||||
data: function() {
|
||||
return {
|
||||
app: this.$root
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
keyBindUpdate: function(action) {
|
||||
const blur = document.createElement('div');
|
||||
blur.className = 'blur';
|
||||
blur.style.backgroundColor = 'rgba(0,0,0,0.25)';
|
||||
blur.style.position = 'fixed';
|
||||
blur.style.top = '0';
|
||||
blur.style.left = '0';
|
||||
blur.style.width = '100%';
|
||||
blur.style.height = '100%';
|
||||
blur.style.zIndex = '9999';
|
||||
blur.style.display = 'flex';
|
||||
blur.style.alignItems = 'center';
|
||||
blur.style.justifyContent = 'center';
|
||||
blur.style.fontSize = '2em';
|
||||
blur.style.color = 'white';
|
||||
blur.innerHTML = `<center>${app.getLz('settings.option.general.keybindings.pressCombination')}<br />${app.getLz('settings.option.general.keybindings.pressEscape')}</center>`
|
||||
document.body.appendChild(blur);
|
||||
|
||||
let keyBind = [];
|
||||
const keyBindTimeout = setTimeout(function () {
|
||||
keyBind = [];
|
||||
document.body.removeChild(blur);
|
||||
}, 30000);
|
||||
const keyBindUpdate = function (e) {
|
||||
if (document.body.contains(blur)) {
|
||||
if (e.key == 'Escape') {
|
||||
document.body.removeChild(blur);
|
||||
clearTimeout(keyBindTimeout);
|
||||
return;
|
||||
} else {
|
||||
if (e.keyCode >= 65 && e.keyCode <= 90 && e.keyCode <= 97 && e.keyCode <= 122) {
|
||||
keyBind.push(e.key.toUpperCase());
|
||||
} else {
|
||||
keyBind.push(e.key);
|
||||
}
|
||||
if (keyBind.length === 2) {
|
||||
if (keyBind[0] !== keyBind[1]) {
|
||||
app.cfg.general.keybindings[action] = keyBind
|
||||
document.body.removeChild(blur);
|
||||
clearTimeout(keyBindTimeout);
|
||||
notyf.success(app.getLz('settings.notyf.general.keybindings.update.success'));
|
||||
app.confirm(app.getLz("settings.prompt.general.keybindings.update.success"), (ok) => {
|
||||
if (ok) ipcRenderer.invoke("relaunchApp")
|
||||
})
|
||||
} else {
|
||||
keyBind = [];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
document.addEventListener('keydown', keyBindUpdate);
|
||||
},
|
||||
keyBindReset: function () {
|
||||
app.cfg.general.keybindings.search = [app.platform == "darwin" ? "Command" : "Control", "F"];
|
||||
app.cfg.general.keybindings.listnow = [app.platform == "darwin" ? "Command" : "Control", "L"];
|
||||
app.cfg.general.keybindings.browse = [app.platform == "darwin" ? "Command" : "Control", "B"];
|
||||
app.cfg.general.keybindings.recentAdd = [app.platform == "darwin" ? "Command" : "Control", "G"];
|
||||
app.cfg.general.keybindings.songs = [app.platform == "darwin" ? "Command" : "Control", "J"];
|
||||
app.cfg.general.keybindings.albums = [app.platform == "darwin" ? "Command" : "Control", "A"];
|
||||
app.cfg.general.keybindings.artists = [app.platform == "darwin" ? "Command" : "Control", "D"];
|
||||
app.cfg.general.keybindings.togglePrivateSession = [app.platform == "darwin" ? "Command" : "Control", "P"];
|
||||
app.cfg.general.keybindings.webRemote = [app.platform == "darwin" ? "Command" : "Control",app.platform == "darwin" ? "Option" : (app.platform == "linux" ? "Shift" : "Alt"), "W"];
|
||||
app.cfg.general.keybindings.audioSettings = [app.platform == "darwin" ? "Command" : "Control",app.platform == "darwin" ? "Option" : (app.platform == "linux" ? "Shift" : "Alt"), "A"];
|
||||
app.cfg.general.keybindings.pluginMenu = [app.platform == "darwin" ? "Command" : "Control",app.platform == "darwin" ? "Option" : (app.platform == "linux" ? "Shift" : "Alt"), "P"];
|
||||
app.cfg.general.keybindings.castToDevices = [app.platform == "darwin" ? "Command" : "Control",app.platform == "darwin" ? "Option" : (app.platform == "linux" ? "Shift" : "Alt"), "C"];
|
||||
app.cfg.general.keybindings.settings = [app.platform == "darwin" ? "Command" : "Control", ","];
|
||||
app.cfg.general.keybindings.zoomn = [app.platform == "darwin" ? "Command" : "Control", "numadd"];
|
||||
app.cfg.general.keybindings.zoomt = [app.platform == "darwin" ? "Command" : "Control", "numsub"];
|
||||
app.cfg.general.keybindings.zoomrst = [app.platform == "darwin" ? "Command" : "Control", "num0"];
|
||||
app.cfg.general.keybindings.openDeveloperTools = [app.platform == "darwin" ? "Command" : "Control", app.platform == "darwin" ? "Option" : "Shift", "I"];
|
||||
notyf.success(app.getLz('settings.notyf.general.keybindings.update.success'));
|
||||
app.confirm(app.getLz("settings.prompt.general.keybindings.update.success"), (ok) => {
|
||||
let keyBind = [];
|
||||
const keyBindTimeout = setTimeout(function() {
|
||||
keyBind = [];
|
||||
document.body.removeChild(blur);
|
||||
}, 30000);
|
||||
const keyBindUpdate = function(e) {
|
||||
if (document.body.contains(blur)) {
|
||||
if (e.key == 'Escape') {
|
||||
document.body.removeChild(blur);
|
||||
clearTimeout(keyBindTimeout);
|
||||
return;
|
||||
} else {
|
||||
if (e.keyCode >= 65 && e.keyCode <= 90 && e.keyCode <= 97 && e.keyCode <= 122) {
|
||||
keyBind.push(e.key.toUpperCase());
|
||||
} else {
|
||||
keyBind.push(e.key);
|
||||
}
|
||||
if (keyBind.length === 2) {
|
||||
if (keyBind[0] !== keyBind[1]) {
|
||||
app.cfg.general.keybindings[action] = keyBind
|
||||
document.body.removeChild(blur);
|
||||
clearTimeout(keyBindTimeout);
|
||||
notyf.success(app.getLz('settings.notyf.general.keybindings.update.success'));
|
||||
app.confirm(app.getLz("settings.prompt.general.keybindings.update.success"), (ok) => {
|
||||
if (ok) ipcRenderer.invoke("relaunchApp")
|
||||
})
|
||||
},
|
||||
getLanguages: function () {
|
||||
let langs = this.$root.lzListing
|
||||
let categories = {
|
||||
"main": [],
|
||||
"fun": [],
|
||||
"unsorted": []
|
||||
})
|
||||
} else {
|
||||
keyBind = [];
|
||||
}
|
||||
// sort by category if category is undefined or empty put it in "unsorted"
|
||||
for (let i = 0; i < langs.length; i++) {
|
||||
if (langs[i].category === undefined || langs[i].category === "") {
|
||||
categories.unsorted.push(langs[i])
|
||||
} else {
|
||||
categories[langs[i].category].push(langs[i])
|
||||
}
|
||||
}
|
||||
// return
|
||||
return categories
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
document.addEventListener('keydown', keyBindUpdate);
|
||||
},
|
||||
keyBindReset: function() {
|
||||
app.cfg.general.keybindings.search = [app.platform == "darwin" ? "Command" : "Control", "F"];
|
||||
app.cfg.general.keybindings.listnow = [app.platform == "darwin" ? "Command" : "Control", "L"];
|
||||
app.cfg.general.keybindings.browse = [app.platform == "darwin" ? "Command" : "Control", "B"];
|
||||
app.cfg.general.keybindings.recentAdd = [app.platform == "darwin" ? "Command" : "Control", "G"];
|
||||
app.cfg.general.keybindings.songs = [app.platform == "darwin" ? "Command" : "Control", "J"];
|
||||
app.cfg.general.keybindings.albums = [app.platform == "darwin" ? "Command" : "Control", "A"];
|
||||
app.cfg.general.keybindings.artists = [app.platform == "darwin" ? "Command" : "Control", "D"];
|
||||
app.cfg.general.keybindings.togglePrivateSession = [app.platform == "darwin" ? "Command" : "Control", "P"];
|
||||
app.cfg.general.keybindings.webRemote = [app.platform == "darwin" ? "Command" : "Control", app.platform == "darwin" ? "Option" : (app.platform == "linux" ? "Shift" : "Alt"), "W"];
|
||||
app.cfg.general.keybindings.audioSettings = [app.platform == "darwin" ? "Command" : "Control", app.platform == "darwin" ? "Option" : (app.platform == "linux" ? "Shift" : "Alt"), "A"];
|
||||
app.cfg.general.keybindings.pluginMenu = [app.platform == "darwin" ? "Command" : "Control", app.platform == "darwin" ? "Option" : (app.platform == "linux" ? "Shift" : "Alt"), "P"];
|
||||
app.cfg.general.keybindings.castToDevices = [app.platform == "darwin" ? "Command" : "Control", app.platform == "darwin" ? "Option" : (app.platform == "linux" ? "Shift" : "Alt"), "C"];
|
||||
app.cfg.general.keybindings.settings = [app.platform == "darwin" ? "Command" : "Control", ","];
|
||||
app.cfg.general.keybindings.zoomn = [app.platform == "darwin" ? "Command" : "Control", "numadd"];
|
||||
app.cfg.general.keybindings.zoomt = [app.platform == "darwin" ? "Command" : "Control", "numsub"];
|
||||
app.cfg.general.keybindings.zoomrst = [app.platform == "darwin" ? "Command" : "Control", "num0"];
|
||||
app.cfg.general.keybindings.openDeveloperTools = [app.platform == "darwin" ? "Command" : "Control", app.platform == "darwin" ? "Option" : "Shift", "I"];
|
||||
notyf.success(app.getLz('settings.notyf.general.keybindings.update.success'));
|
||||
app.confirm(app.getLz("settings.prompt.general.keybindings.update.success"), (ok) => {
|
||||
if (ok) ipcRenderer.invoke("relaunchApp")
|
||||
})
|
||||
},
|
||||
getLanguages: function() {
|
||||
let langs = this.$root.lzListing
|
||||
let categories = {
|
||||
"main": [],
|
||||
"fun": [],
|
||||
"unsorted": []
|
||||
}
|
||||
})
|
||||
</script>
|
||||
// sort by category if category is undefined or empty put it in "unsorted"
|
||||
for (let i = 0; i < langs.length; i++) {
|
||||
if (langs[i].category === undefined || langs[i].category === "") {
|
||||
categories.unsorted.push(langs[i])
|
||||
} else {
|
||||
categories[langs[i].category].push(langs[i])
|
||||
}
|
||||
}
|
||||
// return
|
||||
return categories
|
||||
},
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
|
|
@ -21,7 +21,8 @@
|
|||
<div class="row">
|
||||
<div class="col cider-flex-center">
|
||||
<div>
|
||||
<h4 class="repo-name">{{ (repo.description != null) ? repo.description : repo.full_name }}</h4>
|
||||
<h4 class="repo-name">{{ (repo.description != null) ? repo.description :
|
||||
repo.full_name }}</h4>
|
||||
<div>⭐ {{ repo.stargazers_count }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -37,7 +38,8 @@
|
|||
<div>
|
||||
<h3 class="repo-preview-name">{{ openRepo.description }}</h3>
|
||||
<div>
|
||||
<div class="svg-icon inline" :style="{'--url': 'url(\'./assets/github.svg\')'}"></div>
|
||||
<div class="svg-icon inline"
|
||||
:style="{'--url': 'url(\'./assets/github.svg\')'}"></div>
|
||||
<a class="repo-url" target="_blank" :href="openRepo.html_url">{{ openRepo.full_name
|
||||
}}</a></div>
|
||||
<div>⭐ {{ openRepo.stargazers_count }}</div>
|
||||
|
@ -62,127 +64,127 @@
|
|||
</div>
|
||||
</script>
|
||||
<script>
|
||||
Vue.component('plugins-github', {
|
||||
template: "#plugins-github",
|
||||
props: [],
|
||||
data: function () {
|
||||
return {
|
||||
repos: [],
|
||||
openRepo: {
|
||||
id: -1,
|
||||
name: '',
|
||||
description: '',
|
||||
html_url: '',
|
||||
stargazers_count: 0,
|
||||
owner: {
|
||||
avatar_url: ''
|
||||
},
|
||||
readme: ""
|
||||
},
|
||||
themesInstalled: []
|
||||
}
|
||||
Vue.component('plugins-github', {
|
||||
template: "#plugins-github",
|
||||
props: [],
|
||||
data: function() {
|
||||
return {
|
||||
repos: [],
|
||||
openRepo: {
|
||||
id: -1,
|
||||
name: '',
|
||||
description: '',
|
||||
html_url: '',
|
||||
stargazers_count: 0,
|
||||
owner: {
|
||||
avatar_url: ''
|
||||
},
|
||||
readme: ""
|
||||
},
|
||||
mounted() {
|
||||
this.getRepos();
|
||||
// this.getInstalledThemes();
|
||||
},
|
||||
methods: {
|
||||
getInstalledThemes() {
|
||||
let self = this
|
||||
const themes = ipcRenderer.sendSync("get-themes")
|
||||
// for each theme, get the github_repo property and push it to the themesInstalled array, if not blank
|
||||
themes.forEach(theme => {
|
||||
if (theme.github_repo !== "") {
|
||||
self.themesInstalled.push(theme.github_repo)
|
||||
}
|
||||
})
|
||||
},
|
||||
showRepo(repo) {
|
||||
const self = this
|
||||
const readmeUrl = `https://raw.githubusercontent.com/${repo.full_name}/main/README.md`;
|
||||
var requestOptions = {
|
||||
method: 'GET',
|
||||
redirect: 'follow'
|
||||
};
|
||||
themesInstalled: []
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.getRepos();
|
||||
// this.getInstalledThemes();
|
||||
},
|
||||
methods: {
|
||||
getInstalledThemes() {
|
||||
let self = this
|
||||
const themes = ipcRenderer.sendSync("get-themes")
|
||||
// for each theme, get the github_repo property and push it to the themesInstalled array, if not blank
|
||||
themes.forEach(theme => {
|
||||
if (theme.github_repo !== "") {
|
||||
self.themesInstalled.push(theme.github_repo)
|
||||
}
|
||||
})
|
||||
},
|
||||
showRepo(repo) {
|
||||
const self = this
|
||||
const readmeUrl = `https://raw.githubusercontent.com/${repo.full_name}/main/README.md`;
|
||||
var requestOptions = {
|
||||
method: 'GET',
|
||||
redirect: 'follow'
|
||||
};
|
||||
|
||||
fetch(readmeUrl, requestOptions)
|
||||
.then(response => response.text())
|
||||
.then(result => {
|
||||
self.openRepo = repo
|
||||
self.openRepo.readme = self.convertReadMe(result);
|
||||
})
|
||||
.catch(error => {
|
||||
self.openRepo = repo
|
||||
self.openRepo.readme = `This repository doesn't have a README.md file.`;
|
||||
console.log('error', error)
|
||||
});
|
||||
},
|
||||
convertReadMe(text) {
|
||||
return marked.parse(text)
|
||||
},
|
||||
installThemeRepo(repo) {
|
||||
let self = this
|
||||
let msg = app.stringTemplateParser(app.getLz('settings.option.visual.plugin.github.install.confirm'), {
|
||||
repo: repo.full_name
|
||||
});
|
||||
app.confirm(msg, (res) => {
|
||||
if (res) {
|
||||
ipcRenderer.once("plugin-installed", (event, arg) => {
|
||||
if (arg.success) {
|
||||
self.themes = []
|
||||
notyf.success(app.getLz('settings.notyf.visual.plugin.install.success'));
|
||||
app.confirm(app.getLz("settings.prompt.visual.plugin.github.success"), (ok)=>{
|
||||
if (ok) {
|
||||
ipcRenderer.invoke("relaunchApp")
|
||||
} else {
|
||||
return
|
||||
}
|
||||
})
|
||||
} else {
|
||||
notyf.error(app.getLz('settings.notyf.visual.plugin.install.error'));
|
||||
}
|
||||
});
|
||||
ipcRenderer.invoke("get-github-plugin", repo.html_url)
|
||||
}
|
||||
fetch(readmeUrl, requestOptions)
|
||||
.then(response => response.text())
|
||||
.then(result => {
|
||||
self.openRepo = repo
|
||||
self.openRepo.readme = self.convertReadMe(result);
|
||||
})
|
||||
.catch(error => {
|
||||
self.openRepo = repo
|
||||
self.openRepo.readme = `This repository doesn't have a README.md file.`;
|
||||
console.log('error', error)
|
||||
});
|
||||
},
|
||||
convertReadMe(text) {
|
||||
return marked.parse(text)
|
||||
},
|
||||
installThemeRepo(repo) {
|
||||
let self = this
|
||||
let msg = app.stringTemplateParser(app.getLz('settings.option.visual.plugin.github.install.confirm'), {
|
||||
repo: repo.full_name
|
||||
});
|
||||
app.confirm(msg, (res) => {
|
||||
if (res) {
|
||||
ipcRenderer.once("plugin-installed", (event, arg) => {
|
||||
if (arg.success) {
|
||||
self.themes = []
|
||||
notyf.success(app.getLz('settings.notyf.visual.plugin.install.success'));
|
||||
app.confirm(app.getLz("settings.prompt.visual.plugin.github.success"), (ok) => {
|
||||
if (ok) {
|
||||
ipcRenderer.invoke("relaunchApp")
|
||||
} else {
|
||||
return
|
||||
}
|
||||
})
|
||||
},
|
||||
installThemeURL() {
|
||||
let self = this
|
||||
app.prompt(app.getLz('settings.prompt.visual.plugin.github.URL'), (result) => {
|
||||
if (result) {
|
||||
ipcRenderer.once("plugin-installed", (event, arg) => {
|
||||
if (arg.success) {
|
||||
self.themes = ipcRenderer.sendSync("get-themes")
|
||||
app.confirm(app.getLz("settings.prompt.visual.plugin.github.success"), (ok)=>{
|
||||
if (ok) {
|
||||
ipcRenderer.invoke("relaunchApp")
|
||||
} else {
|
||||
return
|
||||
}
|
||||
})
|
||||
notyf.success(app.getLz('settings.notyf.visual.plugin.install.success'));
|
||||
} else {
|
||||
notyf.error(app.getLz('settings.notyf.visual.plugin.install.error'));
|
||||
}
|
||||
});
|
||||
ipcRenderer.invoke("get-github-plugin", result)
|
||||
}
|
||||
});
|
||||
},
|
||||
getRepos() {
|
||||
let self = this
|
||||
var requestOptions = {
|
||||
method: 'GET',
|
||||
redirect: 'follow'
|
||||
};
|
||||
} else {
|
||||
notyf.error(app.getLz('settings.notyf.visual.plugin.install.error'));
|
||||
}
|
||||
});
|
||||
ipcRenderer.invoke("get-github-plugin", repo.html_url)
|
||||
}
|
||||
})
|
||||
},
|
||||
installThemeURL() {
|
||||
let self = this
|
||||
app.prompt(app.getLz('settings.prompt.visual.plugin.github.URL'), (result) => {
|
||||
if (result) {
|
||||
ipcRenderer.once("plugin-installed", (event, arg) => {
|
||||
if (arg.success) {
|
||||
self.themes = ipcRenderer.sendSync("get-themes")
|
||||
app.confirm(app.getLz("settings.prompt.visual.plugin.github.success"), (ok) => {
|
||||
if (ok) {
|
||||
ipcRenderer.invoke("relaunchApp")
|
||||
} else {
|
||||
return
|
||||
}
|
||||
})
|
||||
notyf.success(app.getLz('settings.notyf.visual.plugin.install.success'));
|
||||
} else {
|
||||
notyf.error(app.getLz('settings.notyf.visual.plugin.install.error'));
|
||||
}
|
||||
});
|
||||
ipcRenderer.invoke("get-github-plugin", result)
|
||||
}
|
||||
});
|
||||
},
|
||||
getRepos() {
|
||||
let self = this
|
||||
var requestOptions = {
|
||||
method: 'GET',
|
||||
redirect: 'follow'
|
||||
};
|
||||
|
||||
fetch("https://api.github.com/search/repositories?q=topic:cidermusicplugin fork:true&per_page=100", requestOptions)
|
||||
.then(response => response.text())
|
||||
.then(result => {
|
||||
self.repos = JSON.parse(result).items
|
||||
})
|
||||
.catch(error => console.log('error', error));
|
||||
}
|
||||
}
|
||||
})
|
||||
fetch("https://api.github.com/search/repositories?q=topic:cidermusicplugin fork:true&per_page=100", requestOptions)
|
||||
.then(response => response.text())
|
||||
.then(result => {
|
||||
self.repos = JSON.parse(result).items
|
||||
})
|
||||
.catch(error => console.log('error', error));
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
|
|
@ -78,120 +78,120 @@
|
|||
</div>
|
||||
</script>
|
||||
<script>
|
||||
Vue.component('themes-github', {
|
||||
template: "#themes-github",
|
||||
props: [],
|
||||
data: function () {
|
||||
return {
|
||||
repos: [],
|
||||
openRepo: {
|
||||
id: -1,
|
||||
name: '',
|
||||
description: '',
|
||||
html_url: '',
|
||||
stargazers_count: 0,
|
||||
owner: {
|
||||
avatar_url: ''
|
||||
},
|
||||
readme: ""
|
||||
},
|
||||
themesInstalled: [],
|
||||
themes: []
|
||||
}
|
||||
Vue.component('themes-github', {
|
||||
template: "#themes-github",
|
||||
props: [],
|
||||
data: function() {
|
||||
return {
|
||||
repos: [],
|
||||
openRepo: {
|
||||
id: -1,
|
||||
name: '',
|
||||
description: '',
|
||||
html_url: '',
|
||||
stargazers_count: 0,
|
||||
owner: {
|
||||
avatar_url: ''
|
||||
},
|
||||
readme: ""
|
||||
},
|
||||
mounted() {
|
||||
this.themes = ipcRenderer.sendSync("get-themes")
|
||||
this.getRepos();
|
||||
this.getInstalledThemes();
|
||||
},
|
||||
methods: {
|
||||
openThemesFolder() {
|
||||
ipcRenderer.invoke("open-path", "themes")
|
||||
},
|
||||
getInstalledThemes() {
|
||||
let self = this
|
||||
const themes = ipcRenderer.sendSync("get-themes")
|
||||
// for each theme, get the github_repo property and push it to the themesInstalled array, if not blank
|
||||
themes.forEach(theme => {
|
||||
if (theme.github_repo !== "" && typeof theme.commit != "") {
|
||||
self.themesInstalled.push(theme.github_repo.toLowerCase())
|
||||
}
|
||||
})
|
||||
},
|
||||
showRepo(repo) {
|
||||
const self = this
|
||||
const readmeUrl = `https://raw.githubusercontent.com/${repo.full_name}/main/README.md`;
|
||||
var requestOptions = {
|
||||
method: 'GET',
|
||||
redirect: 'follow'
|
||||
};
|
||||
themesInstalled: [],
|
||||
themes: []
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.themes = ipcRenderer.sendSync("get-themes")
|
||||
this.getRepos();
|
||||
this.getInstalledThemes();
|
||||
},
|
||||
methods: {
|
||||
openThemesFolder() {
|
||||
ipcRenderer.invoke("open-path", "themes")
|
||||
},
|
||||
getInstalledThemes() {
|
||||
let self = this
|
||||
const themes = ipcRenderer.sendSync("get-themes")
|
||||
// for each theme, get the github_repo property and push it to the themesInstalled array, if not blank
|
||||
themes.forEach(theme => {
|
||||
if (theme.github_repo !== "" && typeof theme.commit != "") {
|
||||
self.themesInstalled.push(theme.github_repo.toLowerCase())
|
||||
}
|
||||
})
|
||||
},
|
||||
showRepo(repo) {
|
||||
const self = this
|
||||
const readmeUrl = `https://raw.githubusercontent.com/${repo.full_name}/main/README.md`;
|
||||
var requestOptions = {
|
||||
method: 'GET',
|
||||
redirect: 'follow'
|
||||
};
|
||||
|
||||
fetch(readmeUrl, requestOptions)
|
||||
.then(response => response.text())
|
||||
.then(result => {
|
||||
self.openRepo = repo
|
||||
self.openRepo.readme = self.convertReadMe(result);
|
||||
})
|
||||
.catch(error => {
|
||||
self.openRepo = repo
|
||||
self.openRepo.readme = `This repository doesn't have a README.md file.`;
|
||||
console.log('error', error)
|
||||
});
|
||||
},
|
||||
convertReadMe(text) {
|
||||
return marked.parse(text)
|
||||
},
|
||||
installThemeRepo(repo) {
|
||||
let self = this
|
||||
let msg = app.stringTemplateParser(app.getLz('settings.option.visual.theme.github.install.confirm'), {
|
||||
repo: repo.full_name
|
||||
});
|
||||
app.confirm(msg, (res) => {
|
||||
if (res) {
|
||||
ipcRenderer.once("theme-installed", (event, arg) => {
|
||||
if (arg.success) {
|
||||
self.themes = ipcRenderer.sendSync("get-themes")
|
||||
self.getInstalledThemes()
|
||||
notyf.success(app.getLz('settings.notyf.visual.theme.install.success'));
|
||||
} else {
|
||||
notyf.error(app.getLz('settings.notyf.visual.theme.install.error'));
|
||||
}
|
||||
});
|
||||
ipcRenderer.invoke("get-github-theme", repo.html_url)
|
||||
}
|
||||
})
|
||||
},
|
||||
installThemeURL() {
|
||||
let self = this
|
||||
app.prompt(app.getLz('settings.prompt.visual.theme.github.URL'), (result) => {
|
||||
if (result) {
|
||||
ipcRenderer.once("theme-installed", (event, arg) => {
|
||||
if (arg.success) {
|
||||
self.themes = ipcRenderer.sendSync("get-themes")
|
||||
notyf.success(app.getLz('settings.notyf.visual.theme.install.success'));
|
||||
} else {
|
||||
notyf.error(app.getLz('settings.notyf.visual.theme.install.error'));
|
||||
}
|
||||
});
|
||||
ipcRenderer.invoke("get-github-theme", result)
|
||||
}
|
||||
});
|
||||
},
|
||||
getRepos() {
|
||||
let self = this
|
||||
var requestOptions = {
|
||||
method: 'GET',
|
||||
redirect: 'follow'
|
||||
};
|
||||
fetch(readmeUrl, requestOptions)
|
||||
.then(response => response.text())
|
||||
.then(result => {
|
||||
self.openRepo = repo
|
||||
self.openRepo.readme = self.convertReadMe(result);
|
||||
})
|
||||
.catch(error => {
|
||||
self.openRepo = repo
|
||||
self.openRepo.readme = `This repository doesn't have a README.md file.`;
|
||||
console.log('error', error)
|
||||
});
|
||||
},
|
||||
convertReadMe(text) {
|
||||
return marked.parse(text)
|
||||
},
|
||||
installThemeRepo(repo) {
|
||||
let self = this
|
||||
let msg = app.stringTemplateParser(app.getLz('settings.option.visual.theme.github.install.confirm'), {
|
||||
repo: repo.full_name
|
||||
});
|
||||
app.confirm(msg, (res) => {
|
||||
if (res) {
|
||||
ipcRenderer.once("theme-installed", (event, arg) => {
|
||||
if (arg.success) {
|
||||
self.themes = ipcRenderer.sendSync("get-themes")
|
||||
self.getInstalledThemes()
|
||||
notyf.success(app.getLz('settings.notyf.visual.theme.install.success'));
|
||||
} else {
|
||||
notyf.error(app.getLz('settings.notyf.visual.theme.install.error'));
|
||||
}
|
||||
});
|
||||
ipcRenderer.invoke("get-github-theme", repo.html_url)
|
||||
}
|
||||
})
|
||||
},
|
||||
installThemeURL() {
|
||||
let self = this
|
||||
app.prompt(app.getLz('settings.prompt.visual.theme.github.URL'), (result) => {
|
||||
if (result) {
|
||||
ipcRenderer.once("theme-installed", (event, arg) => {
|
||||
if (arg.success) {
|
||||
self.themes = ipcRenderer.sendSync("get-themes")
|
||||
notyf.success(app.getLz('settings.notyf.visual.theme.install.success'));
|
||||
} else {
|
||||
notyf.error(app.getLz('settings.notyf.visual.theme.install.error'));
|
||||
}
|
||||
});
|
||||
ipcRenderer.invoke("get-github-theme", result)
|
||||
}
|
||||
});
|
||||
},
|
||||
getRepos() {
|
||||
let self = this
|
||||
var requestOptions = {
|
||||
method: 'GET',
|
||||
redirect: 'follow'
|
||||
};
|
||||
|
||||
fetch("https://api.github.com/search/repositories?q=topic:cidermusictheme fork:true&per_page=100", requestOptions)
|
||||
.then(response => response.text())
|
||||
.then(result => {
|
||||
let items = JSON.parse(result).items
|
||||
self.repos = items
|
||||
})
|
||||
.catch(error => console.log('error', error));
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
fetch("https://api.github.com/search/repositories?q=topic:cidermusictheme fork:true&per_page=100", requestOptions)
|
||||
.then(response => response.text())
|
||||
.then(result => {
|
||||
let items = JSON.parse(result).items
|
||||
self.repos = items
|
||||
})
|
||||
.catch(error => console.log('error', error));
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
|
|
@ -32,9 +32,9 @@
|
|||
<ul class="list-group list-group-flush">
|
||||
<template v-for="theme in themes">
|
||||
<li @click="addStyle(theme.file)"
|
||||
@contextmenu="contextMenu($event, theme)"
|
||||
class="list-group-item list-group-item-dark"
|
||||
:class="{'applied': $root.cfg.visual.styles.includes(theme.file)}">
|
||||
@contextmenu="contextMenu($event, theme)"
|
||||
class="list-group-item list-group-item-dark"
|
||||
:class="{'applied': $root.cfg.visual.styles.includes(theme.file)}">
|
||||
|
||||
<b-row>
|
||||
<b-col class="themeLabel">{{theme.name}}</b-col>
|
||||
|
@ -51,33 +51,34 @@
|
|||
<button class="themeContextMenu codicon codicon-package"></button>
|
||||
</b-col>
|
||||
<b-col sm="auto">
|
||||
<button @click.stop="contextMenu($event, theme)" class="themeContextMenu codicon codicon-list-unordered"></button>
|
||||
<button @click.stop="contextMenu($event, theme)"
|
||||
class="themeContextMenu codicon codicon-list-unordered"></button>
|
||||
</b-col>
|
||||
</template>
|
||||
|
||||
</b-row>
|
||||
</li>
|
||||
<li @click="addStyle(packEntry.file)"
|
||||
@contextmenu="contextMenu($event, theme)"
|
||||
class="list-group-item list-group-item-dark addon"
|
||||
v-for="packEntry in theme.pack"
|
||||
:class="{'applied': $root.cfg.visual.styles.includes(packEntry.file)}"
|
||||
v-if="theme.pack">
|
||||
@contextmenu="contextMenu($event, theme)"
|
||||
class="list-group-item list-group-item-dark addon"
|
||||
v-for="packEntry in theme.pack"
|
||||
:class="{'applied': $root.cfg.visual.styles.includes(packEntry.file)}"
|
||||
v-if="theme.pack">
|
||||
|
||||
<b-row>
|
||||
<b-col class="themeLabel">{{packEntry.name}}</b-col>
|
||||
<template v-if="$root.cfg.visual.styles.includes(packEntry.file)">
|
||||
<b-col sm="auto">
|
||||
<button class="themeContextMenu codicon codicon-check"></button>
|
||||
</b-col>
|
||||
</template>
|
||||
<template v-else>
|
||||
<b-col sm="auto">
|
||||
<button class="themeContextMenu codicon codicon-diff-added"></button>
|
||||
</b-col>
|
||||
</template>
|
||||
</b-row>
|
||||
</li>
|
||||
<b-row>
|
||||
<b-col class="themeLabel">{{packEntry.name}}</b-col>
|
||||
<template v-if="$root.cfg.visual.styles.includes(packEntry.file)">
|
||||
<b-col sm="auto">
|
||||
<button class="themeContextMenu codicon codicon-check"></button>
|
||||
</b-col>
|
||||
</template>
|
||||
<template v-else>
|
||||
<b-col sm="auto">
|
||||
<button class="themeContextMenu codicon codicon-diff-added"></button>
|
||||
</b-col>
|
||||
</template>
|
||||
</b-row>
|
||||
</li>
|
||||
</template>
|
||||
</ul>
|
||||
</div>
|
||||
|
@ -86,17 +87,17 @@
|
|||
<div class="repo-header">
|
||||
<h4>{{ $root.getLz("settings.option.visual.theme.github.applied") }} </h4>
|
||||
</div>
|
||||
<stylestack-editor ref="stackEditor" v-if="themes.length != 0" :themes="themes"/>
|
||||
<stylestack-editor ref="stackEditor" v-if="themes.length != 0" :themes="themes" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script>
|
||||
// do not translate
|
||||
Vue.component('stylestack-editor', {
|
||||
/*html*/
|
||||
template: `
|
||||
// do not translate
|
||||
Vue.component('stylestack-editor', {
|
||||
/*html*/
|
||||
template: `
|
||||
<div class="stylestack-editor" >
|
||||
<draggable class="list-group" v-model="$root.cfg.visual.styles" @end="$root.reloadStyles()">
|
||||
<b-list-group-item variant="dark" v-for="theme in $root.cfg.visual.styles" :key="theme">
|
||||
|
@ -113,255 +114,255 @@
|
|||
</draggable>
|
||||
</div>
|
||||
`,
|
||||
props: {
|
||||
themes: {
|
||||
type: Array,
|
||||
default: [],
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data: function () {
|
||||
return {
|
||||
selected: null,
|
||||
newTheme: null,
|
||||
themeList: []
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
console.log(this.themes)
|
||||
this.themeList = [...this.themes]
|
||||
props: {
|
||||
themes: {
|
||||
type: Array,
|
||||
default: [],
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data: function() {
|
||||
return {
|
||||
selected: null,
|
||||
newTheme: null,
|
||||
themeList: []
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
console.log(this.themes)
|
||||
this.themeList = [...this.themes]
|
||||
|
||||
this.themeList.forEach(theme => {
|
||||
if (theme.pack) {
|
||||
theme.pack.forEach(packEntry => {
|
||||
packEntry.file = theme.file.replace('index.less', '') + packEntry.file
|
||||
this.themeList.push(packEntry)
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
gitHubExplore() {
|
||||
this.$root.openSettingsPage("github-themes")
|
||||
},
|
||||
getThemeName(filename) {
|
||||
try {
|
||||
return this.themeList.find(theme => theme.file === filename).name;
|
||||
} catch (e) {
|
||||
return filename;
|
||||
}
|
||||
},
|
||||
moveUp() {
|
||||
const styles = this.$root.cfg.visual.styles
|
||||
const index = styles.indexOf(this.selected)
|
||||
if (index > 0) {
|
||||
styles.splice(index, 1)
|
||||
styles.splice(index - 1, 0, this.selected)
|
||||
}
|
||||
this.$root.reloadStyles()
|
||||
},
|
||||
moveDown() {
|
||||
const styles = this.$root.cfg.visual.styles
|
||||
const index = styles.indexOf(this.selected)
|
||||
if (index < styles.length - 1) {
|
||||
styles.splice(index, 1)
|
||||
styles.splice(index + 1, 0, this.selected)
|
||||
}
|
||||
this.$root.reloadStyles()
|
||||
},
|
||||
remove(style) {
|
||||
const styles = this.$root.cfg.visual.styles
|
||||
const index = styles.indexOf(style)
|
||||
styles.splice(index, 1)
|
||||
this.$root.reloadStyles()
|
||||
},
|
||||
addStyle(style) {
|
||||
const styles = this.$root.cfg.visual.styles
|
||||
styles.push(style)
|
||||
this.$root.reloadStyles()
|
||||
}
|
||||
this.themeList.forEach(theme => {
|
||||
if (theme.pack) {
|
||||
theme.pack.forEach(packEntry => {
|
||||
packEntry.file = theme.file.replace('index.less', '') + packEntry.file
|
||||
this.themeList.push(packEntry)
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
gitHubExplore() {
|
||||
this.$root.openSettingsPage("github-themes")
|
||||
},
|
||||
getThemeName(filename) {
|
||||
try {
|
||||
return this.themeList.find(theme => theme.file === filename).name;
|
||||
} catch (e) {
|
||||
return filename;
|
||||
}
|
||||
},
|
||||
moveUp() {
|
||||
const styles = this.$root.cfg.visual.styles
|
||||
const index = styles.indexOf(this.selected)
|
||||
if (index > 0) {
|
||||
styles.splice(index, 1)
|
||||
styles.splice(index - 1, 0, this.selected)
|
||||
}
|
||||
this.$root.reloadStyles()
|
||||
},
|
||||
moveDown() {
|
||||
const styles = this.$root.cfg.visual.styles
|
||||
const index = styles.indexOf(this.selected)
|
||||
if (index < styles.length - 1) {
|
||||
styles.splice(index, 1)
|
||||
styles.splice(index + 1, 0, this.selected)
|
||||
}
|
||||
this.$root.reloadStyles()
|
||||
},
|
||||
remove(style) {
|
||||
const styles = this.$root.cfg.visual.styles
|
||||
const index = styles.indexOf(style)
|
||||
styles.splice(index, 1)
|
||||
this.$root.reloadStyles()
|
||||
},
|
||||
addStyle(style) {
|
||||
const styles = this.$root.cfg.visual.styles
|
||||
styles.push(style)
|
||||
this.$root.reloadStyles()
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<script>
|
||||
Vue.component('installed-themes', {
|
||||
template: "#installed-themes",
|
||||
props: [],
|
||||
data: function () {
|
||||
return {
|
||||
repos: [],
|
||||
openRepo: {
|
||||
id: -1,
|
||||
name: '',
|
||||
description: '',
|
||||
html_url: '',
|
||||
stargazers_count: 0,
|
||||
owner: {
|
||||
avatar_url: ''
|
||||
},
|
||||
readme: ""
|
||||
},
|
||||
themesInstalled: [],
|
||||
themes: []
|
||||
}
|
||||
Vue.component('installed-themes', {
|
||||
template: "#installed-themes",
|
||||
props: [],
|
||||
data: function() {
|
||||
return {
|
||||
repos: [],
|
||||
openRepo: {
|
||||
id: -1,
|
||||
name: '',
|
||||
description: '',
|
||||
html_url: '',
|
||||
stargazers_count: 0,
|
||||
owner: {
|
||||
avatar_url: ''
|
||||
},
|
||||
readme: ""
|
||||
},
|
||||
mounted() {
|
||||
this.getThemesList();
|
||||
},
|
||||
methods: {
|
||||
getThemesList() {
|
||||
let self = this
|
||||
let themes = ipcRenderer.sendSync("get-themes")
|
||||
themes.unshift({
|
||||
name: "Acrylic Grain",
|
||||
file: "grain.less"
|
||||
})
|
||||
themes.unshift({
|
||||
name: "Sweetener",
|
||||
file: "sweetener.less"
|
||||
})
|
||||
themes.unshift({
|
||||
name: "Reduce Visuals",
|
||||
file: "reduce_visuals.less"
|
||||
})
|
||||
// themes.unshift({
|
||||
// name: "Inline Drawer",
|
||||
// file: "inline_drawer.less"
|
||||
// })
|
||||
themes.unshift({
|
||||
name: "Dark",
|
||||
file: "dark.less"
|
||||
})
|
||||
this.themes = themes
|
||||
},
|
||||
contextMenu(event, theme) {
|
||||
let self = this
|
||||
let menu = {
|
||||
items: {
|
||||
"uninstall": {
|
||||
name: app.getLz("settings.option.visual.theme.uninstall"),
|
||||
disabled: true,
|
||||
action: () => {
|
||||
app.confirm(app.stringTemplateParser(app.getLz("settings.prompt.visual.theme.uninstallTheme"), {
|
||||
theme: theme.name ?? theme.file
|
||||
}), (res) => {
|
||||
if (res) {
|
||||
console.debug(theme)
|
||||
ipcRenderer.once("theme-uninstalled", (event, args) => {
|
||||
console.debug(event, args)
|
||||
self.getThemesList()
|
||||
})
|
||||
ipcRenderer.invoke("uninstall-theme", theme.path)
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
},
|
||||
"viewInfo": {
|
||||
name: app.getLz("settings.option.visual.theme.viewInfo"),
|
||||
disabled: true,
|
||||
action: () => {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (theme.path) {
|
||||
menu.items.uninstall.disabled = false
|
||||
}
|
||||
this.$root.showMenuPanel(menu, event)
|
||||
},
|
||||
openThemesFolder() {
|
||||
ipcRenderer.invoke("open-path", "themes")
|
||||
},
|
||||
getInstalledThemes() {
|
||||
let self = this
|
||||
const themes = ipcRenderer.sendSync("get-themes")
|
||||
// for each theme, get the github_repo property and push it to the themesInstalled array, if not blank
|
||||
themes.forEach(theme => {
|
||||
if (theme.github_repo !== "" && typeof theme.commit != "") {
|
||||
self.themesInstalled.push(theme.github_repo.toLowerCase())
|
||||
}
|
||||
})
|
||||
},
|
||||
addStyle(filename) {
|
||||
this.$refs.stackEditor.addStyle(filename)
|
||||
},
|
||||
showRepo(repo) {
|
||||
const self = this
|
||||
const readmeUrl = `https://raw.githubusercontent.com/${repo.full_name}/main/README.md`;
|
||||
var requestOptions = {
|
||||
method: 'GET',
|
||||
redirect: 'follow'
|
||||
};
|
||||
|
||||
fetch(readmeUrl, requestOptions)
|
||||
.then(response => response.text())
|
||||
.then(result => {
|
||||
self.openRepo = repo
|
||||
self.openRepo.readme = self.convertReadMe(result);
|
||||
themesInstalled: [],
|
||||
themes: []
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.getThemesList();
|
||||
},
|
||||
methods: {
|
||||
getThemesList() {
|
||||
let self = this
|
||||
let themes = ipcRenderer.sendSync("get-themes")
|
||||
themes.unshift({
|
||||
name: "Acrylic Grain",
|
||||
file: "grain.less"
|
||||
})
|
||||
themes.unshift({
|
||||
name: "Sweetener",
|
||||
file: "sweetener.less"
|
||||
})
|
||||
themes.unshift({
|
||||
name: "Reduce Visuals",
|
||||
file: "reduce_visuals.less"
|
||||
})
|
||||
// themes.unshift({
|
||||
// name: "Inline Drawer",
|
||||
// file: "inline_drawer.less"
|
||||
// })
|
||||
themes.unshift({
|
||||
name: "Dark",
|
||||
file: "dark.less"
|
||||
})
|
||||
this.themes = themes
|
||||
},
|
||||
contextMenu(event, theme) {
|
||||
let self = this
|
||||
let menu = {
|
||||
items: {
|
||||
"uninstall": {
|
||||
name: app.getLz("settings.option.visual.theme.uninstall"),
|
||||
disabled: true,
|
||||
action: () => {
|
||||
app.confirm(app.stringTemplateParser(app.getLz("settings.prompt.visual.theme.uninstallTheme"), {
|
||||
theme: theme.name ?? theme.file
|
||||
}), (res) => {
|
||||
if (res) {
|
||||
console.debug(theme)
|
||||
ipcRenderer.once("theme-uninstalled", (event, args) => {
|
||||
console.debug(event, args)
|
||||
self.getThemesList()
|
||||
})
|
||||
.catch(error => {
|
||||
self.openRepo = repo
|
||||
self.openRepo.readme = `This repository doesn't have a README.md file.`;
|
||||
console.log('error', error)
|
||||
});
|
||||
},
|
||||
convertReadMe(text) {
|
||||
return marked.parse(text)
|
||||
},
|
||||
installThemeRepo(repo) {
|
||||
let self = this
|
||||
let msg = app.stringTemplateParser(app.getLz('settings.option.visual.theme.github.install.confirm'), {
|
||||
repo: repo.full_name
|
||||
});
|
||||
app.confirm(msg, (res) => {
|
||||
if (res) {
|
||||
ipcRenderer.once("theme-installed", (event, arg) => {
|
||||
if (arg.success) {
|
||||
self.themes = ipcRenderer.sendSync("get-themes")
|
||||
self.getInstalledThemes()
|
||||
notyf.success(app.getLz('settings.notyf.visual.theme.install.success'));
|
||||
} else {
|
||||
notyf.error(app.getLz('settings.notyf.visual.theme.install.error'));
|
||||
}
|
||||
});
|
||||
ipcRenderer.invoke("get-github-theme", repo.html_url)
|
||||
}
|
||||
ipcRenderer.invoke("uninstall-theme", theme.path)
|
||||
}
|
||||
})
|
||||
},
|
||||
installThemeURL() {
|
||||
let self = this
|
||||
app.prompt(app.getLz('settings.prompt.visual.theme.github.URL'), (result) => {
|
||||
if (result) {
|
||||
ipcRenderer.once("theme-installed", (event, arg) => {
|
||||
if (arg.success) {
|
||||
self.themes = ipcRenderer.sendSync("get-themes")
|
||||
notyf.success(app.getLz('settings.notyf.visual.theme.install.success'));
|
||||
} else {
|
||||
notyf.error(app.getLz('settings.notyf.visual.theme.install.error'));
|
||||
}
|
||||
});
|
||||
ipcRenderer.invoke("get-github-theme", result)
|
||||
}
|
||||
});
|
||||
},
|
||||
getRepos() {
|
||||
let self = this
|
||||
var requestOptions = {
|
||||
method: 'GET',
|
||||
redirect: 'follow'
|
||||
};
|
||||
|
||||
fetch("https://api.github.com/search/repositories?q=topic:cidermusictheme fork:true", requestOptions)
|
||||
.then(response => response.text())
|
||||
.then(result => {
|
||||
let items = JSON.parse(result).items
|
||||
self.repos = items
|
||||
})
|
||||
.catch(error => console.log('error', error));
|
||||
}
|
||||
},
|
||||
"viewInfo": {
|
||||
name: app.getLz("settings.option.visual.theme.viewInfo"),
|
||||
disabled: true,
|
||||
action: () => {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
if (theme.path) {
|
||||
menu.items.uninstall.disabled = false
|
||||
}
|
||||
this.$root.showMenuPanel(menu, event)
|
||||
},
|
||||
openThemesFolder() {
|
||||
ipcRenderer.invoke("open-path", "themes")
|
||||
},
|
||||
getInstalledThemes() {
|
||||
let self = this
|
||||
const themes = ipcRenderer.sendSync("get-themes")
|
||||
// for each theme, get the github_repo property and push it to the themesInstalled array, if not blank
|
||||
themes.forEach(theme => {
|
||||
if (theme.github_repo !== "" && typeof theme.commit != "") {
|
||||
self.themesInstalled.push(theme.github_repo.toLowerCase())
|
||||
}
|
||||
})
|
||||
},
|
||||
addStyle(filename) {
|
||||
this.$refs.stackEditor.addStyle(filename)
|
||||
},
|
||||
showRepo(repo) {
|
||||
const self = this
|
||||
const readmeUrl = `https://raw.githubusercontent.com/${repo.full_name}/main/README.md`;
|
||||
var requestOptions = {
|
||||
method: 'GET',
|
||||
redirect: 'follow'
|
||||
};
|
||||
|
||||
fetch(readmeUrl, requestOptions)
|
||||
.then(response => response.text())
|
||||
.then(result => {
|
||||
self.openRepo = repo
|
||||
self.openRepo.readme = self.convertReadMe(result);
|
||||
})
|
||||
.catch(error => {
|
||||
self.openRepo = repo
|
||||
self.openRepo.readme = `This repository doesn't have a README.md file.`;
|
||||
console.log('error', error)
|
||||
});
|
||||
},
|
||||
convertReadMe(text) {
|
||||
return marked.parse(text)
|
||||
},
|
||||
installThemeRepo(repo) {
|
||||
let self = this
|
||||
let msg = app.stringTemplateParser(app.getLz('settings.option.visual.theme.github.install.confirm'), {
|
||||
repo: repo.full_name
|
||||
});
|
||||
app.confirm(msg, (res) => {
|
||||
if (res) {
|
||||
ipcRenderer.once("theme-installed", (event, arg) => {
|
||||
if (arg.success) {
|
||||
self.themes = ipcRenderer.sendSync("get-themes")
|
||||
self.getInstalledThemes()
|
||||
notyf.success(app.getLz('settings.notyf.visual.theme.install.success'));
|
||||
} else {
|
||||
notyf.error(app.getLz('settings.notyf.visual.theme.install.error'));
|
||||
}
|
||||
});
|
||||
ipcRenderer.invoke("get-github-theme", repo.html_url)
|
||||
}
|
||||
})
|
||||
},
|
||||
installThemeURL() {
|
||||
let self = this
|
||||
app.prompt(app.getLz('settings.prompt.visual.theme.github.URL'), (result) => {
|
||||
if (result) {
|
||||
ipcRenderer.once("theme-installed", (event, arg) => {
|
||||
if (arg.success) {
|
||||
self.themes = ipcRenderer.sendSync("get-themes")
|
||||
notyf.success(app.getLz('settings.notyf.visual.theme.install.success'));
|
||||
} else {
|
||||
notyf.error(app.getLz('settings.notyf.visual.theme.install.error'));
|
||||
}
|
||||
});
|
||||
ipcRenderer.invoke("get-github-theme", result)
|
||||
}
|
||||
});
|
||||
},
|
||||
getRepos() {
|
||||
let self = this
|
||||
var requestOptions = {
|
||||
method: 'GET',
|
||||
redirect: 'follow'
|
||||
};
|
||||
|
||||
fetch("https://api.github.com/search/repositories?q=topic:cidermusictheme fork:true", requestOptions)
|
||||
.then(response => response.text())
|
||||
.then(result => {
|
||||
let items = JSON.parse(result).items
|
||||
self.repos = items
|
||||
})
|
||||
.catch(error => console.log('error', error));
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
<b-tab>
|
||||
<template #title>
|
||||
<div>
|
||||
<svg-icon url="./assets/settings.svg" classes="svg-md" name="settings-general"/>
|
||||
<svg-icon url="./assets/settings.svg" classes="svg-md" name="settings-general" />
|
||||
</div>
|
||||
<div>
|
||||
{{ $root.getLz('settings.header.general') }}
|
||||
|
@ -61,7 +61,7 @@
|
|||
<label>
|
||||
<input type="checkbox" v-model="$root.cfg.general.privateEnabled"
|
||||
v-on:change="$root.mk.privateEnabled = $root.cfg.general.privateEnabled"
|
||||
switch/>
|
||||
switch />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -71,7 +71,7 @@
|
|||
</div>
|
||||
<div class="md-option-segment md-option-segment_auto">
|
||||
<label>
|
||||
<input type="checkbox" v-model="app.cfg.general.onStartup.enabled" switch/>
|
||||
<input type="checkbox" v-model="app.cfg.general.onStartup.enabled" switch />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -81,7 +81,7 @@
|
|||
</div>
|
||||
<div class="md-option-segment md-option-segment_auto">
|
||||
<label>
|
||||
<input type="checkbox" v-model="app.cfg.general.onStartup.hidden" switch/>
|
||||
<input type="checkbox" v-model="app.cfg.general.onStartup.hidden" switch />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -163,7 +163,7 @@
|
|||
<label>
|
||||
<input type="checkbox"
|
||||
v-model="app.cfg.general.sidebarItems.recentlyAdded"
|
||||
switch/>
|
||||
switch />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -175,7 +175,7 @@
|
|||
<label>
|
||||
<input type="checkbox"
|
||||
v-model="app.cfg.general.sidebarItems.songs"
|
||||
switch/>
|
||||
switch />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -187,7 +187,7 @@
|
|||
<label>
|
||||
<input type="checkbox"
|
||||
v-model="app.cfg.general.sidebarItems.albums"
|
||||
switch/>
|
||||
switch />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -199,7 +199,7 @@
|
|||
<label>
|
||||
<input type="checkbox"
|
||||
v-model="app.cfg.general.sidebarItems.artists"
|
||||
switch/>
|
||||
switch />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -211,7 +211,7 @@
|
|||
<label>
|
||||
<input type="checkbox"
|
||||
v-model="app.cfg.general.sidebarItems.videos"
|
||||
switch/>
|
||||
switch />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -223,7 +223,7 @@
|
|||
<label>
|
||||
<input type="checkbox"
|
||||
v-model="app.cfg.general.sidebarItems.podcasts"
|
||||
switch/>
|
||||
switch />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -247,7 +247,7 @@
|
|||
<div class="md-option-segment md-option-segment_auto">
|
||||
<label>
|
||||
<input type="checkbox" v-model="app.cfg.general.themeUpdateNotification"
|
||||
switch/>
|
||||
switch />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -258,7 +258,7 @@
|
|||
<div class="md-option-segment md-option-segment_auto">
|
||||
<label>
|
||||
<input type="checkbox" v-model="app.cfg.general.showLovedTracksInline"
|
||||
switch/>
|
||||
switch />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -279,7 +279,7 @@
|
|||
<b-tab>
|
||||
<template #title>
|
||||
<div>
|
||||
<svg-icon url="./assets/feather/headphones.svg" classes="svg-md" name="settings-audio"/>
|
||||
<svg-icon url="./assets/feather/headphones.svg" classes="svg-md" name="settings-audio" />
|
||||
</div>
|
||||
<div>
|
||||
{{ $root.getLz('settings.header.audio') }}
|
||||
|
@ -343,7 +343,7 @@
|
|||
<label>
|
||||
<input type="checkbox" v-model="app.cfg.audio.seamless_audio"
|
||||
v-on:change="app.mk._bag.features['seamless-audio-transitions'] = app.cfg.audio.seamless_audio"
|
||||
switch/>
|
||||
switch />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -372,7 +372,7 @@
|
|||
<input type="checkbox" v-model="app.cfg.audio.normalization"
|
||||
v-on:change="toggleNormalization"
|
||||
:disabled="app.cfg.audio.maikiwiAudio.spatial === true || app.cfg.audio.maikiwiAudio.ciderPPE === true || app.cfg.audio.maikiwiAudio.atmosphereRealizer1 === true || app.cfg.audio.maikiwiAudio.atmosphereRealizer2 === true"
|
||||
switch/>
|
||||
switch />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -385,7 +385,7 @@
|
|||
</div>
|
||||
<div class="md-option-segment md-option-segment_auto">
|
||||
<label>
|
||||
<input type="checkbox" v-model="app.cfg.audio.dBSPL" switch/>
|
||||
<input type="checkbox" v-model="app.cfg.audio.dBSPL" switch />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -397,7 +397,7 @@
|
|||
</div>
|
||||
<div class="md-option-segment md-option-segment_auto">
|
||||
<label>
|
||||
<input type="number" v-model="app.cfg.audio.dBSPLcalibration"/>
|
||||
<input type="number" v-model="app.cfg.audio.dBSPLcalibration" />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -408,33 +408,33 @@
|
|||
<b-tab>
|
||||
<template #title>
|
||||
<div>
|
||||
<svg-icon url="./assets/feather/zap.svg" classes="svg-md" name="settings-audiolabs"/>
|
||||
<svg-icon url="./assets/feather/zap.svg" classes="svg-md" name="settings-audiolabs" />
|
||||
</div>
|
||||
<div>
|
||||
{{ $root.getLz('settings.option.audio.audioLab') }}
|
||||
</div>
|
||||
</template>
|
||||
<div class="settings-tab-content">
|
||||
<audiolabs-page/>
|
||||
<audiolabs-page />
|
||||
</div>
|
||||
</b-tab>
|
||||
<b-tab>
|
||||
<template #title>
|
||||
<div>
|
||||
<svg-icon url="./assets/feather/style.svg" classes="svg-md" name="settings-styles"/>
|
||||
<svg-icon url="./assets/feather/style.svg" classes="svg-md" name="settings-styles" />
|
||||
</div>
|
||||
<div>
|
||||
{{ $root.getLz('settings.header.visual.styles') }}
|
||||
</div>
|
||||
</template>
|
||||
<div class="settings-tab-content">
|
||||
<installed-themes/>
|
||||
<installed-themes />
|
||||
</div>
|
||||
</b-tab>
|
||||
<b-tab>
|
||||
<template #title>
|
||||
<div>
|
||||
<svg-icon url="./assets/feather/pen-tool.svg" classes="svg-md" name="settings-visual"/>
|
||||
<svg-icon url="./assets/feather/pen-tool.svg" classes="svg-md" name="settings-visual" />
|
||||
</div>
|
||||
<div>
|
||||
{{ $root.getLz('settings.header.visual') }}
|
||||
|
@ -504,7 +504,7 @@
|
|||
{{$root.getLz('settings.option.visual.windowColor')}}
|
||||
</div>
|
||||
<div class="md-option-segment_auto">
|
||||
<input type="color" v-model="app.cfg.visual.windowColor"/>
|
||||
<input type="color" v-model="app.cfg.visual.windowColor" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="md-option-line">
|
||||
|
@ -513,7 +513,7 @@
|
|||
</div>
|
||||
<div class="md-option-segment_auto">
|
||||
<input type="checkbox" v-model="app.cfg.visual.customAccentColor"
|
||||
:disabled="app.cfg.visual.purplePodcastPlaybackBar" switch/>
|
||||
:disabled="app.cfg.visual.purplePodcastPlaybackBar" switch />
|
||||
</div>
|
||||
</div>
|
||||
<div class="md-option-line child" v-if="app.cfg.visual.customAccentColor">
|
||||
|
@ -521,7 +521,7 @@
|
|||
{{$root.getLz('settings.option.visual.accentColor')}}
|
||||
</div>
|
||||
<div class="md-option-segment_auto">
|
||||
<input type="color" v-model="app.cfg.visual.accentColor"/>
|
||||
<input type="color" v-model="app.cfg.visual.accentColor" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="md-option-line">
|
||||
|
@ -530,7 +530,7 @@
|
|||
</div>
|
||||
<div class="md-option-segment_auto">
|
||||
<input type="checkbox" v-model="app.cfg.visual.purplePodcastPlaybackBar"
|
||||
:disabled="app.cfg.visual.customAccentColor" switch/>
|
||||
:disabled="app.cfg.visual.customAccentColor" switch />
|
||||
</div>
|
||||
</div>
|
||||
<div class="md-option-line">
|
||||
|
@ -538,7 +538,7 @@
|
|||
{{$root.getLz('settings.option.visual.compactArtistHeader')}}
|
||||
</div>
|
||||
<div class="md-option-segment_auto">
|
||||
<input type="checkbox" v-model="app.cfg.visual.compactArtistHeader" switch/>
|
||||
<input type="checkbox" v-model="app.cfg.visual.compactArtistHeader" switch />
|
||||
</div>
|
||||
</div>
|
||||
<div class="md-option-line">
|
||||
|
@ -569,7 +569,7 @@
|
|||
<div class="md-option-segment md-option-segment_auto">
|
||||
<label>
|
||||
<input type="checkbox" v-model="app.cfg.visual.showuserinfo"
|
||||
v-on:change="toggleUserInfo" switch/>
|
||||
v-on:change="toggleUserInfo" switch />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -604,7 +604,7 @@
|
|||
</div>
|
||||
<div class="md-option-segment md-option-segment_auto">
|
||||
<label>
|
||||
<input type="checkbox" v-model="app.cfg.general.close_button_hide" switch/>
|
||||
<input type="checkbox" v-model="app.cfg.general.close_button_hide" switch />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -616,7 +616,7 @@
|
|||
<div class="md-option-segment md-option-segment_auto">
|
||||
<label>
|
||||
<input type="checkbox" v-model="app.cfg.visual.nativeTitleBar" switch
|
||||
@change="promptForRelaunch()"/>
|
||||
@change="promptForRelaunch()" />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -697,7 +697,8 @@
|
|||
</div>
|
||||
<div class="md-option-segment md-option-segment_auto">
|
||||
<label>
|
||||
<input type="checkbox" switch v-model="app.cfg.visual.bg_artwork_rotation"/>
|
||||
<input type="checkbox" switch
|
||||
v-model="app.cfg.visual.bg_artwork_rotation" />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -708,20 +709,20 @@
|
|||
<b-tab>
|
||||
<template #title>
|
||||
<div>
|
||||
<svg-icon url="./assets/feather/plugins.svg" classes="svg-md" name="settings-plugins"/>
|
||||
<svg-icon url="./assets/feather/plugins.svg" classes="svg-md" name="settings-plugins" />
|
||||
</div>
|
||||
<div>
|
||||
{{ $root.getLz('term.plugins') }}
|
||||
</div>
|
||||
</template>
|
||||
<div class="settings-tab-content">
|
||||
<plugins-github/>
|
||||
<plugins-github />
|
||||
</div>
|
||||
</b-tab>
|
||||
<b-tab>
|
||||
<template #title>
|
||||
<div>
|
||||
<svg-icon url="./assets/feather/mic.svg" classes="svg-md" name="settings-lyrics"/>
|
||||
<svg-icon url="./assets/feather/mic.svg" classes="svg-md" name="settings-lyrics" />
|
||||
</div>
|
||||
<div>
|
||||
{{ $root.getLz('settings.header.lyrics') }}
|
||||
|
@ -740,7 +741,7 @@
|
|||
</div>
|
||||
<div class="md-option-segment md-option-segment_auto">
|
||||
<label>
|
||||
<input type="checkbox" v-model="app.cfg.lyrics.enable_mxm" switch/>
|
||||
<input type="checkbox" v-model="app.cfg.lyrics.enable_mxm" switch />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -750,7 +751,7 @@
|
|||
</div>
|
||||
<div class="md-option-segment md-option-segment_auto">
|
||||
<label>
|
||||
<input type="checkbox" v-model="app.cfg.lyrics.mxm_karaoke" switch/>
|
||||
<input type="checkbox" v-model="app.cfg.lyrics.mxm_karaoke" switch />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -844,7 +845,7 @@
|
|||
</div>
|
||||
<div class="md-option-segment md-option-segment_auto">
|
||||
<label>
|
||||
<input type="checkbox" v-model="app.cfg.lyrics.enable_yt" switch/>
|
||||
<input type="checkbox" v-model="app.cfg.lyrics.enable_yt" switch />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -854,7 +855,7 @@
|
|||
</div>
|
||||
<div class="md-option-segment md-option-segment_auto">
|
||||
<label>
|
||||
<input type="checkbox" v-model="app.cfg.lyrics.enable_qq" switch/>
|
||||
<input type="checkbox" v-model="app.cfg.lyrics.enable_qq" switch />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -865,7 +866,7 @@
|
|||
<b-tab>
|
||||
<template #title>
|
||||
<div>
|
||||
<svg-icon url="./assets/feather/radio.svg" classes="svg-md" name="settings-connectivity"/>
|
||||
<svg-icon url="./assets/feather/radio.svg" classes="svg-md" name="settings-connectivity" />
|
||||
</div>
|
||||
<div>
|
||||
{{ $root.getLz('settings.header.connectivity') }}
|
||||
|
@ -886,7 +887,7 @@
|
|||
<div class="md-option-segment md-option-segment_auto">
|
||||
<label>
|
||||
<input type="checkbox" v-model="app.cfg.general.playbackNotifications"
|
||||
switch/>
|
||||
switch />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -899,7 +900,7 @@
|
|||
<div class="md-option-segment md-option-segment_auto">
|
||||
<label>
|
||||
<input type="checkbox" v-model="app.cfg.connectivity.discord_rpc.enabled"
|
||||
switch/>
|
||||
switch />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -926,7 +927,7 @@
|
|||
<div class="md-option-segment md-option-segment_auto">
|
||||
<label>
|
||||
<input type="checkbox"
|
||||
v-model="app.cfg.connectivity.discord_rpc.clear_on_pause" switch/>
|
||||
v-model="app.cfg.connectivity.discord_rpc.clear_on_pause" switch />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -938,7 +939,7 @@
|
|||
<div class="md-option-segment md-option-segment_auto">
|
||||
<label>
|
||||
<input type="checkbox"
|
||||
v-model="app.cfg.connectivity.discord_rpc.hide_buttons" switch/>
|
||||
v-model="app.cfg.connectivity.discord_rpc.hide_buttons" switch />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -950,14 +951,14 @@
|
|||
<div class="md-option-segment md-option-segment_auto">
|
||||
<label>
|
||||
<input type="checkbox"
|
||||
v-model="app.cfg.connectivity.discord_rpc.hide_timestamp" switch/>
|
||||
v-model="app.cfg.connectivity.discord_rpc.hide_timestamp" switch />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="md-option-line" v-show="app.cfg.connectivity.discord_rpc.enabled != false">
|
||||
<div class="md-option-segment">
|
||||
{{$root.getLz('settings.option.connectivity.discordRPC.detailsFormat')}}<br/>
|
||||
{{$root.getLz('settings.option.connectivity.discordRPC.detailsFormat')}}<br />
|
||||
<small>{{$root.getLz('term.variables')}}: {artist}, {composer}, {title},
|
||||
{album},
|
||||
{trackNumber}</small>
|
||||
|
@ -965,7 +966,7 @@
|
|||
<div class="md-option-segment md-option-segment_auto">
|
||||
<label>
|
||||
<input type="text"
|
||||
v-model="app.cfg.connectivity.discord_rpc.details_format"/>
|
||||
v-model="app.cfg.connectivity.discord_rpc.details_format" />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -979,7 +980,8 @@
|
|||
</div>
|
||||
<div class="md-option-segment md-option-segment_auto">
|
||||
<label>
|
||||
<input type="text" v-model="app.cfg.connectivity.discord_rpc.state_format"/>
|
||||
<input type="text"
|
||||
v-model="app.cfg.connectivity.discord_rpc.state_format" />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1018,9 +1020,9 @@
|
|||
<div class="md-option-segment md-option-segment_auto">
|
||||
<label>
|
||||
<form @submit.prevent="submitToken">
|
||||
<input type="text" autofocus id="lfmToken"/>
|
||||
<input type="text" autofocus id="lfmToken" />
|
||||
<input type="submit" class="md-btn"
|
||||
@value="$root.getLz('action.submit')"/>
|
||||
@value="$root.getLz('action.submit')" />
|
||||
</form>
|
||||
</label>
|
||||
</div>
|
||||
|
@ -1032,7 +1034,7 @@
|
|||
<div class="md-option-segment md-option-segment_auto">
|
||||
<label>
|
||||
<input type="number" min="50" max="100"
|
||||
v-model="app.cfg.connectivity.lastfm.scrobble_after"/>
|
||||
v-model="app.cfg.connectivity.lastfm.scrobble_after" />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1044,7 +1046,7 @@
|
|||
<div class="md-option-segment md-option-segment_auto">
|
||||
<label>
|
||||
<input type="checkbox" v-model="app.cfg.connectivity.lastfm.filter_loop"
|
||||
switch/>
|
||||
switch />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1055,7 +1057,7 @@
|
|||
<div class="md-option-segment md-option-segment_auto">
|
||||
<label>
|
||||
<input type="checkbox" v-model="app.cfg.connectivity.lastfm.remove_featured"
|
||||
switch/>
|
||||
switch />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1077,7 +1079,7 @@
|
|||
<b-tab>
|
||||
<template #title>
|
||||
<div>
|
||||
<svg-icon url="./assets/feather/hard-drive.svg" classes="svg-md" name="settings-advanced"/>
|
||||
<svg-icon url="./assets/feather/hard-drive.svg" classes="svg-md" name="settings-advanced" />
|
||||
</div>
|
||||
<div>
|
||||
{{$root.getLz('settings.header.advanced')}}
|
||||
|
@ -1118,7 +1120,7 @@
|
|||
</div>
|
||||
<div class="md-option-segment md-option-segment_auto">
|
||||
<label>
|
||||
<input type="checkbox" v-model="app.cfg.advanced.disableLogging" switch/>
|
||||
<input type="checkbox" v-model="app.cfg.advanced.disableLogging" switch />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1161,7 +1163,7 @@
|
|||
<input type="checkbox"
|
||||
v-model="app.cfg.advanced.experiments.includes('immersive-preview')"
|
||||
@click="app.cfg.advanced.experiments.includes('immersive-preview') ? removeExperiment('immersive-preview') : addExperiment('immersive-preview')"
|
||||
switch/>
|
||||
switch />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1177,7 +1179,7 @@
|
|||
<input type="checkbox"
|
||||
v-model="app.cfg.advanced.experiments.includes('unknown-sources')"
|
||||
@click="app.cfg.advanced.experiments.includes('unknown-sources') ? removeExperiment('unknown-sources') : addExperiment('unknown-sources')"
|
||||
switch/>
|
||||
switch />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1192,7 +1194,7 @@
|
|||
<input type="checkbox"
|
||||
v-model="app.cfg.advanced.experiments.includes('ampv3')"
|
||||
@click="app.cfg.advanced.experiments.includes('ampv3') ? removeExperiment('ampv3') : addExperiment('ampv3')"
|
||||
switch/>
|
||||
switch />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1206,7 +1208,7 @@
|
|||
<div class="md-option-segment md-option-segment_auto">
|
||||
<label>
|
||||
<input type="checkbox" v-model="app.cfg.advanced.playlistTrackMapping"
|
||||
switch/>
|
||||
switch />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1221,7 +1223,7 @@
|
|||
<input type="checkbox"
|
||||
v-model="app.cfg.advanced.experiments.includes('compactui')"
|
||||
@click="app.cfg.advanced.experiments.includes('compactui') ? removeExperiment('compactui') : addExperiment('compactui')"
|
||||
switch :disabled="!!app.getThemeDirective('forceUI')"/>
|
||||
switch :disabled="!!app.getThemeDirective('forceUI')" />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1235,7 +1237,7 @@
|
|||
<input type="checkbox" disabled
|
||||
v-model="app.cfg.advanced.experiments.includes('inline-playlists')"
|
||||
@click="app.cfg.advanced.experiments.includes('inline-playlists') ? removeExperiment('inline-playlists') : addExperiment('inline-playlists')"
|
||||
switch/>
|
||||
switch />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1248,7 +1250,7 @@
|
|||
<div class="md-option-segment md-option-segment_auto">
|
||||
<label>
|
||||
<input type="checkbox" v-model="app.cfg.visual.transparent" switch
|
||||
@change="promptForRelaunch()"/>
|
||||
@change="promptForRelaunch()" />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1280,14 +1282,14 @@
|
|||
<!--keybinds Settings -->
|
||||
<b-tab id="hid">
|
||||
<template>
|
||||
<keybinds-settings/>
|
||||
<keybinds-settings />
|
||||
</template>
|
||||
</b-tab>
|
||||
<!--keybinds-settings -->
|
||||
<!--Github-theme-settings -->
|
||||
<b-tab id="hid">
|
||||
<template>
|
||||
<themes-github/>
|
||||
<themes-github />
|
||||
</template>
|
||||
</b-tab>
|
||||
<!--Github-theme-settings -->
|
||||
|
@ -1383,164 +1385,164 @@
|
|||
</div>
|
||||
</script>
|
||||
<script>
|
||||
Vue.component("settings-window", {
|
||||
template: "#settings-window",
|
||||
data: function () {
|
||||
return {
|
||||
app: this.$root,
|
||||
themes: ipcRenderer.sendSync("get-themes"),
|
||||
tabIndex: 0,
|
||||
canChangeHash: false,
|
||||
lastfmConnecting: false
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
tabIndex: function (val) {
|
||||
if (this.canChangeHash) {
|
||||
// window.location.hash = `#settings/${val}`
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
sidebarVis() {
|
||||
const tabIndex = app.$store.state.pageState['settings'].currentTabIndex
|
||||
if (tabIndex == 3 || tabIndex == 5 || tabIndex == 10) {
|
||||
return true;
|
||||
}
|
||||
return false
|
||||
},
|
||||
close() {
|
||||
this.$root.modals.settings = false
|
||||
},
|
||||
windowBgStyleChange() {
|
||||
this.$root.getNowPlayingArtworkBG(undefined, true)
|
||||
if (this.$root.cfg.visual.window_background_style === "mica") {
|
||||
this.$root.spawnMica()
|
||||
}
|
||||
},
|
||||
reinstallWidevineCDM() {
|
||||
app.confirm(app.getLz("settings.option.experimental.reinstallwidevine.confirm"), (ok) => {
|
||||
if (ok) {
|
||||
ipcRenderer.invoke("reinstall-widevine-cdm");
|
||||
}
|
||||
})
|
||||
},
|
||||
gitHubExplore() {
|
||||
app.openSettingsPage("github-themes")
|
||||
},
|
||||
copyLogs() {
|
||||
ipcRenderer.send('fetch-log')
|
||||
notyf.success(app.getLz('term.share.success'));
|
||||
},
|
||||
openAppData() {
|
||||
ipcRenderer.send('open-appdata')
|
||||
},
|
||||
getLanguages: function () {
|
||||
let langs = this.$root.lzListing
|
||||
let categories = {
|
||||
"main": [],
|
||||
"fun": [],
|
||||
"unsorted": []
|
||||
}
|
||||
// sort by category if category is undefined or empty put it in "unsorted"
|
||||
for (let i = 0; i < langs.length; i++) {
|
||||
if (langs[i].category === undefined || langs[i].category === "") {
|
||||
categories.unsorted.push(langs[i])
|
||||
} else {
|
||||
categories[langs[i].category].push(langs[i])
|
||||
}
|
||||
}
|
||||
// return
|
||||
return categories
|
||||
},
|
||||
addExperiment(flag) {
|
||||
app.cfg.advanced.experiments.push(flag);
|
||||
},
|
||||
removeExperiment(flag) {
|
||||
app.cfg.advanced.experiments.splice(app.cfg.advanced.experiments.indexOf(flag), 1);
|
||||
},
|
||||
toggleNormalization: function () {
|
||||
if (app.cfg.audio.normalization) {
|
||||
CiderAudio.normalizerOn()
|
||||
} else {
|
||||
CiderAudio.normalizerOff()
|
||||
}
|
||||
},
|
||||
changeAudioQuality: function () {
|
||||
app.mk.bitrate = MusicKit.PlaybackBitrate[app.cfg.audio.quality];
|
||||
},
|
||||
toggleUserInfo: function () {
|
||||
app.chrome.hideUserInfo = !app.cfg.visual.showuserinfo
|
||||
},
|
||||
sendDataToMTT: function () {
|
||||
ipcRenderer.invoke('setStoreValue', 'general.close_behavior', app.cfg.general.close_behavior);
|
||||
// setStoreValue does not change plugin store values somehow
|
||||
ipcRenderer.invoke('update-store-mtt', app.cfg.general.close_behavior);
|
||||
},
|
||||
checkIfUpdateDisabled() {
|
||||
if (app.cfg.main.UPDATABLE) return;
|
||||
|
||||
let updateFields = document.getElementsByClassName('update-check');
|
||||
for (let i = 0; i < updateFields.length; i++) {
|
||||
updateFields[i].style = "opacity: 0.5; pointer-events: none;";
|
||||
updateFields[i].title = "Not available on this type of build";
|
||||
}
|
||||
|
||||
},
|
||||
promptForRelaunch() {
|
||||
app.confirm(app.getLz('action.relaunch.confirm'), function (result) {
|
||||
if (result) {
|
||||
ipcRenderer.send('relaunchApp', '');
|
||||
}
|
||||
});
|
||||
},
|
||||
authCC() {
|
||||
ipcRenderer.send('cc-auth')
|
||||
},
|
||||
logoutCC() {
|
||||
ipcRenderer.send('cc-logout')
|
||||
},
|
||||
reloadDiscordRPC() {
|
||||
ipcRenderer.send('reloadRPC')
|
||||
},
|
||||
lfmDisconnect() {
|
||||
this.$root.cfg.connectivity.lastfm.enabled = false;
|
||||
this.$root.cfg.connectivity.lastfm.secrets.username = "";
|
||||
this.$root.cfg.connectivity.lastfm.secrets.key = "";
|
||||
ipcRenderer.send('lastfm:disconnect');
|
||||
},
|
||||
async lfmAuthorize() {
|
||||
this.lastfmConnecting = true;
|
||||
window.open(await ipcRenderer.invoke('lastfm:url'));
|
||||
app.notyf.success(app.getLz('settings.notyf.connectivity.lastfmScrobble.connecting'));
|
||||
|
||||
/* Just a timeout for the button */
|
||||
setTimeout(() => {
|
||||
if (!this.$root.cfg.connectivity.lastfm.enabled) {
|
||||
app.notyf.error(app.getLz('settings.notyf.connectivity.lastfmScrobble.connectError'));
|
||||
console.warn('[lastfm:authorize] Last.fm authorization timed out.');
|
||||
this.lastfmConnecting = false;
|
||||
}
|
||||
}, 20000);
|
||||
|
||||
ipcRenderer.once('lastfm:authenticated', (_e, session) => {
|
||||
this.$root.cfg.connectivity.lastfm.secrets.username = session.username
|
||||
this.$root.cfg.connectivity.lastfm.secrets.key = session.key
|
||||
this.$root.cfg.connectivity.lastfm.enabled = true
|
||||
this.lastfmConnecting = false;
|
||||
app.notyf.success(app.getLz('settings.notyf.connectivity.lastfmScrobble.connectSuccess'));
|
||||
})
|
||||
},
|
||||
filterChange(e) {
|
||||
this.$root.cfg.connectivity.lastfm.filter_types[e.target.value] = e.target.checked;
|
||||
},
|
||||
submitToken() {
|
||||
const token = document.getElementById('lfmToken').value;
|
||||
ipcRenderer.send('lastfm:auth', token);
|
||||
},
|
||||
openLocalSongsPathMenu() {
|
||||
app.modals.pathMenu = true
|
||||
}
|
||||
Vue.component("settings-window", {
|
||||
template: "#settings-window",
|
||||
data: function() {
|
||||
return {
|
||||
app: this.$root,
|
||||
themes: ipcRenderer.sendSync("get-themes"),
|
||||
tabIndex: 0,
|
||||
canChangeHash: false,
|
||||
lastfmConnecting: false
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
tabIndex: function(val) {
|
||||
if (this.canChangeHash) {
|
||||
// window.location.hash = `#settings/${val}`
|
||||
}
|
||||
})
|
||||
</script>
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
sidebarVis() {
|
||||
const tabIndex = app.$store.state.pageState['settings'].currentTabIndex
|
||||
if (tabIndex == 3 || tabIndex == 5 || tabIndex == 10) {
|
||||
return true;
|
||||
}
|
||||
return false
|
||||
},
|
||||
close() {
|
||||
this.$root.modals.settings = false
|
||||
},
|
||||
windowBgStyleChange() {
|
||||
this.$root.getNowPlayingArtworkBG(undefined, true)
|
||||
if (this.$root.cfg.visual.window_background_style === "mica") {
|
||||
this.$root.spawnMica()
|
||||
}
|
||||
},
|
||||
reinstallWidevineCDM() {
|
||||
app.confirm(app.getLz("settings.option.experimental.reinstallwidevine.confirm"), (ok) => {
|
||||
if (ok) {
|
||||
ipcRenderer.invoke("reinstall-widevine-cdm");
|
||||
}
|
||||
})
|
||||
},
|
||||
gitHubExplore() {
|
||||
app.openSettingsPage("github-themes")
|
||||
},
|
||||
copyLogs() {
|
||||
ipcRenderer.send('fetch-log')
|
||||
notyf.success(app.getLz('term.share.success'));
|
||||
},
|
||||
openAppData() {
|
||||
ipcRenderer.send('open-appdata')
|
||||
},
|
||||
getLanguages: function() {
|
||||
let langs = this.$root.lzListing
|
||||
let categories = {
|
||||
"main": [],
|
||||
"fun": [],
|
||||
"unsorted": []
|
||||
}
|
||||
// sort by category if category is undefined or empty put it in "unsorted"
|
||||
for (let i = 0; i < langs.length; i++) {
|
||||
if (langs[i].category === undefined || langs[i].category === "") {
|
||||
categories.unsorted.push(langs[i])
|
||||
} else {
|
||||
categories[langs[i].category].push(langs[i])
|
||||
}
|
||||
}
|
||||
// return
|
||||
return categories
|
||||
},
|
||||
addExperiment(flag) {
|
||||
app.cfg.advanced.experiments.push(flag);
|
||||
},
|
||||
removeExperiment(flag) {
|
||||
app.cfg.advanced.experiments.splice(app.cfg.advanced.experiments.indexOf(flag), 1);
|
||||
},
|
||||
toggleNormalization: function() {
|
||||
if (app.cfg.audio.normalization) {
|
||||
CiderAudio.normalizerOn()
|
||||
} else {
|
||||
CiderAudio.normalizerOff()
|
||||
}
|
||||
},
|
||||
changeAudioQuality: function() {
|
||||
app.mk.bitrate = MusicKit.PlaybackBitrate[app.cfg.audio.quality];
|
||||
},
|
||||
toggleUserInfo: function() {
|
||||
app.chrome.hideUserInfo = !app.cfg.visual.showuserinfo
|
||||
},
|
||||
sendDataToMTT: function() {
|
||||
ipcRenderer.invoke('setStoreValue', 'general.close_behavior', app.cfg.general.close_behavior);
|
||||
// setStoreValue does not change plugin store values somehow
|
||||
ipcRenderer.invoke('update-store-mtt', app.cfg.general.close_behavior);
|
||||
},
|
||||
checkIfUpdateDisabled() {
|
||||
if (app.cfg.main.UPDATABLE) return;
|
||||
|
||||
let updateFields = document.getElementsByClassName('update-check');
|
||||
for (let i = 0; i < updateFields.length; i++) {
|
||||
updateFields[i].style = "opacity: 0.5; pointer-events: none;";
|
||||
updateFields[i].title = "Not available on this type of build";
|
||||
}
|
||||
|
||||
},
|
||||
promptForRelaunch() {
|
||||
app.confirm(app.getLz('action.relaunch.confirm'), function(result) {
|
||||
if (result) {
|
||||
ipcRenderer.send('relaunchApp', '');
|
||||
}
|
||||
});
|
||||
},
|
||||
authCC() {
|
||||
ipcRenderer.send('cc-auth')
|
||||
},
|
||||
logoutCC() {
|
||||
ipcRenderer.send('cc-logout')
|
||||
},
|
||||
reloadDiscordRPC() {
|
||||
ipcRenderer.send('reloadRPC')
|
||||
},
|
||||
lfmDisconnect() {
|
||||
this.$root.cfg.connectivity.lastfm.enabled = false;
|
||||
this.$root.cfg.connectivity.lastfm.secrets.username = "";
|
||||
this.$root.cfg.connectivity.lastfm.secrets.key = "";
|
||||
ipcRenderer.send('lastfm:disconnect');
|
||||
},
|
||||
async lfmAuthorize() {
|
||||
this.lastfmConnecting = true;
|
||||
window.open(await ipcRenderer.invoke('lastfm:url'));
|
||||
app.notyf.success(app.getLz('settings.notyf.connectivity.lastfmScrobble.connecting'));
|
||||
|
||||
/* Just a timeout for the button */
|
||||
setTimeout(() => {
|
||||
if (!this.$root.cfg.connectivity.lastfm.enabled) {
|
||||
app.notyf.error(app.getLz('settings.notyf.connectivity.lastfmScrobble.connectError'));
|
||||
console.warn('[lastfm:authorize] Last.fm authorization timed out.');
|
||||
this.lastfmConnecting = false;
|
||||
}
|
||||
}, 20000);
|
||||
|
||||
ipcRenderer.once('lastfm:authenticated', (_e, session) => {
|
||||
this.$root.cfg.connectivity.lastfm.secrets.username = session.username
|
||||
this.$root.cfg.connectivity.lastfm.secrets.key = session.key
|
||||
this.$root.cfg.connectivity.lastfm.enabled = true
|
||||
this.lastfmConnecting = false;
|
||||
app.notyf.success(app.getLz('settings.notyf.connectivity.lastfmScrobble.connectSuccess'));
|
||||
})
|
||||
},
|
||||
filterChange(e) {
|
||||
this.$root.cfg.connectivity.lastfm.filter_types[e.target.value] = e.target.checked;
|
||||
},
|
||||
submitToken() {
|
||||
const token = document.getElementById('lfmToken').value;
|
||||
ipcRenderer.send('lastfm:auth', token);
|
||||
},
|
||||
openLocalSongsPathMenu() {
|
||||
app.modals.pathMenu = true
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
<script type="text/x-template" id="add-to-playlist">
|
||||
<template>
|
||||
<div class="modal-fullscreen addtoplaylist-panel" @click.self="app.resetState()" @contextmenu.self="app.resetState()">
|
||||
<div class="modal-fullscreen addtoplaylist-panel" @click.self="app.resetState()"
|
||||
@contextmenu.self="app.resetState()">
|
||||
<div class="modal-window">
|
||||
<div class="modal-header">
|
||||
<div class="modal-title">{{app.getLz('action.addToPlaylist')}}</div>
|
||||
<button class="close-btn" @click="app.resetState()" :aria-label="app.getLz('action.close')"></button>
|
||||
<button class="close-btn" @click="app.resetState()"
|
||||
:aria-label="app.getLz('action.close')"></button>
|
||||
</div>
|
||||
<div class="modal-content">
|
||||
<button class="playlist-item"
|
||||
|
@ -12,7 +14,8 @@
|
|||
<div class="icon"><%- include("../svg/plus.svg") %></div>
|
||||
<div class="name">{{app.getLz('action.createPlaylist')}}</div>
|
||||
</button>
|
||||
<sidebar-playlist :playlist-select="playlistSelect" v-for="item in $root.getPlaylistFolderChildren('p.playlistsroot')" :item="item">
|
||||
<sidebar-playlist :playlist-select="playlistSelect"
|
||||
v-for="item in $root.getPlaylistFolderChildren('p.playlistsroot')" :item="item">
|
||||
</sidebar-playlist>
|
||||
</div>
|
||||
<div class="modal-search">
|
||||
|
@ -34,55 +37,55 @@
|
|||
</script>
|
||||
|
||||
<script>
|
||||
Vue.component('add-to-playlist', {
|
||||
template: '#add-to-playlist',
|
||||
data: function () {
|
||||
return {
|
||||
playlistSorted: [],
|
||||
searchQuery: "",
|
||||
focused: "",
|
||||
app: this.$root,
|
||||
}
|
||||
},
|
||||
props: {
|
||||
playlists: {
|
||||
type: Array,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.search()
|
||||
this.$refs.searchInput.focus()
|
||||
this.$refs.searchInput.addEventListener('keydown', (e) => {
|
||||
if (e.keyCode == 13) {
|
||||
if (this.focused != "") {
|
||||
this.addToPlaylist(this.focused)
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
playlistSelect(playlist) {
|
||||
if (playlist.type != "library-playlist-folders") {
|
||||
this.addToPlaylist(playlist.id)
|
||||
}
|
||||
},
|
||||
addToPlaylist(id) {
|
||||
app.addSelectedToPlaylist(id)
|
||||
},
|
||||
search() {
|
||||
this.focused = ""
|
||||
if (this.searchQuery == "") {
|
||||
this.playlistSorted = this.playlists
|
||||
} else {
|
||||
this.playlistSorted = this.playlists.filter(playlist => {
|
||||
return playlist.attributes.name.toLowerCase().indexOf(this.searchQuery.toLowerCase()) > -1
|
||||
})
|
||||
if (this.playlistSorted.length == 1) {
|
||||
this.focused = this.playlistSorted[0].id
|
||||
}
|
||||
}
|
||||
},
|
||||
Vue.component('add-to-playlist', {
|
||||
template: '#add-to-playlist',
|
||||
data: function() {
|
||||
return {
|
||||
playlistSorted: [],
|
||||
searchQuery: "",
|
||||
focused: "",
|
||||
app: this.$root,
|
||||
}
|
||||
},
|
||||
props: {
|
||||
playlists: {
|
||||
type: Array,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.search()
|
||||
this.$refs.searchInput.focus()
|
||||
this.$refs.searchInput.addEventListener('keydown', (e) => {
|
||||
if (e.keyCode == 13) {
|
||||
if (this.focused != "") {
|
||||
this.addToPlaylist(this.focused)
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
playlistSelect(playlist) {
|
||||
if (playlist.type != "library-playlist-folders") {
|
||||
this.addToPlaylist(playlist.id)
|
||||
}
|
||||
},
|
||||
addToPlaylist(id) {
|
||||
app.addSelectedToPlaylist(id)
|
||||
},
|
||||
search() {
|
||||
this.focused = ""
|
||||
if (this.searchQuery == "") {
|
||||
this.playlistSorted = this.playlists
|
||||
} else {
|
||||
this.playlistSorted = this.playlists.filter(playlist => {
|
||||
return playlist.attributes.name.toLowerCase().indexOf(this.searchQuery.toLowerCase()) > -1
|
||||
})
|
||||
if (this.playlistSorted.length == 1) {
|
||||
this.focused = this.playlistSorted[0].id
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<script type="text/x-template" id="sidebar-playlist">
|
||||
<div class="sidebar-playlist" :key="item.id">
|
||||
<button class="app-sidebar-item app-sidebar-item-playlist" :key="item.id"
|
||||
<button class="app-sidebar-item app-sidebar-item-playlist" :key="item.id"
|
||||
:class="item.type != 'library-playlist-folders' ? {'active': $root.page.includes(item.id)} : ['playlist-folder', {'folder-button-active': folderOpened}, isPlaylistSelected]"
|
||||
@contextmenu="playlistContextMenu($event, item.id)"
|
||||
@dragstart="startDrag($event, item)"
|
||||
|
@ -9,14 +9,17 @@
|
|||
:href="item.href"
|
||||
@click='clickEvent()'>
|
||||
<template v-if="!renaming">
|
||||
<svg-icon :url="icon" name="sidebar-playlist"/> {{ item.attributes.name }}
|
||||
<svg-icon :url="icon" name="sidebar-playlist" />
|
||||
{{ item.attributes.name }}
|
||||
<small class="presentNotice" v-if="hasRelatedMediaItems">(Track present)</small>
|
||||
</template>
|
||||
<input type="text" v-model="item.attributes.name" class="pl-rename-field" @blur="rename()" @keydown.enter="rename()" v-else>
|
||||
<input type="text" v-model="item.attributes.name" class="pl-rename-field" @blur="rename()"
|
||||
@keydown.enter="rename()" v-else>
|
||||
</button>
|
||||
<div class="folder-body" v-if="item.type === 'library-playlist-folders' && folderOpened">
|
||||
<template v-if="children.length != 0">
|
||||
<sidebar-playlist v-for="item in children" :relate-media-items="relateMediaItems" :playlist-select="playlistSelect" :item="item" :key="item.id"></sidebar-playlist>
|
||||
<sidebar-playlist v-for="item in children" :relate-media-items="relateMediaItems"
|
||||
:playlist-select="playlistSelect" :item="item" :key="item.id"></sidebar-playlist>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div class="spinner"></div>
|
||||
|
@ -26,263 +29,265 @@
|
|||
</script>
|
||||
|
||||
<script>
|
||||
Vue.component('sidebar-playlist', {
|
||||
template: '#sidebar-playlist',
|
||||
props: {
|
||||
item: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
playlistSelect: {
|
||||
type: Function,
|
||||
required: false
|
||||
},
|
||||
relateMediaItems: {
|
||||
type: Array,
|
||||
required: false,
|
||||
default() {
|
||||
return []
|
||||
}
|
||||
}
|
||||
},
|
||||
data: function () {
|
||||
return {
|
||||
folderOpened: false,
|
||||
children: [],
|
||||
playlistRoot: "p.playlistsroot",
|
||||
renaming: false,
|
||||
icon: "",
|
||||
hasRelatedMediaItems: false
|
||||
}
|
||||
},
|
||||
async mounted() {
|
||||
if (this.item.type !== "library-playlist-folders") {
|
||||
this.icon = ("./assets/feather/list.svg")
|
||||
} else {
|
||||
this.icon = ("./assets/feather/folder.svg")
|
||||
}
|
||||
let playlistMap = this.$root.playlists.trackMapping
|
||||
if (this.relateMediaItems.length != 0) {
|
||||
if (playlistMap[this.relateMediaItems[0]]) {
|
||||
if (playlistMap[this.relateMediaItems[0]].includes(this.item.id)) {
|
||||
this.hasRelatedMediaItems = true
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
clickEvent() {
|
||||
if (this.item.type != "library-playlist-folders") {
|
||||
if (this.playlistSelect) {
|
||||
this.playlistSelect(this.item)
|
||||
} else {
|
||||
this.openPlaylist(this.item)
|
||||
}
|
||||
} else {
|
||||
this.getPlaylistChildren(this.item)
|
||||
}
|
||||
},
|
||||
rename() {
|
||||
this.renaming = false
|
||||
|
||||
if (this.item.type === "library-playlist-folders") {
|
||||
this.$root.editPlaylistFolder(this.item.id, this.item.attributes.name)
|
||||
} else {
|
||||
this.$root.editPlaylist(this.item.id, this.item.attributes.name)
|
||||
}
|
||||
},
|
||||
async getChildren() {
|
||||
let self = this
|
||||
this.children = []
|
||||
this.children = this.$root.playlists.listing.filter(child => {
|
||||
if (child.parent == self.item.id) {
|
||||
return child
|
||||
}
|
||||
})
|
||||
},
|
||||
async move(item, sendTo) {
|
||||
let self = this
|
||||
console.log(sendTo)
|
||||
let type = item.type.replace("library-", "")
|
||||
let typeTo = sendTo.type
|
||||
this.$root.mk.api.v3.music(`/v1/me/library/${type}/${item.id}/parent`, {}, {
|
||||
fetchOptions: {
|
||||
method: "PUT",
|
||||
body: JSON.stringify({
|
||||
data: [{
|
||||
id: sendTo.id,
|
||||
type: typeTo
|
||||
}]
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
// find the item in this.$root.playlists.listing and store it in a variable
|
||||
this.$root.playlists.listing.filter(playlist => {
|
||||
if (playlist.id == item.id) {
|
||||
console.log(playlist)
|
||||
playlist.parent = sendTo.id
|
||||
|
||||
}
|
||||
})
|
||||
if (typeof this.$root.getChildren == "function") {
|
||||
this.$root.getChildren()
|
||||
console.log(this.$root.children)
|
||||
}
|
||||
await this.getChildren()
|
||||
this.$root.sortPlaylists()
|
||||
// await this.$root.refreshPlaylists()
|
||||
},
|
||||
playlistContextMenu(event, playlist_id) {
|
||||
let menu = {
|
||||
items: {
|
||||
"moveToParent": {
|
||||
name: this.$root.getLz('action.moveToTop'),
|
||||
action: () => {
|
||||
let self = this
|
||||
this.move(this.item, {
|
||||
id: this.playlistRoot,
|
||||
type: "library-playlist-folders"
|
||||
})
|
||||
setTimeout(() => { self.getChildren() }, 2000)
|
||||
}
|
||||
},
|
||||
"rename": {
|
||||
name: this.$root.getLz('action.rename'),
|
||||
action: () => {
|
||||
this.renaming = true
|
||||
setTimeout(() => {
|
||||
document.querySelector(".pl-rename-field").focus()
|
||||
document.querySelector(".pl-rename-field").select()
|
||||
}, 100)
|
||||
}
|
||||
},
|
||||
"deleteFromPlaylist": {
|
||||
name: this.$root.getLz('action.removeFromLibrary'),
|
||||
action: () => {
|
||||
this.$root.deletePlaylist(playlist_id)
|
||||
}
|
||||
},
|
||||
"addToFavorites": {
|
||||
name: this.$root.getLz('action.addToFavorites'),
|
||||
disabled: true,
|
||||
hidden: true,
|
||||
action: () => {
|
||||
this.addFavorite(playlist_id, "library-playlists")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (this.item.type === "library-playlist-folders") {
|
||||
menu.items.addToFavorites.disabled = true
|
||||
}
|
||||
app.showMenuPanel(menu, event)
|
||||
},
|
||||
dragOver(evt) {
|
||||
evt.preventDefault();
|
||||
evt.dataTransfer.dropEffect = "move";
|
||||
},
|
||||
onDrop(evt) {
|
||||
let data = JSON.parse(evt.dataTransfer.getData("text/plain"))
|
||||
evt.preventDefault();
|
||||
if (data.id == this.item.id) {
|
||||
return;
|
||||
}
|
||||
console.log(data)
|
||||
if (data) {
|
||||
if (this.item.type == "library-playlists" || this.item.type == "library-playlist-folders") {
|
||||
if (data.type == "library-playlists" && this.item.type == "library-playlists") {
|
||||
return
|
||||
}
|
||||
this.move(data, this.item)
|
||||
}
|
||||
}
|
||||
},
|
||||
startDrag(evt) {
|
||||
evt.dataTransfer.dropEffect = 'move'
|
||||
evt.dataTransfer.effectAllowed = 'move'
|
||||
evt.dataTransfer.setData('text/plain', JSON.stringify(this.item))
|
||||
},
|
||||
openPlaylist(item) {
|
||||
this.$root.appRoute(`playlist_` + item.id);
|
||||
this.$root.showingPlaylist = [];
|
||||
if (item.id == 'ciderlocal') {
|
||||
this.$root.showingPlaylist = {
|
||||
"id": "ciderlocal",
|
||||
"type": "library-playlists",
|
||||
"href": "",
|
||||
"attributes": {
|
||||
"artwork": {
|
||||
"width": null,
|
||||
"height": null,
|
||||
"url": "",
|
||||
"hasP3": false
|
||||
},
|
||||
"dateAdded": "2021-02-16T03:39:47Z",
|
||||
"name": "Local Songs",
|
||||
"canDelete": true,
|
||||
"hasCatalog": true,
|
||||
"canEdit": true,
|
||||
"playParams": {
|
||||
"id": "ciderlocal",
|
||||
"kind": "playlist",
|
||||
"isLibrary": true,
|
||||
},
|
||||
"isPublic": true,
|
||||
"description": {
|
||||
"standard": ""
|
||||
}
|
||||
},
|
||||
"relationships": {
|
||||
"tracks": {
|
||||
"href": "",
|
||||
"data": this.$root.library.localsongs
|
||||
}
|
||||
}
|
||||
}
|
||||
this.$root.playlists.loadingState = 1;
|
||||
} else {
|
||||
this.$root.getPlaylistFromID(this.$root.page.substring(9), true)
|
||||
}
|
||||
},
|
||||
getPlaylistChildren(item) {
|
||||
let self = this
|
||||
this.children = []
|
||||
this.getChildren()
|
||||
this.toggleFolder()
|
||||
|
||||
this.$root.mk.api.v3.music(`v1/me/library/playlist-folders/${item.id}/children`).then(data => {
|
||||
let children = data.data.data;
|
||||
children.forEach(child => {
|
||||
if (!self.$root.playlists.listing.find(listing => listing.id == child.id)) {
|
||||
child.parent = self.item.id
|
||||
self.$root.playlists.listing.push(child)
|
||||
}
|
||||
})
|
||||
|
||||
self.$root.playlists.listing.sort((a, b) => {
|
||||
if (a.type === 'library-playlist-folders' && b.type !== 'library-playlist-folders') {
|
||||
return -1
|
||||
} else if (a.type !== 'library-playlist-folders' && b.type === 'library-playlist-folders') {
|
||||
return 1
|
||||
} else {
|
||||
return 0
|
||||
}
|
||||
})
|
||||
self.getChildren()
|
||||
})
|
||||
},
|
||||
isPlaylistSelected(item) {
|
||||
if (this.$root.showingPlaylist.id == item.id) {
|
||||
return ["active"]
|
||||
} else {
|
||||
return []
|
||||
}
|
||||
},
|
||||
toggleFolder() {
|
||||
this.folderOpened = !this.folderOpened;
|
||||
}
|
||||
Vue.component('sidebar-playlist', {
|
||||
template: '#sidebar-playlist',
|
||||
props: {
|
||||
item: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
playlistSelect: {
|
||||
type: Function,
|
||||
required: false
|
||||
},
|
||||
relateMediaItems: {
|
||||
type: Array,
|
||||
required: false,
|
||||
default() {
|
||||
return []
|
||||
}
|
||||
});
|
||||
</script>
|
||||
}
|
||||
},
|
||||
data: function() {
|
||||
return {
|
||||
folderOpened: false,
|
||||
children: [],
|
||||
playlistRoot: "p.playlistsroot",
|
||||
renaming: false,
|
||||
icon: "",
|
||||
hasRelatedMediaItems: false
|
||||
}
|
||||
},
|
||||
async mounted() {
|
||||
if (this.item.type !== "library-playlist-folders") {
|
||||
this.icon = ("./assets/feather/list.svg")
|
||||
} else {
|
||||
this.icon = ("./assets/feather/folder.svg")
|
||||
}
|
||||
let playlistMap = this.$root.playlists.trackMapping
|
||||
if (this.relateMediaItems.length != 0) {
|
||||
if (playlistMap[this.relateMediaItems[0]]) {
|
||||
if (playlistMap[this.relateMediaItems[0]].includes(this.item.id)) {
|
||||
this.hasRelatedMediaItems = true
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
clickEvent() {
|
||||
if (this.item.type != "library-playlist-folders") {
|
||||
if (this.playlistSelect) {
|
||||
this.playlistSelect(this.item)
|
||||
} else {
|
||||
this.openPlaylist(this.item)
|
||||
}
|
||||
} else {
|
||||
this.getPlaylistChildren(this.item)
|
||||
}
|
||||
},
|
||||
rename() {
|
||||
this.renaming = false
|
||||
|
||||
if (this.item.type === "library-playlist-folders") {
|
||||
this.$root.editPlaylistFolder(this.item.id, this.item.attributes.name)
|
||||
} else {
|
||||
this.$root.editPlaylist(this.item.id, this.item.attributes.name)
|
||||
}
|
||||
},
|
||||
async getChildren() {
|
||||
let self = this
|
||||
this.children = []
|
||||
this.children = this.$root.playlists.listing.filter(child => {
|
||||
if (child.parent == self.item.id) {
|
||||
return child
|
||||
}
|
||||
})
|
||||
},
|
||||
async move(item, sendTo) {
|
||||
let self = this
|
||||
console.log(sendTo)
|
||||
let type = item.type.replace("library-", "")
|
||||
let typeTo = sendTo.type
|
||||
this.$root.mk.api.v3.music(`/v1/me/library/${type}/${item.id}/parent`, {}, {
|
||||
fetchOptions: {
|
||||
method: "PUT",
|
||||
body: JSON.stringify({
|
||||
data: [{
|
||||
id: sendTo.id,
|
||||
type: typeTo
|
||||
}]
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
// find the item in this.$root.playlists.listing and store it in a variable
|
||||
this.$root.playlists.listing.filter(playlist => {
|
||||
if (playlist.id == item.id) {
|
||||
console.log(playlist)
|
||||
playlist.parent = sendTo.id
|
||||
|
||||
}
|
||||
})
|
||||
if (typeof this.$root.getChildren == "function") {
|
||||
this.$root.getChildren()
|
||||
console.log(this.$root.children)
|
||||
}
|
||||
await this.getChildren()
|
||||
this.$root.sortPlaylists()
|
||||
// await this.$root.refreshPlaylists()
|
||||
},
|
||||
playlistContextMenu(event, playlist_id) {
|
||||
let menu = {
|
||||
items: {
|
||||
"moveToParent": {
|
||||
name: this.$root.getLz('action.moveToTop'),
|
||||
action: () => {
|
||||
let self = this
|
||||
this.move(this.item, {
|
||||
id: this.playlistRoot,
|
||||
type: "library-playlist-folders"
|
||||
})
|
||||
setTimeout(() => {
|
||||
self.getChildren()
|
||||
}, 2000)
|
||||
}
|
||||
},
|
||||
"rename": {
|
||||
name: this.$root.getLz('action.rename'),
|
||||
action: () => {
|
||||
this.renaming = true
|
||||
setTimeout(() => {
|
||||
document.querySelector(".pl-rename-field").focus()
|
||||
document.querySelector(".pl-rename-field").select()
|
||||
}, 100)
|
||||
}
|
||||
},
|
||||
"deleteFromPlaylist": {
|
||||
name: this.$root.getLz('action.removeFromLibrary'),
|
||||
action: () => {
|
||||
this.$root.deletePlaylist(playlist_id)
|
||||
}
|
||||
},
|
||||
"addToFavorites": {
|
||||
name: this.$root.getLz('action.addToFavorites'),
|
||||
disabled: true,
|
||||
hidden: true,
|
||||
action: () => {
|
||||
this.addFavorite(playlist_id, "library-playlists")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (this.item.type === "library-playlist-folders") {
|
||||
menu.items.addToFavorites.disabled = true
|
||||
}
|
||||
app.showMenuPanel(menu, event)
|
||||
},
|
||||
dragOver(evt) {
|
||||
evt.preventDefault();
|
||||
evt.dataTransfer.dropEffect = "move";
|
||||
},
|
||||
onDrop(evt) {
|
||||
let data = JSON.parse(evt.dataTransfer.getData("text/plain"))
|
||||
evt.preventDefault();
|
||||
if (data.id == this.item.id) {
|
||||
return;
|
||||
}
|
||||
console.log(data)
|
||||
if (data) {
|
||||
if (this.item.type == "library-playlists" || this.item.type == "library-playlist-folders") {
|
||||
if (data.type == "library-playlists" && this.item.type == "library-playlists") {
|
||||
return
|
||||
}
|
||||
this.move(data, this.item)
|
||||
}
|
||||
}
|
||||
},
|
||||
startDrag(evt) {
|
||||
evt.dataTransfer.dropEffect = 'move'
|
||||
evt.dataTransfer.effectAllowed = 'move'
|
||||
evt.dataTransfer.setData('text/plain', JSON.stringify(this.item))
|
||||
},
|
||||
openPlaylist(item) {
|
||||
this.$root.appRoute(`playlist_` + item.id);
|
||||
this.$root.showingPlaylist = [];
|
||||
if (item.id == 'ciderlocal') {
|
||||
this.$root.showingPlaylist = {
|
||||
"id": "ciderlocal",
|
||||
"type": "library-playlists",
|
||||
"href": "",
|
||||
"attributes": {
|
||||
"artwork": {
|
||||
"width": null,
|
||||
"height": null,
|
||||
"url": "",
|
||||
"hasP3": false
|
||||
},
|
||||
"dateAdded": "2021-02-16T03:39:47Z",
|
||||
"name": "Local Songs",
|
||||
"canDelete": true,
|
||||
"hasCatalog": true,
|
||||
"canEdit": true,
|
||||
"playParams": {
|
||||
"id": "ciderlocal",
|
||||
"kind": "playlist",
|
||||
"isLibrary": true,
|
||||
},
|
||||
"isPublic": true,
|
||||
"description": {
|
||||
"standard": ""
|
||||
}
|
||||
},
|
||||
"relationships": {
|
||||
"tracks": {
|
||||
"href": "",
|
||||
"data": this.$root.library.localsongs
|
||||
}
|
||||
}
|
||||
}
|
||||
this.$root.playlists.loadingState = 1;
|
||||
} else {
|
||||
this.$root.getPlaylistFromID(this.$root.page.substring(9), true)
|
||||
}
|
||||
},
|
||||
getPlaylistChildren(item) {
|
||||
let self = this
|
||||
this.children = []
|
||||
this.getChildren()
|
||||
this.toggleFolder()
|
||||
|
||||
this.$root.mk.api.v3.music(`v1/me/library/playlist-folders/${item.id}/children`).then(data => {
|
||||
let children = data.data.data;
|
||||
children.forEach(child => {
|
||||
if (!self.$root.playlists.listing.find(listing => listing.id == child.id)) {
|
||||
child.parent = self.item.id
|
||||
self.$root.playlists.listing.push(child)
|
||||
}
|
||||
})
|
||||
|
||||
self.$root.playlists.listing.sort((a, b) => {
|
||||
if (a.type === 'library-playlist-folders' && b.type !== 'library-playlist-folders') {
|
||||
return -1
|
||||
} else if (a.type !== 'library-playlist-folders' && b.type === 'library-playlist-folders') {
|
||||
return 1
|
||||
} else {
|
||||
return 0
|
||||
}
|
||||
})
|
||||
self.getChildren()
|
||||
})
|
||||
},
|
||||
isPlaylistSelected(item) {
|
||||
if (this.$root.showingPlaylist.id == item.id) {
|
||||
return ["active"]
|
||||
} else {
|
||||
return []
|
||||
}
|
||||
},
|
||||
toggleFolder() {
|
||||
this.folderOpened = !this.folderOpened;
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -140,12 +140,12 @@
|
|||
</template>
|
||||
<template v-if="$root.cfg.libraryPrefs.localPaths.length != 0">
|
||||
<div class="app-sidebar-header-text"
|
||||
@click="$root.cfg.general.sidebarCollapsed.localLibrary = !$root.cfg.general.sidebarCollapsed.localLibrary"
|
||||
:class="{collapsed: $root.cfg.general.sidebarCollapsed.localLibrary}">
|
||||
Local Library
|
||||
@click="$root.cfg.general.sidebarCollapsed.localLibrary = !$root.cfg.general.sidebarCollapsed.localLibrary"
|
||||
:class="{collapsed: $root.cfg.general.sidebarCollapsed.localLibrary}">
|
||||
Local Library
|
||||
</div>
|
||||
<template v-if="!$root.cfg.general.sidebarCollapsed.localLibrary">
|
||||
<sidebar-playlist :item="{attributes: { name:'Songs'} , id:'ciderlocal'}"></sidebar-playlist>
|
||||
<sidebar-playlist :item="{attributes: { name:'Songs'} , id:'ciderlocal'}"></sidebar-playlist>
|
||||
</template>
|
||||
</template>
|
||||
<template v-if="$root.getPlaylistFolderChildren('p.applemusic').length != 0">
|
||||
|
@ -310,7 +310,7 @@
|
|||
</script>
|
||||
|
||||
<script>
|
||||
Vue.component("cider-app-sidebar", {
|
||||
template: "#cider-app-sidebar"
|
||||
})
|
||||
</script>
|
||||
Vue.component("cider-app-sidebar", {
|
||||
template: "#cider-app-sidebar"
|
||||
})
|
||||
</script>
|
||||
|
|
|
@ -15,123 +15,123 @@
|
|||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no, viewport-fit=cover">
|
||||
<title>Cider</title>
|
||||
<link rel="<%- (env.dev ? " stylesheet" : "stylesheet/less" ) %>" type="text/css" href="style.<%- (env.dev ? "css"
|
||||
: "less" ) %>"/>
|
||||
<!-- <link rel="stylesheet/less" type="text/css" id="userTheme" href="themes/default.less"/>-->
|
||||
<script src="./lib/less.js"></script>
|
||||
<script src="<%- (env.dev ? " ./lib/vue.js" : "./lib/vue.dev.js" ) %>"></script>
|
||||
<script src="./lib/smoothscroll.js"></script>
|
||||
<link rel="manifest" href="./manifest.json?v=2">
|
||||
<script src="https://js-cdn.music.apple.com/hls.js/2.141.0/hls.js/hls.js"></script>
|
||||
<script src="hlscider.js"></script>
|
||||
<script src="./lib/jquery-3.2.1.slim.min.js"></script>
|
||||
<script src="./lib/popper.min.js"></script>
|
||||
<script src="./lib/bootstrap.min.js"></script>
|
||||
<script src="./lib/bootbox.min.js"></script>
|
||||
<script src="./lib/notyf.min.js"></script>
|
||||
<script src="./lib/marked.js"></script>
|
||||
<script src="./lib/velocity.min.js"></script>
|
||||
<script src="./lib/fast-plural-rules.js"></script>
|
||||
<script src="./lib/resonance-audio.min.js"></script>
|
||||
<script src="./lib/stackblur.min.js"></script>
|
||||
<link rel="<%- (env.dev ? " stylesheet" : "stylesheet/less") %>" type="text/css" href="style.<%- (env.dev ? "css"
|
||||
: "less") %>" />
|
||||
<!-- <link rel="stylesheet/less" type="text/css" id="userTheme" href="themes/default.less"/>-->
|
||||
<script src="./lib/less.js"></script>
|
||||
<script src="<%- (env.dev ? " ./lib/vue.js" : "./lib/vue.dev.js"); %>"></script>
|
||||
<script src="./lib/smoothscroll.js"></script>
|
||||
<link rel="manifest" href="./manifest.json?v=2">
|
||||
<script src="https://js-cdn.music.apple.com/hls.js/2.141.0/hls.js/hls.js"></script>
|
||||
<script src="hlscider.js"></script>
|
||||
<script src="./lib/jquery-3.2.1.slim.min.js"></script>
|
||||
<script src="./lib/popper.min.js"></script>
|
||||
<script src="./lib/bootstrap.min.js"></script>
|
||||
<script src="./lib/bootbox.min.js"></script>
|
||||
<script src="./lib/notyf.min.js"></script>
|
||||
<script src="./lib/marked.js"></script>
|
||||
<script src="./lib/velocity.min.js"></script>
|
||||
<script src="./lib/fast-plural-rules.js"></script>
|
||||
<script src="./lib/resonance-audio.min.js"></script>
|
||||
<script src="./lib/stackblur.min.js"></script>
|
||||
|
||||
<style>
|
||||
#LOADER {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: #1E1E1E;
|
||||
z-index: 99999;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
<style>
|
||||
#LOADER {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: #1E1E1E;
|
||||
z-index: 99999;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
#LOADER>svg {
|
||||
width: 128px;
|
||||
}
|
||||
#LOADER > svg {
|
||||
width: 128px;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: light) {
|
||||
#LOADER {
|
||||
background-color: #eee;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@media (prefers-color-scheme: light) {
|
||||
#LOADER {
|
||||
background-color: #eee;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body class="notransparency" oncontextmenu="return false;" loading="1" os-release="<%= parseInt(env.osRelease) %>"
|
||||
platform="<%= env.platform %>">
|
||||
<script src="<%- (env.dev ? " ./lib/vue.js" : "./lib/vue.dev.js" ) %>"></script>
|
||||
<script src="./lib/vue-horizontal.js"></script>
|
||||
<script src="./lib/bootstrap-vue.min.js"></script>
|
||||
<script src="./lib/vuex.min.js"></script>
|
||||
<script src="./lib/sortable.min.js"></script>
|
||||
<script src="./lib/vue-observe-visibility.min.js"></script>
|
||||
<script src="./lib/vuedraggable.umd.min.js"></script>
|
||||
<script>
|
||||
window.quasarConfig = {
|
||||
brand: {
|
||||
primary: '#fc3c44'
|
||||
},
|
||||
config: {
|
||||
dark: true
|
||||
},
|
||||
loadingBar: { skipHijack: true }
|
||||
}
|
||||
</script>
|
||||
<!-- <script src="./lib/quasar/quasar.umd.min.js"></script> -->
|
||||
<script type="module" src="./main/app.js"></script>
|
||||
<body class="notransparency" oncontextmenu="return false;" loading="1" os-release="<%= parseInt(env.osRelease) ;%>"
|
||||
platform="<%= env.platform ;%>">
|
||||
<script src="<%- (env.dev ? " ./lib/vue.js" : "./lib/vue.dev.js"); %>"></script>
|
||||
<script src="./lib/vue-horizontal.js"></script>
|
||||
<script src="./lib/bootstrap-vue.min.js"></script>
|
||||
<script src="./lib/vuex.min.js"></script>
|
||||
<script src="./lib/sortable.min.js"></script>
|
||||
<script src="./lib/vue-observe-visibility.min.js"></script>
|
||||
<script src="./lib/vuedraggable.umd.min.js"></script>
|
||||
<script>
|
||||
window.quasarConfig = {
|
||||
brand: {
|
||||
primary: '#fc3c44'
|
||||
},
|
||||
config: {
|
||||
dark: true
|
||||
},
|
||||
loadingBar: { skipHijack: true }
|
||||
}
|
||||
</script>
|
||||
<!-- <script src="./lib/quasar/quasar.umd.min.js"></script> -->
|
||||
<script type="module" src="./main/app.js"></script>
|
||||
|
||||
<div id="LOADER">
|
||||
<%- include("../assets/cider-round.svg") %>
|
||||
</div>
|
||||
<div id="app" :class="getAppClasses()" v-if="appVisible" :window-state="chrome.windowState" :style="getAppStyle()"
|
||||
:library-visible="(chrome.sidebarCollapsed ? 0 : 1)" :window-style="cfg.visual.directives.windowLayout">
|
||||
<transition name="fsModeSwitch">
|
||||
<div id="app-main" v-show="appMode == 'player'">
|
||||
<%- include('app/chrome-top'); %>
|
||||
<%- include('app/app-navigation'); %>
|
||||
<%- include('app/chrome-bottom'); %>
|
||||
</div>
|
||||
</transition>
|
||||
<transition name="fsModeSwitch">
|
||||
<div class="fullscreen-view-container" v-if="appMode == 'fullscreen'">
|
||||
<fullscreen-view :image="currentArtUrlRaw" :time="mk.currentPlaybackTime - lyricOffset" :lyrics="lyrics"
|
||||
:richlyrics="richlyrics"></fullscreen-view>
|
||||
</div>
|
||||
</transition>
|
||||
<transition name="fsModeSwitch">
|
||||
<div class="fullscreen-view-container" v-if="appMode == 'mini'">
|
||||
<mini-view :image="currentArtUrlRaw" :time="mk.currentPlaybackTime - lyricOffset" :lyrics="lyrics"
|
||||
:richlyrics="richlyrics">
|
||||
</mini-view>
|
||||
</div>
|
||||
</transition>
|
||||
<transition name="fsModeSwitch">
|
||||
<div class="fullscreen-view-container oobe" v-if="appMode == 'oobe'">
|
||||
<cider-oobe></cider-oobe>
|
||||
</div>
|
||||
</transition>
|
||||
<%- include('app/panels'); %>
|
||||
<div class="cursor" v-if="chrome.showCursor"></div>
|
||||
</div>
|
||||
<div id="LOADER">
|
||||
<%- include("../assets/cider-round.svg") %>
|
||||
</div>
|
||||
<div id="app" :class="getAppClasses()" v-if="appVisible" :window-state="chrome.windowState" :style="getAppStyle()"
|
||||
:library-visible="(chrome.sidebarCollapsed ? 0 : 1)" :window-style="cfg.visual.directives.windowLayout">
|
||||
<transition name="fsModeSwitch">
|
||||
<div id="app-main" v-show="appMode == 'player'">
|
||||
<%- include('app/chrome-top'); %>
|
||||
<%- include('app/app-navigation'); %>
|
||||
<%- include('app/chrome-bottom'); %>
|
||||
</div>
|
||||
</transition>
|
||||
<transition name="fsModeSwitch">
|
||||
<div class="fullscreen-view-container" v-if="appMode == 'fullscreen'">
|
||||
<fullscreen-view :image="currentArtUrlRaw" :time="mk.currentPlaybackTime - lyricOffset" :lyrics="lyrics"
|
||||
:richlyrics="richlyrics"></fullscreen-view>
|
||||
</div>
|
||||
</transition>
|
||||
<transition name="fsModeSwitch">
|
||||
<div class="fullscreen-view-container" v-if="appMode == 'mini'">
|
||||
<mini-view :image="currentArtUrlRaw" :time="mk.currentPlaybackTime - lyricOffset" :lyrics="lyrics"
|
||||
:richlyrics="richlyrics">
|
||||
</mini-view>
|
||||
</div>
|
||||
</transition>
|
||||
<transition name="fsModeSwitch">
|
||||
<div class="fullscreen-view-container oobe" v-if="appMode == 'oobe'">
|
||||
<cider-oobe></cider-oobe>
|
||||
</div>
|
||||
</transition>
|
||||
<%- include('app/panels'); %>
|
||||
<div class="cursor" v-if="chrome.showCursor"></div>
|
||||
</div>
|
||||
|
||||
<% for(var i=0; i < Object.keys(env.components).length ; i++) { %>
|
||||
<%- include(env.components[i]); %>
|
||||
<% } %>
|
||||
<% for(var i = 0; i < Object.keys(env.components).length ; i++) { %>
|
||||
<%- include(env.components[i]); %>
|
||||
<% } %>
|
||||
|
||||
<script async
|
||||
src="<%- (env.useV3 ? 'https://js-cdn.music.apple.com/musickit/v3/amp/musickit.js' : 'https://api.cider.sh/musickit.js') %>"
|
||||
data-web-components>
|
||||
</script>
|
||||
<script src="index.js?v=1"></script>
|
||||
<script async
|
||||
src="<%- (env.useV3 ? "https://js-cdn.music.apple.com/musickit/v3/amp/musickit.js" : "https://api.cider.sh/musickit.js"); %>"
|
||||
data-web-components>
|
||||
</script>
|
||||
<script src="index.js?v=1"></script>
|
||||
|
||||
<script type="text/x-template" id="am-musiccovershelf">
|
||||
<script type="text/x-template" id="am-musiccovershelf">
|
||||
<h1>{{ component.attributes.title.stringForDisplay }}</h1>
|
||||
</script>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
</html>
|
||||
|
|
|
@ -6,19 +6,33 @@
|
|||
<p style="text-align: center" id="version">{{ $root.getLz("term.version") }} {{ $root.version }}</p>
|
||||
<p style="text-align: center"> {{$root.getLz('about.thanks')}} </p>
|
||||
|
||||
<p style="text-align: center">"{{$root.getLz('term.appleMusic')}}" - {{$root.getLz('term.copyright')}} © 2022 <a href="https://www.apple.com/" class="dt-footer__link"
|
||||
target="_blank"
|
||||
rel="noopener" data-dt-link-to-exclude="">{{$root.getLz('term.appleInc')}}</a>
|
||||
{{$root.getLz('term.rightsReserved')}}</p>
|
||||
<p style="text-align: center">"{{$root.getLz('term.appleMusic')}}" - {{$root.getLz('term.copyright')}} ©
|
||||
2022 <a href="https://www.apple.com/" class="dt-footer__link"
|
||||
target="_blank"
|
||||
rel="noopener" data-dt-link-to-exclude="">{{$root.getLz('term.appleInc')}}</a>
|
||||
{{$root.getLz('term.rightsReserved')}}</p>
|
||||
<hr>
|
||||
<h3>{{$root.getLz('term.sponsor')}}</h3>
|
||||
<button onclick="window.open('https://github.com/sponsors/ciderapp')" class="md-btn sponsorBtn githubBtn"><img src="./assets/github.svg"/>GitHub Sponsors</button>
|
||||
<button onclick="window.open('https://ko-fi.com/cryptofyre')" class="md-btn sponsorBtn kofiBtn"><img src="./assets/ko_fi.svg"/>Ko-fi</button>
|
||||
<button onclick="window.open('https://opencollective.com/ciderapp')" class="md-btn sponsorBtn opencollectiveBtn"><img src="./assets/open_collective.svg"/>Open Collective</button>
|
||||
<button onclick="window.open('https://github.com/sponsors/ciderapp')"
|
||||
class="md-btn sponsorBtn githubBtn"><img src="./assets/github.svg" />GitHub Sponsors
|
||||
</button>
|
||||
<button onclick="window.open('https://ko-fi.com/cryptofyre')" class="md-btn sponsorBtn kofiBtn"><img
|
||||
src="./assets/ko_fi.svg" />Ko-fi
|
||||
</button>
|
||||
<button onclick="window.open('https://opencollective.com/ciderapp')"
|
||||
class="md-btn sponsorBtn opencollectiveBtn"><img src="./assets/open_collective.svg" />Open
|
||||
Collective
|
||||
</button>
|
||||
<h3>{{$root.getLz('term.socials')}}</h3>
|
||||
<button onclick="window.open('https://github.com/ciderapp/Cider')" class="md-btn sponsorBtn githubBtn"><img src="./assets/github.svg"/>{{$root.getLz('term.github')}}</button>
|
||||
<button onclick="window.open('https://discord.gg/applemusic')" class="md-btn sponsorBtn discordBtn"><img style="height: 26px;" src="./assets/discord.svg"/>{{$root.getLz('term.discord')}}</button>
|
||||
<button onclick="window.open('https://twitter.com/UseCider')" class="md-btn sponsorBtn twitterBtn"><img src="./assets/twitter.svg"/>Twitter</button>
|
||||
<button onclick="window.open('https://github.com/ciderapp/Cider')" class="md-btn sponsorBtn githubBtn">
|
||||
<img src="./assets/github.svg" />{{$root.getLz('term.github')}}
|
||||
</button>
|
||||
<button onclick="window.open('https://discord.gg/applemusic')" class="md-btn sponsorBtn discordBtn"><img
|
||||
style="height: 26px;" src="./assets/discord.svg" />{{$root.getLz('term.discord')}}
|
||||
</button>
|
||||
<button onclick="window.open('https://twitter.com/UseCider')" class="md-btn sponsorBtn twitterBtn"><img
|
||||
src="./assets/twitter.svg" />Twitter
|
||||
</button>
|
||||
|
||||
</div>
|
||||
<div class="col">
|
||||
|
@ -26,14 +40,18 @@
|
|||
<div class="col">
|
||||
<h3>{{$root.getLz('term.ciderTeam')}}</h3>
|
||||
<div class="md-btn teamBtn" v-for="member in team" @click="window.open(member.link)">
|
||||
<img :src="member.avatar"/>
|
||||
<img :src="member.avatar" />
|
||||
<div class="row" style="width:100%;">
|
||||
<div class="col" style="text-align: left;">
|
||||
{{ member.name }}
|
||||
</div>
|
||||
<div class="col" style="text-align: right">
|
||||
<button @click.stop="window.open(member.twitter)" class="social-btn" v-if="member.twitter">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="white" style=""><path d="M24 4.557c-.883.392-1.832.656-2.828.775 1.017-.609 1.798-1.574 2.165-2.724-.951.564-2.005.974-3.127 1.195-.897-.957-2.178-1.555-3.594-1.555-3.179 0-5.515 2.966-4.797 6.045-4.091-.205-7.719-2.165-10.148-5.144-1.29 2.213-.669 5.108 1.523 6.574-.806-.026-1.566-.247-2.229-.616-.054 2.281 1.581 4.415 3.949 4.89-.693.188-1.452.232-2.224.084.626 1.956 2.444 3.379 4.6 3.419-2.07 1.623-4.678 2.348-7.29 2.04 2.179 1.397 4.768 2.212 7.548 2.212 9.142 0 14.307-7.721 13.995-14.646.962-.695 1.797-1.562 2.457-2.549z"></path></svg>
|
||||
<button @click.stop="window.open(member.twitter)" class="social-btn"
|
||||
v-if="member.twitter">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24"
|
||||
viewBox="0 0 24 24" fill="white" style="">
|
||||
<path d="M24 4.557c-.883.392-1.832.656-2.828.775 1.017-.609 1.798-1.574 2.165-2.724-.951.564-2.005.974-3.127 1.195-.897-.957-2.178-1.555-3.594-1.555-3.179 0-5.515 2.966-4.797 6.045-4.091-.205-7.719-2.165-10.148-5.144-1.29 2.213-.669 5.108 1.523 6.574-.806-.026-1.566-.247-2.229-.616-.054 2.281 1.581 4.415 3.949 4.89-.693.188-1.452.232-2.224.084.626 1.956 2.444 3.379 4.6 3.419-2.07 1.623-4.678 2.348-7.29 2.04 2.179 1.397 4.768 2.212 7.548 2.212 9.142 0 14.307-7.721 13.995-14.646.962-.695 1.797-1.562 2.457-2.549z"></path>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
|
@ -51,105 +69,103 @@
|
|||
<img class="md-contributors"
|
||||
style="cursor:pointer;width:100%;"
|
||||
onclick="window.open('https://github.com/ciderapp/Cider/graphs/contributors')"
|
||||
src="https://contrib.rocks/image?repo=ciderapp/Cider&columns=25"/>
|
||||
src="https://contrib.rocks/image?repo=ciderapp/Cider&columns=25" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
<script>
|
||||
Vue.component('about-page', {
|
||||
template: '#about-page',
|
||||
data: function () {
|
||||
return {
|
||||
window: window,
|
||||
version: app.version,
|
||||
team: [
|
||||
{
|
||||
name: 'cryptofyre',
|
||||
link: 'https://github.com/cryptofyre',
|
||||
role: app.getLz('term.developer'),
|
||||
avatar: 'https://avatars.githubusercontent.com/u/33162551?v=4',
|
||||
twitter: 'https://twitter.com/cryptofyre'
|
||||
},
|
||||
{
|
||||
name: 'Core',
|
||||
link: 'https://github.com/coredev-uk',
|
||||
role: app.getLz('term.developer'),
|
||||
avatar: 'https://avatars.githubusercontent.com/u/64542347?v=4',
|
||||
twitter: 'https://twitter.com/core_hdd'
|
||||
},
|
||||
{
|
||||
name: 'Quacksire',
|
||||
link: 'https://github.com/quacksire',
|
||||
role: app.getLz('term.developer'),
|
||||
avatar: 'https://avatars.githubusercontent.com/u/19170969?v=4',
|
||||
twitter: 'https://twitter.com/duckdoquack'
|
||||
},
|
||||
{
|
||||
name: 'booploops',
|
||||
link: 'https://github.com/booploops',
|
||||
role: app.getLz('term.developer'),
|
||||
avatar: 'https://avatars.githubusercontent.com/u/49113086?v=4',
|
||||
twitter: 'https://twitter.com/boopl00ps'
|
||||
},
|
||||
{
|
||||
name: 'vapormusic',
|
||||
link: 'https://github.com/vapormusic',
|
||||
role: app.getLz('term.developer'),
|
||||
avatar: 'https://avatars.githubusercontent.com/u/27716185?v=4'
|
||||
},
|
||||
{
|
||||
name: 'crypticplank',
|
||||
link: 'https://github.com/crypticplank',
|
||||
role: app.getLz('term.developer'),
|
||||
avatar: 'https://avatars.githubusercontent.com/u/52553007?v=4',
|
||||
twitter: 'https://twitter.com/crypticplank'
|
||||
},
|
||||
{
|
||||
name: 'Maikiwi',
|
||||
link: 'https://github.com/maikirakiwi',
|
||||
role: app.getLz('term.developer'),
|
||||
avatar: 'https://avatars.githubusercontent.com/u/74925636?v=4',
|
||||
twitter: 'https://twitter.com/notmaikiwi'
|
||||
},
|
||||
{
|
||||
name: 'yazninja',
|
||||
link: 'https://github.com/yazninja',
|
||||
role: app.getLz('term.developer'),
|
||||
avatar: 'https://avatars.githubusercontent.com/u/71800112?v=4',
|
||||
twitter: 'https://twitter.com/YazNinjaa'
|
||||
},
|
||||
{
|
||||
name: 'GamingLiamStudios',
|
||||
link: 'https://github.com/GamingLiamStudios',
|
||||
role: app.getLz('term.developer'),
|
||||
avatar: 'https://avatars.githubusercontent.com/u/58615717?v=4',
|
||||
twitter: 'https://twitter.com/GLStudios_'
|
||||
},
|
||||
{
|
||||
name: 'Amaru',
|
||||
link: 'https://github.com/Amaru8',
|
||||
role: app.getLz('term.developer'),
|
||||
avatar: 'https://avatars.githubusercontent.com/u/52407090?v=4'
|
||||
},
|
||||
{
|
||||
name: 'Void',
|
||||
link: 'https://twitter.com/MoonyVoid',
|
||||
role: app.getLz('term.socialTeam'),
|
||||
avatar: 'https://pbs.twimg.com/profile_images/1226463559472816129/8LScNYED_400x400.jpg'
|
||||
},
|
||||
{
|
||||
name: 'NoseySG',
|
||||
link: 'https://twitter.com/noah_grose',
|
||||
role: app.getLz('term.socialTeam'),
|
||||
avatar: 'https://pbs.twimg.com/profile_images/1496944907260420099/D5gl6H4J_400x400.jpg'
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
||||
}
|
||||
});
|
||||
</script>
|
||||
Vue.component('about-page', {
|
||||
template: '#about-page',
|
||||
data: function() {
|
||||
return {
|
||||
window: window,
|
||||
version: app.version,
|
||||
team: [
|
||||
{
|
||||
name: 'cryptofyre',
|
||||
link: 'https://github.com/cryptofyre',
|
||||
role: app.getLz('term.developer'),
|
||||
avatar: 'https://avatars.githubusercontent.com/u/33162551?v=4',
|
||||
twitter: 'https://twitter.com/cryptofyre'
|
||||
},
|
||||
{
|
||||
name: 'Core',
|
||||
link: 'https://github.com/coredev-uk',
|
||||
role: app.getLz('term.developer'),
|
||||
avatar: 'https://avatars.githubusercontent.com/u/64542347?v=4',
|
||||
twitter: 'https://twitter.com/core_hdd'
|
||||
},
|
||||
{
|
||||
name: 'Quacksire',
|
||||
link: 'https://github.com/quacksire',
|
||||
role: app.getLz('term.developer'),
|
||||
avatar: 'https://avatars.githubusercontent.com/u/19170969?v=4',
|
||||
twitter: 'https://twitter.com/duckdoquack'
|
||||
},
|
||||
{
|
||||
name: 'booploops',
|
||||
link: 'https://github.com/booploops',
|
||||
role: app.getLz('term.developer'),
|
||||
avatar: 'https://avatars.githubusercontent.com/u/49113086?v=4',
|
||||
twitter: 'https://twitter.com/boopl00ps'
|
||||
},
|
||||
{
|
||||
name: 'vapormusic',
|
||||
link: 'https://github.com/vapormusic',
|
||||
role: app.getLz('term.developer'),
|
||||
avatar: 'https://avatars.githubusercontent.com/u/27716185?v=4'
|
||||
},
|
||||
{
|
||||
name: 'crypticplank',
|
||||
link: 'https://github.com/crypticplank',
|
||||
role: app.getLz('term.developer'),
|
||||
avatar: 'https://avatars.githubusercontent.com/u/52553007?v=4',
|
||||
twitter: 'https://twitter.com/crypticplank'
|
||||
},
|
||||
{
|
||||
name: 'Maikiwi',
|
||||
link: 'https://github.com/maikirakiwi',
|
||||
role: app.getLz('term.developer'),
|
||||
avatar: 'https://avatars.githubusercontent.com/u/74925636?v=4',
|
||||
twitter: 'https://twitter.com/notmaikiwi'
|
||||
},
|
||||
{
|
||||
name: 'yazninja',
|
||||
link: 'https://github.com/yazninja',
|
||||
role: app.getLz('term.developer'),
|
||||
avatar: 'https://avatars.githubusercontent.com/u/71800112?v=4',
|
||||
twitter: 'https://twitter.com/YazNinjaa'
|
||||
},
|
||||
{
|
||||
name: 'GamingLiamStudios',
|
||||
link: 'https://github.com/GamingLiamStudios',
|
||||
role: app.getLz('term.developer'),
|
||||
avatar: 'https://avatars.githubusercontent.com/u/58615717?v=4',
|
||||
twitter: 'https://twitter.com/GLStudios_'
|
||||
},
|
||||
{
|
||||
name: 'Amaru',
|
||||
link: 'https://github.com/Amaru8',
|
||||
role: app.getLz('term.developer'),
|
||||
avatar: 'https://avatars.githubusercontent.com/u/52407090?v=4'
|
||||
},
|
||||
{
|
||||
name: 'Void',
|
||||
link: 'https://twitter.com/MoonyVoid',
|
||||
role: app.getLz('term.socialTeam'),
|
||||
avatar: 'https://pbs.twimg.com/profile_images/1226463559472816129/8LScNYED_400x400.jpg'
|
||||
},
|
||||
{
|
||||
name: 'NoseySG',
|
||||
link: 'https://twitter.com/noah_grose',
|
||||
role: app.getLz('term.socialTeam'),
|
||||
avatar: 'https://pbs.twimg.com/profile_images/1496944907260420099/D5gl6H4J_400x400.jpg'
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
methods: {}
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -1,18 +1,18 @@
|
|||
<script type="text/x-template" id="apple-account-settings">
|
||||
<div style="display:flex;width:100%;height:100%;padding-top: var(--navigationBarHeight);position:absolute;top:0;left:0;">
|
||||
<webview id="foo" src="https://music.apple.com/includes/commerce/account/settings?product=music&isFullscreen=true&isModal=false" style="display:inline-flex; width:100%;"></webview>
|
||||
<webview id="foo"
|
||||
src="https://music.apple.com/includes/commerce/account/settings?product=music&isFullscreen=true&isModal=false"
|
||||
style="display:inline-flex; width:100%;"></webview>
|
||||
</div>
|
||||
</script>
|
||||
<script>
|
||||
Vue.component('apple-account-settings', {
|
||||
template: '#apple-account-settings',
|
||||
mounted() {
|
||||
document.querySelector("#foo").addEventListener("dom-ready", ()=>{
|
||||
// document.querySelector("#foo").executeJavaScript(`document.body.innerHTML += ("<style>.header {display: none!important;} </style>")`)
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
|
||||
}
|
||||
});
|
||||
</script>
|
||||
Vue.component('apple-account-settings', {
|
||||
template: '#apple-account-settings',
|
||||
mounted() {
|
||||
document.querySelector("#foo").addEventListener("dom-ready", () => {
|
||||
// document.querySelector("#foo").executeJavaScript(`document.body.innerHTML += ("<style>.header {display: none!important;} </style>")`)
|
||||
})
|
||||
},
|
||||
methods: {}
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -2,41 +2,47 @@
|
|||
<div class="content-inner">
|
||||
<h1 class="header-text">{{ data.attributes.shortName ?? data.attributes.name}}</h1>
|
||||
<template v-if="data.relationships && data.relationships.grouping">
|
||||
<template v-for="(recom,index) in data.relationships.grouping.data[0].relationships.tabs.data[0].relationships.children.data">
|
||||
<div class="row">
|
||||
<div class="col" v-if="recom.attributes.name != 'Chart Set'">
|
||||
<h3>{{ recom.attributes.name ?? ""}}</h3>
|
||||
</div>
|
||||
<div class="col-auto cider-flex-center" v-if="index != 0 && recom.relationships && ((recom.relationships.children && recom.relationships.children.data.length > 10) || (recom.relationships.contents && recom.relationships.contents.data.length > 10))">
|
||||
<button class="cd-btn-seeall" @click="app.showCollection(recom.relationships.children ? recom.relationships.children : recom.relationships.contents, recom.attributes.name ?? '', 'listen_now')" >{{app.getLz('term.seeAll')}}</button>
|
||||
</div>
|
||||
<template
|
||||
v-for="(recom,index) in data.relationships.grouping.data[0].relationships.tabs.data[0].relationships.children.data">
|
||||
<div class="row">
|
||||
<div class="col" v-if="recom.attributes.name != 'Chart Set'">
|
||||
<h3>{{ recom.attributes.name ?? ""}}</h3>
|
||||
</div>
|
||||
<template v-if="recom.relationships && ((recom.relationships.children && recom.relationships.children.data) || (recom.relationships.contents && recom.relationships.contents.data))">
|
||||
<template v-if="(recom.attributes.name && recom.attributes.name.includes('ideo')) || index === 0">
|
||||
<mediaitem-scroller-horizontal-mvview :imagesize="800" :browsesp="index == 0"
|
||||
:items="recom.relationships.children ? recom.relationships.children.data.limit(10) : recom.relationships.contents.data.limit(10)"></mediaitem-scroller-horizontal-mvview>
|
||||
</template>
|
||||
<template v-else-if="recom.attributes.name == 'Chart Set'">
|
||||
|
||||
</template>
|
||||
<template v-else>
|
||||
<mediaitem-scroller-horizontal-large
|
||||
:items="recom.relationships.children ? recom.relationships.children.data.limit(10) : recom.relationships.contents.data.limit(10)"></mediaitem-scroller-horizontal-large>
|
||||
</template>
|
||||
<div class="col-auto cider-flex-center"
|
||||
v-if="index != 0 && recom.relationships && ((recom.relationships.children && recom.relationships.children.data.length > 10) || (recom.relationships.contents && recom.relationships.contents.data.length > 10))">
|
||||
<button class="cd-btn-seeall"
|
||||
@click="app.showCollection(recom.relationships.children ? recom.relationships.children : recom.relationships.contents, recom.attributes.name ?? '', 'listen_now')">
|
||||
{{app.getLz('term.seeAll')}}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<template
|
||||
v-if="recom.relationships && ((recom.relationships.children && recom.relationships.children.data) || (recom.relationships.contents && recom.relationships.contents.data))">
|
||||
<template v-if="(recom.attributes.name && recom.attributes.name.includes('ideo')) || index === 0">
|
||||
<mediaitem-scroller-horizontal-mvview :imagesize="800" :browsesp="index == 0"
|
||||
:items="recom.relationships.children ? recom.relationships.children.data.limit(10) : recom.relationships.contents.data.limit(10)"></mediaitem-scroller-horizontal-mvview>
|
||||
</template>
|
||||
<template v-else-if="recom.attributes.name == 'Chart Set'">
|
||||
|
||||
</template>
|
||||
<template v-else>
|
||||
<mediaitem-scroller-horizontal-large
|
||||
:items="recom.relationships.children ? recom.relationships.children.data.limit(10) : recom.relationships.contents.data.limit(10)"></mediaitem-scroller-horizontal-large>
|
||||
</template>
|
||||
</template>
|
||||
</template>
|
||||
</template>
|
||||
</template>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script>
|
||||
Vue.component('cider-applecurator', {
|
||||
template: "#cider-applecurator",
|
||||
props: ["data"],
|
||||
data: function() {
|
||||
return {
|
||||
app: this.$root
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
Vue.component('cider-applecurator', {
|
||||
template: "#cider-applecurator",
|
||||
props: ["data"],
|
||||
data: function() {
|
||||
return {
|
||||
app: this.$root
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
|
|
@ -8,7 +8,9 @@
|
|||
<h3>{{app.getLz('home.followedArtists')}}</h3>
|
||||
</div>
|
||||
<div class="col-auto nopadding cider-flex-center">
|
||||
<button class="cd-btn-seeall" @click="syncFavorites()" v-if="!syncingFavs">{{app.getLz('home.syncFavorites')}}</button>
|
||||
<button class="cd-btn-seeall" @click="syncFavorites()" v-if="!syncingFavs">
|
||||
{{app.getLz('home.syncFavorites')}}
|
||||
</button>
|
||||
<div class="spinner" style="height: 26px;" v-else></div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -17,8 +19,10 @@
|
|||
<mediaitem-square :item="artist" kind="small"></mediaitem-square>
|
||||
<button @click="unfollow(artist.id)" class="md-btn md-btn-glyph" style="display:flex;">
|
||||
<div class="sidebar-icon">
|
||||
<div class="svg-icon" :style="{'--url': 'url(./assets/feather/x-circle.svg)'}"></div>
|
||||
</div> {{app.getLz('action.removeFavorite')}}
|
||||
<div class="svg-icon"
|
||||
:style="{'--url': 'url(./assets/feather/x-circle.svg)'}"></div>
|
||||
</div>
|
||||
{{app.getLz('action.removeFavorite')}}
|
||||
</button>
|
||||
</div>
|
||||
</vue-horizontal>
|
||||
|
@ -50,80 +54,81 @@
|
|||
</script>
|
||||
|
||||
<script>
|
||||
Vue.component('cider-artist-feed', {
|
||||
template: '#cider-artist-feed',
|
||||
data: function () {
|
||||
return {
|
||||
app: this.$root,
|
||||
followedArtists: this.$root.cfg.home.followedArtists,
|
||||
artistFeed: [],
|
||||
artists: [],
|
||||
syncingFavs: false
|
||||
}
|
||||
},
|
||||
async mounted() {
|
||||
let self = this
|
||||
await this.getArtistFeed()
|
||||
},
|
||||
methods: {
|
||||
async syncFavorites() {
|
||||
this.syncingFavs = true
|
||||
await app.syncFavorites()
|
||||
await this.getArtistFeed()
|
||||
this.syncingFavs = false
|
||||
},
|
||||
async unfollow(id) {
|
||||
let index = this.followedArtists.indexOf(id)
|
||||
if (index > -1) {
|
||||
this.followedArtists.splice(index, 1)
|
||||
}
|
||||
let artist = this.artists.find(a => a.id == id)
|
||||
let index2 = this.artists.indexOf(artist)
|
||||
if (index2 > -1) {
|
||||
this.artists.splice(index2, 1)
|
||||
}
|
||||
await app.mk.api.v3.music(`/v1/me/favorites`, {
|
||||
"art[url]": "f",
|
||||
"ids[artists]": id,
|
||||
"l": app.mklang,
|
||||
"platform": "web"
|
||||
}, {
|
||||
fetchOptions: {
|
||||
method: "DELETE"
|
||||
}
|
||||
})
|
||||
this.getArtistFeed()
|
||||
},
|
||||
async getArtistFeed() {
|
||||
let artists = this.followedArtists
|
||||
let self = this
|
||||
this.artists = []
|
||||
this.artistFeed = []
|
||||
|
||||
// Apple limits the number of IDs we can provide in a single API call to 50.
|
||||
// Divide it into groups of 50 and send parallel requests
|
||||
let chunks = []
|
||||
for (let artistIdx = 0; artistIdx < artists.length; artistIdx += 50) {
|
||||
chunks.push(artists.slice(artistIdx, artistIdx + 50))
|
||||
}
|
||||
try {
|
||||
const chunkArtistData = await Promise.all(chunks.map(chunk =>
|
||||
this.app.mk.api.v3.music(`/v1/catalog/${app.mk.storefrontId}/artists?ids=${chunk.toString()}&views=latest-release&include[songs]=albums&fields[albums]=artistName,artistUrl,artwork,contentRating,editorialArtwork,editorialVideo,name,playParams,releaseDate,url,trackCount&limit[artists:top-songs]=2&art[url]=f`)))
|
||||
chunkArtistData.forEach(chunkResult =>
|
||||
chunkResult.data.data.forEach(item => {
|
||||
self.artists.push(item)
|
||||
if (item.views["latest-release"].data.length != 0) {
|
||||
self.artistFeed.push(item.views["latest-release"].data[0])
|
||||
}
|
||||
}))
|
||||
// sort artistFeed by attributes.releaseDate descending, date is formatted as "YYYY-MM-DD"
|
||||
this.artistFeed.sort((a, b) => {
|
||||
let dateA = new Date(a.attributes.releaseDate)
|
||||
let dateB = new Date(b.attributes.releaseDate)
|
||||
return dateB - dateA
|
||||
})
|
||||
} catch (err) { }
|
||||
}
|
||||
Vue.component('cider-artist-feed', {
|
||||
template: '#cider-artist-feed',
|
||||
data: function() {
|
||||
return {
|
||||
app: this.$root,
|
||||
followedArtists: this.$root.cfg.home.followedArtists,
|
||||
artistFeed: [],
|
||||
artists: [],
|
||||
syncingFavs: false
|
||||
}
|
||||
},
|
||||
async mounted() {
|
||||
let self = this
|
||||
await this.getArtistFeed()
|
||||
},
|
||||
methods: {
|
||||
async syncFavorites() {
|
||||
this.syncingFavs = true
|
||||
await app.syncFavorites()
|
||||
await this.getArtistFeed()
|
||||
this.syncingFavs = false
|
||||
},
|
||||
async unfollow(id) {
|
||||
let index = this.followedArtists.indexOf(id)
|
||||
if (index > -1) {
|
||||
this.followedArtists.splice(index, 1)
|
||||
}
|
||||
});
|
||||
</script>
|
||||
let artist = this.artists.find(a => a.id == id)
|
||||
let index2 = this.artists.indexOf(artist)
|
||||
if (index2 > -1) {
|
||||
this.artists.splice(index2, 1)
|
||||
}
|
||||
await app.mk.api.v3.music(`/v1/me/favorites`, {
|
||||
"art[url]": "f",
|
||||
"ids[artists]": id,
|
||||
"l": app.mklang,
|
||||
"platform": "web"
|
||||
}, {
|
||||
fetchOptions: {
|
||||
method: "DELETE"
|
||||
}
|
||||
})
|
||||
this.getArtistFeed()
|
||||
},
|
||||
async getArtistFeed() {
|
||||
let artists = this.followedArtists
|
||||
let self = this
|
||||
this.artists = []
|
||||
this.artistFeed = []
|
||||
|
||||
// Apple limits the number of IDs we can provide in a single API call to 50.
|
||||
// Divide it into groups of 50 and send parallel requests
|
||||
let chunks = []
|
||||
for (let artistIdx = 0; artistIdx < artists.length; artistIdx += 50) {
|
||||
chunks.push(artists.slice(artistIdx, artistIdx + 50))
|
||||
}
|
||||
try {
|
||||
const chunkArtistData = await Promise.all(chunks.map(chunk =>
|
||||
this.app.mk.api.v3.music(`/v1/catalog/${app.mk.storefrontId}/artists?ids=${chunk.toString()}&views=latest-release&include[songs]=albums&fields[albums]=artistName,artistUrl,artwork,contentRating,editorialArtwork,editorialVideo,name,playParams,releaseDate,url,trackCount&limit[artists:top-songs]=2&art[url]=f`)))
|
||||
chunkArtistData.forEach(chunkResult =>
|
||||
chunkResult.data.data.forEach(item => {
|
||||
self.artists.push(item)
|
||||
if (item.views["latest-release"].data.length != 0) {
|
||||
self.artistFeed.push(item.views["latest-release"].data[0])
|
||||
}
|
||||
}))
|
||||
// sort artistFeed by attributes.releaseDate descending, date is formatted as "YYYY-MM-DD"
|
||||
this.artistFeed.sort((a, b) => {
|
||||
let dateA = new Date(a.attributes.releaseDate)
|
||||
let dateB = new Date(b.attributes.releaseDate)
|
||||
return dateB - dateA
|
||||
})
|
||||
} catch (err) {
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
<script type="text/x-template" id="cider-artist">
|
||||
<div class="content-inner artist-page"
|
||||
:class="[(data.attributes.editorialVideo && (data.attributes.editorialVideo.motionArtistWide16x9 || data.attributes.editorialVideo.motionArtistFullscreen16x9) || hasHero()) ? 'animated' : '']">
|
||||
<div :class="['artist-header', { 'artist-header-compact': app.cfg.visual.compactArtistHeader }]" :key="data.id" v-observe-visibility="{callback: isHeaderVisible}">
|
||||
<div :class="['artist-header', { 'artist-header-compact': app.cfg.visual.compactArtistHeader }]" :key="data.id"
|
||||
v-observe-visibility="{callback: isHeaderVisible}">
|
||||
<animatedartwork-view
|
||||
:priority="true"
|
||||
v-if="hasAnimated()"
|
||||
|
@ -26,7 +27,7 @@
|
|||
<div class="col cider-flex-center artist-title"
|
||||
:class="{'artist-animation-on': (data.attributes.editorialVideo && (data.attributes.editorialVideo.motionArtistWide16x9 || data.attributes.editorialVideo.motionArtistFullscreen16x9)) || hasHero() }"
|
||||
:style="{ 'color': '#' +hasHeroObject()?.textColor1 ?? ''}"
|
||||
>
|
||||
>
|
||||
<button class="artist-play" @click="app.mk.setStationQueue({artist:'a-'+data.id}).then(()=>{
|
||||
app.mk.play()
|
||||
})" :aria-label="app.getLz('term.play')"><%- include("../svg/play.svg") %></button>
|
||||
|
@ -42,10 +43,10 @@
|
|||
<div class="svg-icon"></div>
|
||||
</button>
|
||||
</div>
|
||||
<div class="artworkContainer"
|
||||
<div class="artworkContainer"
|
||||
v-if="!(data.attributes.editorialVideo && (data.attributes.editorialVideo.motionArtistWide16x9 || data.attributes.editorialVideo.motionArtistFullscreen16x9)) && !hasHero()">
|
||||
<artwork-material :url="data.attributes.artwork.url" size="190" images="1"></artwork-material>
|
||||
</div>
|
||||
<artwork-material :url="data.attributes.artwork.url" size="190" images="1"></artwork-material>
|
||||
</div>
|
||||
<div class="artist-hero" v-if="hasHero() && !hasAnimated()">
|
||||
<mediaitem-artwork shadow="none" :url="hasHero()" size="2048" />
|
||||
</div>
|
||||
|
@ -157,133 +158,133 @@
|
|||
</div>
|
||||
</script>
|
||||
<script>
|
||||
Vue.component('cider-artist', {
|
||||
template: "#cider-artist",
|
||||
props: ['data'],
|
||||
data: function () {
|
||||
return {
|
||||
topSongsExpanded: false,
|
||||
app: this.$root,
|
||||
headerVisible: true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
hasAnimated() {
|
||||
if(this.data.attributes?.editorialVideo && (this.data.attributes?.editorialVideo?.motionArtistWide16x9 || this.data.attributes?.editorialVideo?.motionArtistFullscreen16x9)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
hasHero() {
|
||||
if(this.data.attributes?.editorialArtwork?.centeredFullscreenBackground){
|
||||
return this.data.attributes?.editorialArtwork?.centeredFullscreenBackground.url
|
||||
} else if(this.data.attributes?.editorialArtwork?.bannerUber) {
|
||||
return this.data.attributes?.editorialArtwork?.bannerUber.url
|
||||
} else if(this.data.attributes?.editorialArtwork?.subscriptionHero){
|
||||
return this.data.attributes?.editorialArtwork?.subscriptionHero.url
|
||||
}
|
||||
return false;
|
||||
},
|
||||
hasHeroObject() {
|
||||
if(this.data.attributes?.editorialArtwork?.centeredFullscreenBackground){
|
||||
return this.data.attributes?.editorialArtwork?.centeredFullscreenBackground
|
||||
} else if(this.data.attributes?.editorialArtwork?.bannerUber) {
|
||||
return this.data.attributes?.editorialArtwork?.bannerUber
|
||||
} else if(this.data.attributes?.editorialArtwork?.subscriptionHero){
|
||||
return this.data.attributes?.editorialArtwork?.subscriptionHero
|
||||
}
|
||||
return [];
|
||||
},
|
||||
isHeaderVisible(visible) {
|
||||
this.headerVisible = visible
|
||||
},
|
||||
async artistMenu(event) {
|
||||
let self = this
|
||||
let followAction = "follow"
|
||||
let followActions = {
|
||||
follow: {
|
||||
icon: "./assets/feather/plus-circle.svg",
|
||||
name: app.getLz('action.follow'),
|
||||
action: () => {
|
||||
self.app.cfg.home.followedArtists.push(self.data.id)
|
||||
}
|
||||
},
|
||||
unfollow: {
|
||||
icon: "./assets/feather/x-circle.svg",
|
||||
name: app.getLz('action.unfollow'),
|
||||
action: () => {
|
||||
let index = self.app.cfg.home.followedArtists.indexOf(self.data.id)
|
||||
if (index > -1) {
|
||||
self.app.cfg.home.followedArtists.splice(index, 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
let favoriteActions = {
|
||||
favorite: {
|
||||
icon: "./assets/star.svg",
|
||||
name: app.getLz('action.favorite'),
|
||||
action: () => {
|
||||
app.setArtistFavorite(app.artistPage.data.id, true)
|
||||
}
|
||||
},
|
||||
removeFavorite: {
|
||||
icon: "./assets/star.svg",
|
||||
name: app.getLz('action.removeFavorite'),
|
||||
action: () => {
|
||||
app.setArtistFavorite(app.artistPage.data.id, false)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (this.app.cfg.home.followedArtists.includes(self.data.id)) {
|
||||
followAction = "unfollow"
|
||||
}
|
||||
const inFavorites = (await app.mk.api.v3.music(`/v1/catalog/${app.mk.storefrontId}/artists/${app.artistPage.data.id}`, {
|
||||
"fields[artists]": "inFavorites"
|
||||
})).data.data[0].attributes?.inFavorites
|
||||
app.showMenuPanel({
|
||||
items: [
|
||||
{
|
||||
icon: "./assets/feather/play.svg",
|
||||
name: app.getLz('action.startRadio'),
|
||||
action: () => {
|
||||
app.mk.setStationQueue({artist: self.data.id}).then(() => {
|
||||
app.mk.play()
|
||||
})
|
||||
}
|
||||
},
|
||||
favoriteActions[inFavorites ? "removeFavorite" : "favorite"],
|
||||
// followActions[followAction],
|
||||
{
|
||||
icon: "./assets/feather/share.svg",
|
||||
name: app.getLz('term.share'),
|
||||
action: () => {
|
||||
self.app.copyToClipboard(self.data.attributes.url)
|
||||
}
|
||||
}
|
||||
]
|
||||
}, event)
|
||||
},
|
||||
getArtistPalette(artist) {
|
||||
if (artist["attributes"]["artwork"]) {
|
||||
return {
|
||||
"background": "#" + artist["attributes"]["artwork"]["bgColor"],
|
||||
"color": "#" + artist["attributes"]["artwork"]["textColor1"],
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
"background": "#000000",
|
||||
"color": "#ffffff",
|
||||
}
|
||||
}
|
||||
},
|
||||
getTopResult() {
|
||||
if (this.search.results["meta"]) {
|
||||
return this.search.results[this.search.results.meta.results.order[0]]["data"][0]
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
Vue.component('cider-artist', {
|
||||
template: "#cider-artist",
|
||||
props: ['data'],
|
||||
data: function() {
|
||||
return {
|
||||
topSongsExpanded: false,
|
||||
app: this.$root,
|
||||
headerVisible: true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
hasAnimated() {
|
||||
if (this.data.attributes?.editorialVideo && (this.data.attributes?.editorialVideo?.motionArtistWide16x9 || this.data.attributes?.editorialVideo?.motionArtistFullscreen16x9)) {
|
||||
return true;
|
||||
}
|
||||
})
|
||||
</script>
|
||||
return false;
|
||||
},
|
||||
hasHero() {
|
||||
if (this.data.attributes?.editorialArtwork?.centeredFullscreenBackground) {
|
||||
return this.data.attributes?.editorialArtwork?.centeredFullscreenBackground.url
|
||||
} else if (this.data.attributes?.editorialArtwork?.bannerUber) {
|
||||
return this.data.attributes?.editorialArtwork?.bannerUber.url
|
||||
} else if (this.data.attributes?.editorialArtwork?.subscriptionHero) {
|
||||
return this.data.attributes?.editorialArtwork?.subscriptionHero.url
|
||||
}
|
||||
return false;
|
||||
},
|
||||
hasHeroObject() {
|
||||
if (this.data.attributes?.editorialArtwork?.centeredFullscreenBackground) {
|
||||
return this.data.attributes?.editorialArtwork?.centeredFullscreenBackground
|
||||
} else if (this.data.attributes?.editorialArtwork?.bannerUber) {
|
||||
return this.data.attributes?.editorialArtwork?.bannerUber
|
||||
} else if (this.data.attributes?.editorialArtwork?.subscriptionHero) {
|
||||
return this.data.attributes?.editorialArtwork?.subscriptionHero
|
||||
}
|
||||
return [];
|
||||
},
|
||||
isHeaderVisible(visible) {
|
||||
this.headerVisible = visible
|
||||
},
|
||||
async artistMenu(event) {
|
||||
let self = this
|
||||
let followAction = "follow"
|
||||
let followActions = {
|
||||
follow: {
|
||||
icon: "./assets/feather/plus-circle.svg",
|
||||
name: app.getLz('action.follow'),
|
||||
action: () => {
|
||||
self.app.cfg.home.followedArtists.push(self.data.id)
|
||||
}
|
||||
},
|
||||
unfollow: {
|
||||
icon: "./assets/feather/x-circle.svg",
|
||||
name: app.getLz('action.unfollow'),
|
||||
action: () => {
|
||||
let index = self.app.cfg.home.followedArtists.indexOf(self.data.id)
|
||||
if (index > -1) {
|
||||
self.app.cfg.home.followedArtists.splice(index, 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
let favoriteActions = {
|
||||
favorite: {
|
||||
icon: "./assets/star.svg",
|
||||
name: app.getLz('action.favorite'),
|
||||
action: () => {
|
||||
app.setArtistFavorite(app.artistPage.data.id, true)
|
||||
}
|
||||
},
|
||||
removeFavorite: {
|
||||
icon: "./assets/star.svg",
|
||||
name: app.getLz('action.removeFavorite'),
|
||||
action: () => {
|
||||
app.setArtistFavorite(app.artistPage.data.id, false)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (this.app.cfg.home.followedArtists.includes(self.data.id)) {
|
||||
followAction = "unfollow"
|
||||
}
|
||||
const inFavorites = (await app.mk.api.v3.music(`/v1/catalog/${app.mk.storefrontId}/artists/${app.artistPage.data.id}`, {
|
||||
"fields[artists]": "inFavorites"
|
||||
})).data.data[0].attributes?.inFavorites
|
||||
app.showMenuPanel({
|
||||
items: [
|
||||
{
|
||||
icon: "./assets/feather/play.svg",
|
||||
name: app.getLz('action.startRadio'),
|
||||
action: () => {
|
||||
app.mk.setStationQueue({ artist: self.data.id }).then(() => {
|
||||
app.mk.play()
|
||||
})
|
||||
}
|
||||
},
|
||||
favoriteActions[inFavorites ? "removeFavorite" : "favorite"],
|
||||
// followActions[followAction],
|
||||
{
|
||||
icon: "./assets/feather/share.svg",
|
||||
name: app.getLz('term.share'),
|
||||
action: () => {
|
||||
self.app.copyToClipboard(self.data.attributes.url)
|
||||
}
|
||||
}
|
||||
]
|
||||
}, event)
|
||||
},
|
||||
getArtistPalette(artist) {
|
||||
if (artist["attributes"]["artwork"]) {
|
||||
return {
|
||||
"background": "#" + artist["attributes"]["artwork"]["bgColor"],
|
||||
"color": "#" + artist["attributes"]["artwork"]["textColor1"],
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
"background": "#000000",
|
||||
"color": "#ffffff",
|
||||
}
|
||||
}
|
||||
},
|
||||
getTopResult() {
|
||||
if (this.search.results["meta"]) {
|
||||
return this.search.results[this.search.results.meta.results.order[0]]["data"][0]
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
|
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