mirror of
https://github.com/IrosTheBeggar/mStream.git
synced 2025-10-27 07:31:02 +00:00
1621 lines
61 KiB
JavaScript
1621 lines
61 KiB
JavaScript
// Dropzone
|
|
const myDropzone = new Dropzone(document.body, {
|
|
previewsContainer: false,
|
|
clickable: false,
|
|
url: '/api/v1/file-explorer/upload',
|
|
maxFilesize: null
|
|
});
|
|
|
|
myDropzone.on("addedfile", (file) => {
|
|
if (programState[0].state !== 'fileExplorer') {
|
|
iziToast.error({
|
|
title: 'Files can only be added to the file explorer',
|
|
position: 'topCenter',
|
|
timeout: 3500
|
|
});
|
|
myDropzone.removeFile(file);
|
|
} else if (fileExplorerArray.length < 1) {
|
|
iziToast.error({
|
|
title: 'Cannot Upload File Here',
|
|
position: 'topCenter',
|
|
timeout: 3500
|
|
});
|
|
myDropzone.removeFile(file);
|
|
} else {
|
|
if (file.fullPath) {
|
|
file.directory = getFileExplorerPath() + file.fullPath.substring(0, file.fullPath.indexOf(file.name));
|
|
} else {
|
|
file.directory = getFileExplorerPath();
|
|
}
|
|
}
|
|
});
|
|
|
|
myDropzone.on('sending', (file, xhr, formData) => {
|
|
xhr.setRequestHeader('data-location', encodeURI(file.directory))
|
|
xhr.setRequestHeader('x-access-token', MSTREAMAPI.currentServer.token)
|
|
});
|
|
|
|
myDropzone.on('totaluploadprogress', (percent, uploaded, size) => {
|
|
document.getElementById('upload-progress-inner').style.width = percent + '%';
|
|
if (percent === 100) {
|
|
document.getElementById('upload-progress-inner').style.width = '0%';
|
|
}
|
|
});
|
|
|
|
myDropzone.on('queuecomplete', (file, xhr, formData) => {
|
|
var successCount = 0;
|
|
for (var i = 0; i < myDropzone.files.length; i++) {
|
|
if (myDropzone.files[i].status === 'success') {
|
|
successCount += 1;
|
|
}
|
|
}
|
|
|
|
if (successCount === myDropzone.files.length) {
|
|
iziToast.success({
|
|
title: 'Files Uploaded',
|
|
position: 'topCenter',
|
|
timeout: 3500
|
|
});
|
|
if (programState[0].state === 'fileExplorer') {
|
|
senddir();
|
|
}
|
|
} else if (successCount === 0) {
|
|
// do nothing
|
|
} else {
|
|
iziToast.warning({
|
|
title: successCount + ' out of ' + myDropzone.files.length + ' were uploaded successfully',
|
|
position: 'topCenter',
|
|
timeout: 3500
|
|
});
|
|
|
|
if (programState[0].state === 'fileExplorer') {
|
|
senddir();
|
|
}
|
|
}
|
|
|
|
myDropzone.removeAllFiles()
|
|
});
|
|
|
|
myDropzone.on('error', (err, msg, xhr) => {
|
|
var iziStuff = {
|
|
title: 'Upload Failed',
|
|
position: 'topCenter',
|
|
timeout: 3500
|
|
};
|
|
|
|
if (msg.error) {
|
|
iziStuff.message = msg.error;
|
|
}
|
|
|
|
iziToast.error(iziStuff);
|
|
});
|
|
|
|
|
|
////////////////////////////// Global Variables
|
|
// These vars track your position within the file explorer
|
|
var fileExplorerArray = [];
|
|
// Stores an array of searchable objects
|
|
var currentBrowsingList = [];
|
|
// This variable tracks the state of the explorer column
|
|
var programState = [];
|
|
|
|
let curFileTracker;
|
|
|
|
const entityMap = {
|
|
'&': '&',
|
|
'<': '<',
|
|
'>': '>',
|
|
'"': '"',
|
|
"'": ''',
|
|
'/': '/',
|
|
'`': '`',
|
|
'=': '='
|
|
};
|
|
|
|
function escapeHtml (string) {
|
|
return String(string).replace(/[&<>"'`=\/]/g, (s) => {
|
|
return entityMap[s];
|
|
});
|
|
}
|
|
|
|
function renderAlbum(id, artist, name, albumArtFile, year) {
|
|
return `<li class="collection-item">
|
|
<div ${year ? `data-year="${year}"` : '' } ${artist ? `data-artist="${artist}"` : '' } ${id ? `data-album="${id}"` : '' } class="albumz flex2" onclick="getAlbumsOnClick(this);">
|
|
${albumArtFile ?
|
|
`<img class="album-art-box" loading="lazy" src="${MSTREAMAPI.currentServer.host}album-art/${albumArtFile}?token=${MSTREAMAPI.currentServer.token}">`:
|
|
'<svg xmlns="http://www.w3.org/2000/svg" class="album-art-box" viewBox="0 0 512 512" xml:space="preserve"><path d="M437 75C390.7 28.6 326.7 0 256 0 114.6 0 0 114.6 0 256c0 70.7 28.6 134.7 75 181s110.3 75 181 75c141.4 0 256-114.6 256-256 0-70.7-28.6-134.7-75-181zM256 477.9c-122.3 0-221.9-99.5-221.9-221.9S133.7 34.1 256 34.1 477.9 133.7 477.9 256 378.3 477.9 256 477.9z"/><path d="M256 145.1c-61.3 0-110.9 49.7-110.9 110.9S194.7 366.9 256 366.9 366.9 317.3 366.9 256c0-61.2-49.7-110.9-110.9-110.9zm0 187.7c-42.4 0-76.8-34.4-76.8-76.8s34.4-76.8 76.8-76.8 76.8 34.4 76.8 76.8-34.4 76.8-76.8 76.8z"/><path d="M238.9 238.9H273V273h-34.1zM256 102.4V68.3h-.6c-31 0-60.1 7.6-85.8 21l1-.5c-26 13.5-47.7 31.9-64.5 54.2l-.3.5 27.3 20.5c28.1-37.5 72.4-61.5 122.3-61.5l.6-.1z"/></svg>'}
|
|
<span><b>${name}</b> ${year ? `<br>[${year}]` : ''}</span>
|
|
</div>
|
|
</li>`;
|
|
}
|
|
|
|
function renderArtist(artist) {
|
|
return `<li class="collection-item">
|
|
<div data-artist="${artist}" class="artistz" onclick="getArtistz(this)">${artist}</div>
|
|
</li>`;
|
|
}
|
|
|
|
function renderFileWithMetadataHtml(filepath, lokiId, metadata) {
|
|
return `<li data-lokiid="${lokiId}" class="collection-item">
|
|
<div data-file_location="${filepath}" class="filez flex" onclick="onFileClick(this);">
|
|
<img class="album-art-box" loading="lazy" ${metadata['album-art'] ? `src="${MSTREAMAPI.currentServer.host}album-art/${metadata['album-art']}?token=${MSTREAMAPI.currentServer.token}"` : 'src="assets/img/default.png"'}>
|
|
<div>
|
|
<b><span>${(!metadata || !metadata.title) ? filepath.split("/").pop() : `${metadata.title}`}</span></b>
|
|
${metadata.artist ? `</b><br><span style="font-size:15px;">${metadata.artist}</span>` : ''}
|
|
</div>
|
|
</div>
|
|
<div class="song-button-box">
|
|
<span title="Play Now" onclick="playNow(this);" data-file_location="${filepath}" class="songDropdown">
|
|
<svg xmlns="http://www.w3.org/2000/svg" height="14" width="14" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M15.5 5H11l5 7-5 7h4.5l5-7z"/><path d="M8.5 5H4l5 7-5 7h4.5l5-7z"/></svg>
|
|
</span>
|
|
<span data-lokiid="${lokiId}" class="removePlaylistSong" onclick="removePlaylistSong(this);">remove</span>
|
|
</div>
|
|
</li>`;
|
|
}
|
|
|
|
function createMusicFileHtml(fileLocation, title, aa, rating, subtitle) {
|
|
return `<li class="collection-item">
|
|
<div data-file_location="${fileLocation}" class="filez ${aa ? 'flex2' : ''}" onclick="onFileClick(this);">
|
|
${aa ? `<img loading="lazy" class="album-art-box" ${aa}>` : '<svg class="music-image" height="18" width="18" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40"><path d="M9 37.5c-3.584 0-6.5-2.916-6.5-6.5s2.916-6.5 6.5-6.5a6.43 6.43 0 012.785.634l.715.34V5.429l25-3.846V29c0 3.584-2.916 6.5-6.5 6.5s-6.5-2.916-6.5-6.5 2.916-6.5 6.5-6.5a6.43 6.43 0 012.785.634l.715.34V11.023l-19 2.931V31c0 3.584-2.916 6.5-6.5 6.5z" fill="#8bb7f0"/><path d="M37 2.166V29c0 3.308-2.692 6-6 6s-6-2.692-6-6 2.692-6 6-6a5.93 5.93 0 012.57.586l1.43.68V10.441l-1.152.178-18 2.776-.848.13V31c0 3.308-2.692 6-6 6s-6-2.692-6-6 2.692-6 6-6a5.93 5.93 0 012.57.586l1.43.68V5.858l24-3.692M38 1L12 5v19.683A6.962 6.962 0 009 24a7 7 0 107 7V14.383l18-2.776v11.076A6.962 6.962 0 0031 22a7 7 0 107 7V1z" fill="#4e7ab5"/></svg>'}
|
|
<span>
|
|
${subtitle ? `<b>` : ''}
|
|
<span class="${aa ? '' : 'item-text'}">${rating ? `[${rating}] ` : ''}${title}</span>
|
|
${subtitle ? `</b><br><span>${subtitle}</span>` : ''}
|
|
</span>
|
|
</div>
|
|
<div class="song-button-box">
|
|
<span title="Play Now" onclick="playNow(this);" data-file_location="${fileLocation}" class="songDropdown">
|
|
<svg xmlns="http://www.w3.org/2000/svg" height="14" width="14" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M15.5 5H11l5 7-5 7h4.5l5-7z"/><path d="M8.5 5H4l5 7-5 7h4.5l5-7z"/></svg>
|
|
</span>
|
|
<span title="Add To Playlist" onclick="createPopper3(this);" data-file_location="${fileLocation}" class="fileAddToPlaylist">
|
|
<svg class="pop-f" xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 292.362 292.362"><path class="pop-f" d="M286.935 69.377c-3.614-3.617-7.898-5.424-12.848-5.424H18.274c-4.952 0-9.233 1.807-12.85 5.424C1.807 72.998 0 77.279 0 82.228c0 4.948 1.807 9.229 5.424 12.847l127.907 127.907c3.621 3.617 7.902 5.428 12.85 5.428s9.233-1.811 12.847-5.428L286.935 95.074c3.613-3.617 5.427-7.898 5.427-12.847 0-4.948-1.814-9.229-5.427-12.85z"/></svg>
|
|
</span>
|
|
</div>
|
|
</li>`;
|
|
}
|
|
|
|
function renderDirHtml(name) {
|
|
return `<li class="collection-item">
|
|
<div data-directory="${name}" class="dirz" onclick="handleDirClick(this);">
|
|
<svg class="folder-image" viewBox="0 0 48 48" version="1.0" xmlns="http://www.w3.org/2000/svg"><path fill="#FFA000" d="M38 12H22l-4-4H8c-2.2 0-4 1.8-4 4v24c0 2.2 1.8 4 4 4h31c1.7 0 3-1.3 3-3V16c0-2.2-1.8-4-4-4z"/><path fill="#FFCA28" d="M42.2 18H15.3c-1.9 0-3.6 1.4-3.9 3.3L8 40h31.7c1.9 0 3.6-1.4 3.9-3.3l2.5-14c.5-2.4-1.4-4.7-3.9-4.7z"/></svg>
|
|
<span class="item-text">${name}</span>
|
|
</div>
|
|
<div class="song-button-box">
|
|
<span style="padding-top:1px;" title="Add All To Queue" class="songDropdown" onclick="recursiveAddDir(this);" data-directory="${name}">
|
|
<svg xmlns="http://www.w3.org/2000/svg" height="10" width="10" viewBox="0 0 1280 1276"><path d="M6760 12747 c-80 -5 -440 -10 -800 -11 -701 -2 -734 -4 -943 -57 -330 -84 -569 -281 -681 -563 -103 -256 -131 -705 -92 -1466 12 -241 16 -531 16 -1232 l0 -917 -1587 -4 c-1561 -3 -1590 -3 -1703 -24 -342 -62 -530 -149 -692 -322 -158 -167 -235 -377 -244 -666 -43 -1404 -42 -1813 7 -2355 21 -235 91 -400 233 -548 275 -287 730 -389 1591 -353 1225 51 2103 53 2330 7 l60 -12 6 -1489 c6 -1559 6 -1548 49 -1780 100 -535 405 -835 933 -921 88 -14 252 -17 1162 -24 591 -4 1099 -4 1148 1 159 16 312 56 422 112 118 59 259 181 333 290 118 170 195 415 227 722 18 173 21 593 6 860 -26 444 -32 678 -34 1432 l-2 811 54 7 c30 4 781 6 1670 5 1448 -2 1625 -1 1703 14 151 28 294 87 403 168 214 159 335 367 385 666 15 85 29 393 30 627 0 105 4 242 10 305 43 533 49 1047 15 1338 -44 386 -144 644 -325 835 -131 140 -278 220 -493 270 -92 21 -98 21 -1772 24 l-1680 3 3 1608 c2 1148 0 1635 -8 1706 -49 424 -255 701 -625 841 -243 91 -633 124 -1115 92z" transform="matrix(.1 0 0 -.1 0 1276)"/></svg>
|
|
</span>
|
|
<span data-directory="${name}" title="Download Directory" class="downloadDir" onclick="recursiveFileDownload(this);">
|
|
<svg width="13" height="13" viewBox="0 0 2048 2048" xmlns="http://www.w3.org/2000/svg"><path d="M1803 960q0 53-37 90l-651 652q-39 37-91 37-53 0-90-37l-651-652q-38-36-38-90 0-53 38-91l74-75q39-37 91-37 53 0 90 37l294 294v-704q0-52 38-90t90-38h128q52 0 90 38t38 90v704l294-294q37-37 90-37 52 0 91 37l75 75q37 39 37 91z"/></svg>
|
|
</span>
|
|
</div>
|
|
</li>`
|
|
}
|
|
|
|
function createFileplaylistHtml(dataDirectory) {
|
|
return `<li class="collection-item pointer">
|
|
<div data-directory="${dataDirectory}" class="fileplaylistz" onclick="onFilePlaylistClick(this);">
|
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" width="25" height="25"><path d="M14.5 8a2.495 2.495 0 0 0-2.5 2.5v45c0 1.385 1.115 2.5 2.5 2.5h35c1.385 0 2.5-1.115 2.5-2.5V23l-13.75-1.25L37 8Z" opacity=".2"/><path fill="#1e98d1" d="M14.5 7A2.495 2.495 0 0 0 12 9.5v45c0 1.385 1.115 2.5 2.5 2.5h35c1.385 0 2.5-1.115 2.5-2.5V22l-13.75-1.25L37 7z"/><path d="M37 8v12.5a2.5 2.5 0 0 0 2.5 2.5H52Z" opacity=".2"/><path fill="#67bbe9" d="M37 7v12.5a2.5 2.5 0 0 0 2.5 2.5H52L37 7z"/><path d="M14.5 7A2.495 2.495 0 0 0 12 9.5v1C12 9.115 13.115 8 14.5 8H37V7z" opacity=".2" fill="#fff"/><path d="M24.199 28A2.149 2.085 0 0 0 22 30.086v19.831a2.149 2.085 0 0 0 3.223 1.805l17.704-9.916a2.149 2.085 0 0 0 0-3.61L25.223 28.28a2.149 2.085 0 0 0-1.024-.28z" opacity=".2"/><path d="M24.199 27A2.149 2.085 0 0 0 22 29.086v19.831a2.149 2.085 0 0 0 3.223 1.805l17.704-9.916a2.149 2.085 0 0 0 0-3.61L25.223 27.28a2.149 2.085 0 0 0-1.024-.28z" fill="#fff"/></svg>
|
|
<span class="item-text">${dataDirectory}</span>
|
|
</div>
|
|
<div class="song-button-box">
|
|
<span title="Add All To Queue" class="addFileplaylist" onclick="addFilePlaylist(this);" data-directory="${dataDirectory}">
|
|
<svg xmlns="http://www.w3.org/2000/svg" height="9" width="9" viewBox="0 0 1280 1276"><path d="M6760 12747 c-80 -5 -440 -10 -800 -11 -701 -2 -734 -4 -943 -57 -330 -84 -569 -281 -681 -563 -103 -256 -131 -705 -92 -1466 12 -241 16 -531 16 -1232 l0 -917 -1587 -4 c-1561 -3 -1590 -3 -1703 -24 -342 -62 -530 -149 -692 -322 -158 -167 -235 -377 -244 -666 -43 -1404 -42 -1813 7 -2355 21 -235 91 -400 233 -548 275 -287 730 -389 1591 -353 1225 51 2103 53 2330 7 l60 -12 6 -1489 c6 -1559 6 -1548 49 -1780 100 -535 405 -835 933 -921 88 -14 252 -17 1162 -24 591 -4 1099 -4 1148 1 159 16 312 56 422 112 118 59 259 181 333 290 118 170 195 415 227 722 18 173 21 593 6 860 -26 444 -32 678 -34 1432 l-2 811 54 7 c30 4 781 6 1670 5 1448 -2 1625 -1 1703 14 151 28 294 87 403 168 214 159 335 367 385 666 15 85 29 393 30 627 0 105 4 242 10 305 43 533 49 1047 15 1338 -44 386 -144 644 -325 835 -131 140 -278 220 -493 270 -92 21 -98 21 -1772 24 l-1680 3 3 1608 c2 1148 0 1635 -8 1706 -49 424 -255 701 -625 841 -243 91 -633 124 -1115 92z" transform="matrix(.1 0 0 -.1 0 1276)"/></svg>
|
|
</span>
|
|
<span data-directory="${dataDirectory}" title="Download Playlist" class="downloadFileplaylist" onclick="downloadFileplaylist(this);">
|
|
<svg width="12" height="12" viewBox="0 0 2048 2048" xmlns="http://www.w3.org/2000/svg"><path d="M1803 960q0 53-37 90l-651 652q-39 37-91 37-53 0-90-37l-651-652q-38-36-38-90 0-53 38-91l74-75q39-37 91-37 53 0 90 37l294 294v-704q0-52 38-90t90-38h128q52 0 90 38t38 90v704l294-294q37-37 90-37 52 0 91 37l75 75q37 39 37 91z"/></svg>
|
|
</span>
|
|
</div>
|
|
</li>`;
|
|
}
|
|
|
|
function renderPlaylist(playlistName) {
|
|
return `<li class="collection-item" data-playlistname="${encodeURIComponent(playlistName)}" class="playlist_row_container">
|
|
<span data-playlistname="${encodeURIComponent(playlistName)}" class="playlistz" onclick="onPlaylistClick(this);">${escapeHtml(playlistName)}</span>
|
|
<div class="song-button-box">
|
|
<span data-playlistname="${encodeURIComponent(playlistName)}" class="deletePlaylist" onclick="deletePlaylist(this);">Delete</span>
|
|
</div>
|
|
</li>`;
|
|
}
|
|
|
|
function getLoadingSvg() {
|
|
return '<svg class="spinner" width="65px" height="65px" viewBox="0 0 66 66" xmlns="http://www.w3.org/2000/svg"><circle class="spinner-path" fill="none" stroke-width="6" stroke-linecap="round" cx="33" cy="33" r="30"></circle></svg>';
|
|
}
|
|
|
|
function setBrowserRootPanel(panelName, showBar) {
|
|
if(showBar === false) {
|
|
document.getElementById('directory_bar').style.display = 'none';
|
|
}else {
|
|
document.getElementById('directory_bar').style.display = '';
|
|
}
|
|
|
|
document.getElementById('localSearchBar').value = "";
|
|
document.getElementById('directoryName').innerHTML = '';
|
|
document.getElementById('local_search_btn').style.display = '';
|
|
|
|
([...document.getElementsByClassName('panel_one_name')]).forEach(el => {
|
|
el.innerHTML = panelName;
|
|
});
|
|
|
|
currentBrowsingList = [];
|
|
}
|
|
|
|
///////////////// File Explorer
|
|
function loadFileExplorer() {
|
|
setBrowserRootPanel('File Explorer');
|
|
programState = [{ state: 'fileExplorer' }];
|
|
|
|
// Reset file explorer vars
|
|
fileExplorerArray = [];
|
|
//send this directory to be parsed and displayed
|
|
senddir(true);
|
|
}
|
|
|
|
async function senddir(root) {
|
|
// Construct the directory string
|
|
const directoryString = root === true ? '~' : getFileExplorerPath();
|
|
document.getElementById('filelist').innerHTML = getLoadingSvg();
|
|
|
|
try {
|
|
const response = await MSTREAMAPI.dirparser(directoryString);
|
|
document.getElementById('directoryName').innerHTML = response.path;
|
|
|
|
if(root === true && response.path.length > 1) {
|
|
fileExplorerArray.push(response.path.replaceAll('/', ''));
|
|
programState.push({
|
|
state: 'fileExplorer',
|
|
previousScroll: 0,
|
|
previousSearch: ''
|
|
});
|
|
}
|
|
printdir(response);
|
|
} catch(err) {
|
|
boilerplateFailure(err);
|
|
}
|
|
}
|
|
|
|
// function that will receive JSON array of a directory listing. It will then make a list of the directory and tack on classes for functionality
|
|
function printdir(response) {
|
|
currentBrowsingList = [];
|
|
let filelist = '<ul class="collection">';
|
|
|
|
// Some APIs only return a list of files
|
|
if (response.directories) {
|
|
for (const dir of response.directories) {
|
|
currentBrowsingList.push({ type: 'directory', name: dir.name })
|
|
filelist += renderDirHtml(dir.name);
|
|
}
|
|
}
|
|
|
|
for (const file of response.files) {
|
|
currentBrowsingList.push({ type: file.type, name: file.name })
|
|
if (file.type === 'm3u') {
|
|
filelist += createFileplaylistHtml(file.name);
|
|
} else {
|
|
const title = file.artist != null || file.title != null ? file.artist + ' - ' + file.title : file.name;
|
|
filelist += createMusicFileHtml(file.path || response.path + file.name, title);
|
|
}
|
|
}
|
|
|
|
filelist += '</ul>';
|
|
|
|
// clear the list
|
|
document.getElementById('localSearchBar').value = '';
|
|
|
|
// Post the html to the filelist div
|
|
document.getElementById('filelist').innerHTML = filelist;
|
|
}
|
|
|
|
function getFileExplorerPath() {
|
|
return fileExplorerArray.join("/") + "/";
|
|
}
|
|
|
|
function getDirectoryString2(component) {
|
|
var newString = getFileExplorerPath() + component.getAttribute("data-directory");
|
|
if (newString.substring(0,1) !== '/') {
|
|
newString = "/" + newString
|
|
}
|
|
|
|
return newString;
|
|
}
|
|
|
|
if (typeof(Storage) !== "undefined" && localStorage.getItem("token")) {
|
|
MSTREAMAPI.currentServer.token = localStorage.getItem("token");
|
|
}
|
|
|
|
function handleDirClick(el){
|
|
fileExplorerArray.push(el.getAttribute('data-directory'));
|
|
programState.push({
|
|
state: 'fileExplorer',
|
|
previousScroll: document.getElementById('filelist').scrollTop,
|
|
previousSearch: document.getElementById('localSearchBar').value
|
|
});
|
|
senddir();
|
|
}
|
|
|
|
function boilerplateFailure(err) {
|
|
console.log(err);
|
|
let msg = 'Call Failed';
|
|
// TODO: Check this
|
|
if (err.responseJSON && err.responseJSON.error) {
|
|
msg = err.responseJSON.error;
|
|
}
|
|
|
|
iziToast.error({
|
|
title: msg,
|
|
position: 'topCenter',
|
|
timeout: 3500
|
|
});
|
|
}
|
|
|
|
function onFileClick(el) {
|
|
VUEPLAYERCORE.addSongWizard(el.getAttribute("data-file_location"), {}, true);
|
|
}
|
|
|
|
async function recursiveAddDir(el) {
|
|
try {
|
|
const directoryString = getDirectoryString2(el);
|
|
const res = await MSTREAMAPI.recursiveScan(directoryString);
|
|
addAllSongs(res);
|
|
} catch(err) {
|
|
boilerplateFailure(err);
|
|
}
|
|
}
|
|
|
|
async function onFilePlaylistClick(el) {
|
|
try {
|
|
fileExplorerArray.push(el.getAttribute("data-directory"));
|
|
programState.push({
|
|
state: 'fileExplorer',
|
|
previousScroll: document.getElementById('filelist').scrollTop,
|
|
previousSearch: document.getElementById('search_folders').value
|
|
});
|
|
const directoryString = getFileExplorerPath();
|
|
|
|
document.getElementById('directoryName').innerHTML = '/' + directoryString.substring(0, directoryString.length - 1);
|
|
document.getElementById('filelist').innerHTML = getLoadingSvg();
|
|
|
|
const response = await MSTREAMAPI.loadFileplaylist(directoryString);
|
|
printdir(response);
|
|
}catch(err) {
|
|
boilerplateFailure(err);
|
|
|
|
}
|
|
}
|
|
|
|
async function addFilePlaylist(el) {
|
|
try {
|
|
const res = await MSTREAMAPI.loadFileplaylist(getDirectoryString2(el));
|
|
|
|
const translatedList = [];
|
|
res.files.forEach(f => {
|
|
translatedList.push(f.path)
|
|
})
|
|
|
|
addAllSongs(translatedList);
|
|
}catch(err) {
|
|
boilerplateFailure(err);
|
|
}
|
|
}
|
|
|
|
function addAll() {
|
|
([...document.getElementsByClassName('filez')]).forEach(el => {
|
|
VUEPLAYERCORE.addSongWizard(el.getAttribute("data-file_location"), {}, true);
|
|
});
|
|
}
|
|
|
|
function addAllSongs(res) {
|
|
for (var i = 0; i < res.length; i++) {
|
|
VUEPLAYERCORE.addSongWizard(res[i], {}, true);
|
|
}
|
|
}
|
|
|
|
function playNow(el) {
|
|
VUEPLAYERCORE.addSongWizard(el.getAttribute("data-file_location"), {}, true, MSTREAMPLAYER.positionCache.val + 1);
|
|
}
|
|
|
|
async function init() {
|
|
try {
|
|
const response = await MSTREAMAPI.ping();
|
|
MSTREAMAPI.currentServer.vpaths = response.vpaths;
|
|
VUEPLAYERCORE.playlists.length = 0;
|
|
document.getElementById('pop-f').innerHTML = '<div class="pop-f pop-playlist">Add To Playlist:</div>';
|
|
|
|
response.playlists.forEach(p => {
|
|
VUEPLAYERCORE.playlists.push(p);
|
|
document.getElementById('pop-f').innerHTML += `<div class="pop-list-item" onclick="addToPlaylistUI('${p.name}')">• ${p.name}</div>`;
|
|
});
|
|
|
|
if (response.transcode) {
|
|
MSTREAMPLAYER.transcodeOptions.serverEnabled = true;
|
|
MSTREAMPLAYER.transcodeOptions.defaultCodec = response.transcode.defaultCodec;
|
|
MSTREAMPLAYER.transcodeOptions.defaultBitrate = response.transcode.defaultBitrate;
|
|
MSTREAMPLAYER.transcodeOptions.defaultAlgo = response.transcode.defaultAlgorithm;
|
|
}
|
|
}catch (err) {
|
|
// window.location.href = 'login';
|
|
}
|
|
|
|
// load user settings
|
|
try {
|
|
const ivp = JSON.parse(localStorage.getItem('ignoreVPaths'));
|
|
if (Array.isArray(ivp) || !(ivp instanceof Object)) { throw 'bad!'; }
|
|
MSTREAMPLAYER.ignoreVPaths = ivp;
|
|
} catch (e) {}
|
|
|
|
try {
|
|
// forced to an array to assure we're not stuffing nul values in here
|
|
MSTREAMPLAYER.minRating = JSON.parse(localStorage.getItem('minRating'))[0];
|
|
} catch (e) {}
|
|
|
|
try {
|
|
if(localStorage.getItem('transcode') === 'true' && MSTREAMPLAYER.transcodeOptions.serverEnabled === true) {
|
|
toggleTranscoding(undefined, true);
|
|
}
|
|
MSTREAMPLAYER.transcodeOptions.selectedCodec = localStorage.getItem('trans-codec-select');
|
|
MSTREAMPLAYER.transcodeOptions.selectedBitrate = localStorage.getItem('trans-bitrate-select');
|
|
MSTREAMPLAYER.transcodeOptions.selectedAlgo = localStorage.getItem('trans-algo-select');
|
|
} catch (e) {}
|
|
|
|
// try {
|
|
// const response = await MSTREAMAPI.dbStatus();
|
|
// // if not scanning
|
|
// if (!response.locked || response.locked === false) {
|
|
// clearInterval(startInterval);
|
|
// startInterval = false;
|
|
// document.getElementById('scan-status').innerHTML = '';
|
|
// document.getElementById('scan-status-files').innerHTML = '';
|
|
|
|
// return;
|
|
// }
|
|
|
|
// // Set Interval
|
|
// if (startInterval === false) {
|
|
// startInterval = setInterval(function () {
|
|
// callOnStart();
|
|
// }, 2000);
|
|
// }
|
|
|
|
// // Update status
|
|
// document.getElementById('scan-status').innerHTML = 'Scan In Progress';
|
|
// document.getElementById('scan-status-files').innerHTML = response.totalFileCount + ' files in DB';
|
|
// }catch(err) {
|
|
// document.getElementById('scan-status').innerHTML = '';
|
|
// document.getElementById('scan-status-files').innerHTML = '';
|
|
// clearInterval(startInterval);
|
|
// startInterval = false;
|
|
// }
|
|
}
|
|
|
|
function createPopper3(el) {
|
|
if (curFileTracker === el.getAttribute("data-file_location")) {
|
|
curFileTracker = undefined;
|
|
document.getElementById("pop-f").style.visibility = "hidden";
|
|
return;
|
|
}
|
|
|
|
curFileTracker = el.getAttribute("data-file_location")
|
|
Popper.createPopper(el, document.getElementById('pop-f'), {
|
|
placement: 'bottom-end',
|
|
onFirstUpdate: function (data) {
|
|
document.getElementById("pop-f").style.visibility = "visible";
|
|
},
|
|
modifiers: [
|
|
{
|
|
name: 'flip',
|
|
options: {
|
|
boundariesElement: 'scrollParent',
|
|
},
|
|
},
|
|
{
|
|
name: 'preventOverflow',
|
|
options: {
|
|
boundariesElement: 'scrollParent',
|
|
},
|
|
},
|
|
]
|
|
});
|
|
}
|
|
|
|
const myModal = new HystModal({});
|
|
|
|
function openShareModal() {
|
|
myModal.open('#sharePlaylist');
|
|
}
|
|
|
|
function openSaveModal() {
|
|
myModal.open('#savePlaylist');
|
|
}
|
|
|
|
function openNewPlaylistModal() {
|
|
myModal.open('#newPlaylist');
|
|
}
|
|
|
|
function openPlaybackModal() {
|
|
myModal.open('#speedModal');
|
|
}
|
|
|
|
function openEditModal() {
|
|
myModal.open('#editServer');
|
|
}
|
|
|
|
async function addToPlaylistUI(playlist) {
|
|
try {
|
|
await MSTREAMAPI.addToPlaylist(playlist, curFileTracker);
|
|
iziToast.success({
|
|
title: 'Song Added!',
|
|
position: 'topCenter',
|
|
timeout: 3500
|
|
});
|
|
}catch(err) {
|
|
iziToast.error({
|
|
title: 'Failed to add song',
|
|
position: 'topCenter',
|
|
timeout: 3500
|
|
});
|
|
}
|
|
}
|
|
|
|
/////////////// Download Playlist
|
|
function downloadPlaylist() {
|
|
// Loop through array and add each file to the playlist
|
|
const downloadFiles = [];
|
|
for (let i = 0; i < MSTREAMPLAYER.playlist.length; i++) {
|
|
downloadFiles.push(MSTREAMPLAYER.playlist[i].rawFilePath);
|
|
}
|
|
|
|
if (downloadFiles < 1) {
|
|
return;
|
|
}
|
|
|
|
// Use key if necessary
|
|
document.getElementById('downform').action = "api/v1/download/zip?token=" + MSTREAMAPI.currentServer.token;
|
|
|
|
let input = document.createElement("INPUT");
|
|
input.type = 'hidden';
|
|
input.name = 'fileArray';
|
|
input.value = JSON.stringify(downloadFiles);
|
|
document.getElementById('downform').appendChild(input);
|
|
|
|
//submit form
|
|
document.getElementById('downform').submit();
|
|
// clear the form
|
|
document.getElementById('downform').innerHTML = '';
|
|
}
|
|
|
|
function recursiveFileDownload(el) {
|
|
const directoryString = getDirectoryString2(el);
|
|
document.getElementById('downform').action = "api/v1/download/directory?token=" + MSTREAMAPI.currentServer.token;
|
|
|
|
let input = document.createElement("INPUT");
|
|
input.type = 'hidden';
|
|
input.name = 'directory';
|
|
input.value = directoryString;
|
|
document.getElementById('downform').appendChild(input);
|
|
|
|
//submit form
|
|
document.getElementById('downform').submit();
|
|
// clear the form
|
|
document.getElementById('downform').innerHTML = '';
|
|
}
|
|
|
|
function downloadFileplaylist(el) {
|
|
document.getElementById('downform').action = "api/v1/download/m3u?token=" + MSTREAMAPI.currentServer.token;
|
|
|
|
const input = document.createElement("INPUT");
|
|
input.type = 'hidden';
|
|
input.name = 'path';
|
|
input.value = getDirectoryString2(el);
|
|
document.getElementById('downform').appendChild(input);
|
|
|
|
//submit form
|
|
document.getElementById('downform').submit();
|
|
// clear the form
|
|
document.getElementById('downform').innerHTML = '';
|
|
}
|
|
|
|
function getArtistz(el) {
|
|
const artist = el.getAttribute('data-artist');
|
|
programState.push({
|
|
state: 'artist',
|
|
name: artist,
|
|
previousScroll: document.getElementById('filelist').scrollTop,
|
|
previousSearch: document.getElementById('localSearchBar').value
|
|
});
|
|
|
|
getArtistsAlbums(artist)
|
|
}
|
|
|
|
async function getArtistsAlbums(artist) {
|
|
setBrowserRootPanel('Albums');
|
|
document.getElementById('directoryName').innerHTML = 'Artist: ' + artist;
|
|
document.getElementById('filelist').innerHTML = getLoadingSvg();
|
|
|
|
try {
|
|
const response = await MSTREAMAPI.artistAlbums(artist);
|
|
let albums = '';
|
|
response.albums.forEach(value => {
|
|
const albumString = value.name ? value.name : 'SINGLES';
|
|
// 'value.name === null ? artist : null' is some clever shit that only passes in artist info when the album is null
|
|
// This is so we get the singles for this artist
|
|
// If the album is specified, we don't want to limit by artist
|
|
albums += renderAlbum(value.name, value.name === null ? artist : null, albumString, value.album_art_file, value.year);
|
|
currentBrowsingList.push({ type: 'album', name: value.name, artist: artist, album_art_file: value.album_art_file })
|
|
});
|
|
|
|
document.getElementById('filelist').innerHTML = albums;
|
|
}catch (err) {
|
|
document.getElementById('filelist').innerHTML = '<div>Server call failed</div>';
|
|
return boilerplateFailure(err);
|
|
}
|
|
}
|
|
|
|
function onSearchButtonClick() {
|
|
// Hide Filepath
|
|
document.getElementById('search_folders').classList.toggle('super-hide');
|
|
// Show Search Input
|
|
document.getElementById('directoryName').classList.toggle('super-hide');
|
|
|
|
if (!document.getElementById('search_folders').classList.contains('super-hide')) {
|
|
document.getElementById("localSearchBar").focus();
|
|
} else {
|
|
document.getElementById('localSearchBar').value = '';
|
|
document.getElementById('localSearchBar').dispatchEvent(new Event('change'));
|
|
}
|
|
}
|
|
|
|
async function onBackButton() {
|
|
if (programState.length < 2) {
|
|
return;
|
|
}
|
|
|
|
const thisState = programState.pop();
|
|
const backState = programState[programState.length - 1];
|
|
|
|
if (backState.state === 'allPlaylists') {
|
|
await getAllPlaylists(undefined);
|
|
} else if (backState.state === 'allAlbums') {
|
|
await getAllAlbums(undefined);
|
|
} else if (backState.state === 'allArtists') {
|
|
await getAllArtists(undefined);
|
|
} else if (backState.state === 'artist') {
|
|
await getArtistsAlbums(backState.name);
|
|
} else if (backState.state === 'fileExplorer') {
|
|
fileExplorerArray.pop();
|
|
await senddir();
|
|
} else if (backState.state === 'searchPanel') {
|
|
setupSearchPanel(backState.searchTerm, undefined);
|
|
}
|
|
|
|
// Fill in Search Bar
|
|
if (backState.state !== 'searchPanel' && thisState.previousSearch) {
|
|
document.getElementById('localSearchBar').value = thisState.previousSearch;
|
|
document.getElementById('localSearchBar').dispatchEvent(new Event('keyup'));
|
|
}
|
|
|
|
// Scroll to position
|
|
if (thisState.previousScroll) {
|
|
document.getElementById('filelist').scrollTop = thisState.previousScroll;
|
|
}
|
|
}
|
|
|
|
///////////////////// Playlists
|
|
async function getAllPlaylists() {
|
|
setBrowserRootPanel('Playlists');
|
|
document.getElementById('filelist').innerHTML = getLoadingSvg();
|
|
document.getElementById('directoryName').innerHTML = '<input class="newPlaylistButton btn green" style="height:24px;" value="New Playlist" type="button" onclick="openNewPlaylistModal();">';
|
|
programState = [ {state: 'allPlaylists' }];
|
|
|
|
try {
|
|
const response = await MSTREAMAPI.getAllPlaylists();
|
|
VUEPLAYERCORE.playlists.length = 0;
|
|
document.getElementById('pop-f').innerHTML = '<div class="pop-f pop-playlist">Add To Playlist:</div>';
|
|
|
|
// loop through the json array and make an array of corresponding divs
|
|
let playlists = '<ul class="collection">';
|
|
response.forEach(p => {
|
|
playlists += renderPlaylist(p.name);
|
|
const lol = { name: p.name, type: 'playlist' };
|
|
currentBrowsingList.push(lol);
|
|
VUEPLAYERCORE.playlists.push(lol);
|
|
document.getElementById('pop-f').innerHTML += `<div class="pop-list-item" onclick="addToPlaylistUI('${p.name}')">• ${p.name}</div>`;
|
|
});
|
|
playlists += '</ul>'
|
|
|
|
document.getElementById('filelist').innerHTML = playlists;
|
|
}catch (err) {
|
|
document.getElementById('filelist').innerHTML = '<div>Server call failed</div>';
|
|
return boilerplateFailure(err);
|
|
}
|
|
}
|
|
|
|
function deletePlaylist(el) {
|
|
const playlistname = decodeURIComponent(el.getAttribute('data-playlistname'));
|
|
|
|
iziToast.question({
|
|
timeout: 10000,
|
|
close: false,
|
|
overlayClose: true,
|
|
overlay: true,
|
|
displayMode: 'once',
|
|
id: 'question',
|
|
zindex: 99999,
|
|
title: `Delete '${playlistname}'?`,
|
|
position: 'center',
|
|
buttons: [
|
|
['<button><b>Delete</b></button>', async (instance, toast) => {
|
|
try {
|
|
await MSTREAMAPI.deletePlaylist(playlistname)
|
|
document.querySelector('li[data-playlistname="'+encodeURIComponent(playlistname)+'"]').remove();
|
|
}catch(err) {
|
|
boilerplateFailure(err);
|
|
}
|
|
instance.hide({ transitionOut: 'fadeOut' }, toast, 'button');
|
|
}, true],
|
|
['<button>Go Back</button>', (instance, toast) => {
|
|
instance.hide({ transitionOut: 'fadeOut' }, toast, 'button');
|
|
}],
|
|
]
|
|
});
|
|
}
|
|
|
|
async function onPlaylistClick(el) {
|
|
try {
|
|
const playlistname = decodeURIComponent(el.getAttribute('data-playlistname'));
|
|
document.getElementById('directoryName').innerHTML = 'Playlist: ' + playlistname;
|
|
document.getElementById('filelist').innerHTML = getLoadingSvg();
|
|
currentBrowsingList = [];
|
|
programState.push({
|
|
state: 'playlist',
|
|
name: playlistname,
|
|
previousScroll: document.getElementById('filelist').scrollTop,
|
|
previousSearch: document.getElementById('localSearchBar').value
|
|
});
|
|
document.getElementById('localSearchBar').value = '';
|
|
const response = await MSTREAMAPI.loadPlaylist(playlistname);
|
|
|
|
// Add the playlist name to the modal
|
|
document.getElementById('playlist_name').value = playlistname;
|
|
|
|
let files = '';
|
|
response.forEach(value => {
|
|
currentBrowsingList.push({
|
|
type: 'file',
|
|
name: (!value.metadata || !value.metadata.title) ? value.filepath : `${value.metadata.artist} - ${value.metadata.title}`,
|
|
metadata: value.metadata,
|
|
filepath: value.filepath,
|
|
lokiId: value.lokiId
|
|
});
|
|
|
|
files += renderFileWithMetadataHtml(value.filepath, value.lokiId, value.metadata);
|
|
});
|
|
|
|
document.getElementById('filelist').innerHTML = files;
|
|
}catch(err) {
|
|
document.getElementById('filelist').innerHTML = '<div>Server call failed</div>';
|
|
boilerplateFailure(response, error);
|
|
}
|
|
}
|
|
|
|
function removePlaylistSong(el) {
|
|
try {
|
|
const lokiId = el.getAttribute('data-lokiid');
|
|
MSTREAMAPI.removePlaylistSong(lokiId);
|
|
|
|
// remove from currentBrowsingList
|
|
currentBrowsingList = currentBrowsingList.filter(item =>{
|
|
return item.lokiId !== lokiId
|
|
});
|
|
|
|
document.querySelector(`li[data-lokiid="${lokiId}"]`).remove();
|
|
}catch(err) {
|
|
return boilerplateFailure(err);
|
|
}
|
|
}
|
|
|
|
async function newPlaylist() {
|
|
document.getElementById('new_playlist').disabled = true;
|
|
try {
|
|
const title = document.getElementById('new_playlist_name').value;
|
|
await MSTREAMAPI.newPlaylist(title);
|
|
myModal.close();
|
|
iziToast.success({
|
|
title: 'Playlist Created',
|
|
position: 'topCenter',
|
|
timeout: 3000
|
|
});
|
|
|
|
document.getElementById("newPlaylistForm").reset();
|
|
VUEPLAYERCORE.playlists.push({ name: title, type: 'playlist'});
|
|
document.getElementById('pop-f').innerHTML += `<div class="pop-list-item" onclick="addToPlaylistUI('${title}')">• ${title}</div>`;
|
|
|
|
if (programState[0].state === 'allPlaylists') {
|
|
getAllPlaylists();
|
|
}
|
|
}catch (err) {
|
|
boilerplateFailure(err);
|
|
}
|
|
document.getElementById('new_playlist').disabled = false;
|
|
}
|
|
|
|
async function savePlaylist() {
|
|
if (MSTREAMPLAYER.playlist.length == 0) {
|
|
iziToast.warning({
|
|
title: 'No playlist to save!',
|
|
position: 'topCenter',
|
|
timeout: 3500
|
|
});
|
|
return;
|
|
}
|
|
|
|
try {
|
|
document.getElementById('save_playlist').disabled = true;
|
|
const title = document.getElementById('playlist_name').value;
|
|
|
|
//loop through array and add each file to the playlist
|
|
const songs = [];
|
|
for (let i = 0; i < MSTREAMPLAYER.playlist.length; i++) {
|
|
songs.push(MSTREAMPLAYER.playlist[i].filepath);
|
|
}
|
|
|
|
MSTREAMAPI.savePlaylist(title,songs);
|
|
|
|
myModal.close();
|
|
iziToast.success({
|
|
title: 'Playlist Saved',
|
|
position: 'topCenter',
|
|
timeout: 3000
|
|
});
|
|
|
|
if (programState[0].state === 'allPlaylists') {
|
|
getAllPlaylists();
|
|
}
|
|
|
|
VUEPLAYERCORE.playlists.push({ name: title, type: 'playlist'});
|
|
document.getElementById('pop-f').innerHTML += `<div class="pop-list-item" onclick="addToPlaylistUI('${title}')">• ${title}</div>`;
|
|
}catch(err) {
|
|
boilerplateFailure(err);
|
|
}
|
|
}
|
|
|
|
/////////////// Artists
|
|
async function getAllArtists() {
|
|
setBrowserRootPanel('Artists');
|
|
document.getElementById('filelist').innerHTML = getLoadingSvg();
|
|
programState = [{ state: 'allArtists' }];
|
|
|
|
try {
|
|
const response = await MSTREAMAPI.artists();
|
|
// parse through the json array and make an array of corresponding divs
|
|
let artists = '<ul class="collection">';
|
|
response.artists.forEach(value => {
|
|
artists += renderArtist(value);
|
|
currentBrowsingList.push({ type: 'artist', name: value });
|
|
});
|
|
artists += '</ul>';
|
|
|
|
document.getElementById('filelist').innerHTML = artists;
|
|
}catch(err) {
|
|
document.getElementById('filelist').innerHTML = '<div>Server call failed</div>';
|
|
boilerplateFailure(response, error);
|
|
}
|
|
}
|
|
|
|
function getArtistz(el) {
|
|
const artist = el.getAttribute('data-artist');
|
|
programState.push({
|
|
state: 'artist',
|
|
name: artist,
|
|
previousScroll: document.getElementById('filelist').scrollTop,
|
|
previousSearch: document.getElementById('localSearchBar').value
|
|
});
|
|
|
|
getArtistsAlbums(artist)
|
|
}
|
|
|
|
async function getArtistsAlbums(artist) {
|
|
setBrowserRootPanel('Albums');
|
|
document.getElementById('directoryName').innerHTML = 'Artist: ' + artist;
|
|
document.getElementById('filelist').innerHTML = getLoadingSvg();
|
|
|
|
try {
|
|
const response = await MSTREAMAPI.artistAlbums(artist);
|
|
let albums = '<ul>';
|
|
response.albums.forEach(value => {
|
|
const albumString = value.name ? value.name : 'SINGLES';
|
|
// 'value.name === null ? artist : null' is some clever shit that only passes in artist info when the album is null
|
|
// This is so we get the singles for this artist
|
|
// If the album is specified, we don't want to limit by artist
|
|
albums += renderAlbum(value.name, value.name === null ? artist : null, albumString, value.album_art_file, value.year);
|
|
currentBrowsingList.push({ type: 'album', name: value.name, artist: artist, album_art_file: value.album_art_file })
|
|
});
|
|
albums += '</ul>';
|
|
|
|
document.getElementById('filelist').innerHTML = albums;
|
|
}catch(err) {
|
|
document.getElementById('filelist').innerHTML = '<div>Server call failed</div>';
|
|
boilerplateFailure(response, error);
|
|
}
|
|
}
|
|
|
|
/////////////// Albums
|
|
async function getAllAlbums() {
|
|
setBrowserRootPanel('Albums');
|
|
document.getElementById('filelist').innerHTML = getLoadingSvg();
|
|
|
|
programState = [{ state: 'allAlbums' }];
|
|
|
|
try {
|
|
const response = await MSTREAMAPI.albums();
|
|
//parse through the json array and make an array of corresponding divs
|
|
let albums = '<ul class="collection">';
|
|
response.albums.forEach(value => {
|
|
currentBrowsingList.push({
|
|
type: 'album',
|
|
name: value.name,
|
|
'album_art_file': value.album_art_file
|
|
});
|
|
|
|
albums += renderAlbum(value.name, undefined, value.name, value.album_art_file, value.year);
|
|
});
|
|
albums += '</ul>'
|
|
|
|
document.getElementById('filelist').innerHTML = albums;
|
|
}catch (err) {
|
|
document.getElementById('filelist').innerHTML = '<div>Server call failed</div>';
|
|
return boilerplateFailure(err);
|
|
}
|
|
}
|
|
|
|
function getAlbumsOnClick(el) {
|
|
getAlbumSongs(
|
|
el.hasAttribute('data-album') ? el.getAttribute('data-album') : null,
|
|
el.hasAttribute('data-artist') ? el.getAttribute('data-artist') : null,
|
|
el.hasAttribute('data-year') ? el.getAttribute('data-year') : null);
|
|
}
|
|
|
|
async function getAlbumSongs(album, artist, year) {
|
|
document.getElementById('directoryName').innerHTML = 'Album: ' + album;
|
|
|
|
programState.push({
|
|
state: 'album',
|
|
name: album,
|
|
previousScroll: document.getElementById('filelist').scrollTop,
|
|
previousSearch: document.getElementById('localSearchBar').value
|
|
});
|
|
|
|
//clear the list
|
|
document.getElementById('filelist').innerHTML = getLoadingSvg();
|
|
currentBrowsingList = [];
|
|
|
|
document.getElementById('localSearchBar').value = '';
|
|
|
|
try {
|
|
const response = await MSTREAMAPI.albumSongs(album, artist, year)
|
|
//parse through the json array and make an array of corresponding divs
|
|
let files = '<ul class="collection">';
|
|
response.forEach(song => {
|
|
currentBrowsingList.push({ type: 'file', name: song.metadata.title ? song.metadata.title : song.metadata.filename });
|
|
files += createMusicFileHtml(song.filepath, song.metadata.title ? song.metadata.title : song.metadata.filename, undefined, undefined, song.metadata.artist ? song.metadata.artist : undefined);
|
|
});
|
|
files += '</ul>';
|
|
|
|
document.getElementById('filelist').innerHTML = files;
|
|
}catch(err) {
|
|
document.getElementById('filelist').innerHTML = '<div>Server call failed</div>';
|
|
boilerplateFailure(err);
|
|
}
|
|
}
|
|
|
|
////////////// Rated Songs
|
|
async function getRatedSongs() {
|
|
setBrowserRootPanel('Starred');
|
|
document.getElementById('filelist').innerHTML = getLoadingSvg();
|
|
programState = [{ state: 'allRated' }];
|
|
|
|
try {
|
|
const response = await MSTREAMAPI.getRated();
|
|
//parse through the json array and make an array of corresponding divs
|
|
let files = '';
|
|
response.forEach(value => {
|
|
let rating = (value.metadata.rating / 2);
|
|
if (!Number.isInteger(rating)) {
|
|
rating = rating.toFixed(1);
|
|
}
|
|
|
|
currentBrowsingList.push({
|
|
type: 'file',
|
|
name: value.metadata.artist ? value.metadata.artist + ' - ' + value.metadata.title : value.filepath,
|
|
metadata: value.metadata
|
|
});
|
|
|
|
files += createMusicFileHtml(value.filepath,
|
|
value.metadata.title ? value.metadata.title : value.filepath,
|
|
value.metadata['album-art'] ? `src="${MSTREAMAPI.currentServer.host}album-art/${value.metadata['album-art']}?token=${MSTREAMAPI.currentServer.token}"` : `src="assets/img/default.png"`,
|
|
rating,
|
|
value.metadata.artist ? `<span style="font-size:15px;">${value.metadata.artist}</span>` : undefined);
|
|
});
|
|
|
|
document.getElementById('filelist').innerHTML = files;
|
|
}catch (err) {
|
|
document.getElementById('filelist').innerHTML = '<div>Server call failed</div>';
|
|
return boilerplateFailure(err);
|
|
}
|
|
}
|
|
|
|
///////////////// Recently Added
|
|
function getRecentlyAdded() {
|
|
setBrowserRootPanel('Recently Added');
|
|
document.getElementById('filelist').innerHTML = getLoadingSvg();
|
|
document.getElementById('directoryName').innerHTML = 'Get last <input onkeydown="submitRecentlyAdded();" onfocusout="redoRecentlyAdded();" id="recently-added-limit" class="recently-added-input" type="number" min="1" step="1" value="100"> songs';
|
|
|
|
redoRecentlyAdded();
|
|
}
|
|
|
|
async function redoRecentlyAdded() {
|
|
currentBrowsingList = [];
|
|
programState = [{ state: 'recentlyAdded'}];
|
|
|
|
try {
|
|
const response = await MSTREAMAPI.getRecentlyAdded(document.getElementById('recently-added-limit').value);
|
|
//parse through the json array and make an array of corresponding divs
|
|
let filelist = '<ul class="collection">';
|
|
response.forEach(el => {
|
|
currentBrowsingList.push({
|
|
type: 'file',
|
|
name: el.metadata.title ? el.metadata.artist + ' - ' + el.metadata.title : el.filepath.split("/").pop()
|
|
});
|
|
|
|
filelist += createMusicFileHtml(el.filepath,
|
|
el.metadata.title ? `${el.metadata.title}`: el.filepath.split("/").pop(),
|
|
el.metadata['album-art'] ? `src="${MSTREAMAPI.currentServer.host}album-art/${el.metadata['album-art']}?token=${MSTREAMAPI.currentServer.token}"` : `src="assets/img/default.png"`,
|
|
undefined,
|
|
el.metadata.artist ? `<span style="font-size:15px;">${el.metadata.artist}</span>` : undefined);
|
|
});
|
|
|
|
filelist += '</ul>'
|
|
|
|
document.getElementById('filelist').innerHTML = filelist;
|
|
}catch(err) {
|
|
document.getElementById('filelist').innerHTML = '<div>Server call failed</div>';
|
|
return boilerplateFailure(err);
|
|
}
|
|
}
|
|
|
|
function submitRecentlyAdded() {
|
|
if (event.keyCode === 13) {
|
|
document.getElementById("recently-added-limit").blur();
|
|
}
|
|
}
|
|
|
|
///////////////// Transcode
|
|
function setupTranscodePanel(){
|
|
setBrowserRootPanel('Transcode', false);
|
|
|
|
if (!MSTREAMPLAYER.transcodeOptions.serverEnabled) {
|
|
document.getElementById('filelist').innerHTML = '<p><b>Transcoding is disabled on this server</b></p>';
|
|
return;
|
|
}
|
|
|
|
document.getElementById('filelist').innerHTML = `
|
|
<div class="browser-panel">
|
|
<div>
|
|
<label for="enable_transcoding_locally">
|
|
<input type="checkbox" class="filled-in" onchange="toggleTranscoding(this);" id="enable_transcoding_locally"
|
|
name="transcode" ${MSTREAMPLAYER.transcodeOptions.frontendEnabled ? 'checked' : ''}/>
|
|
<span>Enable Transcoding</span>
|
|
</label>
|
|
</div>
|
|
<p>
|
|
Default Codec:<br> <b>${MSTREAMPLAYER.transcodeOptions.defaultCodec} ${MSTREAMPLAYER.transcodeOptions.defaultBitrate} ${MSTREAMPLAYER.transcodeOptions.defaultAlgo}</b>
|
|
</p>
|
|
<form>
|
|
<label for="trans-codec-select">Codec</label>
|
|
<select onchange="changeTranscodeCodec();" class="browser-default trans-input" name="pets" id="trans-codec-select">
|
|
<option value="">Default</option>
|
|
<option value="opus">Opus OGG</option>
|
|
<option value="mp3">mp3</option>
|
|
<option value="aac">AAC</option>
|
|
</select>
|
|
<br>
|
|
<label for="trans-bitrate-select">Bit Rate</label>
|
|
<select onchange="changeTranscodeBitrate();" class="browser-default trans-input" name="pets" id="trans-bitrate-select">
|
|
<option value="">Default</option>
|
|
<option value="64k">64k</option>
|
|
<option value="96k">96k</option>
|
|
<option value="128k">128k</option>
|
|
<option value="192k">192k</option>
|
|
</select>
|
|
<br>
|
|
<label for="trans-algo-select">Algorithm</label>
|
|
<select onchange="changeTranscodeAlgo();" class="browser-default trans-input" name="pets" id="trans-algo-select">
|
|
<option value="">Default</option>
|
|
<option value="buffer">Buffer</option>
|
|
<option value="stream">Stream</option>
|
|
</select>
|
|
</form>
|
|
</div>`;
|
|
|
|
document.getElementById('trans-codec-select').value = MSTREAMPLAYER.transcodeOptions.selectedCodec ? MSTREAMPLAYER.transcodeOptions.selectedCodec : "";
|
|
document.getElementById('trans-bitrate-select').value = MSTREAMPLAYER.transcodeOptions.selectedBitrate ? MSTREAMPLAYER.transcodeOptions.selectedBitrate : "";
|
|
document.getElementById('trans-algo-select').value = MSTREAMPLAYER.transcodeOptions.selectedAlgo ? MSTREAMPLAYER.transcodeOptions.selectedAlgo : "";
|
|
}
|
|
|
|
function changeTranscodeBitrate() {
|
|
const value = document.getElementById("trans-bitrate-select").value;
|
|
MSTREAMPLAYER.transcodeOptions.selectedBitrate = value ? value : null;
|
|
value ? localStorage.setItem('trans-bitrate-select', value) : localStorage.removeItem('trans-bitrate-select');
|
|
}
|
|
|
|
function changeTranscodeCodec() {
|
|
const value = document.getElementById("trans-codec-select").value;
|
|
MSTREAMPLAYER.transcodeOptions.selectedCodec = value ? value : null;
|
|
value ? localStorage.setItem('trans-codec-select', value) : localStorage.removeItem('trans-codec-select');
|
|
}
|
|
|
|
function changeTranscodeAlgo() {
|
|
const value = document.getElementById("trans-algo-select").value;
|
|
MSTREAMPLAYER.transcodeOptions.selectedAlgo = value ? value : null;
|
|
value ? localStorage.setItem('trans-algo-select', value) : localStorage.removeItem('trans-algo-select');
|
|
}
|
|
|
|
function toggleTranscoding(el, manual){
|
|
// checkbox button while we convert the playlist
|
|
if (el) { el.disabled = true; }
|
|
|
|
const checked = manual || el.checked;
|
|
|
|
const a = checked ? 'media/' : 'transcode/';
|
|
const b = checked ? 'transcode/' : 'media/';
|
|
|
|
document.getElementById("ffmpeg-logo").style.stroke = checked ? '#388E3C' : '#DDD';
|
|
MSTREAMPLAYER.transcodeOptions.frontendEnabled = checked ? true : false;
|
|
|
|
localStorage.setItem('transcode', checked ? true : false);
|
|
|
|
// Convert playlist
|
|
for (let i = 0; i < MSTREAMPLAYER.playlist.length; i++) {
|
|
MSTREAMPLAYER.playlist[i].url = MSTREAMPLAYER.playlist[i].url.replace(a, b);
|
|
}
|
|
|
|
// re-enable checkbox
|
|
if (el) { el.disabled = false; }
|
|
}
|
|
|
|
///////////////////////////// Mobile Stuff
|
|
function getMobilePanel(){
|
|
setBrowserRootPanel('Mobile Apps', false);
|
|
|
|
document.getElementById('filelist').innerHTML =
|
|
`<div class='mobile-links'>
|
|
<a target='_blank' href='https://play.google.com/store/apps/details?id=mstream.music&pcampaignid=MKT-Other-global-all-co-prtnr-py-PartBadge-Mar2515-1'><img alt='Get it on Google Play' src='https://play.google.com/intl/en_us/badges/images/generic/en_badge_web_generic.png'/></a>
|
|
<div class='mobile-placeholder'> </div>
|
|
</div>
|
|
<div class='app-text'>
|
|
<a target='_blank' href='/qr'>Checkout the QR Code tool to help add your server to the app</a>
|
|
</div>`;
|
|
}
|
|
|
|
////////////////////////// Share playlists
|
|
async function submitShareForm() {
|
|
try {
|
|
document.getElementById('share_it').disabled = true;
|
|
const shareTimeInDays = document.getElementById('share_time').value;
|
|
|
|
//loop through array and add each file to the playlist
|
|
const stuff = [];
|
|
for (let i = 0; i < MSTREAMPLAYER.playlist.length; i++) {
|
|
stuff.push(MSTREAMPLAYER.playlist[i].filepath);
|
|
}
|
|
|
|
if (stuff.length == 0) {
|
|
document.getElementById('share_it').disabled = false;
|
|
return;
|
|
}
|
|
|
|
const response = await MSTREAMAPI.makeShared(stuff, shareTimeInDays);
|
|
const adrs = window.location.protocol + '//' + window.location.host + '/shared/' + response.playlistId;
|
|
document.getElementById('share-textarea').value = adrs;
|
|
}catch (err) {
|
|
boilerplateFailure(err);
|
|
}
|
|
|
|
document.getElementById('share_it').disabled = false;
|
|
}
|
|
|
|
///////////////// Auto DJ
|
|
function autoDjPanel() {
|
|
setBrowserRootPanel('Auto DJ', false);
|
|
|
|
let newHtml = '<br><p>Auto DJ randomly generates a playlist. Click the \'DJ\' button on the bottom enable it</p><h3>Use Folders</h3><p>';
|
|
for (let i = 0; i < MSTREAMAPI.currentServer.vpaths.length; i++) {
|
|
let checkedString = '';
|
|
if (!MSTREAMPLAYER.ignoreVPaths[MSTREAMAPI.currentServer.vpaths[i]]) {
|
|
checkedString = 'checked';
|
|
}
|
|
newHtml += `
|
|
<label for="autodj-folder-${MSTREAMAPI.currentServer.vpaths[i]}">
|
|
<input ${checkedString} id="autodj-folder-${MSTREAMAPI.currentServer.vpaths[i]}" type="checkbox"
|
|
value="${MSTREAMAPI.currentServer.vpaths[i]}" name="autodj-folders" onchange="onAutoDJFolderChange(this)">
|
|
<span>${MSTREAMAPI.currentServer.vpaths[i]}</span>
|
|
</label><br>`;
|
|
}
|
|
|
|
newHtml += '</p><h3>Minimum Rating</h3> <select class="browser-default" onchange="updateAutoDJRatings(this)" id="autodj-ratings">';
|
|
for (let i = 0; i < 11; i++) {
|
|
newHtml += `<option ${(Number(MSTREAMPLAYER.minRating) === i) ? 'selected' : ''} value="${i}">${(i ===0) ? 'Disabled' : +(i/2).toFixed(1)}</option>`;
|
|
}
|
|
newHtml += '</select>';
|
|
newHtml += '<br><br><br><p><input type="button" value="Toggle Auto DJ" onclick="MSTREAMPLAYER.toggleAutoDJ();"></p>'
|
|
|
|
document.getElementById('filelist').innerHTML = newHtml;
|
|
}
|
|
|
|
function onAutoDJFolderChange(el) {
|
|
// Don't allow user to deselect all options
|
|
if (document.querySelector('input[name=autodj-folders]:checked') === null) {
|
|
el.checked = true;
|
|
iziToast.warning({
|
|
title: 'Auto DJ requires a directory',
|
|
position: 'topCenter',
|
|
timeout: 3500
|
|
});
|
|
return;
|
|
}
|
|
|
|
if (el.checked) {
|
|
MSTREAMPLAYER.ignoreVPaths[el.value] = false;
|
|
} else {
|
|
MSTREAMPLAYER.ignoreVPaths[el.value] = true;
|
|
}
|
|
|
|
localStorage.setItem('ignoreVPaths', JSON.stringify(MSTREAMPLAYER.ignoreVPaths));
|
|
}
|
|
|
|
function updateAutoDJRatings(el) {
|
|
MSTREAMPLAYER.minRating = el.value;
|
|
localStorage.setItem('minRating', JSON.stringify([MSTREAMPLAYER.minRating]));
|
|
}
|
|
|
|
////////////// Jukebox
|
|
function setupJukeboxPanel() {
|
|
setBrowserRootPanel('Jukebox Mode', false);
|
|
|
|
let newHtml;
|
|
if (JUKEBOX.stats.live !== false && JUKEBOX.connection !== false) {
|
|
newHtml = createJukeboxPanel();
|
|
} else {
|
|
newHtml = `
|
|
<div>
|
|
<h5>Jukebox Mode allows you to control this page remotely</h5>
|
|
<input class="btn green" value="Connect" type="button" onclick="connectToJukeBox(this)">
|
|
</div>`;
|
|
}
|
|
|
|
// Add the content
|
|
document.getElementById('filelist').innerHTML = newHtml;
|
|
}
|
|
|
|
function createJukeboxPanel() {
|
|
if (JUKEBOX.stats.error !== false) {
|
|
return '<div>An error occurred. Please refresh the page and try again</div>';
|
|
}
|
|
|
|
const address = `${window.location.protocol}//${window.location.host}/remote/${JUKEBOX.stats.adminCode}`;
|
|
return `<div class="autoselect">
|
|
<h4>Code: ${JUKEBOX.stats.adminCode}</h4>
|
|
<h4><a target="_blank" href="${address}">${address}</a><h4>
|
|
${qrcodegen.QrCode.encodeText(address, qrcodegen.QrCode.Ecc.MEDIUM).toSvgString(2)}
|
|
</div>`;
|
|
}
|
|
|
|
function connectToJukeBox(el) {
|
|
el.disabled = true;
|
|
el.style.display = 'none';
|
|
|
|
document.getElementById('filelist').innerHTML += getLoadingSvg();
|
|
|
|
JUKEBOX.createWebsocket(MSTREAMAPI.currentServer.token, false, () => {
|
|
setupJukeboxPanel();
|
|
});
|
|
}
|
|
|
|
//////////////////////// Local Search
|
|
function runLocalSearch(el) {
|
|
// Do nothing if we are in the search panel
|
|
if (document.getElementById('db-search')) {
|
|
return;
|
|
}
|
|
|
|
const searchVal = el.value;
|
|
let filelist = '';
|
|
currentBrowsingList.forEach(x => {
|
|
const lowerCase = x.name !== null ? x.name.toLowerCase() : 'null';
|
|
if (lowerCase.indexOf(searchVal.toLowerCase()) !== -1) {
|
|
if (x.type === 'directory') {
|
|
filelist += renderDirHtml(x.name);
|
|
} else if (x.type === 'playlist') {
|
|
filelist += renderPlaylist(x.name);
|
|
} else if (x.type === 'album') {
|
|
const albumString = x.name ? x.name : 'SINGLES';
|
|
filelist += renderAlbum(x.name, x.name === null ? x.artist : null, albumString, x.album_art_file);
|
|
} else if (x.type === 'artist') {
|
|
filelist += renderArtist(x.name);
|
|
} else {
|
|
if (programState[programState.length - 1].state === 'playlist') {
|
|
filelist += renderFileWithMetadataHtml(x.filepath, x.lokiId, x.metadata);
|
|
} else if (x.type == "m3u") {
|
|
filelist += createFileplaylistHtml(x.name);
|
|
} else {
|
|
const fileLocation = x.path || getFileExplorerPath() + x.name;
|
|
const title = x.artist != null || x.title != null ? x.artist + ' - ' + x.title : x.name;
|
|
filelist += createMusicFileHtml(fileLocation, title);
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
document.getElementById('filelist').innerHTML= filelist;
|
|
}
|
|
|
|
//////////////////////// Search
|
|
const searchToggles = {
|
|
albums: true,
|
|
artists: true,
|
|
files: false,
|
|
titles: true
|
|
}
|
|
|
|
const searchMap = {
|
|
albums: {
|
|
name: 'Album',
|
|
class: 'albumz',
|
|
data: 'album',
|
|
func: 'getAlbumsOnClick'
|
|
},
|
|
artists: {
|
|
name: 'Artist',
|
|
class: 'artistz',
|
|
data: 'artist',
|
|
func: 'getArtistz'
|
|
},
|
|
files: {
|
|
name: 'File',
|
|
class: 'filez',
|
|
data: 'file_location',
|
|
func: 'onFileClick'
|
|
},
|
|
title: {
|
|
name: 'Song',
|
|
class: 'filez',
|
|
data: 'file_location',
|
|
func: 'onFileClick'
|
|
}
|
|
};
|
|
|
|
function setupSearchPanel(searchTerm) {
|
|
setBrowserRootPanel('Search DB');
|
|
document.getElementById('local_search_btn').style.display = 'none';
|
|
programState = [{ state: 'searchPanel' }];
|
|
|
|
let valString = '';
|
|
if (searchTerm) { valString = `value="${searchTerm}"`; }
|
|
|
|
document.getElementById('filelist').innerHTML =
|
|
`<div>
|
|
<form id="db-search" action="javascript:submitSearchForm()" class="flex">
|
|
<input ${valString} id="search-term" required type="text" placeholder="Search Database">
|
|
<!-- <button type="submit" class="searchButton">
|
|
<svg fill="#DDD" viewBox="-150 -50 1224 1174" height="24px" width="24px" xmlns="http://www.w3.org/2000/svg"><path d="M960 832L710.875 582.875C746.438 524.812 768 457.156 768 384 768 171.969 596 0 384 0 171.969 0 0 171.969 0 384c0 212 171.969 384 384 384 73.156 0 140.812-21.562 198.875-57L832 960c17.5 17.5 46.5 17.375 64 0l64-64c17.5-17.5 17.5-46.5 0-64zM384 640c-141.375 0-256-114.625-256-256s114.625-256 256-256 256 114.625 256 256-114.625 256-256 256z"></path></svg>
|
|
</button> -->
|
|
</form>
|
|
</div>
|
|
<div class="flex">
|
|
<label class="grow" for="search-in-artists">
|
|
<input ${(searchToggles.artists === true ? 'checked' : '')} id="search-in-artists" class="filled-in" type="checkbox">
|
|
<span>Artists</span>
|
|
</label>
|
|
<label class="grow" for="search-in-albums">
|
|
<input ${(searchToggles.albums === true ? 'checked' : '')} id="search-in-albums" class="filled-in" type="checkbox">
|
|
<span>Albums</span>
|
|
</label>
|
|
<label class="grow" for="search-in-titles">
|
|
<input ${(searchToggles.titles === true ? 'checked' : '')} id="search-in-titles" class="filled-in" type="checkbox">
|
|
<span>Song Titles</span>
|
|
</label>
|
|
<label class="grow" for="search-in-filepaths">
|
|
<input ${(searchToggles.files === true ? 'checked' : '')} id="search-in-filepaths" class="filled-in" type="checkbox">
|
|
<span>File Paths</span>
|
|
</label>
|
|
</div>
|
|
<div id="search-results"></div>`;
|
|
|
|
document.getElementById('search_folders').value = '';
|
|
document.getElementById('search_folders').dispatchEvent(new Event('change'));
|
|
|
|
if (searchTerm) {
|
|
submitSearchForm();
|
|
}
|
|
}
|
|
|
|
async function submitSearchForm() {
|
|
try {
|
|
document.getElementById('search-results').innerHTML += '<div class="loading-screen"><svg class="spinner" width="65px" height="65px" viewBox="0 0 66 66" xmlns="http://www.w3.org/2000/svg"><circle class="spinner-path" fill="none" stroke-width="6" stroke-linecap="round" cx="33" cy="33" r="30"></circle></svg></div>'
|
|
|
|
var postObject = { search: document.getElementById('search-term').value};
|
|
if (document.getElementById("search-in-artists") && document.getElementById("search-in-artists").checked === false) { postObject.noArtists = true; }
|
|
searchToggles.artists = document.getElementById("search-in-artists").checked;
|
|
if (document.getElementById("search-in-albums") && document.getElementById("search-in-albums").checked === false) { postObject.noAlbums = true; }
|
|
searchToggles.albums = document.getElementById("search-in-albums").checked;
|
|
if (document.getElementById("search-in-filepaths") && document.getElementById("search-in-filepaths").checked === false) { postObject.noFiles = true; }
|
|
searchToggles.files = document.getElementById("search-in-filepaths").checked;
|
|
if (document.getElementById("search-in-titles") && document.getElementById("search-in-titles").checked === false) { postObject.noTitles = true; }
|
|
searchToggles.titles = document.getElementById("search-in-titles").checked;
|
|
|
|
const res = await MSTREAMAPI.search(postObject);
|
|
|
|
if (programState[0].state === 'searchPanel') {
|
|
programState[0].searchTerm = postObject.search;
|
|
}
|
|
|
|
let noResultsFlag = true;
|
|
|
|
// Populate list
|
|
let searchList = '<ul class="collection">';
|
|
Object.keys(res).forEach((key) => {
|
|
res[key].forEach((value, i) => {
|
|
noResultsFlag = false;
|
|
|
|
// perform some operation on a value;
|
|
searchList += `<li class="collection-item">
|
|
<div onclick="${searchMap[key].func}(this);" data-${searchMap[key].data}="${value.filepath ? value.filepath : value.name}" class="${searchMap[key].class} left">
|
|
<b>${searchMap[key].name}:</b> ${value.name}
|
|
</div>
|
|
${
|
|
key === 'files' || key === 'title' ? `<div class="song-button-box">
|
|
<span title="Play Now" onclick="playNow(this);" data-file_location="${value.filepath}" class="songDropdown">
|
|
<svg xmlns="http://www.w3.org/2000/svg" height="12" width="12" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M15.5 5H11l5 7-5 7h4.5l5-7z"/><path d="M8.5 5H4l5 7-5 7h4.5l5-7z"/></svg>
|
|
</span>
|
|
<span title="Add To Playlist" onclick="createPopper3(this);" data-file_location="${value.filepath}" class="fileAddToPlaylist">
|
|
<svg class="pop-f" xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 292.362 292.362"><path class="pop-f" d="M286.935 69.377c-3.614-3.617-7.898-5.424-12.848-5.424H18.274c-4.952 0-9.233 1.807-12.85 5.424C1.807 72.998 0 77.279 0 82.228c0 4.948 1.807 9.229 5.424 12.847l127.907 127.907c3.621 3.617 7.902 5.428 12.85 5.428s9.233-1.811 12.847-5.428L286.935 95.074c3.613-3.617 5.427-7.898 5.427-12.847 0-4.948-1.814-9.229-5.427-12.85z"/></svg>
|
|
</span>
|
|
</div>` : ''
|
|
}
|
|
</li>`;
|
|
});
|
|
});
|
|
|
|
searchList += '</ul>'
|
|
|
|
if (noResultsFlag === true) {
|
|
searchList = '<h5>No Results Found</h5>';
|
|
}
|
|
|
|
document.getElementById('search-results').innerHTML = searchList;
|
|
}catch(err) {
|
|
boilerplateFailure(err);
|
|
}
|
|
}
|
|
|
|
////////////////// Layout
|
|
function setupLayoutPanel() {
|
|
setBrowserRootPanel('Layout', false);
|
|
|
|
const newHtml = `
|
|
<div>
|
|
<div class="switch">
|
|
<label>
|
|
<input type="checkbox">
|
|
<span class="lever"></span>
|
|
Player On Bottom
|
|
</label>
|
|
</div>
|
|
<br>
|
|
<div class="switch">
|
|
<label>
|
|
<input type="checkbox">
|
|
<span class="lever"></span>
|
|
Metadata in Queue
|
|
</label>
|
|
</div>
|
|
<br>
|
|
<div class="switch">
|
|
<label>
|
|
<input type="checkbox">
|
|
<span class="lever"></span>
|
|
Single Browser
|
|
</label>
|
|
</div>
|
|
<br>
|
|
<div class="switch">
|
|
<label>
|
|
<input type="checkbox">
|
|
<span class="lever"></span>
|
|
Classic Layout
|
|
</label>
|
|
</div>
|
|
<br>
|
|
<div class="switch">
|
|
<label>
|
|
<input type="checkbox">
|
|
<span class="lever"></span>
|
|
Light Mode
|
|
</label>
|
|
</div>
|
|
</div>`;
|
|
|
|
// Add the content
|
|
document.getElementById('filelist').innerHTML = newHtml;
|
|
}
|
|
|
|
function flipPlayer() {
|
|
document.getElementById('content').style.flexDirection = 'column-reverse'
|
|
}
|
|
|
|
async function updateServer() {
|
|
try {
|
|
document.getElementById('save_server').disabled = true;
|
|
|
|
const res = await MSTREAMAPI.login(document.getElementById('server_username').value,
|
|
document.getElementById('server_password').value,
|
|
document.getElementById('server_address').value);
|
|
|
|
MSTREAMAPI.currentServer.host = document.getElementById('server_address').value;
|
|
MSTREAMAPI.currentServer.username = document.getElementById('server_username').value;
|
|
|
|
MSTREAMAPI.currentServer.token = res.token;
|
|
}catch(err) {
|
|
boilerplateFailure(err);
|
|
}finally {
|
|
document.getElementById('save_server').disabled = false;
|
|
}
|
|
}
|
|
|
|
function isElectron() {
|
|
// Renderer process
|
|
if (typeof window !== 'undefined' && typeof window.process === 'object' && window.process.type === 'renderer') {
|
|
return true;
|
|
}
|
|
|
|
// Main process
|
|
if (typeof process !== 'undefined' && typeof process.versions === 'object' && !!process.versions.electron) {
|
|
return true;
|
|
}
|
|
|
|
// Detect the user agent when the `nodeIntegration` option is set to true
|
|
if (typeof navigator === 'object' && typeof navigator.userAgent === 'string' && navigator.userAgent.indexOf('Electron') >= 0) {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
function initElectron() {
|
|
const navEl = document.getElementById('sidenav');
|
|
|
|
// remove links
|
|
navEl.removeChild( document.querySelector('#admin-side-link'));
|
|
navEl.removeChild( document.querySelector('#logout-side-link'));
|
|
|
|
// add link to edit server
|
|
navEl.innerHTML += `<div class="side-nav-item my-waves" onclick="changeView(openEditModal, this);">
|
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" height="24" width="24" fill="#FFF"><path d="M0 0h24v24H0z" fill="none"/><path d="M3 3h8v8H3zm10 0h8v8h-8zM3 13h8v8H3zm15 0h-2v3h-3v2h3v3h2v-3h3v-2h-3z"/></svg>
|
|
<span>Edit Server</span>
|
|
</div>`;
|
|
|
|
// check if server
|
|
if (!MSTREAMAPI.currentServer.host) {
|
|
openEditModal();
|
|
}else {
|
|
loadFileExplorer();
|
|
init();
|
|
}
|
|
// if not edit server panel
|
|
}
|
|
|
|
if (isElectron()) {
|
|
initElectron();
|
|
} else {
|
|
init();
|
|
loadFileExplorer();
|
|
}
|