File structure update - all source files now in src directory, cider-ui renamed to renderer, main/backend-related files in main directory, base implementation of mpris and start of backend rework

This commit is contained in:
Core 2021-12-19 06:02:38 +00:00
parent 29be5dd481
commit 7d3e513187
85 changed files with 114 additions and 10 deletions

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

View file

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!-- Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) --><path fill="white" d="M257.5 445.1l-22.2 22.2c-9.4 9.4-24.6 9.4-33.9 0L7 273c-9.4-9.4-9.4-24.6 0-33.9L201.4 44.7c9.4-9.4 24.6-9.4 33.9 0l22.2 22.2c9.5 9.5 9.3 25-.4 34.3L136.6 216H424c13.3 0 24 10.7 24 24v32c0 13.3-10.7 24-24 24H136.6l120.5 114.8c9.8 9.3 10 24.8.4 34.3z"/></svg>

Before

Width:  |  Height:  |  Size: 521 B

View file

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!-- Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) --><path fill="white" d="M11.5 280.6l192 160c20.6 17.2 52.5 2.8 52.5-24.6V96c0-27.4-31.9-41.8-52.5-24.6l-192 160c-15.3 12.8-15.3 36.4 0 49.2zm256 0l192 160c20.6 17.2 52.5 2.8 52.5-24.6V96c0-27.4-31.9-41.8-52.5-24.6l-192 160c-15.3 12.8-15.3 36.4 0 49.2z"/></svg>

Before

Width:  |  Height:  |  Size: 500 B

View file

@ -1,18 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
<!-- Generator: Sketch 3.2.2 (9983) - http://www.bohemiancoding.com/sketch -->
<title>ic_cast_black_24dp</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" sketch:type="MSPage">
<g id="ic_cast_black_24dp" sketch:type="MSArtboardGroup">
<g id="ic_remove_circle_white_24dp" sketch:type="MSLayerGroup">
<path d="M1,18 L1,21 L4,21 C4,19.34 2.66,18 1,18 L1,18 Z M1,14 L1,16 C3.76,16 6,18.24 6,21 L8,21 C8,17.13 4.87,14 1,14 L1,14 Z M1,10 L1,12 C5.97,12 10,16.03 10,21 L12,21 C12,14.92 7.07,10 1,10 L1,10 Z M21,3 L3,3 C1.9,3 1,3.9 1,5 L1,8 L3,8 L3,5 L21,5 L21,19 L14,19 L14,21 L21,21 C22.1,21 23,20.1 23,19 L23,5 C23,3.9 22.1,3 21,3 L21,3 Z" id="cast" fill="white" sketch:type="MSShapeGroup"></path>
<rect id="bounds" sketch:type="MSShapeGroup" x="0" y="0" width="24" height="24"></rect>
</g>
</g>
<g id="assets" sketch:type="MSLayerGroup" transform="translate(-208.000000, -106.000000)">
<g id="64px" transform="translate(0.000000, 114.000000)"></g>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.4 KiB

View file

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="white" viewBox="0 0 320 512"><!-- Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) --><path d="M34.52 239.03L228.87 44.69c9.37-9.37 24.57-9.37 33.94 0l22.67 22.67c9.36 9.36 9.37 24.52.04 33.9L131.49 256l154.02 154.75c9.34 9.38 9.32 24.54-.04 33.9l-22.67 22.67c-9.37 9.37-24.57 9.37-33.94 0L34.52 272.97c-9.37-9.37-9.37-24.57 0-33.94z"/></svg>

Before

Width:  |  Height:  |  Size: 511 B

View file

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!-- Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) --><path fill="white" d="M500.5 231.4l-192-160C287.9 54.3 256 68.6 256 96v320c0 27.4 31.9 41.8 52.5 24.6l192-160c15.3-12.8 15.3-36.4 0-49.2zm-256 0l-192-160C31.9 54.3 0 68.6 0 96v320c0 27.4 31.9 41.8 52.5 24.6l192-160c15.3-12.8 15.3-36.4 0-49.2z"/></svg>

Before

Width:  |  Height:  |  Size: 493 B

View file

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!-- Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) --><path fill="white" d="M80 368H16a16 16 0 0 0-16 16v64a16 16 0 0 0 16 16h64a16 16 0 0 0 16-16v-64a16 16 0 0 0-16-16zm0-320H16A16 16 0 0 0 0 64v64a16 16 0 0 0 16 16h64a16 16 0 0 0 16-16V64a16 16 0 0 0-16-16zm0 160H16a16 16 0 0 0-16 16v64a16 16 0 0 0 16 16h64a16 16 0 0 0 16-16v-64a16 16 0 0 0-16-16zm416 176H176a16 16 0 0 0-16 16v32a16 16 0 0 0 16 16h320a16 16 0 0 0 16-16v-32a16 16 0 0 0-16-16zm0-320H176a16 16 0 0 0-16 16v32a16 16 0 0 0 16 16h320a16 16 0 0 0 16-16V80a16 16 0 0 0-16-16zm0 160H176a16 16 0 0 0-16 16v32a16 16 0 0 0 16 16h320a16 16 0 0 0 16-16v-32a16 16 0 0 0-16-16z"/></svg>

Before

Width:  |  Height:  |  Size: 831 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 12 KiB

View file

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!-- Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) --><path fill="white" d="M144 479H48c-26.5 0-48-21.5-48-48V79c0-26.5 21.5-48 48-48h96c26.5 0 48 21.5 48 48v352c0 26.5-21.5 48-48 48zm304-48V79c0-26.5-21.5-48-48-48h-96c-26.5 0-48 21.5-48 48v352c0 26.5 21.5 48 48 48h96c26.5 0 48-21.5 48-48z"/></svg>

Before

Width:  |  Height:  |  Size: 487 B

View file

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!-- Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) --><path fill="white" d="M424.4 214.7L72.4 6.6C43.8-10.3 0 6.1 0 47.9V464c0 37.5 40.7 60.1 72.4 41.3l352-208c31.4-18.5 31.5-64.1 0-82.6z"/></svg>

Before

Width:  |  Height:  |  Size: 384 B

View file

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!-- Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) --><path fill="white" d="M464 32H336c-26.5 0-48 21.5-48 48v128c0 26.5 21.5 48 48 48h80v64c0 35.3-28.7 64-64 64h-8c-13.3 0-24 10.7-24 24v48c0 13.3 10.7 24 24 24h8c88.4 0 160-71.6 160-160V80c0-26.5-21.5-48-48-48zm-288 0H48C21.5 32 0 53.5 0 80v128c0 26.5 21.5 48 48 48h80v64c0 35.3-28.7 64-64 64h-8c-13.3 0-24 10.7-24 24v48c0 13.3 10.7 24 24 24h8c88.4 0 160-71.6 160-160V80c0-26.5-21.5-48-48-48z"/></svg>

Before

Width:  |  Height:  |  Size: 640 B

View file

@ -1,47 +0,0 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 18.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 60 60" style="enable-background:new 0 0 60 60;" xml:space="preserve">
<g>
<path fill="white" d="M42,12H20.414l7.293-7.293c0.391-0.391,0.391-1.023,0-1.414s-1.023-0.391-1.414,0l-8.999,8.999
c-0.093,0.092-0.166,0.203-0.217,0.326c-0.101,0.244-0.101,0.52,0,0.764c0.051,0.123,0.124,0.234,0.217,0.326l8.999,8.999
C26.488,22.902,26.744,23,27,23s0.512-0.098,0.707-0.293c0.391-0.391,0.391-1.023,0-1.414L20.414,14H42c8.822,0,16,7.178,16,16
c0,4.252-1.668,8.264-4.696,11.295c-0.391,0.391-0.391,1.024,0,1.414c0.195,0.195,0.451,0.293,0.707,0.293s0.512-0.098,0.707-0.293
C58.124,39.3,60,34.786,60,30C60,20.075,51.925,12,42,12z"/>
<path fill="white" d="M35.707,37.293c-0.391-0.391-1.023-0.391-1.414,0s-0.391,1.023,0,1.414L41.586,46H18C9.178,46,2,38.822,2,30
c0-3.783,1.359-7.46,3.828-10.354c0.358-0.421,0.309-1.052-0.111-1.41c-0.419-0.359-1.052-0.31-1.41,0.111
C1.529,21.604,0,25.741,0,30c0,9.925,8.075,18,18,18h23.586l-7.293,7.293c-0.391,0.391-0.391,1.023,0,1.414
C34.488,56.902,34.744,57,35,57s0.512-0.098,0.707-0.293l9-9c0.391-0.391,0.391-1.023,0-1.414L35.707,37.293z"/>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.6 KiB

View file

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!-- Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) --><path fill="white" d="M505 442.7L405.3 343c-4.5-4.5-10.6-7-17-7H372c27.6-35.3 44-79.7 44-128C416 93.1 322.9 0 208 0S0 93.1 0 208s93.1 208 208 208c48.3 0 92.7-16.4 128-44v16.3c0 6.4 2.5 12.5 7 17l99.7 99.7c9.4 9.4 24.6 9.4 33.9 0l28.3-28.3c9.4-9.4 9.4-24.6.1-34zM208 336c-70.7 0-128-57.2-128-128 0-70.7 57.2-128 128-128 70.7 0 128 57.2 128 128 0 70.7-57.2 128-128 128z"/></svg>

Before

Width:  |  Height:  |  Size: 618 B

View file

@ -1,45 +0,0 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 18.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 230.055 230.055" style="enable-background:new 0 0 230.055 230.055;" xml:space="preserve">
<path fill="white" d="M199.419,124.497c-3.516-3.515-9.213-3.515-12.729,0c-3.515,3.515-3.515,9.213,0,12.728l12.637,12.636h-8.406
c-8.177,0-16.151-2.871-22.453-8.083l-32.346-26.751l32.345-26.751c6.303-5.212,14.277-8.083,22.454-8.083h8.406L186.69,92.83
c-3.515,3.515-3.515,9.213,0,12.728c1.758,1.757,4.061,2.636,6.364,2.636s4.606-0.879,6.364-2.636l28-28
c3.515-3.515,3.515-9.213,0-12.728l-28-28c-3.516-3.515-9.213-3.515-12.729,0c-3.515,3.515-3.515,9.213,0,12.728l12.637,12.636
h-8.406c-12.354,0-24.403,4.337-33.926,12.211L122,103.348L82.564,70.733c-6.658-5.507-15.084-8.54-23.724-8.54H9
c-4.971,0-9,4.029-9,9s4.029,9,9,9h49.841c4.462,0,8.813,1.566,12.252,4.411l36.786,30.423L71.094,145.45
c-3.439,2.844-7.791,4.411-12.253,4.411H9c-4.971,0-9,4.029-9,9s4.029,9,9,9h49.841c8.64,0,17.065-3.033,23.725-8.54L122,126.707
l34.996,28.943c9.521,7.875,21.57,12.211,33.925,12.211h8.406l-12.637,12.636c-3.515,3.515-3.515,9.213,0,12.728
c1.758,1.757,4.061,2.636,6.364,2.636s4.606-0.879,6.364-2.636l28-28c3.515-3.515,3.515-9.213,0-12.728L199.419,124.497z"/>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 584 B

View file

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512"><!-- Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) --><path fill="white" d="M215.03 72.04L126.06 161H24c-13.26 0-24 10.74-24 24v144c0 13.25 10.74 24 24 24h102.06l88.97 88.95c15.03 15.03 40.97 4.47 40.97-16.97V89.02c0-21.47-25.96-31.98-40.97-16.98zm123.2 108.08c-11.58-6.33-26.19-2.16-32.61 9.45-6.39 11.61-2.16 26.2 9.45 32.61C327.98 229.28 336 242.62 336 257c0 14.38-8.02 27.72-20.92 34.81-11.61 6.41-15.84 21-9.45 32.61 6.43 11.66 21.05 15.8 32.61 9.45 28.23-15.55 45.77-45 45.77-76.88s-17.54-61.32-45.78-76.87z"/></svg>

Before

Width:  |  Height:  |  Size: 710 B

View file

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512"><!-- Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) --><path fill="white" d="M215.03 71.05L126.06 160H24c-13.26 0-24 10.74-24 24v144c0 13.25 10.74 24 24 24h102.06l88.97 88.95c15.03 15.03 40.97 4.47 40.97-16.97V88.02c0-21.46-25.96-31.98-40.97-16.97zm233.32-51.08c-11.17-7.33-26.18-4.24-33.51 6.95-7.34 11.17-4.22 26.18 6.95 33.51 66.27 43.49 105.82 116.6 105.82 195.58 0 78.98-39.55 152.09-105.82 195.58-11.17 7.32-14.29 22.34-6.95 33.5 7.04 10.71 21.93 14.56 33.51 6.95C528.27 439.58 576 351.33 576 256S528.27 72.43 448.35 19.97zM480 256c0-63.53-32.06-121.94-85.77-156.24-11.19-7.14-26.03-3.82-33.12 7.46s-3.78 26.21 7.41 33.36C408.27 165.97 432 209.11 432 256s-23.73 90.03-63.48 115.42c-11.19 7.14-14.5 22.07-7.41 33.36 6.51 10.36 21.12 15.14 33.12 7.46C447.94 377.94 480 319.54 480 256zm-141.77-76.87c-11.58-6.33-26.19-2.16-32.61 9.45-6.39 11.61-2.16 26.2 9.45 32.61C327.98 228.28 336 241.63 336 256c0 14.38-8.02 27.72-20.92 34.81-11.61 6.41-15.84 21-9.45 32.61 6.43 11.66 21.05 15.8 32.61 9.45 28.23-15.55 45.77-45 45.77-76.88s-17.54-61.32-45.78-76.86z"/></svg>

Before

