Track sorting
This commit is contained in:
parent
69b65fb8ec
commit
dcfd0dc241
9
public/icon/clear-button.svg
Normal file
9
public/icon/clear-button.svg
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="Capa_1" x="0px" y="0px" width="512px" height="512px" viewBox="0 0 357 357" style="enable-background:new 0 0 357 357;" xml:space="preserve">
|
||||||
|
<g>
|
||||||
|
<g id="clear">
|
||||||
|
<polygon points="357,35.7 321.3,0 178.5,142.8 35.7,0 0,35.7 142.8,178.5 0,321.3 35.7,357 178.5,214.2 321.3,357 357,321.3 214.2,178.5 " fill="#FFFFFF"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 582 B |
9
public/icon/drop-down-arrow.svg
Normal file
9
public/icon/drop-down-arrow.svg
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="Capa_1" x="0px" y="0px" width="512px" height="512px" viewBox="0 0 255 255" style="enable-background:new 0 0 255 255;" xml:space="preserve">
|
||||||
|
<g>
|
||||||
|
<g id="arrow-drop-down">
|
||||||
|
<polygon points="0,63.75 127.5,191.25 255,63.75 " fill="#FFFFFF"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 503 B |
9
public/icon/drop-up-arrow.svg
Normal file
9
public/icon/drop-up-arrow.svg
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="Capa_1" x="0px" y="0px" width="512px" height="512px" viewBox="0 0 255 255" style="enable-background:new 0 0 255 255;" xml:space="preserve">
|
||||||
|
<g>
|
||||||
|
<g id="arrow-drop-up">
|
||||||
|
<polygon points="0,191.25 127.5,63.75 255,191.25 " fill="#FFFFFF"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 502 B |
304
public/index.css
304
public/index.css
@ -1,32 +1,32 @@
|
|||||||
* {
|
* {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
body {
|
body {
|
||||||
background-color: #0d171e;
|
background-color: #0d171e;
|
||||||
font-family: sans-serif;
|
font-family: sans-serif;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
}
|
}
|
||||||
.container {
|
.container {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
}
|
}
|
||||||
#search {
|
#search {
|
||||||
color: #fff;
|
color: #fff;
|
||||||
background-color: #152b3a;
|
background-color: #152b3a;
|
||||||
border: 0;
|
border: 0;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
font-size: 2.5em;
|
font-size: 2.5em;
|
||||||
border-left: 10px solid #112330;
|
border-left: 10px solid #112330;
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
.table-container {
|
.table-container {
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
}
|
}
|
||||||
.player {
|
.player {
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -34,65 +34,79 @@ body {
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
background-color: #152b3a;
|
background-color: #152b3a;
|
||||||
}
|
}
|
||||||
.player audio {
|
.player audio {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
.player #playing {
|
.player #playing {
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
}
|
}
|
||||||
table {
|
table {
|
||||||
table-layout: fixed;
|
table-layout: fixed;
|
||||||
border-spacing: 0;
|
border-spacing: 0;
|
||||||
border-collapse: collapse;
|
border-collapse: collapse;
|
||||||
}
|
}
|
||||||
th {
|
th {
|
||||||
text-align: left;
|
text-align: left;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
th .order {
|
||||||
|
width: 12px;
|
||||||
|
height: 12px;
|
||||||
|
display: inline-block;
|
||||||
|
background-image: url(icon/drop-up-arrow.svg);
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-size: 16px;
|
||||||
|
background-position: center;
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
th .order.dn {
|
||||||
|
background-image: url(icon/drop-down-arrow.svg);
|
||||||
}
|
}
|
||||||
th.small {
|
th.small {
|
||||||
width: 5%;
|
width: 5%;
|
||||||
}
|
}
|
||||||
td {
|
td {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
td,th {
|
td,th {
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
}
|
}
|
||||||
tr:nth-child(even) {
|
tr:nth-child(even) {
|
||||||
background-color: #0f1b23;
|
background-color: #0f1b23;
|
||||||
}
|
}
|
||||||
.pages {
|
.pages {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
min-height: max-content;
|
min-height: max-content;
|
||||||
}
|
}
|
||||||
.pages .paging {
|
.pages .paging {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-size: 3em;
|
font-size: 3em;
|
||||||
}
|
}
|
||||||
.paging.btn {
|
.paging.btn {
|
||||||
background-color: #112635;
|
background-color: #112635;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
.paging.btn.inner {
|
.paging.btn.inner {
|
||||||
background-color: #102331;
|
background-color: #102331;
|
||||||
}
|
}
|
||||||
.paging.bg {
|
.paging.bg {
|
||||||
background-color: #0e202c;
|
background-color: #0e202c;
|
||||||
}
|
}
|
||||||
.player-controls {
|
.player-controls {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
height: 40px;
|
height: 40px;
|
||||||
background-color: #0c2233;
|
background-color: #0c2233;
|
||||||
}
|
}
|
||||||
.player-controls .grow {
|
.player-controls .grow {
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
}
|
}
|
||||||
.player-controls span {
|
.player-controls span {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
.player-controls .icon {
|
.player-controls .icon {
|
||||||
width: 30px;
|
width: 30px;
|
||||||
@ -105,49 +119,49 @@ tr:nth-child(even) {
|
|||||||
padding: 0 5px;
|
padding: 0 5px;
|
||||||
}
|
}
|
||||||
.player-controls .timestamp {
|
.player-controls .timestamp {
|
||||||
margin-top: 0.9em;
|
margin-top: 0.9em;
|
||||||
font-size: 0.8em;
|
font-size: 0.8em;
|
||||||
padding: 0 5px;
|
padding: 0 5px;
|
||||||
min-width: 8em;
|
min-width: 8em;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
.play-btn {
|
.play-btn {
|
||||||
background-image: url('icon/play.svg');
|
background-image: url('icon/play.svg');
|
||||||
}
|
}
|
||||||
.pause-btn {
|
.pause-btn {
|
||||||
background-image: url('icon/pause.svg');
|
background-image: url('icon/pause.svg');
|
||||||
}
|
}
|
||||||
.mute-btn {
|
.mute-btn {
|
||||||
background-image: url('icon/volume.svg');
|
background-image: url('icon/volume.svg');
|
||||||
}
|
}
|
||||||
.mute1-btn {
|
.mute1-btn {
|
||||||
background-image: url('icon/volume-low.svg');
|
background-image: url('icon/volume-low.svg');
|
||||||
}
|
}
|
||||||
.muted-btn {
|
.muted-btn {
|
||||||
background-image: url('icon/volume-off.svg');
|
background-image: url('icon/volume-off.svg');
|
||||||
}
|
}
|
||||||
.next-btn {
|
.next-btn {
|
||||||
background-image: url('icon/play-next.svg');
|
background-image: url('icon/play-next.svg');
|
||||||
}
|
}
|
||||||
.prev-btn {
|
.prev-btn {
|
||||||
background-image: url('icon/play-prev.svg');
|
background-image: url('icon/play-prev.svg');
|
||||||
}
|
}
|
||||||
.volume {
|
.volume {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
}
|
}
|
||||||
.volume .volume-bar {
|
.volume .volume-bar {
|
||||||
width: 5em;
|
width: 5em;
|
||||||
}
|
}
|
||||||
.volume .volume-bar .seek-inner {
|
.volume .volume-bar .seek-inner {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
.seek-container {
|
.seek-container {
|
||||||
height: 8px;
|
height: 8px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin: 16px 5px 0 5px;
|
margin: 16px 5px 0 5px;
|
||||||
background-color: #00131b;
|
background-color: #00131b;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
.seek-inner {
|
.seek-inner {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
@ -155,27 +169,27 @@ tr:nth-child(even) {
|
|||||||
background-color: #00b7ff;
|
background-color: #00b7ff;
|
||||||
}
|
}
|
||||||
.ctx-menu {
|
.ctx-menu {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
background-color: #0c2233;
|
background-color: #0c2233;
|
||||||
border: 2px solid #031421;
|
border: 2px solid #031421;
|
||||||
}
|
}
|
||||||
.ctx-menu ul {
|
.ctx-menu ul {
|
||||||
list-style: none;
|
list-style: none;
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
.ctx-menu ul li {
|
.ctx-menu ul li {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
.ctx-item, .dropdown-content div {
|
.ctx-item, .dropdown-content div {
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
.ctx-item:nth-child(even), .dropdown-content div:nth-child(even) {
|
.ctx-item:nth-child(even), .dropdown-content div:nth-child(even) {
|
||||||
background-color: #0b1f2f;
|
background-color: #0b1f2f;
|
||||||
}
|
}
|
||||||
.ctx-item:hover, .dropdown-content div:hover {
|
.ctx-item:hover, .dropdown-content div:hover {
|
||||||
background-color: #0c273c;
|
background-color: #0c273c;
|
||||||
}
|
}
|
||||||
.inline-flex {
|
.inline-flex {
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -184,20 +198,24 @@ tr:nth-child(even) {
|
|||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
.inline-flex input {
|
.inline-flex input {
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
}
|
}
|
||||||
#search-clear {
|
#search-clear {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
.btn-clear {
|
.btn-clear {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: 10px;
|
right: 10px;
|
||||||
top: 12px;
|
top: 12px;
|
||||||
font-size: 2em;
|
bottom: 12px;
|
||||||
opacity: 0.5;
|
font-size: 2em;
|
||||||
padding: 0 10px;
|
opacity: 0.5;
|
||||||
|
padding: 0 10px;
|
||||||
|
background: url(icon/clear-button.svg) no-repeat;
|
||||||
|
background-size: 16px;
|
||||||
|
background-position: center;
|
||||||
}
|
}
|
||||||
.queue-tag {
|
.queue-tag {
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
@ -213,15 +231,15 @@ tr:nth-child(even) {
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
.dropdown-button::after {
|
.dropdown-button::after {
|
||||||
content: "";
|
content: "";
|
||||||
background: url(icon/down-arrow.svg) no-repeat;
|
background: url(icon/down-arrow.svg) no-repeat;
|
||||||
background-size: auto auto;
|
background-size: auto auto;
|
||||||
background-size: 16px;
|
background-size: 16px;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
width: 16px;
|
width: 16px;
|
||||||
height: 16px;
|
height: 16px;
|
||||||
right: 5px;
|
right: 5px;
|
||||||
top: 40%;
|
top: 40%;
|
||||||
}
|
}
|
||||||
.dropdown-content {
|
.dropdown-content {
|
||||||
display: none;
|
display: none;
|
||||||
@ -232,7 +250,7 @@ tr:nth-child(even) {
|
|||||||
z-index: 1;
|
z-index: 1;
|
||||||
}
|
}
|
||||||
.dropdown-content div {
|
.dropdown-content div {
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
}
|
}
|
||||||
.dropdown:hover .dropdown-content {
|
.dropdown:hover .dropdown-content {
|
||||||
display: block;
|
display: block;
|
||||||
@ -243,39 +261,95 @@ tr:nth-child(even) {
|
|||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
.playing-bar span {
|
.playing-bar span {
|
||||||
z-index: 10;
|
z-index: 10;
|
||||||
}
|
}
|
||||||
canvas#visualizer {
|
canvas#visualizer {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
display: block;
|
display: block;
|
||||||
opacity: 0.4;
|
opacity: 0.4;
|
||||||
z-index: 9;
|
z-index: 9;
|
||||||
|
}
|
||||||
|
.sidebar.active.background {
|
||||||
|
pointer-events: initial;
|
||||||
|
}
|
||||||
|
.sidebar.active .drop {
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
.sidebar.active .bar {
|
||||||
|
max-width: 340px;
|
||||||
|
}
|
||||||
|
.sidebar.background {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
.sidebar.sb-abs {
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
.sidebar.drop {
|
||||||
|
background-color: #060606;
|
||||||
|
z-index: 11;
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity 0.2s ease-out;
|
||||||
|
}
|
||||||
|
.sidebar.bar {
|
||||||
|
z-index: 12;
|
||||||
|
max-width: 0px;
|
||||||
|
background-color: rgba(17, 35, 48, 0.9);
|
||||||
|
overflow-x: hidden;
|
||||||
|
transition: max-width 0.2s linear;
|
||||||
|
}
|
||||||
|
.sidebar.bar h2 {
|
||||||
|
padding: 18px;
|
||||||
|
}
|
||||||
|
.sidebar.content {
|
||||||
|
width: 340px;
|
||||||
|
}
|
||||||
|
.sidebar .option {
|
||||||
|
padding: 10px;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
.sidebar .option.checkbox {
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
.sidebar .option label {
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
|
.sidebar .option.checkbox input {
|
||||||
|
margin: 4px 10px;
|
||||||
}
|
}
|
||||||
@media only screen and (max-width: 600px) {
|
@media only screen and (max-width: 600px) {
|
||||||
tr td:nth-child(1), th:nth-child(1) {
|
tr td:nth-child(1), th:nth-child(1) {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
tr td:nth-child(3), th:nth-child(3) {
|
tr td:nth-child(3), th:nth-child(3) {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
tr td:nth-child(4), th:nth-child(4) {
|
tr td:nth-child(4), th:nth-child(4) {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
tr td:nth-child(5), th:nth-child(5) {
|
tr td:nth-child(5), th:nth-child(5) {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
tr td:nth-child(6), th:nth-child(6) {
|
tr td:nth-child(6), th:nth-child(6) {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
.pages .paging {
|
.pages .paging {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-size: 1.3em;
|
font-size: 1.3em;
|
||||||
}
|
}
|
||||||
.allowance {
|
.allowance {
|
||||||
margin-bottom: 100px !important;
|
margin-bottom: 100px !important;
|
||||||
}
|
}
|
||||||
.volume .volume-bar {
|
.volume .volume-bar {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,10 +14,11 @@
|
|||||||
<div class="dropdown-content">
|
<div class="dropdown-content">
|
||||||
<div data-value="all">All Tracks</div>
|
<div data-value="all">All Tracks</div>
|
||||||
<div data-value="queue">Queue</div>
|
<div data-value="queue">Queue</div>
|
||||||
|
<div data-value="options">Options</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<input type="text" id="search" placeholder="Search" class="flex-row">
|
<input type="text" id="search" placeholder="Search" class="flex-row">
|
||||||
<span class="btn-clear" id="search-clear">x</span>
|
<span class="btn-clear" id="search-clear"></span>
|
||||||
</div>
|
</div>
|
||||||
<div class="table-container flex-row">
|
<div class="table-container flex-row">
|
||||||
<table width="100%">
|
<table width="100%">
|
||||||
@ -73,6 +74,39 @@
|
|||||||
<li><a class="ctx-item" data-action="download">Download</a></li>
|
<li><a class="ctx-item" data-action="download">Download</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="sidebar background" id="options-drop">
|
||||||
|
<div class="sidebar drop sb-abs"></div>
|
||||||
|
<div class="sidebar bar sb-abs">
|
||||||
|
<h2>Options</h2>
|
||||||
|
<div class="sidebar content" id="options">
|
||||||
|
<div class="option checkbox">
|
||||||
|
<label for="st-autoplay">Automatically play next track</label>
|
||||||
|
<input type="checkbox" id="st-autoplay" name="autoplay">
|
||||||
|
</div>
|
||||||
|
<div class="option checkbox">
|
||||||
|
<label for="st-trackids" title="Shows track number in album instead when unchecked">Show track IDs</label>
|
||||||
|
<input type="checkbox" id="st-trackids" name="trackids">
|
||||||
|
</div>
|
||||||
|
<div class="option">
|
||||||
|
<label for="st-sortby">Sort tracks by</label>
|
||||||
|
<select id="st-sortby" name="sortby">
|
||||||
|
<option value="id">Track ID / Number</option>
|
||||||
|
<option value="title">Title</option>
|
||||||
|
<option value="artist">Artist</option>
|
||||||
|
<option value="album">Album</option>
|
||||||
|
<option value="year">Year</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="option">
|
||||||
|
<label for="st-sortdir">Sort direction</label>
|
||||||
|
<select id="st-sortdir" name="sortdir">
|
||||||
|
<option value="asc">Ascending order</option>
|
||||||
|
<option value="desc">Descending order</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<script type="text/javascript" src="index.js"></script>
|
<script type="text/javascript" src="index.js"></script>
|
||||||
<script type="text/javascript" src="player.js"></script>
|
<script type="text/javascript" src="player.js"></script>
|
||||||
<script type="text/javascript" src="visuals.js"></script>
|
<script type="text/javascript" src="visuals.js"></script>
|
||||||
|
149
public/index.js
149
public/index.js
@ -4,15 +4,17 @@
|
|||||||
var clear = document.getElementById('search-clear')
|
var clear = document.getElementById('search-clear')
|
||||||
var audio = document.getElementById('player')
|
var audio = document.getElementById('player')
|
||||||
var playing = document.getElementById('playing')
|
var playing = document.getElementById('playing')
|
||||||
|
var optdrop = document.getElementById('options-drop')
|
||||||
|
var optmenu = document.getElementById('options')
|
||||||
|
|
||||||
var menu = document.getElementById('menu')
|
var menu = document.getElementById('menu')
|
||||||
|
|
||||||
var tableHead = '<tr> \
|
var tableHead = '<tr> \
|
||||||
<th class="small">#</th> \
|
<th data-sort-by="id" class="small">#</th> \
|
||||||
<th>Track</th> \
|
<th data-sort-by="title">Track</th> \
|
||||||
<th>Artist</th> \
|
<th data-sort-by="artist">Artist</th> \
|
||||||
<th>Album</th> \
|
<th data-sort-by="album">Album</th> \
|
||||||
<th class="small">Year</th> \
|
<th data-sort-by="year" class="small">Year</th> \
|
||||||
<th class="small">Duration</th> \
|
<th class="small">Duration</th> \
|
||||||
</tr>'
|
</tr>'
|
||||||
var nowPlaying = 0
|
var nowPlaying = 0
|
||||||
@ -35,6 +37,14 @@
|
|||||||
var playlist = null
|
var playlist = null
|
||||||
var pSel = document.getElementById('playlist-select')
|
var pSel = document.getElementById('playlist-select')
|
||||||
|
|
||||||
|
// Options
|
||||||
|
var options = {
|
||||||
|
autoplay: true,
|
||||||
|
trackids: true,
|
||||||
|
sortby: 'id',
|
||||||
|
sortdir: 'asc',
|
||||||
|
}
|
||||||
|
|
||||||
window.mobilecheck = function() {
|
window.mobilecheck = function() {
|
||||||
var check = false;
|
var check = false;
|
||||||
(function(a){if(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(a)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0,4))) check = true;})(navigator.userAgent||navigator.vendor||window.opera);
|
(function(a){if(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(a)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0,4))) check = true;})(navigator.userAgent||navigator.vendor||window.opera);
|
||||||
@ -81,6 +91,16 @@
|
|||||||
return time
|
return time
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function elementsToArray (elms) {
|
||||||
|
let array = []
|
||||||
|
for (let i in elms) {
|
||||||
|
let el = elms[i]
|
||||||
|
if (!(el instanceof Element)) continue
|
||||||
|
array.push(el)
|
||||||
|
}
|
||||||
|
return array
|
||||||
|
}
|
||||||
|
|
||||||
function httpGet (url, callback) {
|
function httpGet (url, callback) {
|
||||||
return new Promise(function (resolve, reject) {
|
return new Promise(function (resolve, reject) {
|
||||||
var xmlHttp = new XMLHttpRequest()
|
var xmlHttp = new XMLHttpRequest()
|
||||||
@ -237,7 +257,7 @@
|
|||||||
let trTag = document.createElement('tr')
|
let trTag = document.createElement('tr')
|
||||||
trTag.className = 'track'
|
trTag.className = 'track'
|
||||||
trTag.setAttribute('data-id', track.id)
|
trTag.setAttribute('data-id', track.id)
|
||||||
trTag.innerHTML += '<td>' + track.id + '</td>'
|
trTag.innerHTML += '<td>' + (options.trackids ? track.id : (track.track || ' ')) + '</td>'
|
||||||
trTag.innerHTML += '<td>' + title + '</td>'
|
trTag.innerHTML += '<td>' + title + '</td>'
|
||||||
trTag.innerHTML += '<td>' + (track.artist || '') + '</td>'
|
trTag.innerHTML += '<td>' + (track.artist || '') + '</td>'
|
||||||
trTag.innerHTML += '<td>' + (track.album || '') + '</td>'
|
trTag.innerHTML += '<td>' + (track.album || '') + '</td>'
|
||||||
@ -246,6 +266,32 @@
|
|||||||
return trTag
|
return trTag
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleHeads () {
|
||||||
|
if (playlist === 0) return
|
||||||
|
let els = elementsToArray(document.querySelectorAll('th'))
|
||||||
|
let sortarr = document.createElement('span')
|
||||||
|
sortarr.className = 'order' + (options.sortdir === 'desc' ? ' dn' : '')
|
||||||
|
for (let i in els) {
|
||||||
|
let head = els[i]
|
||||||
|
let sortattr = head.getAttribute('data-sort-by')
|
||||||
|
if (!sortattr || sortattr === '') continue
|
||||||
|
if (sortattr === options.sortby) {
|
||||||
|
head.appendChild(sortarr)
|
||||||
|
}
|
||||||
|
|
||||||
|
head.addEventListener('click', function (e) {
|
||||||
|
if (options.sortby !== sortattr) {
|
||||||
|
options.sortdir = 'asc'
|
||||||
|
options.sortby = sortattr
|
||||||
|
return showTracks(pageNum)
|
||||||
|
}
|
||||||
|
|
||||||
|
options.sortdir = (options.sortdir === 'asc' ? 'desc' : 'asc')
|
||||||
|
showTracks(pageNum)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function constructList (tracks) {
|
function constructList (tracks) {
|
||||||
table.innerHTML = tableHead
|
table.innerHTML = tableHead
|
||||||
|
|
||||||
@ -264,6 +310,8 @@
|
|||||||
|
|
||||||
table.appendChild(tag)
|
table.appendChild(tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handleHeads()
|
||||||
}
|
}
|
||||||
|
|
||||||
function recursionQueueList (index) {
|
function recursionQueueList (index) {
|
||||||
@ -320,7 +368,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (query.trim() === '') {
|
if (query.trim() === '') {
|
||||||
return httpGet('/api/tracks?page=' + page).then(function (data) {
|
return httpGet('/api/tracks?page=' + page + '&sort=' + options.sortby + '&sortdir=' + options.sortdir).then(function (data) {
|
||||||
pageNum = page
|
pageNum = page
|
||||||
pages = data.pageCount
|
pages = data.pageCount
|
||||||
constructList(data.tracks)
|
constructList(data.tracks)
|
||||||
@ -335,7 +383,7 @@
|
|||||||
clear.style.display = 'block'
|
clear.style.display = 'block'
|
||||||
}
|
}
|
||||||
|
|
||||||
httpGet('/api/tracks/search?q=' + query + '&page=' + page).then(function (data) {
|
httpGet('/api/tracks/search?q=' + query + '&page=' + page + '&sort=' + options.sortby + '&sortdir=' + options.sortdir).then(function (data) {
|
||||||
pageNum = page
|
pageNum = page
|
||||||
pages = data.pageCount
|
pages = data.pageCount
|
||||||
constructList(data.tracks)
|
constructList(data.tracks)
|
||||||
@ -372,17 +420,27 @@
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var ignoreFirst = false
|
||||||
|
function toggleOptions () {
|
||||||
|
if (optdrop.className.indexOf('active') !== -1) {
|
||||||
|
optdrop.className = 'sidebar background'
|
||||||
|
} else {
|
||||||
|
optdrop.className = 'sidebar background active'
|
||||||
|
ignoreFirst = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function handleSelect () {
|
function handleSelect () {
|
||||||
let btn = pSel.querySelector('.dropdown-button')
|
let btn = pSel.querySelector('.dropdown-button')
|
||||||
let btns = pSel.querySelectorAll('.dropdown-content div')
|
let btns = elementsToArray(pSel.querySelectorAll('.dropdown-content div'))
|
||||||
|
|
||||||
for (let i in btns) {
|
for (let i in btns) {
|
||||||
let btni = btns[i]
|
let btni = btns[i]
|
||||||
if (!(btni instanceof Element)) continue
|
|
||||||
let cnt = btni.getAttribute('data-value')
|
let cnt = btni.getAttribute('data-value')
|
||||||
|
|
||||||
btni.addEventListener('click', function (e) {
|
btni.addEventListener('click', function (e) {
|
||||||
btn.innerHTML = btni.innerHTML
|
let last = btn.innerHTML
|
||||||
|
let set = btni.innerHTML
|
||||||
switch (cnt) {
|
switch (cnt) {
|
||||||
case 'all':
|
case 'all':
|
||||||
playlist = null
|
playlist = null
|
||||||
@ -390,19 +448,72 @@
|
|||||||
case 'queue':
|
case 'queue':
|
||||||
playlist = 0
|
playlist = 0
|
||||||
break
|
break
|
||||||
|
case 'options':
|
||||||
|
toggleOptions()
|
||||||
|
set = last
|
||||||
|
break
|
||||||
default:
|
default:
|
||||||
showPlaylist(cnt)
|
showPlaylist(cnt)
|
||||||
}
|
}
|
||||||
|
btn.innerHTML = set
|
||||||
showTracks(pageNum)
|
showTracks(pageNum)
|
||||||
}, false)
|
}, false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function saveOptions () {
|
||||||
|
if (!window.localStorage) return
|
||||||
|
let itms = JSON.stringify(options)
|
||||||
|
window.localStorage.setItem('options', itms)
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadOptions () {
|
||||||
|
if (!window.localStorage) return
|
||||||
|
let itms = window.localStorage.getItem('options')
|
||||||
|
if (!itms || itms === '') return
|
||||||
|
let obj = {}
|
||||||
|
try {
|
||||||
|
obj = JSON.parse(itms)
|
||||||
|
} catch (e) {}
|
||||||
|
options = Object.assign({}, options, obj)
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleOptions () {
|
||||||
|
let elms = elementsToArray(optmenu.querySelectorAll('input'))
|
||||||
|
elms = elms.concat(elementsToArray(optmenu.querySelectorAll('select')))
|
||||||
|
for (let i in elms) {
|
||||||
|
let inpt = elms[i]
|
||||||
|
if (!(inpt instanceof Element)) continue
|
||||||
|
let opt = inpt.getAttribute('name')
|
||||||
|
let type = inpt.getAttribute('type')
|
||||||
|
|
||||||
|
if (type == 'checkbox') {
|
||||||
|
inpt.checked = options[opt]
|
||||||
|
inpt.addEventListener('change', function (event) {
|
||||||
|
options[opt] = event.target.checked
|
||||||
|
showTracks(pageNum)
|
||||||
|
saveOptions()
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
inpt.value = options[opt]
|
||||||
|
inpt.addEventListener('change', function (event) {
|
||||||
|
options[opt] = event.target.value
|
||||||
|
showTracks(pageNum)
|
||||||
|
saveOptions()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
input.addEventListener('keyup', function (e) {
|
input.addEventListener('keyup', function (e) {
|
||||||
e.which === 13 && showTracks(input.value.trim() === '' ? (pagePrev !== 0 ? pagePrev : 1) : 1)
|
e.which === 13 && showTracks(input.value.trim() === '' ? (pagePrev !== 0 ? pagePrev : 1) : 1)
|
||||||
}, false)
|
}, false)
|
||||||
|
|
||||||
audio.addEventListener('ended', playNext, false)
|
audio.addEventListener('ended', function (e) {
|
||||||
|
if (options.autoplay) {
|
||||||
|
playNext(e)
|
||||||
|
}
|
||||||
|
}, false)
|
||||||
|
|
||||||
clear.addEventListener('click', function () {
|
clear.addEventListener('click', function () {
|
||||||
input.value = ''
|
input.value = ''
|
||||||
@ -454,7 +565,21 @@
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
var optcont = document.querySelector('.sidebar.bar')
|
||||||
|
document.addEventListener('click', function (event) {
|
||||||
|
// event.target.closest(optcont) === null
|
||||||
|
if (!optcont.contains(event.target) && optdrop.className.indexOf('active') !== -1) {
|
||||||
|
if (ignoreFirst) {
|
||||||
|
ignoreFirst = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
toggleOptions()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
loadOptions()
|
||||||
showTracks(1)
|
showTracks(1)
|
||||||
handleHash(window.location.hash)
|
handleHash(window.location.hash)
|
||||||
handleSelect()
|
handleSelect()
|
||||||
|
handleOptions()
|
||||||
})()
|
})()
|
||||||
|
@ -17,12 +17,25 @@ const port = process.env.PORT || 3000
|
|||||||
|
|
||||||
const router = express.Router()
|
const router = express.Router()
|
||||||
|
|
||||||
|
const sortfields = ['id', 'track', 'artist', 'title', 'album', 'year']
|
||||||
|
const srchcategories = ['title', 'artist', 'album']
|
||||||
|
|
||||||
router.get('/tracks', async (req, res) => {
|
router.get('/tracks', async (req, res) => {
|
||||||
let page = parseInt(req.query.page) || 1
|
let page = parseInt(req.query.page) || 1
|
||||||
if (isNaN(page)) {
|
if (isNaN(page)) {
|
||||||
page = 1
|
page = 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let sort = req.query.sort
|
||||||
|
if (!sort || sortfields.indexOf(sort.toLowerCase()) === -1) {
|
||||||
|
sort = 'artist'
|
||||||
|
}
|
||||||
|
|
||||||
|
let sortdir = req.query.sortdir
|
||||||
|
if (!sortdir || (sortdir !== 'desc' && sortdir !== 'asc')) {
|
||||||
|
sortdir = 'asc'
|
||||||
|
}
|
||||||
|
|
||||||
let db = await dbPromise
|
let db = await dbPromise
|
||||||
let count = (await db.get('SELECT COUNT(*) FROM Track'))['COUNT(*)']
|
let count = (await db.get('SELECT COUNT(*) FROM Track'))['COUNT(*)']
|
||||||
|
|
||||||
@ -31,7 +44,7 @@ router.get('/tracks', async (req, res) => {
|
|||||||
if (page > pageCount) page = pageCount
|
if (page > pageCount) page = pageCount
|
||||||
|
|
||||||
let offset = (page - 1) * tracksPerPage
|
let offset = (page - 1) * tracksPerPage
|
||||||
let tracks = await db.all('SELECT * FROM Track LIMIT ? OFFSET ?', tracksPerPage, offset)
|
let tracks = await db.all(`SELECT * FROM Track ORDER BY ${sort} ${sortdir.toUpperCase()} LIMIT ? OFFSET ?`, tracksPerPage, offset)
|
||||||
|
|
||||||
for (let i in tracks) {
|
for (let i in tracks) {
|
||||||
delete tracks[i].file
|
delete tracks[i].file
|
||||||
@ -42,7 +55,6 @@ router.get('/tracks', async (req, res) => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
let srchcategories = ['title', 'artist', 'album']
|
|
||||||
router.get('/tracks/search', async (req, res) => {
|
router.get('/tracks/search', async (req, res) => {
|
||||||
let query = req.query.q
|
let query = req.query.q
|
||||||
let qr = ''
|
let qr = ''
|
||||||
@ -72,6 +84,16 @@ router.get('/tracks/search', async (req, res) => {
|
|||||||
|
|
||||||
if (!exact) query = `%${query}%`
|
if (!exact) query = `%${query}%`
|
||||||
|
|
||||||
|
let sort = req.query.sort
|
||||||
|
if (!sort || sortfields.indexOf(sort.toLowerCase()) === -1) {
|
||||||
|
sort = 'artist'
|
||||||
|
}
|
||||||
|
|
||||||
|
let sortdir = req.query.sortdir
|
||||||
|
if (!sortdir || (sortdir !== 'desc' && sortdir !== 'asc')) {
|
||||||
|
sortdir = 'asc'
|
||||||
|
}
|
||||||
|
|
||||||
// Paging
|
// Paging
|
||||||
let page = parseInt(req.query.page) || 1
|
let page = parseInt(req.query.page) || 1
|
||||||
if (isNaN(page)) {
|
if (isNaN(page)) {
|
||||||
@ -85,7 +107,8 @@ router.get('/tracks/search', async (req, res) => {
|
|||||||
if (page > pageCount) page = pageCount
|
if (page > pageCount) page = pageCount
|
||||||
|
|
||||||
let offset = (page - 1) * tracksPerPage
|
let offset = (page - 1) * tracksPerPage
|
||||||
let tracks = await db.all(`SELECT * FROM Track WHERE ${qr} LIKE ? LIMIT ? OFFSET ?`, query, tracksPerPage, offset)
|
let tracks = await db.all(`SELECT * FROM Track WHERE ${qr} LIKE ? ORDER BY ${sort} ${sortdir.toUpperCase()} LIMIT ? OFFSET ?`,
|
||||||
|
query, tracksPerPage, offset)
|
||||||
|
|
||||||
for (let i in tracks) {
|
for (let i in tracks) {
|
||||||
delete tracks[i].file
|
delete tracks[i].file
|
||||||
|
Loading…
Reference in New Issue
Block a user