"use strict";
// SPDX-License-Identifier: GPL-3.0-or-later
// myMPD (c) 2018-2024 Juergen Mang <mail@jcgames.de>
// https://github.com/jcorporation/mympd
/** @module Playback_js */
/**
* Handles Playback
* @returns {void}
*/
function handlePlayback() {
sendAPI("MYMPD_API_PLAYER_CURRENT_SONG", {}, parseCurrentSong, false);
}
/**
* Initializes the playback html elements
* @returns {void}
*/
function initViewPlayback() {
elGetById('PlaybackListTags').addEventListener('click', function(event) {
if (event.target.nodeName === 'P' ||
event.target.nodeName === 'SPAN')
{
gotoBrowse(event);
}
}, false);
}
/**
* Parses the MYMPD_API_PLAYER_CURRENT_SONG jsonrpc response
* @param {object} obj jsonrpc response
* @returns {void}
*/
function parseCurrentSong(obj) {
const list = elGetById('PlaybackList');
unsetUpdateView(list);
const textNotification = [];
const pageTitle = [];
if (isEmptyTag(obj.result.Title) === false) {
textNotification.push(obj.result.Title);
}
mediaSessionSetMetadata(obj.result.Title, obj.result.Artist, obj.result.Album, obj.result.uri);
setCurrentCover(obj.result.uri);
const footerAlbumEl = elGetById('footerAlbum');
const footerArtistEl = elGetById('footerArtist');
const footerTitleEl = elGetById('footerTitle');
const footerCoverEl = elGetById('footerCover');
const footerDividerEl = elGetById('footerDivider');
const PlaybackTitleEl = elGetById('PlaybackTitle');
const PlaybackCoverEl = elGetById('PlaybackCover');
for (const el of [footerTitleEl, footerArtistEl, footerAlbumEl, footerCoverEl,
PlaybackTitleEl, PlaybackCoverEl])
{
el.classList.remove('clickable');
}
if (isEmptyTag(obj.result.Artist) === false) {
const artists = joinArray(obj.result.Artist);
textNotification.push(artists);
pageTitle.push(artists);
footerArtistEl.textContent = artists;
setData(footerArtistEl, 'name', obj.result.Artist);
footerArtistEl.classList.add('clickable');
}
else {
elClear(footerArtistEl);
setData(footerArtistEl, 'name', ['']);
}
if (isEmptyTag(obj.result.Album) === false) {
textNotification.push(obj.result.Album);
footerAlbumEl.textContent = obj.result.Album;
setData(footerAlbumEl, 'name', obj.result.Album);
setData(footerAlbumEl, 'AlbumId', obj.result.AlbumId);
footerAlbumEl.classList.add('clickable');
footerAlbumEl.setAttribute('data-tag', 'Album');
footerDividerEl.classList.remove('d-none');
}
else if (isEmptyTag(obj.result.Album) === true &&
isEmptyTag(obj.result.Name) === false)
{
footerAlbumEl.textContent = obj.result.Name;
footerAlbumEl.setAttribute('data-tag', 'undefined');
footerDividerEl.classList.add('d-none');
}
else {
elClear(footerAlbumEl);
setData(footerAlbumEl, 'name', '');
setData(footerAlbumEl, 'AlbumId', '');
footerAlbumEl.setAttribute('data-tag', 'undefined');
footerDividerEl.classList.add('d-none');
}
if (isEmptyTag(obj.result.Title) === false) {
pageTitle.push(obj.result.Title);
PlaybackTitleEl.textContent = obj.result.Title;
setData(PlaybackTitleEl, 'uri', obj.result.uri);
footerTitleEl.textContent = obj.result.Title;
footerCoverEl.classList.add('clickable');
PlaybackTitleEl.classList.add('clickable');
PlaybackCoverEl.classList.add('clickable');
}
else {
if (currentState.songPos === -1) {
PlaybackTitleEl.textContent = tn('Not playing');
footerTitleEl.textContent = tn('Not playing');
}
else {
elClear(PlaybackTitleEl);
elClear(footerTitleEl);
}
setData(PlaybackTitleEl, 'uri', '');
}
document.title = 'myMPD: ' + pageTitle.join(smallSpace + nDash + smallSpace);
footerCoverEl.title = pageTitle.join(smallSpace + nDash + smallSpace);
if (isValidUri(obj.result.uri) === true &&
isStreamUri(obj.result.uri) === false)
{
// valid uri and not a stream
footerTitleEl.classList.add('clickable');
PlaybackTitleEl.classList.add('clickable');
}
if (obj.result.uri !== undefined) {
obj.result['Filetype'] = filetype(obj.result.uri, true);
elEnableId('PlaybackAddToPlaylist');
}
else {
obj.result['Filetype'] = '';
elDisableId('PlaybackAddToPlaylist');
}
if (features.featStickers === true) {
const PlaybackSongFeedbackEl = elGetById('PlaybackSongFeedback').firstElementChild;
const PlaybackSongStickerEl = elGetById('PlaybackSongSticker');
setData(PlaybackSongFeedbackEl, 'uri', obj.result.uri);
if (isValidUri(obj.result.uri) === false ||
isStreamUri(obj.result.uri) === true)
{
elDisableBtnGroup(PlaybackSongFeedbackEl);
elDisableBtnGroup(PlaybackSongStickerEl);
}
else {
elEnableBtnGroup(PlaybackSongFeedbackEl);
elEnableBtnGroup(PlaybackSongStickerEl);
}
setFeedback(PlaybackSongFeedbackEl, obj.result.like, obj.result.rating);
}
setPlaybackCardTags(obj.result);
const bookletEl = elGetById('PlaybackBooklet');
elClear(bookletEl);
if (isEmptyTag(obj.result.bookletPath) === false) {
bookletEl.appendChild(
elCreateText('span', {"class": ["mi", "me-2"]}, 'description')
);
bookletEl.appendChild(
elCreateTextTn('a', {"target": "_blank", "href": myEncodeURI(subdir + obj.result.bookletPath)}, 'Booklet')
);
}
const infoTxtEl = elGetById('PlaybackInfoTxt');
elClear(infoTxtEl);
if (isEmptyTag(obj.result.infoTxtPath) === false) {
infoTxtEl.appendChild(
elCreateText('span', {"class": ["mi", "me-2"]}, 'article')
);
infoTxtEl.appendChild(
elCreateTextTn('span', {"href": myEncodeURI(subdir + obj.result.infoTxtPath)}, 'Album info')
);
setData(infoTxtEl, 'uri', obj.result.infoTxtPath);
}
else {
rmData(infoTxtEl, 'uri');
}
//update queue card
queueSetCurrentSong();
//update title in queue view for streams
const playingTr = elGetById('queueSongId' + obj.result.currentSongId);
if (playingTr !== null) {
const titleCol = playingTr.querySelector('[data-col=Title');
if (titleCol !== null) {
titleCol.textContent = getDisplayTitle(obj.result.Name, obj.result.Title);
}
setData(playingTr, 'name', obj.result.Title);
}
if (currentState.state === 'play') {
//check if song has really changed
if (currentSongObj === null ||
currentSongObj.Title !== obj.result.Title ||
currentSongObj.uri !== obj.result.uri)
{
showNotification(textNotification.join('\n'), 'player', 'info');
}
}
setScrollViewHeight(list);
//remember current song
currentSongObj = obj.result;
}
/**
* Sets the values of the tags displayed in the playback view
* @param {object} songObj song object (result object of MYMPD_API_PLAYER_CURRENT_SONG jsonrpc response)
* @returns {void}
*/
function setPlaybackCardTags(songObj) {
if (songObj.webradio === undefined) {
elHideId('PlaybackListWebradio');
elShowId('PlaybackListTags');
for (const col of settings.viewPlayback.fields) {
const c = elGetById('current' + col);
if (c === null) {
continue;
}
switch(col) {
case 'Lyrics':
getLyrics(songObj.uri, c.querySelector('p'));
break;
case 'AudioFormat':
//songObj has no audioformat definition - use current state
elReplaceChild(c.querySelector('p'), printValue('AudioFormat', currentState.AudioFormat));
break;
default: {
const value = songObj[col];
const valueEl = c.querySelector('p');
elReplaceChild(valueEl, printValue(col, value, songObj));
if (isEmptyTag(value) === true ||
settings.tagListBrowse.includes(col) === false)
{
valueEl.classList.remove('clickable');
}
else {
valueEl.classList.add('clickable');
}
setData(c, 'name', value);
if (col === 'Album') {
setData(c, 'AlbumId', songObj.AlbumId);
}
}
}
}
const mbField = addMusicbrainzFields(songObj, true);
if (mbField !== null) {
elReplaceChildId('currentMusicbrainz', mbField);
}
else {
elClearId('currentMusicbrainz');
}
}
else {
//webradio info
const PlaybackListWebradio = elGetById('PlaybackListWebradio');
elShow(PlaybackListWebradio);
elHideId('PlaybackListTags');
const webradioName = elCreateText('p', {"class": ["clickable"]}, songObj.webradio.Name);
if (songObj.webradio.Type === 'webradiodb') {
setData(webradioName, 'href', {"cmd": "showWebradiodbDetails", "options": [songObj.webradio.StreamUri]});
}
else {
setData(webradioName, 'href', {"cmd": "editRadioFavorite", "options": [songObj.webradio.StreamUri]});
}
webradioName.addEventListener('click', function(event) {
parseCmd(event, getData(event.target, 'href'));
}, false);
elReplaceChild(PlaybackListWebradio,
elCreateNodes('div', {"class": ["col-xl-6"]}, [
elCreateTextTn('small', {}, 'Webradio'),
webradioName
])
);
PlaybackListWebradio.appendChild(
elCreateNodes('div', {"class": ["col-xl-6"]}, [
elCreateTextTn('small', {}, 'Genres'),
elCreateText('p', {}, joinArray(songObj.webradio.Genres))
])
);
PlaybackListWebradio.appendChild(
elCreateNodes('div', {"class": ["col-xl-6"]}, [
elCreateTextTn('small', {}, 'Country'),
elCreateText('p', {}, songObj.webradio.Country +
(songObj.webradio.State !== '' && songObj.webradio.State !== undefined ? smallSpace + nDash + smallSpace + songObj.webradio.State : ''))
])
);
PlaybackListWebradio.appendChild(
elCreateNodes('div', {"class": ["col-xl-6"]}, [
elCreateTextTn('small', {}, 'Languages'),
elCreateText('p', {}, joinArray(songObj.webradio.Languages))
])
);
if (songObj.webradio.Homepage !== '') {
PlaybackListWebradio.appendChild(
elCreateNodes('div', {"class": ["col-xl-6"]}, [
elCreateTextTn('small', {}, 'Homepage'),
elCreateNode('p', {},
printValue('homepage', songObj.webradio.Homepage)
)
])
);
}
if (songObj.webradio.Codec !== '' &&
songObj.webradio.Codec !== undefined)
{
PlaybackListWebradio.appendChild(
elCreateNodes('div', {"class": ["col-xl-6"]}, [
elCreateTextTn('small', {}, 'Format'),
elCreateText('p', {}, songObj.webradio.Codec +
(songObj.webradio.Bitrate !== ''
? ' / ' + songObj.webradio.Bitrate + ' ' + tn('kbit')
: ''
)
)
])
);
}
if (songObj.webradio.Description !== '') {
PlaybackListWebradio.appendChild(
elCreateNodes('div', {"class": ["col-xl-6"]}, [
elCreateTextTn('small', {}, 'Description'),
elCreateText('p', {}, songObj.webradio.Description)
])
);
}
}
}
/**
* Handler for the PlaybackTitle element click event
* @returns {void}
*/
//eslint-disable-next-line no-unused-vars
function clickTitle() {
const uri = getDataId('PlaybackTitle', 'uri');
if (isValidUri(uri) === true &&
isStreamUri(uri) === false)
{
songDetails(uri);
}
}
/**
* Adds the current playing song to a playlist
* @returns {void}
*/
//eslint-disable-next-line no-unused-vars
function showAddToPlaylistCurrentSong() {
const uri = getDataId('PlaybackTitle', 'uri');
if (uri !== '') {
showAddToPlaylist('song', [uri]);
}
}
/**
* Shows the edit sticker modal for the current song
* @param {Event} event triggering click event
* @returns {void}
*/
//eslint-disable-next-line no-unused-vars
function showCurrentSongSticker(event) {
event.preventDefault();
showStickerModal(currentSongObj.uri, 'song');
}