Width:  |  Height:  |  Size: 1.2 KiB

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,778 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="preconnect" href="https://amp-api.music.apple.com/" crossorigin/>
<link rel="preconnect" href="https://api.music.apple.com/" crossorigin/>
<link rel="preconnect" href="https://is1-ssl.mzstatic.com/" crossorigin/>
<link rel="preconnect" href="https://is2-ssl.mzstatic.com/" crossorigin/>
<link rel="preconnect" href="https://is3-ssl.mzstatic.com/" crossorigin/>
<link rel="preconnect" href="https://is4-ssl.mzstatic.com/" crossorigin/>
<link rel="preconnect" href="https://is5-ssl.mzstatic.com/" crossorigin/>
<link rel="preconnect" href="https://play.itunes.apple.com/" crossorigin/>
<link rel="preconnect" href="https://aod-ssl.itunes.apple.com/" crossorigin/>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no, viewport-fit=cover">
<title>Cider</title>
<link rel="stylesheet" href="style-old.css?v=2">
<script src="vue.js"></script>
<script src="sortable.min.js"></script>
<script src="vuedraggable.umd.min.js"></script>
<link rel="manifest" href="./manifest.json?v=2">
</head>
<body oncontextmenu="return false;" loading="1">
<div id="app">
<div id="app-main">
<div class="app-chrome">
<div class="app-chrome--left">
<div class="app-chrome-item full-height">
<div class="app-title"></div>
</div>
<div class="app-chrome-item">
<button class="playback-button--small shuffle" v-if="mk.shuffleMode == 0"
@click="mk.shuffleMode = 1"></button>
<button class="playback-button--small shuffle active" v-else @click="mk.shuffleMode = 0"></button>
</div>
<div class="app-chrome-item">
<button class="playback-button previous" @click="mk.skipToPreviousItem()"></button>
</div>
<div class="app-chrome-item">
<button class="playback-button pause" @click="mk.pause()" v-if="mk.isPlaying"></button>
<button class="playback-button play" @click="mk.play()" v-else></button>
</div>
<div class="app-chrome-item">
<button class="playback-button next" @click="mk.skipToNextItem()"></button>
</div>
<div class="app-chrome-item">
<button class="playback-button--small repeat" v-if="mk.repeatMode == 0"
@click="mk.repeatMode = 1"></button>
<button class="playback-button--small repeat active" @click="mk.repeatMode = 2"
v-else-if="mk.repeatMode == 1"></button>
<button class="playback-button--small repeat repeatOne" @click="mk.repeatMode = 0"
v-else-if="mk.repeatMode == 2"></button>
</div>
</div>
<div class="app-chrome--center">
<div class="app-chrome-item playback-controls">
<template v-if="mkReady()">
<div class="app-playback-controls">
<div class="artwork" :style="{'--artwork': getNowPlayingArtwork(42)}"></div>
<div class="playback-info">
<div class="song-name">
{{ mk.nowPlayingItem["attributes"]["name"] }}
</div>
<div class="song-artist">
{{ mk.nowPlayingItem["attributes"]["artistName"] }} - {{
mk.nowPlayingItem["attributes"]["albumName"] }}
</div>
<div class="song-progress">
<input type="range" step="0.01" min="0"
@change="mk.seekToTime($event.target.value)"
:max="mk.currentPlaybackDuration"
:value="playerLCD.playbackDuration">
</div>
</div>
<div class="actions">❤️</div>
</div>
</template>
</div>
</div>
<div class="app-chrome--right">
<div class="app-chrome-item volume display--large">
<input type="range" class="" step="0.01" min="0" max="1" v-model="mk.volume"
v-if="typeof mk.volume != 'undefined'">
</div>
<div class="app-chrome-item generic">
<button class="playback-button--small">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 30 22" version="1.1" fill="#fff"
style="width: 100%; height: 100%; fill-rule: evenodd; clip-rule: evenodd; stroke-linejoin: round; stroke-miterlimit: 1.41421">
<path
d="M16.811,12.75c0.245,-0.355 0.389,-0.786 0.389,-1.25c0,-1.215 -0.985,-2.2 -2.2,-2.2c-1.215,0 -2.2,0.985 -2.2,2.2c0,0.466 0.145,0.898 0.392,1.254l-0.83,1.047c-0.537,-0.616 -0.862,-1.42 -0.862,-2.301c0,-1.933 1.567,-3.5 3.5,-3.5c1.933,0 3.5,1.567 3.5,3.5c0,0.879 -0.324,1.683 -0.859,2.297l-0.83,-1.047Zm1.271,1.604c0.694,-0.749 1.118,-1.752 1.118,-2.854c0,-2.32 -1.88,-4.2 -4.2,-4.2c-2.32,0 -4.2,1.88 -4.2,4.2c0,1.103 0.425,2.107 1.121,2.857l-0.814,1.028c-0.993,-0.995 -1.607,-2.368 -1.607,-3.885c0,-3.038 2.462,-5.5 5.5,-5.5c3.038,0 5.5,2.462 5.5,5.5c0,1.515 -0.613,2.887 -1.604,3.882l-0.814,-1.028Zm1.252,1.58c1.151,-1.126 1.866,-2.697 1.866,-4.434c0,-3.424 -2.776,-6.2 -6.2,-6.2c-3.424,0 -6.2,2.776 -6.2,6.2c0,1.739 0.716,3.311 1.869,4.437l-0.811,1.023c-1.452,-1.368 -2.358,-3.308 -2.358,-5.46c0,-4.142 3.358,-7.5 7.5,-7.5c4.142,0 7.5,3.358 7.5,7.5c0,2.15 -0.905,4.089 -2.355,5.457l-0.811,-1.023Zm-0.227,2.066l-8.219,0c-0.355,0 -0.515,-0.434 -0.27,-0.717l4.058,-5.12c0.178,-0.217 0.474,-0.217 0.652,0l4.058,5.12c0.237,0.283 0.085,0.717 -0.279,0.717Z"
style="fill-rule:nonzero"></path>
</svg>
</button>
</div>
<div class="app-chrome-item generic">
<button class="playback-button--small queue"></button>
</div>
<div class="app-chrome-item generic">
<button class="playback-button--small lyrics"
@click="drawertest = !drawertest; lyricon =!lyricon; if(drawertest == true){loadLyrics();}"
></button>
</div>
<div class="app-chrome-item full-height">
<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>
<div class="app-navigation">
<div id="app-sidebar">
<div class="app-sidebar-header">
<div class="search-input-container">
<div class="search-input--icon"></div>
<input type="search"
spellcheck="false"
@click="showSearch()"
@change="showSearch();searchQuery()"
placeholder="Search..."
v-model="search.term"
class="search-input">
</div>
</div>
<div class="app-sidebar-content">
<div class="app-sidebar-header-text">
Apple Music
</div>
<sidebar-library-item name="Listen Now" page="listen_now"></sidebar-library-item>
<sidebar-library-item name="Browse" page="browse"></sidebar-library-item>
<sidebar-library-item name="Radio" page="radio"></sidebar-library-item>
<div class="app-sidebar-header-text">
Library
</div>
<sidebar-library-item name="Songs" page="library-songs"></sidebar-library-item>
<sidebar-library-item name="Albums" page="library-albums"></sidebar-library-item>
<sidebar-library-item name="Artists" page="library-artists"></sidebar-library-item>
<sidebar-library-item name="Made For You" page="library-madeforyou"></sidebar-library-item>
<div class="app-sidebar-header-text">
Playlists
</div>
<button class="app-sidebar-item" v-for="item in playlists.listing" :key="item.id" :href="item.href"
@click='app.page=`playlist_` + item.id ; showingPlaylist = [];getPlaylistFromID(app.page.substring(9))'>
{{ item.attributes.name }}
</button>
</div>
<transition name="wpfade">
<div class="app-sidebar-content" v-if="chrome.menuOpened">
<button class="app-sidebar-item" @click="chrome.hideUserInfo = !chrome.hideUserInfo">
Toggle Personal Info
</button>
<button class="app-sidebar-item">
About
</button>
<button class="app-sidebar-item">
Discord
</button>
<button class="app-sidebar-item">
Settings
</button>
<button class="app-sidebar-item">
Sign Out
</button>
</div>
</transition>
<div class="app-sidebar-footer">
<input type="range" class="display--small">
<button class="app-sidebar-button" style="width:100%"
@click="chrome.menuOpened = !chrome.menuOpened">
<template v-if="chrome.userinfo.attributes">
<img class="sidebar-user-icon" loading="lazy"
:src="getMediaItemArtwork(chrome.userinfo.attributes['artwork'] ? chrome.userinfo.attributes['artwork']['url'] : '', 26)"
/>
</template>
<div class="sidebar-user-text" v-if="!chrome.hideUserInfo">
<template v-if="chrome.userinfo.attributes">
<div class="fullname text-overflow-elipsis">{{ chrome.userinfo.attributes.name }}</div>
<div class="handle-text text-overflow-elipsis">@{{ chrome.userinfo.attributes.handle
}}
</div>
</template>
<template v-else>
Sign in
</template>
</div>
<div class="sidebar-user-text" v-else>
Cider
</div>
</button>
</div>
<div class="app-sidebar-notification" v-if="library.songs.downloadState == 1">
<div>Updating your library...</div>
<div>{{ library.songs.meta.progress }} / {{ library.songs.meta.total }}</div>
<div style="width: 100%">
<progress style="width: 80%;" :value="library.songs.meta.progress"
:max="library.songs.meta.total"></progress>
</div>
</div>
</div>
<div id="app-content">
<!-- Playlist / Album page-->
<transition name="wpfade">
<template v-if="page.includes('playlist_')">
<cider-playlist :data="showingPlaylist"></cider-playlist>
</template>
</transition>
<transition name="wpfade">
<template v-if="page.includes('album_')">
<cider-playlist :data="showingPlaylist"></cider-playlist>
</template>
</transition>
</transition>
<!-- Browse -->
<transition name="wpfade">
<template v-if="page == 'browse'">
<div class="content-inner">
<button id="apple-music-authorize" class="md-btn md-btn-primary" @click="init()">Start
MusicKit
</button>
<button id="apple-music-unauthorize" class="md-btn md-btn-primary" @click="unauthorize()">
Stop
MusicKit
</button>
<br>
<template v-if="mk.nowPlayingItem">
currentPlaybackProgress: {{ app.mk.currentPlaybackProgress }}
<br>
currentPlaybackDuration: {{ app.mk.currentPlaybackDuration }}
</template>
<div><input type="text" v-model="quickPlayQuery">
<button @click="quickPlay(quickPlayQuery)">Play</button>
</div>
<h1 class="header-text">Browse</h1>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed euismod, urna eu tincidunt
consectetur, nisl nunc euismod nisi, eu porttitor nisl nisi euismod nisi.
</p>
<div class="media-item--small">
<div class="artwork">
</div>
<div class="text">
Text
</div>
<div class="subtext">
Subtext
</div>
</div>
<br>
<br>
<h1 class="header-text">Listen Now</h1>
<div class="winbox">
<div class="fancy">990kbps</div>
<div class="">
<button class="md-btn md-btn-primary">Audio Quality Settings</button>
</div>
</div>
<button class="md-btn" @click="drawertest = !drawertest">Toggle Drawer</button>
<button class="md-btn">Button</button>
<button class="md-btn md-btn-primary">Button</button>
</div>
</template>
</transition>
<!-- Listen Now -->
<transition v-on:enter="getListenNow()" name="wpfade">
<template v-if="page == 'listen_now'" @created="console.log('listennow')">
<cider-listen-now :data="listennow"></cider-listen-now>
</template>
</transition>
<!-- Radio -->
<transition v-on:enter="getRadioStations()" name="wpfade">
<template v-if="page == 'radio'" @created="console.log('radio')">
<div class="content-inner">
<h1 class="header-text">Radio</h1>
<h3>Recent Stations</h3>
<mediaitem-square :item="item" v-for="item in radio.personal"></mediaitem-square>
</div>
</template>
</transition>
<!-- Search -->
<transition name="wpfade">
<template v-if="page == 'search'">
<cider-search :search="search"></cider-search>
</template>
</transition>
<!-- Library - Songs -->
<transition name="wpfade" v-on:enter="getLibrarySongsFull()">
<template v-if="page == 'library-songs'">
<div class="content-inner">
<h1 class="header-text">Songs</h1>
<div class="search-input-container" style="width:100%;margin: 16px 0px;">
<div class="search-input--icon"></div>
<input type="search"
style="width:100%;"
spellcheck="false"
placeholder="Search..."
@input="searchLibrarySongs"
v-model="library.songs.search"
class="search-input">
</div>
<mediaitem-list-item :item="item"
v-for="item in library.songs.displayListing"></mediaitem-list-item>
</div>
</template>
</transition>
<!-- Library - Albums -->
<transition name="wpfade" v-on:enter="getLibraryAlbums()">
<template v-if="page == 'library-albums'">
<div class="content-inner">
<h1 class="header-text">Albums</h1>
<div class="search-input-container" style="width:100%;margin: 16px 0px;">
<div class="search-input--icon"></div>
<input type="search"
style="width:100%;"
spellcheck="false"
placeholder="Search..."
class="search-input">
</div>
<mediaitem-square-large :item="item"
v-for="item in library.albums.listing"></mediaitem-square-large>
</div>
</template>
</transition>
</div>
<transition name="drawertransition">
<div class="app-drawer" v-if="drawertest">
<lyrics-view v-if="drawertest && lyricon" :time="lyriccurrenttime" :lyrics="lyrics"></lyrics-view>
</div>
</transition>
</div>
</div>
<transition name="wpfade">
<img v-show="chrome.artworkReady"
@load="chrome.artworkReady = true"
class="bg-artwork"
:src="getNowPlayingArtworkBG(32)">
</transition>
<transition name="wpfade">
<div class="bg-artwork--placeholder" v-else></div>
</transition>
</div>
<script type="text/x-template" id="mediaitem-artwork">
<template v-if="type == 'artists'">
<div class="mediaitem-artwork rounded"
>
<img :src="app.getMediaItemArtwork(url, size)"
class="mediaitem-artwork--img">
</div>
</template>
<template v-else>
<div class="mediaitem-artwork"
>
<img :src="app.getMediaItemArtwork(url, size)"
class="mediaitem-artwork--img">
</div>
</template>
</script>
<!-- Generic Collection of MediaItems -->
<script type="text/x-template" id="collection-view-generic">
<template>
<div class="content-inner">
</div>
</template>
</script>
<!-- Listen Now -->
<script type="text/x-template" id="cider-listen-now">
<div class="content-inner">
<h1 class="header-text">Listen Now</h1>
<template v-for="recom in data.data">
<div class="row">
<div class="col">
<h3>{{ recom.attributes.title ? recom.attributes.title.stringForDisplay : ""}}</h3>
</div>
<div class="col-auto flex-center" v-if="recom.relationships.contents.data.length >= 10">
<button class="cd-btn-seeall">See All</button>
</div>
</div>
<template v-if="recom.attributes.display.kind == 'MusicCoverShelf'">
<mediaitem-scroller-horizontal-large
:items="recom.relationships.contents.data.limit(10)"></mediaitem-scroller-horizontal-large>
</template>
<template v-else-if="recom.attributes.display.kind == 'MusicSuperHeroShelf'">
</template>
<template v-else>
<mediaitem-scroller-horizontal-sp
:items="recom.relationships.contents.data.limit(10)"></mediaitem-scroller-horizontal-sp>
</template>
</template>
</div>
</script>
<!-- Album / Playlist View -->
<script type="text/x-template" id="cider-playlist">
<div class="content-inner">
<template v-if="data != [] && data.attributes != []">
<div class="playlist-display row">
<div class="col-auto">
<mediaitem-artwork
:url="(data.attributes != null && data.attributes.artwork != null) ? data.attributes.artwork.url : (data.relationships.tracks.data.length > 0 ? data.relationships.tracks.data[0].attributes.artwork.url ?? '':'')"
size="200"
></mediaitem-artwork>
</div>
<div class="col playlist-info">
<div class="playlist-name">{{data.attributes.name ?? (data.attributes.title ?? '') ?? ''}}</div>
<div class="playlist-artist" v-if="data.attributes.artistName">{{data.attributes.artistName ??
''}}
</div>
<div class="playlist-desc"
v-html="((data.attributes.editorialNotes) ? (data.attributes.editorialNotes.short ?? (data.attributes.editorialNotes.standard ?? '') ) : (data.attributes.description ? (data.attributes.description.short ?? (data.attributes.description.standard ?? '')) : ''))"></div>
</div>
</div>
<mediaitem-list-item :item="item"
v-for="item in data.relationships.tracks.data"></mediaitem-list-item>
<div class="playlist-time">{{app.getTotalTime()}}</div>
</template>
</div>
</script>
<!-- Search -->
<script type="text/x-template" id="cider-search">
<div class="content-inner">
<div class="row">
<div class="col-sm" style="width: auto;" v-if="getTopResult()">
<template>
<h3>Top Result</h3>
<mediaitem-square-large :item="getTopResult()"></mediaitem-square>
</template>
</div>
<div class="col" v-if="search.results.songs">
<div class="row">
<div class="col">
<h3>Songs</h3>
</div>
<div class="col-auto flex-center" v-if="search.results.songs.data.length >= 6">
<button class="cd-btn-seeall">See All</button>
</div>
</div>
<div>
<mediaitem-list-item :item="item"
v-for="item in search.results.songs.data.limit(6)"></mediaitem-list-item>
</div>
</div>
</div>
<template v-if="search.results['meta']">
<template v-if="search.results.albums">
<div class="row">
<div class="col">
<h3>Albums</h3>
</div>
<div class="col-auto flex-center" v-if="search.results.albums.data.length >= 10">
<button class="cd-btn-seeall">See All</button>
</div>
</div>
<mediaitem-scroller-horizontal-large
:items="search.results.albums.data.limit(10)"></mediaitem-scroller-horizontal-large>
</template>
<template v-if="search.results.artists">
<div class="row">
<div class="col">
<h3>Artists</h3>
</div>
<div class="col-auto flex-center" v-if="search.results.artists.data.length >= 5">
<button class="cd-btn-seeall">See All</button>
</div>
</div>
<mediaitem-square-large :item="item"
v-for="item in search.results.artists.data.limit(5)"></mediaitem-square-large>
</template>
<template v-if="search.results.playlists">
<div class="row">
<div class="col">
<h3>Playlists</h3>
</div>
<div class="col-auto flex-center" v-if="search.results.playlists.data.length >= 10">
<button class="cd-btn-seeall">See All</button>
</div>
</div>
<mediaitem-square-large :item="item"
v-for="item in search.results.playlists.data.limit(10)"></mediaitem-square-large>
</template>
</template>
</div>
</script>
<script type="text/x-template" id="am-musiccovershelf">
<h1>{{ component.attributes.title.stringForDisplay }}</h1>
</script>
<!-- Sidebar Item -->
<script type="text/x-template" id="sidebar-library-item">
<button class="app-sidebar-item"
:class="$parent.getSidebarItemClass(page)"
@click="$parent.page = page">{{ name }}
</button>
</script>
<!-- Horizontal MediaItem Scroller -->
<script type="text/x-template" id="mediaitem-scroller-horizontal">
<template>
<div class="cd-hmedia-scroller">
<mediaitem-square :item="item"
v-for="item in items"></mediaitem-square>
</div>
</template>
</script>
<!-- Horizontal MediaItem Scroller (Large) -->
<script type="text/x-template" id="mediaitem-scroller-horizontal-large">
<template>
<div class="cd-hmedia-scroller">
<mediaitem-square-large :item="item"
v-for="item in items"></mediaitem-square-large>
</div>
</template>
</script>
<!-- Horizontal MediaItem Scroller (SP : Special) -->
<script type="text/x-template" id="mediaitem-scroller-horizontal-sp">
<template>
<div class="cd-hmedia-scroller">
<mediaitem-square-sp :item="item"
v-for="item in items"></mediaitem-square-sp>
</div>
</template>
</script>
<!-- MediaItem List Item -->
<script type="text/x-template" id="mediaitem-list-item">
<template>
<div @click="app.playMediaItemById(item.attributes.playParams.id ?? item.id, item.attributes.playParams.kind ?? item.type, item.attributes.playParams.isLibrary ?? false, item.attributes.url)"
class="cd-mediaitem-list-item">
<div class="artwork">
<mediaitem-artwork
:url="item.attributes.artwork ? item.attributes.artwork.url : ''"
size="34"
:type="item.type"
></mediaitem-artwork>
</div>
<div class="info-rect">
<div class="title text-overflow-elipsis">
{{ item.attributes.name }}
</div>
<div class="subtitle text-overflow-elipsis">
<template v-if="item.attributes.artistName">
{{ item.attributes.artistName }}
<template v-if="item.attributes.albumName">
- {{ item.attributes.albumName }}
</template>
</template>
</div>
</div>
<div class="content-rating" v-if="item.attributes.contentRating">
{{ item.attributes.contentRating }}
</div>
</div>
</template>
</script>
<!-- MediaItem Horizontal Rectangle -->
<script type="text/x-template" id="mediaitem-hrect">
<template>
<div @click="app.playMediaItemById(item.attributes.playParams.id ?? item.id, item.attributes.playParams.kind ?? item.type, item.attributes.playParams.isLibrary ?? false, item.attributes.url)"
class="cd-mediaitem-hrect">
<div class="artwork">
<mediaitem-artwork
:url="item.attributes.artwork ? item.attributes.artwork.url : ''"
size="70"
:type="item.type"
></mediaitem-artwork>
</div>
<div class="info-rect">
<div class="title text-overflow-elipsis">
{{ item.attributes.name }}
</div>
<div class="subtitle text-overflow-elipsis">
{{ item.type }}
<template v-if="item.attributes.artistName">
∙ {{ item.attributes.artistName }}
</template>
</div>
</div>
</div>
</template>
</script>
<!-- MediaItem Square -->
<script type="text/x-template" id="mediaitem-square">
<template>
<div @click="app.playMediaItemById(item.attributes.playParams.id ?? item.id, item.attributes.playParams.kind ?? item.type, item.attributes.playParams.isLibrary ?? false, item.attributes.url)"
class="cd-mediaitem-square">
<div class="artwork">
<mediaitem-artwork
:url="item.attributes.artwork ? item.attributes.artwork.url : ''"
size="300"
:type="item.type"
></mediaitem-artwork>
</div>
<div class="title text-overflow-elipsis">
{{ item.attributes.name }}
</div>
<div class="subtitle text-overflow-elipsis" v-if="item.attributes.artistName">
{{ item.attributes.artistName }}
</div>
</div>
</template>
</script>
<!-- MediaItem Square (Large) -->
<script type="text/x-template" id="mediaitem-square-large">
<template>
<div style="position: relative; display: inline-flex;">
<div @click.self='app.routeView(item)'
class="cd-mediaitem-square-large">
<div class="artwork">
<mediaitem-artwork
:url="item.attributes.artwork ? item.attributes.artwork.url : ''"
size="300"
:type="item.type"
></mediaitem-artwork>
</div>
<div class="cd-mediaitem-square-large-overlay" @click.self='app.routeView(item)'>
<div class="button" style="
border-radius: 50%;
background: rgba(50,50,50,0.7);"
:style="[(!(item.attributes.playParams ? (item.attributes.playParams.kind ?? (item.type ?? '')): (item.type ?? '')).includes('radioStation') && !(item.attributes.playParams ? (item.attributes.playParams.kind ?? (item.type ?? '')): (item.type ?? '')).includes('song')) ? {'margin': '140px',
width: '40px',
height: '40px',} :
{margin: '35px',
width: '120px',
height: '120px',}]"
@click="app.playMediaItem(item)">
<svg fill="white" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 27 27" class="glyph">
<path d="M11.3545232,18.4180929 L18.4676039,14.242665 C19.0452323,13.9290954 19.0122249,13.1204156 18.4676039,12.806846 L11.3545232,8.63141809 C10.7603912,8.26833741 9.98471883,8.54889976 9.98471883,9.19254279 L9.98471883,17.8404645 C9.98471883,18.5006112 10.7108802,18.7976773 11.3545232,18.4180929 Z"></path>
</svg>
</div>
</div>
<div class="title text-overflow-elipsis" @click='app.routeView(item)'>
{{ item.attributes.name ?? '' }}
</div>
<div class="subtitle text-overflow-elipsis" v-if="item.attributes.artistName">
{{ item.attributes.artistName ?? '' }}
</div>
</div>
<div class="cd-mediaitem-square-large-overlay" @click.self='app.routeView(item)'>
<div class="button" style="
border-radius: 50%;
background: rgba(50,50,50,0.7);"
:style="[(!(item.attributes.playParams ? (item.attributes.playParams.kind ?? (item.type ?? '')): (item.type ?? '')).includes('radioStation') && !(item.attributes.playParams ? (item.attributes.playParams.kind ?? (item.type ?? '')): (item.type ?? '')).includes('song')) ? {'margin': '140px',
width: '40px',
height: '40px',} :
{margin: '35px',
width: '120px',
height: '120px',}]"
@click="app.playMediaItem(item)">
<svg fill="white" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 27 27" class="glyph">
<path d="M11.3545232,18.4180929 L18.4676039,14.242665 C19.0452323,13.9290954 19.0122249,13.1204156 18.4676039,12.806846 L11.3545232,8.63141809 C10.7603912,8.26833741 9.98471883,8.54889976 9.98471883,9.19254279 L9.98471883,17.8404645 C9.98471883,18.5006112 10.7108802,18.7976773 11.3545232,18.4180929 Z"></path>
</svg>
</div>
</div>
</div>
</template>
</script>
<!-- MediaItem Square SP -->
<script type="text/x-template" id="mediaitem-square-sp">
<template>
<div style="position: relative; display: inline-flex;">
<div @click.self='app.routeView(item)'
class="cd-mediaitem-square-sp"
:style="{'--spcolor' : (item.attributes.artwork.bgColor != null) ? ('#'+item.attributes.artwork.bgColor) : `black`}">
<div class="artwork">
<mediaitem-artwork
:url="item.attributes.artwork ? item.attributes.artwork.url : ''"
size="300"
:type="item.type"
></mediaitem-artwork>
</div>
<div class="cd-mediaitem-square-large-overlay" @click.self='app.routeView(item)'>
<div class="button" style="
border-radius: 50%;
background: rgba(50,50,50,0.7);"
:style="[(!(item.attributes.playParams ? (item.attributes.playParams.kind ?? (item.type ?? '')): (item.type ?? '')).includes('radioStation') && !(item.attributes.playParams ? (item.attributes.playParams.kind ?? (item.type ?? '')): (item.type ?? '')).includes('song')) ? {'margin': '140px',
width: '40px',
height: '40px',} :
{margin: '35px',
width: '120px',
height: '120px',}]"
@click="app.playMediaItem(item)">
<svg fill="white" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 27 27" class="glyph">
<path d="M11.3545232,18.4180929 L18.4676039,14.242665 C19.0452323,13.9290954 19.0122249,13.1204156 18.4676039,12.806846 L11.3545232,8.63141809 C10.7603912,8.26833741 9.98471883,8.54889976 9.98471883,9.19254279 L9.98471883,17.8404645 C9.98471883,18.5006112 10.7108802,18.7976773 11.3545232,18.4180929 Z"></path>
</svg>
</div>
</div>
<div class="title text-overflow-elipsis"
:style="{'color' : (item.attributes.artwork.textColor1 != null) ? ('#'+item.attributes.artwork.textColor1) : `#eee`}"
style="font-weight: 600">
{{ item.attributes.name }}
</div>
<div class="subtitle text-overflow-elipsis"
:style="{'color' : (item.attributes.artwork.textColor1 != null) ? ('#'+item.attributes.artwork.textColor1) : `#eee`}"
style="padding-left: 4px;padding-right: 4px; display: -webkit-box;-webkit-box-orient: vertical; -webkit-line-clamp: 2;white-space: normal;">
{{ (item.attributes.editorialNotes != null) ? item.attributes.editorialNotes.short
:(item.attributes.artistName ?? '') }}
</div>
</div>
<div class="cd-mediaitem-square-large-overlay" @click.self='app.routeView(item)'>
<div class="button" style="
border-radius: 50%;
background: rgba(50,50,50,0.7);"
:style="[(!(item.attributes.playParams ? (item.attributes.playParams.kind ?? (item.type ?? '')): (item.type ?? '')).includes('radioStation') && !(item.attributes.playParams ? (item.attributes.playParams.kind ?? (item.type ?? '')): (item.type ?? '')).includes('song')) ? {'margin': '140px',
width: '40px',
height: '40px',} :
{margin: '35px',
width: '120px',
height: '120px',}]"
@click="app.playMediaItem(item)">
<svg fill="white" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 27 27" class="glyph">
<path d="M11.3545232,18.4180929 L18.4676039,14.242665 C19.0452323,13.9290954 19.0122249,13.1204156 18.4676039,12.806846 L11.3545232,8.63141809 C10.7603912,8.26833741 9.98471883,8.54889976 9.98471883,9.19254279 L9.98471883,17.8404645 C9.98471883,18.5006112 10.7108802,18.7976773 11.3545232,18.4180929 Z"></path>
</svg>
</div>
</div>
</div>
</template>
</script>
<script type="text/x-template" id="lyrics-view">
<div class="md-body lyric-body">
<template v-if="lyrics">
<template v-for="lyric in lyrics" v-if="lyric.line != 'lrcInstrumental'">
<h3 class="lyric-line" @click="app.seekTo(lyric.startTime, false)"
v-bind:class="{ active: app.getLyricClass(lyric.startTime, lyric.endTime)}">
{{ lyric.line }}
<div class="lyrics-translation" v-if="lyric.translation && lyric.translation != ''">
{{ lyric.translation }}
<div>
</h3>
</template>
<template v-else>
<h3 class="lyric-line" @click="app.seekTo(lyric.startTime, false)" :start="lyric.startTime"
:end="lyric.endTime"
v-bind:class="{ active: app.getLyricClass(lyric.startTime, lyric.endTime)}">
<div class="lyricWaiting">
<div class='WaitingDot1'></div>
<div class='WaitingDot2'></div>
<div class='WaitingDot3'></div>
</div>
</h3>
</template>
</template>
<template v-else>
No Lyrics Available
</template>
</div>
</script>
<script src="https://js-cdn.music.apple.com/musickit/v2/amp/musickit.js"></script>
<script src="index.js?v=1"></script>
</body>
</html>

File diff suppressed because one or more lines are too long

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,2 +0,0 @@
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} didnt 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

View file

@ -1 +0,0 @@
{"version":3,"file":"sw.js","sources":["C:/Users/vieta/AppData/Local/Temp/b97cb0fb56dd447f95668d4898340903/sw.js"],"sourcesContent":["import {registerRoute as workbox_routing_registerRoute} from 'C:/Users/vieta/AppData/Roaming/nvm/v14.18.1/node_modules/workbox-cli/node_modules/workbox-routing/registerRoute.mjs';\nimport {CacheFirst as workbox_strategies_CacheFirst} from 'C:/Users/vieta/AppData/Roaming/nvm/v14.18.1/node_modules/workbox-cli/node_modules/workbox-strategies/CacheFirst.mjs';\nimport {precacheAndRoute as workbox_precaching_precacheAndRoute} from 'C:/Users/vieta/AppData/Roaming/nvm/v14.18.1/node_modules/workbox-cli/node_modules/workbox-precaching/precacheAndRoute.mjs';/**\n * Welcome to your Workbox-powered service worker!\n *\n * You'll need to register this file in your web app.\n * See https://goo.gl/nhQhGp\n *\n * The rest of the code is auto-generated. Please don't update this file\n * directly; instead, make changes to your Workbox build configuration\n * and re-run your build process.\n * See https://goo.gl/2aRDsh\n */\n\n\n\n\n\n\n\n\nself.addEventListener('message', (event) => {\n if (event.data && event.data.type === 'SKIP_WAITING') {\n self.skipWaiting();\n }\n});\n\n\n\n\n/**\n * The precacheAndRoute() method efficiently caches and responds to\n * requests for URLs in the manifest.\n * See https://goo.gl/S9QRab\n */\nworkbox_precaching_precacheAndRoute([\n {\n \"url\": \"ameframework.css\",\n \"revision\": \"4bcc8646bb5742638fad52b94e231601\"\n },\n {\n \"url\": \"apple-hls.js\",\n \"revision\": \"2b74055662676b0fcc2d4a4bf994a9dc\"\n },\n {\n \"url\": \"hlscider.js\",\n \"revision\": \"cf7f512e83e32694f2c94f904714fe4c\"\n },\n {\n \"url\": \"index_old.html\",\n \"revision\": \"c21f3e9c5b015599d3ab07639f64a7a8\"\n },\n {\n \"url\": \"index.js\",\n \"revision\": \"8591a69fc9c975a063eb264b7447f173\"\n },\n {\n \"url\": \"less.js\",\n \"revision\": \"b6e574e4d680686786a28e7e71a17bbc\"\n },\n {\n \"url\": \"musickit.js\",\n \"revision\": \"211d80891c3336c1795cb83df58d4b63\"\n },\n {\n \"url\": \"sortable.min.js\",\n \"revision\": \"5cbc31ebec32adf60e27b76418e79d93\"\n },\n {\n \"url\": \"style-old.css\",\n \"revision\": \"aea9ea49df13f2deee42b68654aeea06\"\n },\n {\n \"url\": \"todo.js\",\n \"revision\": \"18d49fabcb96de8bd11455877d8eacb6\"\n },\n {\n \"url\": \"vue-observe-visibility.min.js\",\n \"revision\": \"5a52e761f6aa71b4f65a7b458f698b95\"\n },\n {\n \"url\": \"vue.js\",\n \"revision\": \"0a9a4681294d8c5f476687eea6e74842\"\n },\n {\n \"url\": \"vuedraggable.umd.min.js\",\n \"revision\": \"9a84fec5263bb510cee88e1c3b9583cc\"\n }\n], {\n \"ignoreURLParametersMatching\": [/^utm_/, /^fbclid$/, /^X-Amz-Algorithm/, /^X-Amz-Date/, /^X-Amz-SignedHeaders/, /^X-Amz-Expires/, /^X-Amz-Credential/, /^X-Amz-Signature/]\n});\n\n\n\n\nworkbox_routing_registerRoute(/\\.(?:png|jpg|jpeg|svg|webp)$/, new workbox_strategies_CacheFirst({ \"cacheName\":\"imageinternet\", plugins: [] }), 'GET');\nworkbox_routing_registerRoute(/https:\\/\\/is[0-9]-ssl\\.mzstatic\\.com\\/image+/, new workbox_strategies_CacheFirst(), 'GET');\nworkbox_routing_registerRoute(/^https:\\/\\/store-\\d{3}\\.blobstore\\.apple\\.com\\/.{65}\\/image+/, new workbox_strategies_CacheFirst(), 'GET');\n\n\n\n\n"],"names":["self","addEventListener","event","data","type","skipWaiting","workbox_strategies_CacheFirst","plugins"],"mappings":"0nBAqBAA,KAAKC,iBAAiB,WAAYC,IAC5BA,EAAMC,MAA4B,iBAApBD,EAAMC,KAAKC,MAC3BJ,KAAKK,oCAY2B,CAClC,KACS,4BACK,oCAEd,KACS,wBACK,oCAEd,KACS,uBACK,oCAEd,KACS,0BACK,oCAEd,KACS,oBACK,oCAEd,KACS,mBACK,oCAEd,KACS,uBACK,oCAEd,KACS,2BACK,oCAEd,KACS,yBACK,oCAEd,KACS,mBACK,oCAEd,KACS,yCACK,oCAEd,KACS,kBACK,oCAEd,KACS,mCACK,qCAEb,6BAC8B,CAAC,QAAS,WAAY,mBAAoB,cAAe,uBAAwB,iBAAkB,oBAAqB,sCAM3H,+BAAgC,IAAIC,aAA8B,WAAc,gBAAiBC,QAAS,KAAO,uBACjH,+CAAgD,IAAID,aAAiC,uBACrF,+DAAgE,IAAIA,aAAiC"}

View file

@ -1,162 +0,0 @@
// 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
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"
});
// Radio page
await app.mk.api.recentRadioStations("",
{l: "en-gb",
"platform": "web",
"art[url]": "f"});
// Recently Added
await app.mk.api.library.recentlyAdded({
"platform": "web",
include: {
"library-albums": ["artists"],
"library-artists": ["catalog"]
},
fields: {
artists: ["url"],
albums: "artistName,artistUrl,artwork,contentRating,editorialArtwork,name,playParams,releaseDate,url"
},
includeOnly: ["catalog", "artists"],
limit: 25
}, {
reload: !0,
includePagination: !0
})
// 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.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)
})
// Made For You
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)
})
// Artist View Top Songs
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)
})
// download entire 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 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:

View file

@ -1,59 +0,0 @@
<script type="text/x-template" id="animatedartwork-view">
<template v-if="video">
<div class="animated" v-bind:vid="app.hashCode(video).toString()">
<video ref="video" class="animated-artwork-video" loop id="animated-artwork"></video>
</div>
</template>
</script>
<script>
Vue.component('animatedartwork-view', {
template: '#animatedartwork-view',
props: ['video', 'hls'],
mounted() {
if (this.video) {
this.$nextTick(function () {
var config = {
backBufferLength: 0,
enableWebVTT: false,
enableCEA708Captions: false,
emeEnabled: false,
abrEwmaDefaultEstimate: 10000,
testBandwidth: false
};
if (this.hls) {
console.log('detached');
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);
this.hls.loadLevel = 4;
}
})
}
},
async beforeDestroy() {
if(this.hls) {
await this.hls.destroy();
this.hls = null
console.log('killed')
}
}
});
</script>

View file

@ -1,14 +0,0 @@
<div class="modal-backdrop">
<div class="modal-dialog">
<div class="modal-header">
<button type="button" class="close">&times;</button>
<h4 class="modal-title" v-html="title"></h4>
</div>
<div class="modal-content" v-html="content">
</div>
<div class="modal-footer">
</div>
</div>
</div>

View file

@ -1,14 +0,0 @@
<script type="text/x-template" id="hello-world">
<button @click="sayHello()">Hello world!</button>
</script>
<script>
Vue.component('hello-world', {
template: '#hello-world',
methods: {
sayHello: function () {
alert('Hello world!');
}
}
});
</script>

View file

@ -1,20 +0,0 @@
<script type="text/x-template" id="karaoke-in">
<div class="karaoke-viewer">
<div class="lyric">
<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)">
<span class="verse verse-active">{{ verse.c }}</span>
</template>
<template v-else>
<span class="verse">{{ verse.c }}</span>
</template>
</div>
</template>
<template v-else>
<div class="verse-group">{{ segment.x }}</div>
</template>
</div>
</div>
</script>

View file

@ -1,162 +0,0 @@
<script type="text/x-template" id="lyrics-view">
<div ref="lyricsview" class="md-body lyric-body">
<template v-if="lyrics && lyrics != [] && lyrics.length > 0">
<template v-for="(lyric, index) in lyrics" v-if="lyric.line != 'lrcInstrumental'">
<h3 class="lyric-line" @click="if(lyric.startTime != 9999999) app.seekTo(lyric.startTime, false)"
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>
</template>
</div>
</template>
<template v-else>
<div class="norm" >
{{ lyric.line }}
</div>
</template>
<div class="lyrics-translation" v-if="lyric.translation && lyric.translation != ''">
{{ lyric.translation }}
</div>
</h3>
</template>
<template v-else>
<h3 class="lyric-line" @click="if(lyric.startTime != 9999999) app.seekTo(lyric.startTime, false)"
:start="lyric.startTime"
:end="lyric.endTime" v-bind:line-index="index.toString()">
<div class="lyricWaiting">
<div class='WaitingDot1'></div>
<div class='WaitingDot2'></div>
<div class='WaitingDot3'></div>
</div>
</h3>
</template>
</template>
<template v-else>
<div class="no-lyrics">
Loading... / Lyrics not found./ Instrumental.
</template>
</div>
</script>
<script>
Vue.component('lyrics-view', {
template: '#lyrics-view',
props: ["time", "lyrics", "richlyrics", "translation", "onindex"],
watch: {
time: function () {
if (app.lyricon && app.drawer.open) {
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: {
getActiveLyric() {
// console.log(this.time);
const delayfix = 0.35
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 && this.$refs.lyricsview.querySelector(`.lyric-line[line-index="${i}"]`)) {
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 (checkIfScrollIsStatic) {
this.$refs.lyricsview.querySelector(`.lyric-line[line-index="${i}"]`).scrollIntoView({
behavior: "smooth",
block: "center"
})
}
}
} else if (app.currentLyricsLine == 0) {
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{
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 []
}
}
});
</script>

View file

@ -1,62 +0,0 @@
<script type="text/x-template" id="mediaitem-artwork">
<template v-if="type == 'artists'">
<div class="mediaitem-artwork rounded" :key="url" :style="{'box-shadow': shadow ? 'var(--mediaItemShadow-Shadow)' : ''}">
<img :src="app.getMediaItemArtwork(url, size)"
class="mediaitem-artwork--img">
</div>
</template>
<template v-else>
<div class="mediaitem-artwork" :key="url" :style="{'box-shadow': shadow ? 'var(--mediaItemShadow-Shadow)' : ''}"
v-observe-visibility="{callback: visibilityChanged}">
<img :src="app.getMediaItemArtwork(url, size)" v-if="isVisible"
class="mediaitem-artwork--img">
<div v-if="video && isVisible" class="animatedartwork-view-box">
<animatedartwork-view :video="video"></animatedartwork-view>
</div>
</div>
</template>
</script>
<script>
Vue.component('mediaitem-artwork', {
template: '#mediaitem-artwork',
props: {
size: {
type: String,
default: '120'
},
url: {
type: String,
default: ''
},
type: {
type: String,
default: ''
},
video: {
type: String,
required: false
},
shadow: {
type: Boolean,
default: false
}
},
data: function () {
return {
isVisible: false
}
},
methods: {
getArtworkStyle() {
return {
width: this.size + 'px',
height: this.size + 'px'
};
},
visibilityChanged: function (isVisible, entry) {
this.isVisible = isVisible
}
}
});
</script>

View file

@ -1,32 +0,0 @@
<script type="text/x-template" id="mediaitem-hrect">
<template>
<div @click="app.playMediaItemById(item.attributes.playParams.id ?? item.id, item.attributes.playParams.kind ?? item.type, item.attributes.playParams.isLibrary ?? false, item.attributes.url)"
class="cd-mediaitem-hrect">
<div class="artwork">
<mediaitem-artwork
:url="item.attributes.artwork ? item.attributes.artwork.url : ''"
size="70"
:type="item.type"></mediaitem-artwork>
</div>
<div class="info-rect">
<div class="title text-overflow-elipsis">
{{ item.attributes.name }}
</div>
<div class="subtitle text-overflow-elipsis">
{{ item.type }}
<template v-if="item.attributes.artistName">
∙ {{ item.attributes.artistName }}
</template>
</div>
</div>
</div>
</template>
</script>
<script>
Vue.component('mediaitem-hrect', {
template: '#mediaitem-hrect',
props: ['item'],
methods: {}
});
</script>

View file

@ -1,269 +0,0 @@
<script type="text/x-template" id="mediaitem-list-item">
<template>
<div v-observe-visibility="{callback: visibilityChanged}"
@contextmenu="contextMenu"
@click="select"
:data-id="item.attributes.playParams.id ?? item.id"
:data-type="item.attributes.playParams.kind ?? item.type"
:data-index="index"
:data-guid="guid"
class="cd-mediaitem-list-item"
:class="{'mediaitem-selected': app.select_hasMediaItem(guid)}">
<template v-if="isVisible">
<div class="isLibrary" v-if="showLibraryStatus == true">
<button @click="addToLibrary()"
v-if="!app.isInLibrary(item.attributes.playParams) && !addedToLibrary">🖤
</button>
<button v-else>❤️</button>
</div>
<div class="artwork" v-if="showArtwork == true">
<mediaitem-artwork
:url="item.attributes.artwork ? item.attributes.artwork.url : ''"
size="50"
:type="item.type"></mediaitem-artwork>
<button class="overlay-play" @click="playTrack()"><%- include("../svg/play.svg") %></button>
</div>
<div class="info-rect" :style="{'padding-left': (showArtwork ? '' : '16px')}" @dblclick="playTrack()">
<div class="title text-overflow-elipsis">
{{ item.attributes.name }}
</div>
<div class="subtitle text-overflow-elipsis" style="-webkit-box-orient: horizontal;">
<template v-if="item.attributes.artistName">
<div class="artist item-navigate text-overflow-elipsis"
@click="app.searchAndNavigate(item,'artist')">
{{ item.attributes.artistName }}
</div>
<template v-if="item.attributes.albumName">&nbsp;-&nbsp;</template>
<template v-if="item.attributes.albumName">
<div class="artist item-navigate text-overflow-elipsis"
@click="app.searchAndNavigate(item,'album')">
{{ item.attributes.albumName }}
</div>
</template>
</template>
</div>
</div>
<div class="content-rating" v-if="item.attributes.contentRating" @dblclick="playTrack()">
{{ item.attributes.contentRating }}
</div>
<template v-if="showMetaData == true" @dblclick="playTrack()">
<div class="metainfo">
{{ item.attributes.releaseDate ? new Date(item.attributes.releaseDate).toLocaleDateString()
: "" }}
</div>
<div class="metainfo">
{{ item.attributes.genreNames[0] ?? "" }}
</div>
</template>
<div class="duration" v-if="showDuration" @dblclick="playTrack()">
{{ msToMinSec(item.attributes.durationInMillis ?? 0) }}
</div>
</template>
</div>
</template>
</script>
<script>
Vue.component('mediaitem-list-item', {
template: '#mediaitem-list-item',
data: function () {
return {
isVisible: false,
addedToLibrary: false,
guid: uuidv4()
}
},
props: {
'item': {type: Object, required: true},
'parent': {type: Object, required: false},
'index': {type: Object, 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},
},
methods: {
select(e) {
if (e.shiftKey) {
if (this.index != -1) {
if(app.selectedMediaItems.length == 0) {
app.select_selectMediaItem(this.item.attributes.playParams.id ?? this.item.id, this.item.attributes.playParams.kind ?? this.item.type, this.index, this.guid)
}
let allMediaItems = document.querySelectorAll(".cd-mediaitem-list-item[data-index]")
let startIndex = Math.min(...app.selectedMediaItems.map(item => item.index))
let endIndex = Math.max(...app.selectedMediaItems.map(item => item.index))
if (this.index < startIndex) {
for (let i = this.index; i <= endIndex; i++) {
let item = allMediaItems[i]
if (item) {
app.select_selectMediaItem(item.getAttribute("data-id"),
item.getAttribute("data-type"),
item.getAttribute("data-index"),
item.getAttribute("data-guid"))
}
}
} else if (this.index > endIndex) {
for (let i = startIndex; i <= this.index; i++) {
let item = allMediaItems[i]
if (item) {
app.select_selectMediaItem(item.getAttribute("data-id"),
item.getAttribute("data-type"),
item.getAttribute("data-index"),
item.getAttribute("data-guid"))
}
}
} else {
for (let i = startIndex; i <= endIndex; i++) {
let item = allMediaItems[i]
if (item) {
app.select_selectMediaItem(item.getAttribute("data-id"),
item.getAttribute("data-type"),
item.getAttribute("data-index"),
item.getAttribute("data-guid"))
}
}
}
}
} else if (e.ctrlKey) {
if (app.select_hasMediaItem(this.guid)) {
app.select_removeMediaItem(this.guid)
} else {
app.select_selectMediaItem(this.item.attributes.playParams.id ?? this.item.id, this.item.attributes.playParams.kind ?? this.item.type, this.index, this.guid)
}
} else {
if (app.select_hasMediaItem(this.guid)) {
app.selectedMediaItems = []
} else {
app.selectedMediaItems = []
app.select_selectMediaItem(this.item.attributes.playParams.id ?? this.item.id, this.item.attributes.playParams.kind ?? this.item.type, this.index, this.guid)
}
}
},
contextMenu(event) {
let self = this
let useMenu = "normal"
if (app.selectedMediaItems.length <= 1) {
app.selectedMediaItems = []
app.select_selectMediaItem(this.item.attributes.playParams.id ?? this.item.id, this.item.attributes.playParams.kind ?? this.item.type, this.index, this.guid)
} else {
useMenu = "multiple"
}
let menus = {
multiple: {
items: [
{
name: `Play ${app.selectedMediaItems.length} tracks next`,
action: () => {
let itemsToPlay = {}
app.selectedMediaItems.forEach(item => {
if (!itemsToPlay[item.kind]) {
itemsToPlay[item.kind] = []
}
itemsToPlay[item.kind].push(item.id)
})
// loop through itemsToPlay
for (let kind in itemsToPlay) {
let ids = itemsToPlay[kind]
if (ids.length > 0) {
app.mk.playNext({[kind + "s"]: itemsToPlay[kind]})
}
}
console.log(itemsToPlay)
app.selectedMediaItems = []
}
},
{
name: `Play ${app.selectedMediaItems.length} tracks later`,
action: () => {
let itemsToPlay = {}
app.selectedMediaItems.forEach(item => {
if (!itemsToPlay[item.kind]) {
itemsToPlay[item.kind] = []
}
itemsToPlay[item.kind].push(item.id)
})
// loop through itemsToPlay
for (let kind in itemsToPlay) {
let ids = itemsToPlay[kind]
if (ids.length > 0) {
app.mk.playLater({[kind + "s"]: itemsToPlay[kind]})
}
}
app.selectedMediaItems = []
}
},
]
},
normal: {
items: [
{
"name": "Start Radio",
"action": function () {
app.mk.setStationQueue({song: self.item.attributes.playParams.id ?? self.item.id}).then(() => {
app.mk.play()
app.selectedMediaItems = []
})
}
},
{
"name": "Play Next",
"action": function () {
app.mk.playNext({[self.item.attributes.playParams.kind ?? self.item.type]: self.item.attributes.playParams.id ?? self.item.id})
app.mk.queue._reindex()
app.selectedMediaItems = []
}
},
{
"name": "Play Later",
"action": function () {
app.mk.playLater({[self.item.attributes.playParams.kind ?? self.item.type]: self.item.attributes.playParams.id ?? self.item.id})
app.mk.queue._reindex()
app.selectedMediaItems = []
}
},
{
"name": "Go to Artist",
"action": function () {
app.searchAndNavigate(self.item, 'artist')
}
},
{
"name": "Go to Album",
"action": function () {
app.searchAndNavigate(self.item, 'album')
}
},
]
}
}
CiderContextMenu.Create(event, menus[useMenu])
},
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
}
},
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);
} else {
app.playMediaItemById(item.attributes.playParams.id ?? item.id, item.attributes.playParams.kind ?? item.type, item.attributes.playParams.isLibrary ?? false, item.attributes.url)
}
}
}
});
</script>

View file

@ -1,61 +0,0 @@
<script type="text/x-template" id="mediaitem-mvview-sp">
<template>
<div style="position: relative; display: inline-flex;">
<div @click.self='app.routeView(item)'
class="cd-mediaitem-mvview">
<div class="title-browse-sp bold " @click='app.routeView(item)'>
{{ badge ? badge.designBadge : ""}}
</div>
<div class="title-browse-sp " >
{{ (badge != null && badge.designTag != null) ? badge.designTag : (item.attributes.name ?? '') }}
</div>
<div class="title-browse-sp semibold" v-if="!(badge != null && badge.designTag != null)" >
{{ (item.attributes.artistName ?? (item.attributes.curatorName ?? '')) }}
</div>
<div class="artwork">
<mediaitem-artwork
:url="item.attributes.artwork ? item.attributes.artwork.url : ''"
:video="(item.attributes != null && item.attributes.editorialVideo != null) ? (item.attributes.editorialVideo.motionDetailSquare ? item.attributes.editorialVideo.motionDetailSquare.video : (item.attributes.editorialVideo.motionSquareVideo1x1 ? item.attributes.editorialVideo.motionSquareVideo1x1.video : '')) : '' "
:size="imagesize ?? 300"
></mediaitem-artwork>
</div>
<div class="cd-mediaitem-mvview-overlay" @click.self='app.routeView(item)'>
<div class="button" style="
border-radius: 50%;
background: rgba(50,50,50,0.7);"
:style="[(!(item.attributes.playParams ? (item.attributes.playParams.kind ?? (item.type ?? '')): (item.type ?? '')).includes('radioStation') && !(item.attributes.playParams ? (item.attributes.playParams.kind ?? (item.type ?? '')): (item.type ?? '')).includes('song')) ? {'margin': '200px',
'margin-left': '250px',
width: '40px',
height: '40px',} :
{margin: '35px', 'margin-left': '95px',
width: '120px',
height: '120px',}]" @click="app.playMediaItem(item)">
<%- include("../svg/play.svg") %>
</div>
</div>
</div>
<div class="cd-mediaitem-mvview-overlay" @click.self='app.routeView(item)' tabindex="0">
<div class="button" style="
border-radius: 50%;
background: rgba(50,50,50,0.7);"
:style="[(!(item.attributes.playParams ? (item.attributes.playParams.kind ?? (item.type ?? '')): (item.type ?? '')).includes('radioStation') && !(item.attributes.playParams ? (item.attributes.playParams.kind ?? (item.type ?? '')): (item.type ?? '')).includes('song')) ? {'margin': '200px',
'margin-left': '250px',
width: '40px',
height: '40px',} :
{margin: '35px', 'margin-left': '95px',
width: '120px',
height: '120px',}]" @click="app.playMediaItem(item)">
<%- include("../svg/play.svg") %>
</div>
</div>
</div>
</template>
</script>
<script>
Vue.component('mediaitem-mvview-sp', {
template: '#mediaitem-mvview-sp',
props: ['item', "imagesize","badge"],
methods: {}
});
</script>

View file

@ -1,59 +0,0 @@
<script type="text/x-template" id="mediaitem-mvview">
<template>
<div style="position: relative; display: inline-flex;">
<div @click.self='app.routeView(item)'
class="cd-mediaitem-mvview">
<div class="artwork">
<mediaitem-artwork
:url="item.attributes.artwork ? item.attributes.artwork.url : ''"
:video="(item.attributes != null && item.attributes.editorialVideo != null) ? (item.attributes.editorialVideo.motionDetailSquare ? item.attributes.editorialVideo.motionDetailSquare.video : (item.attributes.editorialVideo.motionSquareVideo1x1 ? item.attributes.editorialVideo.motionSquareVideo1x1.video : '')) : '' "
:size="imagesize ?? 300"
></mediaitem-artwork>
</div>
<div class="cd-mediaitem-mvview-overlay" @click.self='app.routeView(item)'>
<div class="button" style="
border-radius: 50%;
background: rgba(50,50,50,0.7);"
:style="[(!(item.attributes.playParams ? (item.attributes.playParams.kind ?? (item.type ?? '')): (item.type ?? '')).includes('radioStation') && !(item.attributes.playParams ? (item.attributes.playParams.kind ?? (item.type ?? '')): (item.type ?? '')).includes('song')) ? {'margin': '140px',
'margin-left': '250px',
width: '40px',
height: '40px',} :
{margin: '35px', 'margin-left': '95px',
width: '120px',
height: '120px',}]" @click="app.playMediaItem(item)">
<%- include("../svg/play.svg") %>
</div>
</div>
<div class="title text-overflow-elipsis" @click='app.routeView(item)'>
{{ item.attributes.name ?? '' }}
</div>
<div class="subtitle text-overflow-elipsis item-navigate" v-if="item.attributes.artistName" :style = "{'z-index': ((item.attributes.editorialNotes == null) && item.attributes.artistName) ? '4' : ''}" @click="if(item.attributes.artistName)app.searchAndNavigate(item,'artist')">
{{ item.attributes.artistName ?? '' }}
</div>
</div>
<div class="cd-mediaitem-mvview-overlay" @click.self='app.routeView(item)' tabindex="0">
<div class="button" style="
border-radius: 50%;
background: rgba(50,50,50,0.7);"
:style="[(!(item.attributes.playParams ? (item.attributes.playParams.kind ?? (item.type ?? '')): (item.type ?? '')).includes('radioStation') && !(item.attributes.playParams ? (item.attributes.playParams.kind ?? (item.type ?? '')): (item.type ?? '')).includes('song')) ? {'margin': '140px',
'margin-left': '250px',
width: '40px',
height: '40px',} :
{margin: '35px', 'margin-left': '95px',
width: '120px',
height: '120px',}]" @click="app.playMediaItem(item)">
<%- include("../svg/play.svg") %>
</div>
</div>
</div>
</template>
</script>
<script>
Vue.component('mediaitem-mvview', {
template: '#mediaitem-mvview',
props: ['item', "imagesize"],
methods: {}
});
</script>

View file

@ -1,17 +0,0 @@
<script type="text/x-template" id="mediaitem-scroller-horizontal-large">
<template>
<div class="cd-hmedia-scroller">
<mediaitem-square-large :item="item"
v-for="item in items"></mediaitem-square-large>
</div>
</template>
</script>
<script>
Vue.component('mediaitem-scroller-horizontal-large', {
template: '#mediaitem-scroller-horizontal-large',
props: ['items'],
methods: {}
});
</script>

View file

@ -1,23 +0,0 @@
<script type="text/x-template" id="mediaitem-scroller-horizontal-mvview">
<template>
<div class="cd-hmedia-scroller">
<template v-if="browsesp">
<mediaitem-mvview-sp :item="item ? (item.attributes.kind ? item : ((item.relationships && item.relationships.contents ) ? item.relationships.contents.data[0] : item)) : []" :imagesize="imagesize"
:badge="item.attributes" v-for="item in items"></mediaitem-mvview-sp>
</template>
<template v-else>
<mediaitem-mvview :item="item ? (item.attributes.kind ? item : ((item.relationships && item.relationships.contents ) ? item.relationships.contents.data[0] : item)) : []" :imagesize="imagesize"
v-for="item in items"></mediaitem-mvview>
</template>
</div>
</template>
</script>
<script>
Vue.component('mediaitem-scroller-horizontal-mvview', {
template: '#mediaitem-scroller-horizontal-mvview',
props: ['items',"imagesize","browsesp"],
methods: {}
});
</script>

View file

@ -1,16 +0,0 @@
<script type="text/x-template" id="mediaitem-scroller-horizontal-sp">
<template>
<div class="cd-hmedia-scroller">
<mediaitem-square-sp :item="item"
v-for="item in items"></mediaitem-square-sp>
</div>
</template>
</script>
<script>
Vue.component('mediaitem-scroller-horizontal-sp', {
template: '#mediaitem-scroller-horizontal-sp',
props: ['items'],
methods: {}
});
</script>

View file

@ -1,16 +0,0 @@
<script type="text/x-template" id="mediaitem-scroller-horizontal">
<template>
<div class="cd-hmedia-scroller">
<mediaitem-square :item="item"
v-for="item in items"></mediaitem-square>
</div>
</template>
</script>
<script>
Vue.component('mediaitem-scroller-horizontal', {
template: '#mediaitem-scroller-horizontal',
props: ['items'],
methods: {}
});
</script>

View file

@ -1,171 +0,0 @@
<script type="text/x-template" id="mediaitem-square-large">
<template>
<div ref="main" style="position: relative; display: inline-flex;" @contextmenu="contextMenu">
<div @click.self='app.routeView(item)'
class="cd-mediaitem-square-large" ref="main2">
<div class="artwork">
<mediaitem-artwork
:url="item.attributes.artwork ? item.attributes.artwork.url : ''"
:video="(item.attributes != null && item.attributes.editorialVideo != null) ? (item.attributes.editorialVideo.motionDetailSquare ? item.attributes.editorialVideo.motionDetailSquare.video : (item.attributes.editorialVideo.motionSquareVideo1x1 ? item.attributes.editorialVideo.motionSquareVideo1x1.video : '')) : '' "
size="300"
:type="item.type"></mediaitem-artwork>
</div>
<div class="cd-mediaitem-square-large-overlay" @click.self='app.routeView(item)'>
<div class="button" style="
border-radius: 50%;
background: rgba(50,50,50,0.7);"
:style="[(!(item.attributes.playParams ? (item.attributes.playParams.kind ?? (item.type ?? '')): (item.type ?? '')).includes('radioStation') && !(item.attributes.playParams ? (item.attributes.playParams.kind ?? (item.type ?? '')): (item.type ?? '')).includes('song')) ? {'margin': '140px','position': 'absolute',
width: '40px',
height: '40px',} :
{margin: '35px', 'position': 'absolute',
width: '120px',
height: '120px',}]" @click="app.playMediaItem(item)">
<%- include("../svg/play.svg") %>
</div>
<div class="button" style="
border-radius: 50%;
background: rgba(50,50,50,0.7);"
:style="[(!(item.attributes.playParams ? (item.attributes.playParams.kind ?? (item.type ?? '')): (item.type ?? '')).includes('radioStation') && !(item.attributes.playParams ? (item.attributes.playParams.kind ?? (item.type ?? '')): (item.type ?? '')).includes('song')) ? {'position': 'absolute','margin': '140px',
width: '40px', 'margin-left': '10px',
height: '40px',} :
{display: 'none',margin: '35px',
width: '120px',
height: '120px',}]" @click="clickContext() ">
<%- include("../svg/more.svg") %>
</div>
</div>
<div class="title text-overflow-elipsis" @click='app.routeView(item)'>
{{ item.attributes.name ?? '' }}
</div>
<div class="subtitle text-overflow-elipsis item-navigate" v-if="item.attributes.artistName" :style = "{'z-index': ((item.attributes.editorialNotes == null) && item.attributes.artistName) ? '4' : ''}" @click="if(item.attributes.artistName)app.searchAndNavigate(item,'artist')">
{{ item.attributes.artistName ?? '' }}
</div>
</div>
<div class="cd-mediaitem-square-large-overlay" @click.self='app.routeView(item)' tabindex="0">
<div class="button" style="
border-radius: 50%;
background: rgba(50,50,50,0.7);"
:style="[(!(item.attributes.playParams ? (item.attributes.playParams.kind ?? (item.type ?? '')): (item.type ?? '')).includes('radioStation') && !(item.attributes.playParams ? (item.attributes.playParams.kind ?? (item.type ?? '')): (item.type ?? '')).includes('song')) ? {'margin': '140px',
width: '40px',
height: '40px',} :
{margin: '35px',
width: '120px',
height: '120px',}]" @click="app.playMediaItem(item)">
<%- include("../svg/play.svg") %>
</div>
<div class="button" style="
border-radius: 50%;
background: rgba(50,50,50,0.7);"
:style="[(!(item.attributes.playParams ? (item.attributes.playParams.kind ?? (item.type ?? '')): (item.type ?? '')).includes('radioStation') && !(item.attributes.playParams ? (item.attributes.playParams.kind ?? (item.type ?? '')): (item.type ?? '')).includes('song')) ? {'position': 'absolute','margin': '140px',
width: '40px', 'margin-left': '10px',
height: '40px',} :
{display: 'none',margin: '35px',
width: '120px',
height: '120px',}]" @click="console.log('as');contextMenu()">
<%- include("../svg/more.svg") %>
</div>
</div>
</div>
</template>
</script>
<script>
Vue.component('mediaitem-square-large', {
template: '#mediaitem-square-large',
props: ['item'],
methods: {
clickContext() {
var evt = document.createEvent('MouseEvent');
var rect = this.$refs.main2.getBoundingClientRect();
evt.initMouseEvent(
"contextmenu",
true /* bubble */, true /* cancelable */,
window, null,
0, 0, rect.x + 100, rect.y +100, /* coordinates */
false, false, false, false, /* modifier keys */
0 /*left*/, null
);
this.$refs.main.dispatchEvent(evt);
}
,contextMenu(event) {
if (!event){event = this.$refs.main} else {console.log(event)}
let self = this
let useMenu = "normal"
if (app.selectedMediaItems.length <= 1) {
app.selectedMediaItems = []
app.select_selectMediaItem(this.item.attributes.playParams.id ?? this.item.id, this.item.attributes.playParams.kind ?? this.item.type, this.index, this.guid)
} else {
useMenu = "multiple"
}
let menus = {
multiple: {
items: [
{
name: `Play ${app.selectedMediaItems.length} tracks next`,
action: () => {
let itemsToPlay = {}
app.selectedMediaItems.forEach(item => {
if (!itemsToPlay[item.kind]) {
itemsToPlay[item.kind] = []
}
itemsToPlay[item.kind].push(item.id)
})
// loop through itemsToPlay
for (let kind in itemsToPlay) {
let ids = itemsToPlay[kind]
if (ids.length > 0) {
app.mk.playNext({[kind + "s"]: itemsToPlay[kind]})
}
}
console.log(itemsToPlay)
app.selectedMediaItems = []
}
},
{
name: `Play ${app.selectedMediaItems.length} tracks later`,
action: () => {
let itemsToPlay = {}
app.selectedMediaItems.forEach(item => {
if (!itemsToPlay[item.kind]) {
itemsToPlay[item.kind] = []
}
itemsToPlay[item.kind].push(item.id)
})
// loop through itemsToPlay
for (let kind in itemsToPlay) {
let ids = itemsToPlay[kind]
if (ids.length > 0) {
app.mk.playLater({[kind + "s"]: itemsToPlay[kind]})
}
}
app.selectedMediaItems = []
}
},
]
},
normal: {
items: [
{
"name": "Play Next",
"action": function () {
app.mk.playNext({[self.item.attributes.playParams.kind ?? self.item.type]: self.item.attributes.playParams.id ?? self.item.id})
app.mk.queue._reindex()
app.selectedMediaItems = []
}
},
{
"name": "Play Later",
"action": function () {
app.mk.playLater({[self.item.attributes.playParams.kind ?? self.item.type]: self.item.attributes.playParams.id ?? self.item.id})
app.mk.queue._reindex()
app.selectedMediaItems = []
}
},
]
}
}
CiderContextMenu.Create(event, menus[useMenu])
},}
});
</script>

View file

@ -1,179 +0,0 @@
<script type="text/x-template" id="mediaitem-square-sp">
<template>
<div ref="main" style="position: relative; display: inline-flex;" @contextmenu="contextMenu">
<div @click.self='app.routeView(item)'
class="cd-mediaitem-square-sp" ref="main2" :style="{'--spcolor' : (item.attributes.artwork.bgColor != null) ? ('#'+item.attributes.artwork.bgColor) : `black`}">
<div class="artwork">
<mediaitem-artwork
:url="item.attributes.artwork ? item.attributes.artwork.url : ''"
size="300"
:video="(item.attributes != null && item.attributes.editorialVideo != null) ? (item.attributes.editorialVideo.motionDetailSquare ? item.attributes.editorialVideo.motionDetailSquare.video : (item.attributes.editorialVideo.motionSquareVideo1x1 ? item.attributes.editorialVideo.motionSquareVideo1x1.video : '')) : '' "
:type="item.type"></mediaitem-artwork>
</div>
<div class="cd-mediaitem-square-large-overlay" @click.self='app.routeView(item)'>
<div class="button" style="
border-radius: 50%;
background: rgba(50,50,50,0.7);"
:style="[(!(item.attributes.playParams ? (item.attributes.playParams.kind ?? (item.type ?? '')): (item.type ?? '')).includes('radioStation') && !(item.attributes.playParams ? (item.attributes.playParams.kind ?? (item.type ?? '')): (item.type ?? '')).includes('song')) ? {'margin': '140px','position': 'absolute',
width: '40px',
height: '40px',} :
{margin: '35px','position': 'absolute',
width: '120px',
height: '120px',}]" @click="app.playMediaItem(item)">
<%- include("../svg/play.svg") %>
</div>
<div class="button" style="
border-radius: 50%;
background: rgba(50,50,50,0.7);"
:style="[(!(item.attributes.playParams ? (item.attributes.playParams.kind ?? (item.type ?? '')): (item.type ?? '')).includes('radioStation') && !(item.attributes.playParams ? (item.attributes.playParams.kind ?? (item.type ?? '')): (item.type ?? '')).includes('song')) ? {'position': 'absolute','margin': '140px',
width: '40px', 'margin-left': '10px',
height: '40px',} :
{display: 'none',margin: '35px',
width: '120px',
height: '120px',}]" @click="clickContext()">
<%- include("../svg/more.svg") %>
</div>
</div>
<div class="title text-overflow-elipsis"
:style="{'color' : (item.attributes.artwork.textColor1 != null) ? ('#'+item.attributes.artwork.textColor1) : `#eee`}" style="font-weight: 600">
{{ item.attributes.name }}
</div>
<div class="subtitle text-overflow-elipsis "
:class="{'item-navigate': ((item.attributes.editorialNotes == null) && item.attributes.artistName)}"
:style="{ 'z-index': ((item.attributes.editorialNotes == null) && item.attributes.artistName) ? '4' : '' ,'color' : (item.attributes.artwork.textColor1 != null) ? ('#'+item.attributes.artwork.textColor1) : `#eee`}" style="padding-left: 4px;padding-right: 4px; display: -webkit-box;-webkit-box-orient: vertical; -webkit-line-clamp: 2;white-space: normal;"
@click="if((item.attributes.editorialNotes == null) && item.attributes.artistName)app.searchAndNavigate(item,'artist')"
>
{{ (item.attributes.editorialNotes != null) ? item.attributes.editorialNotes.short
:(item.attributes.artistName ?? '') }}
</div>
</div>
<div class="cd-mediaitem-square-large-overlay" @click.self='app.routeView(item)' tabindex="0">
<div class="button" style="
border-radius: 50%;
background: rgba(50,50,50,0.7);"
:style="[(!(item.attributes.playParams ? (item.attributes.playParams.kind ?? (item.type ?? '')): (item.type ?? '')).includes('radioStation') && !(item.attributes.playParams ? (item.attributes.playParams.kind ?? (item.type ?? '')): (item.type ?? '')).includes('song')) ? {'margin': '140px',
width: '40px',
height: '40px',} :
{margin: '35px',
width: '120px',
height: '120px',}]" @click="app.playMediaItem(item)">
<%- include("../svg/play.svg") %>
</div>
<div class="button" style="
border-radius: 50%;
background: rgba(50,50,50,0.7);"
:style="[(!(item.attributes.playParams ? (item.attributes.playParams.kind ?? (item.type ?? '')): (item.type ?? '')).includes('radioStation') && !(item.attributes.playParams ? (item.attributes.playParams.kind ?? (item.type ?? '')): (item.type ?? '')).includes('song')) ? {'position': 'absolute','margin': '140px',
width: '40px', 'margin-left': '10px',
height: '40px',} :
{display: 'none',margin: '35px',
width: '120px',
height: '120px',}]" @click="clickContext()">
<%- include("../svg/more.svg") %>
</div>
</div>
</div>
</template>
</script>
<script>
Vue.component('mediaitem-square-sp', {
template: '#mediaitem-square-sp',
props: ['item'],
methods: { clickContext() {
var evt = document.createEvent('MouseEvent');
var rect = this.$refs.main2.getBoundingClientRect();
evt.initMouseEvent(
"contextmenu",
true /* bubble */, true /* cancelable */,
window, null,
0, 0, rect.x + 100, rect.y +100, /* coordinates */
false, false, false, false, /* modifier keys */
0 /*left*/, null
);
this.$refs.main.dispatchEvent(evt);
}
,contextMenu(event) {
if (!event){event = this.$refs.main} else {console.log(event)}
let self = this
let useMenu = "normal"
if (app.selectedMediaItems.length <= 1) {
app.selectedMediaItems = []
app.select_selectMediaItem(this.item.attributes.playParams.id ?? this.item.id, this.item.attributes.playParams.kind ?? this.item.type, this.index, this.guid)
} else {
useMenu = "multiple"
}
let menus = {
multiple: {
items: [
{
name: `Play ${app.selectedMediaItems.length} tracks next`,
action: () => {
let itemsToPlay = {}
app.selectedMediaItems.forEach(item => {
if (!itemsToPlay[item.kind]) {
itemsToPlay[item.kind] = []
}
itemsToPlay[item.kind].push(item.id)
})
// loop through itemsToPlay
for (let kind in itemsToPlay) {
let ids = itemsToPlay[kind]
if (ids.length > 0) {
app.mk.playNext({[kind + "s"]: itemsToPlay[kind]})
}
}
console.log(itemsToPlay)
app.selectedMediaItems = []
}
},
{
name: `Play ${app.selectedMediaItems.length} tracks later`,
action: () => {
let itemsToPlay = {}
app.selectedMediaItems.forEach(item => {
if (!itemsToPlay[item.kind]) {
itemsToPlay[item.kind] = []
}
itemsToPlay[item.kind].push(item.id)
})
// loop through itemsToPlay
for (let kind in itemsToPlay) {
let ids = itemsToPlay[kind]
if (ids.length > 0) {
app.mk.playLater({[kind + "s"]: itemsToPlay[kind]})
}
}
app.selectedMediaItems = []
}
},
]
},
normal: {
items: [
{
"name": "Play Next",
"action": function () {
app.mk.playNext({[self.item.attributes.playParams.kind ?? self.item.type]: self.item.attributes.playParams.id ?? self.item.id})
app.mk.queue._reindex()
app.selectedMediaItems = []
}
},
{
"name": "Play Later",
"action": function () {
app.mk.playLater({[self.item.attributes.playParams.kind ?? self.item.type]: self.item.attributes.playParams.id ?? self.item.id})
app.mk.queue._reindex()
app.selectedMediaItems = []
}
},
]
}
}
CiderContextMenu.Create(event, menus[useMenu])
},}
});
</script>

View file

@ -1,27 +0,0 @@
<script type="text/x-template" id="mediaitem-square">
<template>
<div tabindex="0" @click="app.playMediaItemById(item.attributes.playParams.id ?? item.id, item.attributes.playParams.kind ?? item.type, item.attributes.playParams.isLibrary ?? false, item.attributes.url)"
class="cd-mediaitem-square">
<div class="artwork">
<mediaitem-artwork
:url="item.attributes.artwork ? item.attributes.artwork.url : ''"
size="300"
:type="item.type"></mediaitem-artwork>
</div>
<div class="title text-overflow-elipsis">
{{ item.attributes.name }}
</div>
<div class="subtitle text-overflow-elipsis" v-if="item.attributes.artistName">
{{ item.attributes.artistName }}
</div>
</div>
</template>
</script>
<script>
Vue.component('mediaitem-square', {
template: '#mediaitem-square',
props: ['item'],
methods: {}
});
</script>

View file

@ -1,60 +0,0 @@
<script type="text/x-template" id="queue-item">
<template>
<div v-observe-visibility="{callback: visibilityChanged}"
@contextmenu="contextMenu"
class="cd-mediaitem-list-item">
<template v-if="isVisible">
<div class="artwork">
<mediaitem-artwork
:url="item.attributes.artwork ? item.attributes.artwork.url : ''"
size="34"
:type="item.type"></mediaitem-artwork>
</div>
<div class="info-rect" :style="{'padding-left': '16px'}">
<div class="title text-overflow-elipsis">
{{ item.attributes.name }}
</div>
<div class="subtitle text-overflow-elipsis" style="-webkit-box-orient: horizontal;">
<template v-if="item.attributes.artistName" >
<div class="artist item-navigate text-overflow-elipsis" @click="app.searchAndNavigate(item,'artist')">
{{ item.attributes.artistName }}
</div>
<template v-if="item.attributes.albumName">&nbsp;-&nbsp;</template>
<template v-if="item.attributes.albumName">
<div class="artist item-navigate text-overflow-elipsis" @click="app.searchAndNavigate(item,'album')">
{{ item.attributes.albumName }}
</div>
</template>
</template>
</div>
</div>
<div class="duration">
{{ msToMinSec(item.attributes.durationInMillis ?? 0) }}
</div>
</template>
</div>
</template>
</script>
<script>
Vue.component('queue-item', {
template: '#queue-item',
props: ['item'],
data: function () {
return {}
},
methods: {
contextMenu(event) {
let self = this
CiderContextMenu.Create(event, {
items: [{
"name": "Remove from queue",
"action": function () {
}
}]
});
}
}
});
</script>

View file

@ -1,137 +0,0 @@
<script type="text/x-template" id="cider-queue">
<div class="queue-panel">
<div class="row">
<div class="col">
<h3 class="queue-header-text">Queue</h3>
</div>
<div class="col-auto flex-center">
<button class="autoplay" :style="{'background': app.mk.autoplayEnabled ? 'var(--keyColor)' : ''}" @click="app.mk.autoplayEnabled = !app.mk.autoplayEnabled">AUTO</button>
</div>
</div>
<div class="queue-body">
<draggable v-model="queueItems" @start="drag=true" @end="drag=false;move()">
<template v-for="(queueItem, position) in queueItems">
<div v-if="position <= queuePosition" style="display: none;">{{ position }}</div>
<div class="cd-queue-item"
:class="{selected: selectedItems.includes(position)}"
@click="select($event, position)"
@dblclick="playQueueItem(position)" v-else :key="position"
@contextmenu="selected = position;queueContext($event, queueItem.item, position)">
<div class="row">
<div class="col-auto flex-center">
<div class="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.albumName }} - {{ queueItem.item.attributes.artistName }}</div>
</div>
</div>
</div>
</template>
</draggable>
</div>
<div class="queue-footer">
<button class="md-btn" style="width:100%;" v-if="queueItems.length > 1" @click="app.mk.clearQueue();updateQueue()">Clear All</button>
</div>
</div>
</script>
<script>
Vue.component('cider-queue', {
template: '#cider-queue',
data: function () {
return {
drag: false,
queuePosition: 0,
queueItems: [],
selected: -1,
selectedItems: []
}
},
mounted() {
this.updateQueue()
},
methods: {
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": "Remove from queue",
"action": function () {
self.queueItems.splice(position, 1)
app.mk.queue._queueItems = self.queueItems;
app.mk.queue._reindex()
}
},
{
"name": "Start Radio",
"action": function () {
app.mk.setStationQueue({
song: item.attributes.playParams.id ?? item.id
}).then(() => {
app.mk.play()
})
}
},
]
},
multiple: {
items: [{
"name": `Remove ${self.selectedItems.length} tracks from queue`,
"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 = []
}
}]
}
}
CiderContextMenu.Create(event, menus[useMenu]);
},
playQueueItem(index) {
app.mk.changeToMediaAtIndex(index)
},
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()
}
}
});
</script>

View file

@ -1,507 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="preconnect" href="https://amp-api.music.apple.com/" crossorigin/>
<link rel="preconnect" href="https://api.music.apple.com/" crossorigin/>
<link rel="preconnect" href="https://is1-ssl.mzstatic.com/" crossorigin/>
<link rel="preconnect" href="https://is2-ssl.mzstatic.com/" crossorigin/>
<link rel="preconnect" href="https://is3-ssl.mzstatic.com/" crossorigin/>
<link rel="preconnect" href="https://is4-ssl.mzstatic.com/" crossorigin/>
<link rel="preconnect" href="https://is5-ssl.mzstatic.com/" crossorigin/>
<link rel="preconnect" href="https://play.itunes.apple.com/" crossorigin/>
<link rel="preconnect" href="https://aod-ssl.itunes.apple.com/" crossorigin/>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no, viewport-fit=cover">
<title>Cider</title>
<link rel="stylesheet/less" type="text/css" href="style.less"/>
<script src="less.js"></script>
<script src="vue.js"></script>
<script src="sortable.min.js"></script>
<script src="vue-observe-visibility.min.js"></script>
<script src="sortable.min.js"></script>
<script src="vuedraggable.umd.min.js"></script>
<link rel="manifest" href="./manifest.json?v=2">
<script src="https://js-cdn.music.apple.com/hls.js/2.141.0/hls.js/hls.js"></script>
<script src="hlscider.js"></script>
</head>
<body oncontextmenu="return false;" loading="1" platform="<%= env.platform %>">
<div id="app">
<div id="app-main">
<div class="mv-chrome" v-if="chrome.topChromeVisible == false"></div>
<div class="app-chrome" :style="{'display': chrome.topChromeVisible ? '' : 'none'}">
<div class="app-chrome--left">
<div class="app-chrome-item full-height">
<div class="app-title"></div>
</div>
<div class="app-chrome-item">
<button class="playback-button--small shuffle" v-if="mk.shuffleMode == 0"
@click="mk.shuffleMode = 1"></button>
<button class="playback-button--small shuffle active" v-else
@click="mk.shuffleMode = 0"></button>
</div>
<div class="app-chrome-item">
<button class="playback-button previous" @click="mk.skipToPreviousItem()"></button>
</div>
<div class="app-chrome-item">
<button class="playback-button pause" @click="mk.pause()" v-if="mk.isPlaying"></button>
<button class="playback-button play" @click="mk.play()" v-else></button>
</div>
<div class="app-chrome-item">
<button class="playback-button next" @click="mk.skipToNextItem()"></button>
</div>
<div class="app-chrome-item">
<button class="playback-button--small repeat" v-if="mk.repeatMode == 0"
@click="mk.repeatMode = 1"></button>
<button class="playback-button--small repeat active" @click="mk.repeatMode = 2"
v-else-if="mk.repeatMode == 1"></button>
<button class="playback-button--small repeat repeatOne" @click="mk.repeatMode = 0"
v-else-if="mk.repeatMode == 2"></button>
</div>
</div>
<div class="app-chrome--center">
<div class="app-chrome-item playback-controls">
<template v-if="mkReady()">
<div class="app-playback-controls" @mouseover="chrome.progresshover = true" @mouseleave="chrome.progresshover = false">
<div class="artwork"></div>
<div class="playback-info">
<div class="song-name" >
{{ mk.nowPlayingItem["attributes"]["name"] }}
</div>
<div class="song-artist " style="display: inline-block; -webkit-box-orient: horizontal; white-space: nowrap;">
<div class="item-navigate song-artist" style="display: inline-block;" @click="app.getNowPlayingItemDetailed(`artist`)">
{{ mk.nowPlayingItem["attributes"]["artistName"] }}
</div>
<div class="song-artist item-navigate" style="display: inline-block;" @click="app.getNowPlayingItemDetailed('album')">
{{ (mk.nowPlayingItem["attributes"]["albumName"]) ? (" - " + mk.nowPlayingItem["attributes"]["albumName"]) : "" }}
</div>
</div>
<div class="song-progress">
<div class="song-duration" style="justify-content: space-between; height: 1px;" :style="[chrome.progresshover ? {'display': 'flex'} : {'display' : 'none'} ]">
<p style="width: auto">{{ convertToMins(getSongProgress()) }}</p>
<p style="width: auto">{{ convertToMins(mk.currentPlaybackDuration) }}</p>
</div>
<input type="range" step="0.01" min="0" :style="progressBarStyle()"
@input="playerLCD.desiredDuration = $event.target.value;playerLCD.userInteraction = true"
@mouseup="mk.seekToTime($event.target.value);playerLCD.desiredDuration = 0;playerLCD.userInteraction = false"
:max="mk.currentPlaybackDuration" :value="getSongProgress()">
</div>
</div>
<template v-if="mk.nowPlayingItem['attributes']['playParams']">
<div class="actions" v-if="isInLibrary(mk.nowPlayingItem['attributes']['playParams'])">
❤️
</div>
<div class="actions" v-else>🖤</div>
</template>
</div>
</template>
</div>
</div>
<div class="app-chrome--right">
<div class="app-chrome-item volume display--large">
<input type="range" class="" step="0.01" min="0" max="1" v-model="mk.volume"
v-if="typeof mk.volume != 'undefined'">
</div>
<div class="app-chrome-item generic">
<button class="playback-button--small">
<%- include("svg/cast.svg") %>
</button>
</div>
<div class="app-chrome-item generic">
<button class="playback-button--small queue" :class="{'active': drawer.panel == 'queue'}" @click="invokeDrawer('queue')"></button>
</div>
<div class="app-chrome-item generic">
<button class="playback-button--small lyrics" :class="{'active': drawer.panel == 'lyrics'}"
@click="invokeDrawer('lyrics')"></button>
</div>
<div class="app-chrome-item full-height">
<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>
<div class="app-navigation" v-cloak>
<div id="app-sidebar">
<div class="app-sidebar-header">
<div class="search-input-container">
<div class="search-input--icon"></div>
<input type="search" spellcheck="false" @click="showSearch()"
@focus="search.showHints = true"
@blur="setTimeout(()=>{search.showHints = false}, 100)"
v-on:keyup.enter="searchQuery();search.showHints = false"
@change="showSearch();" @input="getSearchHints()" placeholder="Search..."
v-model="search.term"
ref="searchInput"
class="search-input">
</div>
</div>
<div class="search-hints-container" v-if="search.showHints && search.hints.length != 0">
<div class="search-hints">
<button class="search-hint" v-for="hint in search.hints"
@click="search.term = hint;search.showHints = false;searchQuery(hint)">
{{ hint }}
</button>
</div>
</div>
<div class="app-sidebar-content">
<div class="app-sidebar-header-text">
Apple Music
</div>
<sidebar-library-item name="Listen Now" page="listen_now"></sidebar-library-item>
<sidebar-library-item name="Browse" page="browse"></sidebar-library-item>
<sidebar-library-item name="Radio" page="radio"></sidebar-library-item>
<div class="app-sidebar-header-text">
Library
</div>
<sidebar-library-item name="Recently Added" page="library-recentlyadded"></sidebar-library-item>
<sidebar-library-item name="Songs" page="library-songs"></sidebar-library-item>
<sidebar-library-item name="Albums" page="library-albums"></sidebar-library-item>
<sidebar-library-item name="Artists" page="library-artists"></sidebar-library-item>
<sidebar-library-item name="Made For You" page="library-madeforyou"></sidebar-library-item>
<div class="app-sidebar-header-text">
Playlists
</div>
<button class="app-sidebar-item" v-for="item in playlists.listing" :key="item.id"
:href="item.href"
@click='appRoute(`playlist_` + item.id); showingPlaylist = [];getPlaylistFromID(app.page.substring(9))'>
{{ item.attributes.name }}
</button>
</div>
<transition name="wpfade">
<div class="usermenu-container" v-if="chrome.menuOpened">
<div class="usermenu-body">
<button class="usermenu-item" @click="chrome.hideUserInfo = !chrome.hideUserInfo">
Toggle Personal Info
</button>
<button class="usermenu-item">
About
</button>
<button class="usermenu-item" @click="window.open('https://discord.gg/CezHYdXHEM')">
Discord
</button>
<button class="usermenu-item" @click="page = 'settings'">
Settings
</button>
<button class="usermenu-item" @click="mk.unauthorize()">
Sign Out
</button>
</div>
</div>
</transition>
<div class="app-sidebar-footer">
<input type="range" class="web-slider display--small" step="0.01" min="0" max="1"
v-model="mk.volume"
v-if="typeof mk.volume != 'undefined'">
<button class="app-sidebar-button" style="width:100%"
:class="{active: chrome.menuOpened}"
@blur="setTimeout(()=>{chrome.menuOpened = false}, 100)"
@click="(chrome.userinfo.id) ? chrome.menuOpened = !chrome.menuOpened : false">
<img class="sidebar-user-icon" loading="lazy"
:src="getMediaItemArtwork(chrome.hideUserInfo ? 'http://localhost:9000/assets/logocut.png' : (chrome.userinfo.attributes['artwork'] ? chrome.userinfo.attributes['artwork']['url'] : ''), 26)"/>
<div class="sidebar-user-text" v-if="!chrome.hideUserInfo">
<template v-if="chrome.userinfo.id">
<div class="fullname text-overflow-elipsis">{{ chrome.userinfo.attributes.name }}
</div>
<div class="handle-text text-overflow-elipsis">@{{ chrome.userinfo.attributes.handle
}}
</div>
</template>
<template v-else>
<div @click="mk.authorize()">
Sign In
</div>
</template>
</div>
<div class="sidebar-user-text" v-else>
Cider
</div>
</button>
</div>
<div class="app-sidebar-notification" v-if="library.downloadNotification.show">
<div>{{ library.downloadNotification.message }}</div>
<div>{{ library.downloadNotification.progress }} / {{ library.downloadNotification.total }}</div>
<div style="width: 100%">
<progress style="width: 80%;" :value="library.downloadNotification.progress"
:max="library.downloadNotification.total"></progress>
</div>
</div>
</div>
<div id="app-content">
<div id="navigation-bar">
<button class="nav-item" @click="history.back()"><%- include('svg/chevron-left.svg') %></button>
<button class="nav-item" @click="history.forward()"><%- include('svg/chevron-right.svg') %></button>
</div>
<!-- Artist Page -->
<transition name="wpfade">
<template v-if="page == 'artist-page' && artistPage.data.attributes">
<cider-artist :data="artistPage.data"></cider-artist>
</template>
</transition>
<transition name="wpfade">
<%- include('pages/zoo') %>
</transition>
<transition name="wpfade">
<%- include('pages/webview') %>
</transition>
<!-- Collection List -->
<transition name="wpfade">
<template v-if="page == 'collection-list'">
<cider-collection-list :data="collectionList.response" :type="collectionList.type" :title="collectionList.title"></cider-collection-list>
</template>
</transition>
<!-- Playlist / Album page-->
<transition name="wpfade">
<template v-if="page.includes('playlist_')">
<cider-playlist :data="showingPlaylist"></cider-playlist>
</template>
</transition>
<transition name="wpfade">
<template v-if="page.includes('album_')">
<cider-playlist :data="showingPlaylist"></cider-playlist>
</template>
</transition>
<transition name="wpfade">
<template v-if="page.includes('recordLabel_')">
<cider-recordlabel :data="showingPlaylist"></cider-recordlabel>
</template>
</transition>
<transition name="wpfade">
<template v-if="page.includes('curator_')">
<cider-recordlabel :data="showingPlaylist"></cider-recordlabel>
</template>
</transition>
<!-- Browse -->
<transition v-on:enter="app.getBrowsePage(); console.log('browse')" name="wpfade">
<template v-if="page == 'browse'">
<!-- <div class="content-inner">
<button id="apple-music-authorize" class="md-btn md-btn-primary" @click="init()">Start
MusicKit
</button>
<button id="apple-music-unauthorize" class="md-btn md-btn-primary"
@click="unauthorize()">
Stop
MusicKit
</button>
<br>
<template v-if="mk.nowPlayingItem">
currentPlaybackProgress: {{ app.mk.currentPlaybackProgress }}
<br>
currentPlaybackDuration: {{ app.mk.currentPlaybackDuration }}
</template>
<div><input type="text" v-model="quickPlayQuery">
<button @click="quickPlay(quickPlayQuery)">Play</button>
</div>
<h1 class="header-text">Browse</h1>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed euismod, urna eu
tincidunt
consectetur, nisl nunc euismod nisi, eu porttitor nisl nisi euismod nisi.
</p>
<div class="media-item--small">
<div class="artwork">
</div>
<div class="text">
Text
</div>
<div class="subtext">
Subtext
</div>
</div>
<br>
<br>
<h1 class="header-text">Listen Now</h1>
<div class="winbox">
<div class="fancy">990kbps</div>
<div class="">
<button class="md-btn md-btn-primary">Audio Quality Settings</button>
</div>
</div>
<button class="md-btn" @click="drawertest = !drawertest">Toggle Drawer</button>
<button class="md-btn">Button</button>
<button class="md-btn md-btn-primary">Button</button>
</div> -->
<cider-browse :data="browsepage"></cider-browse>
</template>
</transition>
<!-- Listen Now -->
<transition v-on:enter="getListenNow()" name="wpfade">
<template v-if="page == 'listen_now'" @created="console.log('listennow')">
<cider-listen-now :data="listennow"></cider-listen-now>
</template>
</transition>
<!-- Radio -->
<transition v-on:enter="getRadioStations()" name="wpfade">
<template v-if="page == 'radio'" @created="console.log('radio')">
<div class="content-inner">
<h1 class="header-text">Radio</h1>
<h3>Recent Stations</h3>
<mediaitem-square :item="item" v-for="item in radio.personal"></mediaitem-square>
</div>
</template>
</transition>
<!-- Settings -->
<transition name="wpfade">
<template v-if="page == 'settings'">
<cider-settings></cider-settings>
</template>
</transition>
<!-- Search -->
<transition name="wpfade">
<template v-if="page == 'search'">
<cider-search :search="search"></cider-search>
</template>
</transition>
<!-- Library - Songs -->
<transition name="wpfade" v-on:enter="getLibrarySongsFull()">
<%- include('pages/library-songs') %>
</transition>
<!-- Library - Albums -->
<transition name="wpfade" v-on:enter="getLibraryAlbumsFull()">
<%- include('pages/library-albums') %>');
%>
</transition>
</div>
<transition name="drawertransition">
<div class="app-drawer" v-if="drawer.open">
<lyrics-view v-if="drawer.panel == 'lyrics'" :time="lyriccurrenttime" :lyrics="lyrics" :richlyrics="richlyrics"></lyrics-view>
<cider-queue ref="queue" v-if="drawer.panel == 'queue'"></cider-queue>
</div>
</transition>
</div>
</div>
<transition name="wpfade">
<img v-show="chrome.artworkReady" @load="chrome.artworkReady = true" class="bg-artwork"
>
</transition>
<transition name="wpfade">
<div class="bg-artwork--placeholder" v-else></div>
</transition>
<div id="apple-music-video-container">
<div id="apple-music-video-player-controls">
<div id="player-exit" title="Close" onclick="app.exitMV()">
<svg fill="white" xmlns="http://www.w3.org/2000/svg" width="21" height="21" viewBox="0 0 21 21"
aria-role="presentation" focusable="false">
<path
d="M10.5 21C4.724 21 0 16.275 0 10.5S4.724 0 10.5 0 21 4.725 21 10.5 16.276 21 10.5 21zm-3.543-5.967a.96.96 0 00.693-.295l2.837-2.842 2.85 2.842c.167.167.41.295.693.295.552 0 1.001-.461 1.001-1.012 0-.281-.115-.512-.295-.704L11.899 10.5l2.85-2.855a.875.875 0 00.295-.68c0-.55-.45-.998-1.001-.998a.871.871 0 00-.668.295l-2.888 2.855-2.862-2.843a.891.891 0 00-.668-.281.99.99 0 00-1.001.986c0 .269.116.512.295.678L9.088 10.5l-2.837 2.843a.926.926 0 00-.295.678c0 .551.45 1.012 1.001 1.012z"
fill-rule="nonzero"/>
</svg>
</div>
<div id="captions">{{((lyricon) ? ((lyrics.length > 0 ) ?
lyrics[currentLyricsLine].line.replace('lrcInstrumental','') : "") : '') + ((lyricon) ? ((lyrics.length > 0 ) ?
(lyrics[currentLyricsLine].translation ? ('\n\r' + lyrics[currentLyricsLine].translation) : ""): "") : '')}}
</div>
<div id="player-pip" @click="document.querySelector('video#apple-music-video-player').requestPictureInPicture()"
title="Picture-in-Picture">
<%- include("svg/fullscreen.svg") %>
</div>
<div id="player-fullscreen" @click="document.querySelector('video#apple-music-video-player').requestFullscreen()"
title="Fullscreen">
<%- include("svg/fullscreen.svg") %>
</div>
</div>
<div id="apple-music-video-player"></div>
</div>
</div>
<%- include("components/mediaitem-artwork"); %>
<!-- Generic Collection of MediaItems -->
<script type="text/x-template" id="collection-view-generic">
<template>
<div class="content-inner">
</div>
</template>
</script>
<!-- Browse -->
<%- include('pages/browse') %>
<!-- Settings -->
<%- include('pages/settings') %>
<!-- Listen Now -->
<%- include('pages/listen_now') %>
<!-- Playlists / Albums -->
<%- include('pages/cider-playlist') %>
<!-- Record Label -->
<%- include('pages/recordLabel') %>
<!-- Collection List -->
<%- include('pages/collection-list') %>
<!-- Artist Page -->
<%- include('pages/artist') %>
<!-- Search -->
<%- include('pages/search') %>
<script type="text/x-template" id="am-musiccovershelf">
<h1>{{ component.attributes.title.stringForDisplay }}</h1>
</script>
<!-- Sidebar Item -->
<script type="text/x-template" id="sidebar-library-item">
<button class="app-sidebar-item"
:class="$parent.getSidebarItemClass(page)" @click="app.appRoute(page)">
{{ name }}
</button>
</script>
<!-- Queue -->
<%- include('components/queue') %>
<!-- Queue Item -->
<%- include('components/queue-item') %>
<!-- Horizontal MediaItem Scroller -->
<%- include('components/mediaitem-scroller-horizontal') %>
<!-- Horizontal MediaItem Scroller (Large) -->
<%- include('components/mediaitem-scroller-horizontal-large') %>
<!-- Horizontal MediaItem Scroller (SP : Special) -->
<%- include('components/mediaitem-scroller-horizontal-sp') %>
<!-- Horizontal MediaItem Scroller (MV) -->
<%- include('components/mediaitem-scroller-horizontal-mvview') %>
<!-- MediaItem List Item -->
<%- include('components/mediaitem-list-item') %>
<!-- MediaItem Horizontal Rectangle -->
<%- include('components/mediaitem-hrect') %>
<!-- MediaItem Square -->
<%- include('components/mediaitem-square') %>
<!-- MediaItem Square (Large) -->
<%- include('components/mediaitem-square-large') %>
<!-- MediaItem Square SP -->
<%- include('components/mediaitem-square-sp') %>
<!-- MediaItem MusicVideo -->
<%- include('components/mediaitem-mvview') %>
<!-- MediaItem MusicVideo SP -->
<%- include('components/mediaitem-mvview-sp') %>
<!-- Animated Artwork View -->
<%- include('components/animatedartwork-view') %>
<!-- Lyrics View -->
<%- include('components/lyrics-view') %>
<script src="musickit.js?v=1"></script>
<script>
if (typeof MusicKit == 'undefined') {
document.write(unescape("%3Cscript src='https://js-cdn.music.apple.com/musickit/v2/amp/musickit.js' type='text/javascript'%3E%3C/script%3E"));
}
</script>
<script src="index.js?v=1"></script>
</body>
</html>

View file

@ -1,19 +0,0 @@
Major thanks to the Cider Development Team and all of our contributors.
<p>"Apple Music" - Copyright © 2021 <a href="https://www.apple.com/" class="dt-footer__link"
target="_blank"
rel="noopener" data-dt-link-to-exclude="">Apple Inc.</a>
All Rights
Reserved.</p>
cryptofyre - Developer - https://github.com/cryptofyre
Core - Developer - https://github.com/coredev-uk
Quacksire - Developer - https://github.com/child-duckling
booploops - Developer - https://github.com/booploops
vapormusic - Developer - https://github.com/vapormusic
Void - Social Communications Team - https://twitter.com/MoonyVoid
NoseySG - Social Communications Team - https://twitter.com/noah_grose
<img class="md-contributors"
onclick="window.open('https://github.com/ciderapp/Cider/graphs/contributors')"
src="https://contrib.rocks/image?repo=ciderapp/Cider"/>

View file

@ -1,173 +0,0 @@
<script type="text/x-template" id="cider-artist">
<div class="content-inner artist-page">
<div class="artist-header" :style="getArtistPalette(data)">
<animatedartwork-view
v-if="data.attributes.editorialVideo && (data.attributes.editorialVideo.motionArtistWide16x9 || data.attributes.editorialVideo.motionArtistFullscreen16x9)"
:video="data.attributes.editorialVideo.motionArtistWide16x9.video ?? (data.attributes.editorialVideo.motionArtistFullscreen16x9.video ?? '')">
</animatedartwork-view>
<div class="row">
<div class="col-sm" style="width: auto;">
<div class="artist-image" v-if="!(data.attributes.editorialVideo && (data.attributes.editorialVideo.motionArtistWide16x9 || data.attributes.editorialVideo.motionArtistFullscreen16x9))">
<mediaitem-artwork
:shadow="true"
:url="data.attributes.artwork ? data.attributes.artwork.url : ''"
size="220" type="artists"></mediaitem-artwork>
<button class="overlay-play" @click="app.mk.setStationQueue({artist:'a-'+data.id}).then(()=>{
app.mk.play()
})">
<%- include("../svg/play.svg") %>
</button>
</div>
</div>
<div class="col flex-center artist-title"
:class="{'artist-animation-on': (data.attributes.editorialVideo && (data.attributes.editorialVideo.motionArtistWide16x9 || data.attributes.editorialVideo.motionArtistFullscreen16x9)) }"
>
<button class="artist-play" @click="app.mk.setStationQueue({artist:'a-'+data.id}).then(()=>{
app.mk.play()
})"><%- include("../svg/play.svg") %></button>
<h1>{{ data.attributes.name }}</h1>
</div>
</div>
<button class="artist-more" @click="artistMenu"></button>
</div>
<div class="artist-body">
<div class="row well">
<div class="col">
<div class="row">
<div class="col-auto" v-if="data.views['latest-release'].data.length != 0">
<h3>Latest Release</h3>
<div style="width: auto;margin: 0 auto;">
<mediaitem-square-sp v-for="song in data.views['latest-release'].data"
:item="song">
</mediaitem-square-sp>
</div>
</div>
<div class="col" v-if="data.views['top-songs']">
<div class="row">
<div class="col" style="padding:0px;">
<h3>Top Songs</h3>
</div>
<div class="col-auto flex-center" v-if="data.views['top-songs'].data.length >= 10" style="padding:0px;">
<button class="cd-btn-seeall" @click="app.showArtistView(data.id, data.attributes.name + ' - Top Songs', 'top-songs')">See All</button>
</div>
</div>
<mediaitem-list-item
v-for="(song, index) in data.views['top-songs'].data.limit(topSongsExpanded ? 10 : 5)"
:index="index"
:item="song"></mediaitem-list-item>
<button class="showmoreless"
@click="topSongsExpanded = !topSongsExpanded">
<template v-if="!topSongsExpanded">
Show more
</template>
<template v-else>
Show less
</template>
</button>
</div>
</div>
</div>
</div>
<div class="row well">
<div class="col">
<template v-for="(view) in data.meta.views.order"
v-if="(data.views[view].data.length != 0) && (view != 'latest-release') && (view != 'top-songs')">
<div class="row">
<div class="col">
<h3>{{ data.views[view].attributes.title ?
data.views[view].attributes.title : "???"}}
</h3>
</div>
<div class="col-auto flex-center" v-if="data.views[view].data.length >= 10">
<button class="cd-btn-seeall" @click="app.showArtistView(data.id, data.attributes.name + ' - ' + data.views[view].attributes.title, view)">See All</button>
</div>
</div>
<template v-if="!((data.views[view].attributes.title ?
data.views[view].attributes.title : '???').includes('Video') || (data.views[view].attributes.title ?
data.views[view].attributes.title : '???').includes('More To See'))">
<mediaitem-scroller-horizontal-large :items="data.views[view].data.limit(10)">
</mediaitem-scroller-horizontal-large>
</template>
<template v-else>
<mediaitem-scroller-horizontal-mvview
:items="data.views[view].data.limit(10)"></mediaitem-scroller-horizontal-mvview>
</template>
</template>
<div class="row">
<div class="col" v-if="data.attributes.artistBio">
<h3>About {{ data.attributes.name }}</h3>
<p v-html="data.attributes.artistBio"></p>
</div>
<div class="col">
<div v-if="data.attributes.origin">
<h3>{{ data.attributes.isGroup ? "Origin" : "Hometown" }}</h3>
{{ data.attributes.origin }}
</div>
<div v-if="data.attributes.bornOrFormed">
<h3>{{ data.attributes.isGroup ? "Formed" : "Born" }}</h3>
{{ data.attributes.bornOrFormed }}
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</script>
<script>
Vue.component('cider-artist', {
template: "#cider-artist",
props: ['data'],
data: function () {
return {
topSongsExpanded: false
}
},
methods: {
artistMenu (event) {
let self = this
CiderContextMenu.Create(event, {
items: [
{
name: "Play Artist Radio",
action: ()=>{
app.mk.setStationQueue({artist:self.data.id}).then(()=>{
app.mk.play()
})
}
},
{
name: "Follow Artist",
action: ()=>{}
},
{
name: "Share",
action: ()=>{}
}
]
})
},
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>

View file

@ -1,37 +0,0 @@
<script type="text/x-template" id="cider-browse">
<div class="content-inner">
<h1 class="header-text">Browse</h1>
<template v-if="data.relationships && data.relationships.tabs">
<template v-for="(recom,index) in data.relationships.tabs.data[0].relationships.children.data">
<div class="row">
<div class="col" v-if="recom.attributes.name != 'Chart Set'">
<h3>{{ recom.attributes.name ?? ""}}</h3>
</div>
<div class="col-auto flex-center" v-if="index != 0 && recom.relationships && ((recom.relationships.children && recom.relationships.children.data.length > 10) || (recom.relationships.contents && recom.relationships.contents.data.length > 10))">
<button class="cd-btn-seeall" @click="app.showCollection(recom.relationships.children ? recom.relationships.children : recom.relationships.contents, recom.attributes.name ?? '', 'listen_now')" >See All</button>
</div>
</div>
<template v-if="recom.relationships && ((recom.relationships.children && recom.relationships.children.data) || (recom.relationships.contents && recom.relationships.contents.data))">
<template v-if="(['385']).includes(recom.attributes.editorialElementKind) || 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'">
<!-- ignored -->
</template>
<template v-else>
<mediaitem-scroller-horizontal-large
:items="recom.relationships.children ? recom.relationships.children.data.limit(10) : recom.relationships.contents.data.limit(10)"></mediaitem-scroller-horizontal-large>
</template>
</template>
</template>
</template>
</div>
</script>
<script>
Vue.component('cider-browse', {
template: "#cider-browse",
props: ["data"]
})
</script>

View file

@ -1,90 +0,0 @@
<script type="text/x-template" id="cider-playlist">
<template v-if="data != [] && data.attributes != null">
<div class="content-inner playlist-page" :style="{'--bgColor': (data.attributes.artwork != null && data.attributes.artwork['bgColor'] != null) ? ('#' + data.attributes.artwork.bgColor) : ''}">
<div class="playlist-display row"
:style="{
background: (data.attributes.artwork != null && data.attributes.artwork['bgColor'] != null) ? ('#' + data.attributes.artwork.bgColor) : '',
color: (data.attributes.artwork != null && data.attributes.artwork['textColor1'] != null) ? ('#' + data.attributes.artwork.textColor1) : ''
}">
<div class="col-auto flex-center">
<div style="width: 260px;height:260px;">
<mediaitem-artwork
:url="(data.attributes != null && data.attributes.artwork && data.attributes.artwork != null) ? data.attributes.artwork.url : ((data.relationships != null && data.relationships.tracks.data.length > 0) ? data.relationships.tracks.data[0].attributes.artwork.url ?? '':'')"
:video="(data.attributes != null && data.attributes.editorialVideo != null) ? (data.attributes.editorialVideo.motionDetailSquare ? data.attributes.editorialVideo.motionDetailSquare.video : (data.attributes.editorialVideo.motionSquareVideo1x1 ? data.attributes.editorialVideo.motionSquareVideo1x1.video : '')) : '' "
size="260"
></mediaitem-artwork>
</div>
</div>
<div class="col playlist-info">
<template v-if="!editorialNotesExpanded">
<div>
<div class="playlist-name">{{data.attributes ? (data.attributes.name ??
(data.attributes.title ?? '') ?? '') : ''}}
</div>
<div class="playlist-artist item-navigate" v-if="data.attributes && data.attributes.artistName" @click="if(data.attributes && data.attributes.artistName){ app.searchAndNavigate(data,'artist')}">
{{data.attributes ? (data.attributes.artistName ?? '') :''}}
</div>
<div class="playlist-desc" v-if="data.attributes.editorialNotes">
<div class="content"
v-html="((data.attributes.editorialNotes) ? (data.attributes.editorialNotes.standard ?? (data.attributes.editorialNotes.short ?? '') ) : (data.attributes.description ? (data.attributes.description.standard ?? (data.attributes.description.short ?? '')) : ''))"></div>
<button class="more-btn" @click="editorialNotesExpanded = !editorialNotesExpanded">
More
</button>
</div>
</div>
</template>
<template v-if="editorialNotesExpanded">
<div class="playlist-desc-expanded">
<div class="content"
v-html="((data.attributes.editorialNotes) ? (data.attributes.editorialNotes.standard ?? (data.attributes.editorialNotes.short ?? '') ) : (data.attributes.description ? (data.attributes.description.standard ?? (data.attributes.description.short ?? '')) : ''))"></div>
<button class="more-btn" @click="editorialNotesExpanded = !editorialNotesExpanded">Less
</button>
</div>
</template>
<div class="playlist-controls">
<button class="wr-btn" style="min-width: 120px;"
@click="app.mk.shuffleMode = 0;app.playMediaItemById(data.attributes.playParams.id ?? data.id, data.attributes.playParams.kind ?? data.type, data.attributes.playParams.isLibrary ?? false, data.attributes.url)">
Play
</button>
<button class="wr-btn" style="min-width: 120px;"
@click="app.mk.shuffleMode = 1;app.playMediaItemById(data.attributes.playParams.id ?? data.id, data.attributes.playParams.kind ?? data.type, data.attributes.playParams.isLibrary ?? false, data.attributes.url)">
Shuffle
</button>
</div>
</div>
</div>
<div class="playlist-body">
<div class="well">
<mediaitem-list-item :item="item" :parent="getItemParent(data)" :index="index"
v-for="(item,index) in data.relationships.tracks.data"></mediaitem-list-item>
</div>
<div class="playlist-time">
{{data.attributes.releaseDate}}
</div>
<div class="playlist-time item-navigate" @click="app.searchAndNavigate(data,'recordLabel') " style="width: 50%;">
{{data.attributes.copyright}}
</div>
<div class="playlist-time">{{app.getTotalTime()}}</div>
</div>
</div>
</template>
</script>
<script>
Vue.component('cider-playlist', {
template: "#cider-playlist",
props: ["data"],
data: function () {
return {
editorialNotesExpanded: false,
}
},
methods: {
getItemParent: function (data) {
kind = data.attributes.playParams.kind;
id = data.attributes.playParams.id;
return `${kind}:${id}`
}
}
})
</script>

View file

@ -1,124 +0,0 @@
<script type="text/x-template" id="cider-collection-list">
<div class="content-inner collection-page">
<h3 class="header-text" v-observe-visibility="{callback: headerVisibility}">{{ title }}</h3>
<div v-if="data['data'] != 'null'" class="well">
<template v-for="(item, key) in data.data">
<template v-if="item.type == 'artists'">
<mediaitem-square-large :item="item"></mediaitem-square-large>
</template>
<template v-else>
<mediaitem-list-item
v-if="item.attributes.playParams.kind == 'song'"
:index="key"
:item="item"></mediaitem-list-item>
<mediaitem-mvview v-else-if="item.attributes.playParams.kind == 'musicVideo'" :item="item"></mediaitem-mvview>
<mediaitem-square-large v-else :item="item"></mediaitem-square-large>
</template>
</template>
<button v-if="triggerEnabled" style="opacity:0;height: 32px;" v-observe-visibility="{callback: visibilityChanged}">Show More</button>
</div>
<transition name="fabfade">
<button class="top-fab" v-show="showFab" @click="scrollToTop()">
<%- include("../svg/arrow-up.svg") %>
</button>
</transition>
</div>
</script>
<script>
Vue.component('cider-collection-list', {
template: "#cider-collection-list",
props: {
data: {
type: Object,
required: true
},
title: {
type: String,
required: false
},
type: {
type: String,
required: false,
default: "artists"
}
},
data: function () {
return {
triggerEnabled: true,
canSeeTrigger: false,
showFab: false
}
},
methods: {
scrollToTop() {
let target = document.querySelector(".header-text")
target.scrollIntoView({behavior: "smooth", block: "start", inline: "nearest"})
},
getNext() {
// if this.data.next is not null, then we can run this.data.next() and concat to this.data.data to get the next page
switch(this.type) {
default:
case "artists":
if (this.data.next && this.triggerEnabled) {
this.triggerEnabled = false;
this.data.next().then(data => {
console.log(data);
this.data.next = data.next;
this.data.data = this.data.data.concat(data.data);
this.triggerEnabled = true;
});
}else{
console.log("No next page");
this.triggerEnabled = false;
}
break;
case "search":
if (this.data.next && this.triggerEnabled) {
this.triggerEnabled = false;
this.data.next().then(data => {
console.log(data);
this.data.next = data[this.data.groups].next;
this.data.data = this.data.data.concat(data[this.data.groups].data.data);
this.triggerEnabled = true;
});
}else{
console.log("No next page");
this.triggerEnabled = false;
}
break;
case "listen_now":
case "curator":
if (this.data.next && this.triggerEnabled) {
this.triggerEnabled = false;
app.mk.api.v3.music(this.data.next).then(data => {
console.log(data);
this.data.next = data.data.next;
this.data.data = this.data.data.concat(data.data.data);
this.triggerEnabled = true;
});
}else{
console.log("No next page");
this.triggerEnabled = false;
}
break;
}
},
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>

View file

@ -1,56 +0,0 @@
<template v-if="page == 'library-albums'">
<div class="content-inner">
<div class="row">
<div class="col" style="padding:0px;">
<h1 class="header-text">Albums</h1>
</div>
<div class="col-auto">
<button v-if="library.albums.downloadState == 2" @click="getLibraryAlbumsFull(true)" class="reload-btn"><%- include('../svg/redo.svg') %></button>
</div>
</div>
<div class="row">
<div class="col" style="padding:0px;">
<div class="search-input-container" style="width:100%;margin: 16px 0px;">
<div class="search-input--icon"></div>
<input type="search"
style="width:100%;"
spellcheck="false"
placeholder="Search..."
@input="searchLibraryAlbums"
v-model="library.albums.search" class="search-input">
</div>
</div>
<div class="col-auto flex-center">
<div class="row">
<div class="col">
<select class="md-select" v-model="library.albums.sorting" @change="searchLibraryAlbums()">
<optgroup label="Sort By">
<option v-for="(sort, index) in library.albums.sortingOptions" :value="index">{{ sort }}</option>
</optgroup>
</select>
</div>
<div class="col">
<select class="md-select" v-model="library.albums.sortOrder" @change="searchLibraryAlbums()">
<optgroup label="Sort Order">
<option value="asc">Ascending</option>
<option value="desc">Descending</option>
</optgroup>
</select>
</div>
<div class="col">
<select class="md-select" v-model="library.albums.viewAs">
<optgroup label="View As">
<option value="covers">Cover Art</option>
<option value="list">List</option>
</optgroup>
</select>
</div>
</div>
</div>
</div>
<mediaitem-square-large v-if="library.albums.viewAs == 'covers'" :item="item" v-for="item in library.albums.displayListing">
</mediaitem-square-large>
<mediaitem-list-item v-if="library.albums.viewAs == 'list'" :show-duration="false" :show-meta-data="true" :show-library-status="false" :item="item" v-for="item in library.albums.displayListing">
</mediaitem-list-item>
</div>
</template>

View file

@ -1,46 +0,0 @@
<template v-if="page == 'library-songs'">
<div class="content-inner">
<div class="row">
<div class="col" style="padding:0px;">
<h1 class="header-text">Songs</h1>
</div>
<div class="col-auto">
<button v-if="library.songs.downloadState == 2" @click="getLibrarySongsFull(true)" class="reload-btn"><%- include('../svg/redo.svg') %></button>
</div>
</div>
<div class="row">
<div class="col" style="padding:0px;">
<div class="search-input-container" style="width:100%;margin: 16px 0px;">
<div class="search-input--icon"></div>
<input type="search"
style="width:100%;"
spellcheck="false"
placeholder="Search..."
@input="searchLibrarySongs"
v-model="library.songs.search" class="search-input">
</div>
</div>
<div class="col-auto flex-center">
<div class="row">
<div class="col">
<select class="md-select" v-model="library.songs.sorting" @change="searchLibrarySongs()">
<optgroup label="Sort By">
<option v-for="(sort, index) in library.songs.sortingOptions" :value="index">{{ sort }}</option>
</optgroup>
</select>
</div>
<div class="col">
<select class="md-select" v-model="library.songs.sortOrder" @change="searchLibrarySongs()">
<optgroup label="Sort Order">
<option value="asc">Ascending</option>
<option value="desc">Descending</option>
</optgroup>
</select>
</div>
</div>
</div>
</div>
<div v-if="library.songs.downloadState == 3">Library contains no songs.</div>
<mediaitem-list-item :item="item" :parent="'librarysongs'" :index="index" :show-meta-data="true" :show-library-status="false" v-for="(item, index) in library.songs.displayListing"></mediaitem-list-item>
</div>
</template>

View file

@ -1,32 +0,0 @@
<script type="text/x-template" id="cider-listen-now">
<div class="content-inner">
<h1 class="header-text">Listen Now</h1>
<template v-for="recom in data.data">
<div class="row">
<div class="col">
<h3>{{ recom.attributes.title ? recom.attributes.title.stringForDisplay : ""}}</h3>
</div>
<div class="col-auto flex-center" v-if="recom.relationships.contents.data.length >= 10">
<button class="cd-btn-seeall" @click="app.showCollection(recom.relationships.contents, recom.attributes.title ? recom.attributes.title.stringForDisplay : '', 'listen_now')" >See All</button>
</div>
</div>
<template v-if="recom.attributes.display.kind == 'MusicCoverShelf'">
<mediaitem-scroller-horizontal-large
:items="recom.relationships.contents.data.limit(10)"></mediaitem-scroller-horizontal-large>
</template>
<template v-else-if="recom.attributes.display.kind == 'MusicSuperHeroShelf'">
</template>
<template v-else>
<mediaitem-scroller-horizontal-sp
:items="recom.relationships.contents.data.limit(10)"></mediaitem-scroller-horizontal-sp>
</template>
</template>
</div>
</script>
<script>
Vue.component('cider-listen-now', {
template: "#cider-listen-now",
props: ["data"]
})
</script>

View file

@ -1,101 +0,0 @@
<script type="text/x-template" id="cider-recordlabel">
<div class="content-inner artist-page">
<div class="artist-header" :style="getArtistPalette(data)">
<div class="row">
<div class="col-sm" style="width: auto;">
<div class="artist-image">
<mediaitem-artwork
:shadow="true"
:url="data.attributes.artwork ? data.attributes.artwork.url : ''"
size="220" type="artists"></mediaitem-artwork>
</div>
</div>
<div class="col flex-center"
>
<h1>{{ data.attributes.name }}</h1>
</div>
</div>
</div>
<div class="artist-body">
<div v-if = "app.showingPlaylist.attributes.description">
<div class="row">
<h3>About </h3>
</div>
<div class="row">
<div>{{ app.showingPlaylist.attributes.description.standard }}</div>
</div>
</div>
<template v-if="data.views && data.views['latest-releases']">
<div class="row">
<div class="col">
<h3>{{ data.views["latest-releases"].attributes.title ?? ""}}</h3>
</div>
<div class="col-auto flex-center" v-if="data.views['latest-releases'].data.length >= 10">
<button class="cd-btn-seeall" @click="app.showRecordLabelView(data.id, data.attributes.name + ' - Latest Releases', 'latest-releases')">See All</button>
</div>
</div>
<mediaitem-square-large :item="item" v-for="item in data.views['latest-releases'].data">
</mediaitem-square-large>
</template>
<template v-if="data.views && data.views['top-releases']">
<div class="row">
<div class="col">
<h3>{{ data.views["top-releases"].attributes.title ?? ""}}</h3>
</div>
<div class="col-auto flex-center" v-if="data.views['top-releases'].data.length >= 10">
<button class="cd-btn-seeall" @click="app.showRecordLabelView(data.id, data.attributes.name + ' - Top Releases', 'top-releases')">See All</button>
</div>
</div>
<mediaitem-square-large :item="item" v-for="item in data.views['top-releases'].data">
</mediaitem-square-large>
</template>
<template v-if="data.relationships && data.relationships.playlists && data.relationships.playlists.data.length > 0">
<div class="row">
<div class="col">
<h3>Playlists</h3>
</div>
<div class="col-auto flex-center" v-if="data.relationships.playlists.data.length >= 5">
<button class="cd-btn-seeall" @click="app.showCollection(data.relationships.playlists, data.attributes.name + ' - Playlists', 'curator')">See All</button>
</div>
</div>
<mediaitem-square-large :item="item" v-for="item in data.relationships.playlists.data.limit(5)">
</mediaitem-square-large>
</template>
</div>
</div>
</script>
<script>
Vue.component('cider-recordlabel', {
template: "#cider-recordlabel",
props: ['data'],
data: function () {
return {
topSongsExpanded: false
}
},
methods: {
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>

View file

@ -1,64 +0,0 @@
<script type="text/x-template" id="cider-search">
<div class="content-inner">
<div class="row">
<div class="col-sm" style="width: auto;" v-if="getTopResult()">
<template>
<h3>Top Result</h3>
<mediaitem-square-large :item="getTopResult()"></mediaitem-square-large>
</template>
</div>
<div class="col" v-if="search.results.song">
<div class="row">
<div class="col">
<h3>Songs</h3>
</div>
<div class="col-auto flex-center" @click="app.showSearchView(app.search.term, 'song', app.friendlyTypes('song'))" v-if="search.results.song.data.length >= 6">
<button class="cd-btn-seeall">See All</button>
</div>
</div>
<div>
<mediaitem-list-item :item="item" :index="index"
v-for="(item, index) in search.results.song.data.limit(6)"></mediaitem-list-item>
</div>
</div>
</div>
<template v-if="search.results['meta']">
<template
v-for="section in search.results.meta.results.order" v-if="section != 'song' && section != 'top'">
<div class="row">
<div class="col">
<h3>{{ app.friendlyTypes(section) }}</h3>
</div>
<div class="col-auto flex-center" v-if="search.results[section].data.length >= 10">
<button class="cd-btn-seeall" @click="app.showSearchView(app.search.term, section, app.friendlyTypes(section))">See All</button>
</div>
</div>
<template v-if="!app.friendlyTypes(section).includes('Video')">
<mediaitem-scroller-horizontal-large
:items="search.results[section].data.limit(10)"></mediaitem-scroller-horizontal-large>
</template>
<template v-else>
<mediaitem-scroller-horizontal-mvview
:items="search.results[section].data.limit(10)"></mediaitem-scroller-horizontal-mvview>
</template>
</template>
</template>
</div>
</script>
<script>
Vue.component('cider-search', {
template: "#cider-search",
props: ['search'],
methods: {
getTopResult() {
if (this.search.results["meta"]) {
return this.search.results[this.search.results.meta.results.order[0]]["data"][0]
} else {
return false;
}
}
}
})
</script>

View file

@ -1,178 +0,0 @@
<script type="text/x-template" id="cider-settings">
<div class="content-inner settings-page">
<h1 class="header-text">Settings <small>(non functional, stay tuned)</small></h1>
<div class="md-option-container">
<div class="md-option-line">
<div class="md-option-segment">
Audio Quality
</div>
<div class="md-option-segment md-option-segment_auto">
<select class="md-select" style="width:180px;">
<option value="990">Extreme</option>
<option value="256">High</option>
<option value="64">Low</option>
</select>
</div>
</div>
<div class="md-option-line">
<div class="md-option-segment">
Seamless Audio Transitions
</div>
<div class="md-option-segment md-option-segment_auto">
<input type="checkbox" switch/>
</div>
</div>
<div class="md-option-line">
<div class="md-option-segment">
Animated Artwork
</div>
<div class="md-option-segment md-option-segment_auto">
<select class="md-select">
<option value="0">Always</option>
<option value="1">Limit to pages and special entries</option>
<option value="2">Disable Everywhere</option>
</select>
</div>
</div>
<div class="md-option-line">
<div class="md-option-segment">
Discord Rich Presence
</div>
<div class="md-option-segment md-option-segment_auto">
<select class="md-select">
<option value="0">Disabled</option>
<option value="1">Display as 'Cider'</option>
<option value="2">Display as 'Apple Music'</option>
</select>
</div>
</div>
<div class="md-option-line">
<div class="md-option-segment">
Enable AudioContext Functionality
<br>
<small>Enabling AudioContext functionality will allow for extended audio features like Equalizers and Visualizers, however on some systems this may cause stuttering in audio tracks.</small>
</div>
<div class="md-option-segment md-option-segment_auto">
<input type="checkbox" switch/>
</div>
</div>
<div class="md-option-line">
<div class="md-option-segment">
LastFM Scrobbling
</div>
<div class="md-option-segment md-option-segment_auto">
<input type="checkbox" switch/>
</div>
</div>
<div class="md-option-line">
<div class="md-option-segment">
LastFM Scrobble Delay
</div>
<div class="md-option-segment md-option-segment_auto">
<input type="checkbox" switch/>
</div>
</div>
<div class="md-option-line">
<div class="md-option-segment">
Theme
</div>
<div class="md-option-segment md-option-segment_auto">
<select class="md-select">
<option value="0">Cider</option>
</select>
</div>
</div>
<div class="md-option-line">
<div class="md-option-segment">
Theme Options
</div>
<div class="md-option-segment md-option-segment_auto">
<button class="btn">Theme Options</button>
</div>
</div>
<div class="md-option-line">
<div class="md-option-segment">
Scrollbars
</div>
<div class="md-option-segment md-option-segment_auto">
<select class="md-select">
<option value="0">Show on hover</option>
<option value="1">Always show</option>
<option value="2">Hidden</option>
</select>
</div>
</div>
<div class="md-option-line">
<div class="md-option-segment">
Refresh Rate
</div>
<div class="md-option-segment md-option-segment_auto">
<select class="md-select">
<option value='0'>Automatic</option>
<option value='30'>30</option>
<option value='60'>60</option>
<option value='144'>144</option>
<option value='175'>175</option>
<option value='240'>240</option>
<option value='360'>30</option>
</select>
</div>
</div>
<div class="md-option-line">
<div class="md-option-segment">
Enable Musixmatch Lyrics
</div>
<div class="md-option-segment md-option-segment_auto">
<input type="checkbox" switch/>
</div>
</div>
<div class="md-option-line">
<div class="md-option-segment">
Musixmatch Preferred Language
</div>
<div class="md-option-segment md-option-segment_auto">
<input type="checkbox" switch/>
</div>
</div>
<div class="md-option-line">
<div class="md-option-segment">
Close Button Behavior
</div>
<div class="md-option-segment md-option-segment_auto">
<select class="md-select">
<option value='0'>Minimize to system tray</option>
<option value='1'>Minimize to taskbar ? dock</option>
<option value='2'>Quit Cider</option>
</select>
</div>
</div>
<div class="md-option-line">
<div class="md-option-segment">
Open Cider on Startup
</div>
<div class="md-option-segment md-option-segment_auto">
<select class="md-select">
<option value='0'>Never</option>
<option value='1'>Always</option>
<option value='2'>Always, minimized</option>
<option value='2'>Always, hidden in tray</option>
</select>
</div>
</div>
</div>
</div>
</script>
<script>
Vue.component('cider-settings', {
template: "#cider-settings",
props: [],
data: function () {
return {
}
},
methods: {
}
})
</script>

View file

@ -1,5 +0,0 @@
<template v-if="page == 'webview'">
<div style="display:flex;width:100%;height:100%">
<webview id="foo" :src="webview.url" style="display:inline-flex; width:100%;"></webview>
</div>
</template>

View file

@ -1,7 +0,0 @@
<template v-if="page == 'zoo'">
<div class="content-inner">
<h3>Welcome to element park. *BERR NERR NERR NERR NERRRRR BERR NER NER NER NERRR BERRR NR NR NRRRR*</h3>
<button @click="app.playMediaItemById('1592151778', 'album')">Play Test Album</button>
<cider-queue ref="queue"></cider-queue>
</div>
</template>

View file

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512" fill="currentColor"><!-- Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) --><path d="M34.9 289.5l-22.2-22.2c-9.4-9.4-9.4-24.6 0-33.9L207 39c9.4-9.4 24.6-9.4 33.9 0l194.3 194.3c9.4 9.4 9.4 24.6 0 33.9L413 289.4c-9.5 9.5-25 9.3-34.3-.4L264 168.6V456c0 13.3-10.7 24-24 24h-32c-13.3 0-24-10.7-24-24V168.6L69.2 289.1c-9.3 9.8-24.8 10-34.3.4z"/></svg>

Before

Width:  |  Height:  |  Size: 531 B

View file

@ -1,4 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 30 22" version="1.1" fill="#fff"
style="width: 100%; height: 100%; fill-rule: evenodd; clip-rule: evenodd; stroke-linejoin: round; stroke-miterlimit: 1.41421">
<path d="M16.811,12.75c0.245,-0.355 0.389,-0.786 0.389,-1.25c0,-1.215 -0.985,-2.2 -2.2,-2.2c-1.215,0 -2.2,0.985 -2.2,2.2c0,0.466 0.145,0.898 0.392,1.254l-0.83,1.047c-0.537,-0.616 -0.862,-1.42 -0.862,-2.301c0,-1.933 1.567,-3.5 3.5,-3.5c1.933,0 3.5,1.567 3.5,3.5c0,0.879 -0.324,1.683 -0.859,2.297l-0.83,-1.047Zm1.271,1.604c0.694,-0.749 1.118,-1.752 1.118,-2.854c0,-2.32 -1.88,-4.2 -4.2,-4.2c-2.32,0 -4.2,1.88 -4.2,4.2c0,1.103 0.425,2.107 1.121,2.857l-0.814,1.028c-0.993,-0.995 -1.607,-2.368 -1.607,-3.885c0,-3.038 2.462,-5.5 5.5,-5.5c3.038,0 5.5,2.462 5.5,5.5c0,1.515 -0.613,2.887 -1.604,3.882l-0.814,-1.028Zm1.252,1.58c1.151,-1.126 1.866,-2.697 1.866,-4.434c0,-3.424 -2.776,-6.2 -6.2,-6.2c-3.424,0 -6.2,2.776 -6.2,6.2c0,1.739 0.716,3.311 1.869,4.437l-0.811,1.023c-1.452,-1.368 -2.358,-3.308 -2.358,-5.46c0,-4.142 3.358,-7.5 7.5,-7.5c4.142,0 7.5,3.358 7.5,7.5c0,2.15 -0.905,4.089 -2.355,5.457l-0.811,-1.023Zm-0.227,2.066l-8.219,0c-0.355,0 -0.515,-0.434 -0.27,-0.717l4.058,-5.12c0.178,-0.217 0.474,-0.217 0.652,0l4.058,5.12c0.237,0.283 0.085,0.717 -0.279,0.717Z" style="fill-rule:nonzero"></path>
</svg>

Before

Width:  |  Height:  |  Size: 1.3 KiB

View file

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 320 512"><!-- Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) --><path d="M34.52 239.03L228.87 44.69c9.37-9.37 24.57-9.37 33.94 0l22.67 22.67c9.36 9.36 9.37 24.52.04 33.9L131.49 256l154.02 154.75c9.34 9.38 9.32 24.54-.04 33.9l-22.67 22.67c-9.37 9.37-24.57 9.37-33.94 0L34.52 272.97c-9.37-9.37-9.37-24.57 0-33.94z"/></svg>

Before

Width:  |  Height:  |  Size: 518 B

View file

@ -1 +0,0 @@
<svg aria-hidden="true" data-prefix="fas" data-icon="chevron-right" fill="currentColor" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512" class="svg-inline--fa fa-chevron-right fa-w-10 fa-7x"><path fill="currentColor" d="M285.476 272.971L91.132 467.314c-9.373 9.373-24.569 9.373-33.941 0l-22.667-22.667c-9.357-9.357-9.375-24.522-.04-33.901L188.505 256 34.484 101.255c-9.335-9.379-9.317-24.544.04-33.901l22.667-22.667c9.373-9.373 24.569-9.373 33.941 0L285.475 239.03c9.373 9.372 9.373 24.568.001 33.941z" class=""/></svg>

Before

Width:  |  Height:  |  Size: 538 B

View file

@ -1,55 +0,0 @@
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
fill="#eee" viewBox="0 0 384.97 384.97" style="enable-background:new 0 0 384.97 384.97;" xml:space="preserve">
<g>
<g id="Fullscreen_1_">
<path d="M372.939,216.545c-6.123,0-12.03,5.269-12.03,12.03v132.333H24.061V24.061h132.333c6.388,0,12.03-5.642,12.03-12.03
S162.409,0,156.394,0H24.061C10.767,0,0,10.767,0,24.061v336.848c0,13.293,10.767,24.061,24.061,24.061h336.848
c13.293,0,24.061-10.767,24.061-24.061V228.395C384.97,221.731,380.085,216.545,372.939,216.545z"/>
<path d="M372.939,0H252.636c-6.641,0-12.03,5.39-12.03,12.03s5.39,12.03,12.03,12.03h91.382L99.635,268.432
c-4.668,4.668-4.668,12.235,0,16.903c4.668,4.668,12.235,4.668,16.891,0L360.909,40.951v91.382c0,6.641,5.39,12.03,12.03,12.03
s12.03-5.39,12.03-12.03V12.03l0,0C384.97,5.558,379.412,0,372.939,0z"/>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.1 KiB

View file

@ -1,3 +0,0 @@
<svg fill="white" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 27 27" class="glyph">
<path d="M8.89547677 13.5330073c0-1.1057457-.97371638-2.0959657-2.09596577-2.0959657-1.13875305 0-2.0794621.99022-2.0794621 2.0959657 0 1.1222494.94070905 2.0794621 2.0794621 2.0794621 1.12224939 0 2.09596577-.9572127 2.09596577-2.0794621zm6.68398533 0c0-1.1057457-.9572127-2.0959657-2.0794621-2.0959657-1.1222494 0-2.0794621.99022-2.0794621 2.0959657 0 1.1222494.9572127 2.0794621 2.0794621 2.0794621 1.1222494 0 2.0794621-.9572127 2.0794621-2.0794621zm6.700489 0c0-1.1057457-.940709-2.0959657-2.0794621-2.0959657-1.1222494 0-2.0959658.99022-2.0959658 2.0959657 0 1.1222494.9737164 2.0794621 2.0959658 2.0794621 1.1387531 0 2.0794621-.9572127 2.0794621-2.0794621z"></path>
</svg>

Before

Width:  |  Height:  |  Size: 772 B

View file

@ -1,3 +0,0 @@
<svg fill="white" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 27 27" class="glyph">
<path d="M11.3545232,18.4180929 L18.4676039,14.242665 C19.0452323,13.9290954 19.0122249,13.1204156 18.4676039,12.806846 L11.3545232,8.63141809 C10.7603912,8.26833741 9.98471883,8.54889976 9.98471883,9.19254279 L9.98471883,17.8404645 C9.98471883,18.5006112 10.7108802,18.7976773 11.3545232,18.4180929 Z"></path>
</svg>

Before

Width:  |  Height:  |  Size: 409 B

View file

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 512 512"><!-- Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) --><path d="M500.33 0h-47.41a12 12 0 0 0-12 12.57l4 82.76A247.42 247.42 0 0 0 256 8C119.34 8 7.9 119.53 8 256.19 8.1 393.07 119.1 504 256 504a247.1 247.1 0 0 0 166.18-63.91 12 12 0 0 0 .48-17.43l-34-34a12 12 0 0 0-16.38-.55A176 176 0 1 1 402.1 157.8l-101.53-4.87a12 12 0 0 0-12.57 12v47.41a12 12 0 0 0 12 12h200.33a12 12 0 0 0 12-12V12a12 12 0 0 0-12-12z"/></svg>

Before

Width:  |  Height:  |  Size: 622 B

View file

@ -1 +0,0 @@
var VueObserveVisibility=function(e){"use strict";function t(e){return(t="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function i(e,t){for(var i=0;i<t.length;i++){var n=t[i];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(e,n.key,n)}}function n(e){return function(e){if(Array.isArray(e)){for(var t=0,i=new Array(e.length);t<e.length;t++)i[t]=e[t];return i}}(e)||function(e){if(Symbol.iterator in Object(e)||"[object Arguments]"===Object.prototype.toString.call(e))return Array.from(e)}(e)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance")}()}var r=function(){function e(t,i,n){!function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}(this,e),this.el=t,this.observer=null,this.frozen=!1,this.createObserver(i,n)}var t,r,o;return t=e,(r=[{key:"createObserver",value:function(e,t){var i=this;if(this.observer&&this.destroyObserver(),!this.frozen){var r;if(this.options="function"==typeof(r=e)?{callback:r}:r,this.callback=function(e,t){i.options.callback(e,t),e&&i.options.once&&(i.frozen=!0,i.destroyObserver())},this.callback&&this.options.throttle){var o=(this.options.throttleOptions||{}).leading;this.callback=function(e,t){var i,r,o,s=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{},l=function(l){for(var a=arguments.length,c=new Array(a>1?a-1:0),u=1;u<a;u++)c[u-1]=arguments[u];if(o=c,!i||l!==r){var f=s.leading;"function"==typeof f&&(f=f(l,r)),i&&l===r||!f||e.apply(void 0,[l].concat(n(o))),r=l,clearTimeout(i),i=setTimeout(function(){e.apply(void 0,[l].concat(n(o))),i=0},t)}};return l._clear=function(){clearTimeout(i),i=null},l}(this.callback,this.options.throttle,{leading:function(e){return"both"===o||"visible"===o&&e||"hidden"===o&&!e}})}this.oldResult=void 0,this.observer=new IntersectionObserver(function(e){var t=e[0];if(e.length>1){var n=e.find(function(e){return e.isIntersecting});n&&(t=n)}if(i.callback){var r=t.isIntersecting&&t.intersectionRatio>=i.threshold;if(r===i.oldResult)return;i.oldResult=r,i.callback(r,t)}},this.options.intersection),t.context.$nextTick(function(){i.observer&&i.observer.observe(i.el)})}}},{key:"destroyObserver",value:function(){this.observer&&(this.observer.disconnect(),this.observer=null),this.callback&&this.callback._clear&&(this.callback._clear(),this.callback=null)}},{key:"threshold",get:function(){return this.options.intersection&&"number"==typeof this.options.intersection.threshold?this.options.intersection.threshold:0}}])&&i(t.prototype,r),o&&i(t,o),e}();function o(e,t,i){var n=t.value;if(n)if("undefined"==typeof IntersectionObserver)console.warn("[vue-observe-visibility] IntersectionObserver API is not available in your browser. Please install this polyfill: https://github.com/w3c/IntersectionObserver/tree/master/polyfill");else{var o=new r(e,n,i);e._vue_visibilityState=o}}function s(e){var t=e._vue_visibilityState;t&&(t.destroyObserver(),delete e._vue_visibilityState)}var l={bind:o,update:function(e,i,n){var r=i.value;if(!function e(i,n){if(i===n)return!0;if("object"===t(i)){for(var r in i)if(!e(i[r],n[r]))return!1;return!0}return!1}(r,i.oldValue)){var l=e._vue_visibilityState;r?l?l.createObserver(r,n):o(e,{value:r},n):s(e)}},unbind:s};function a(e){e.directive("observe-visibility",l)}var c={version:"1.0.0",install:a},u=null;return"undefined"!=typeof window?u=window.Vue:"undefined"!=typeof global&&(u=global.Vue),u&&u.use(c),e.ObserveVisibility=l,e.default=c,e.install=a,e}({});

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -1,193 +0,0 @@
const {BrowserWindow, ipcMain, shell, app} = require("electron")
const {join} = require("path")
const getPort = require("get-port");
const express = require("express");
const path = require("path");
const windowStateKeeper = require("electron-window-state");
const os = require('os');
// Analytics for debugging.
const ElectronSentry = require("@sentry/electron");
ElectronSentry.init({dsn: "https://68c422bfaaf44dea880b86aad5a820d2@o954055.ingest.sentry.io/6112214"});
const CiderBase = {
CreateBrowserWindow() {
// Set default window sizes
const mainWindowState = windowStateKeeper({
defaultWidth: 1024,
defaultHeight: 600
});
let win = null
const options = {
icon: join(__dirname, `../icons/icon.ico`),
width: mainWindowState.width,
height: mainWindowState.height,
x: mainWindowState.x,
y: mainWindowState.y,
minWidth: 844,
minHeight: 410,
frame: false,
title: "Cider",
vibrancy: 'dark',
hasShadow: false,
webPreferences: {
webviewTag: true,
plugins: true,
nodeIntegration: true,
nodeIntegrationInWorker: false,
webSecurity: false,
allowRunningInsecureContent: true,
enableRemoteModule: true,
sandbox: true,
nativeWindowOpen: true,
contextIsolation: false,
preload: join(__dirname, '../preload/cider-preload.js')
}
}
CiderBase.InitWebServer()
// Create the BrowserWindow
if (process.platform === "darwin" || process.platform === "linux") {
win = new BrowserWindow(options)
} else {
const {BrowserWindow} = require("electron-acrylic-window");
win = new BrowserWindow(options)
}
// intercept "https://js-cdn.music.apple.com/hls.js/2.141.0/hls.js/hls.js" and redirect to local file "./apple-hls.js" instead
win.webContents.session.webRequest.onBeforeRequest(
{
urls: ["https://*/*.js"]
},
(details, callback) => {
if (details.url.includes("hls.js")) {
callback({
redirectURL: "http://localhost:9000/apple-hls.js"
})
} else {
callback({
cancel: false
})
}
}
)
let location = "http://localhost:9000/"
win.loadURL(location)
win.on("closed", () => {
win = null
})
// Register listeners on Window to track size and position of the Window.
mainWindowState.manage(win);
// IPC stuff (senders)
ipcMain.on("cider-platform", (event) => {
event.returnValue = process.platform
})
// IPC stuff (listeners)
ipcMain.on('close', () => { // listen for close event
win.close();
})
ipcMain.handle('getStoreValue', (event, key, defaultValue) => {
return (defaultValue ? app.cfg.get(key, true) : app.cfg.get(key));
});
ipcMain.handle('setStoreValue', (event, key, value) => {
app.cfg.set(key, value);
});
ipcMain.on('getStore', (event) => {
event.returnValue = app.cfg.store
})
ipcMain.on('setStore', (event, store) => {
app.cfg.store = store
})
ipcMain.on('maximize', () => { // listen for maximize event
if (win.isMaximized()) {
win.unmaximize()
} else {
win.maximize()
}
})
ipcMain.on('minimize', () => { // listen for minimize event
win.minimize();
})
if (process.platform === "win32") {
let WND_STATE = {
MINIMIZED: 0,
NORMAL: 1,
MAXIMIZED: 2,
FULL_SCREEN: 3
}
let wndState = WND_STATE.NORMAL
win.on("resize", (_event) => {
const isMaximized = win.isMaximized()
const isMinimized = win.isMinimized()
const isFullScreen = win.isFullScreen()
const state = wndState;
if (isMinimized && state !== WND_STATE.MINIMIZED) {
wndState = WND_STATE.MINIMIZED
} else if (isFullScreen && state !== WND_STATE.FULL_SCREEN) {
wndState = WND_STATE.FULL_SCREEN
} else if (isMaximized && state !== WND_STATE.MAXIMIZED) {
wndState = WND_STATE.MAXIMIZED
win.webContents.executeJavaScript(`app.chrome.maximized = true`)
} else if (state !== WND_STATE.NORMAL) {
wndState = WND_STATE.NORMAL
win.webContents.executeJavaScript(`app.chrome.maximized = false`)
}
})
}
// Set window Handler
win.webContents.setWindowOpenHandler(({url}) => {
if (url.includes("apple") || url.includes("localhost")) {
return { action: "allow"}
}
shell.openExternal(url).catch(() => {})
return {
action: 'deny'
}
})
return win
},
EnvironmentVariables: {
"env": {
platform: os.platform()
}
},
async InitWebServer() {
const webRemotePort = await getPort({port : 9000});
const webapp = express();
const webRemotePath = path.join(__dirname, '../cider-ui/');
webapp.set("views", path.join(webRemotePath, "views"));
webapp.set("view engine", "ejs");
webapp.use(express.static(webRemotePath));
webapp.get('/', function (req, res) {
//res.sendFile(path.join(webRemotePath, 'index_old.html'));
res.render("main", CiderBase.EnvironmentVariables)
});
webapp.listen(webRemotePort, function () {
console.log(`Web Remote listening on port ${webRemotePort}`);
});
},
}
module.exports = CiderBase;

View file

@ -1,8 +0,0 @@
const electron = require('electron')
console.log('Loaded Preload')
process.once('loaded', () => {
console.log("Setting ipcRenderer")
global.ipcRenderer = electron.ipcRenderer;
});