~hristoast/mousikofidi

3d9e1a3f0c32c7f731b00330e0a8b8c4ce696250 — Hristos N. Triantafillou 9 months ago c22254d
Try to display cover art (#8)

Make several assumptions in order to try and show what the album art
is for the particular directory or file.
A example/MousikoFidi Sample Cover Art.png => example/MousikoFidi Sample Cover Art.png +1 -0
@@ 0,0 1,1 @@
../mousikofidi/static/fidi.png
\ No newline at end of file

M example/fidi.yml => example/fidi.yml +2 -0
@@ 1,5 1,7 @@
config:
  cover_art: true
  favicon_path: /fidi.png
  holidays: true
  icons: false
  logo_path: /fidi.png
  music_dirs:

M mousikofidi/mousikofidi.py => mousikofidi/mousikofidi.py +58 -0
@@ 209,6 209,7 @@ def browse_dir(context: dict, unescaped_path: str) -> dict:
    for d in context["music_dirs"]:
        music_dirs.append(d["raw"])

    context["cover_art"] = select_cover_art(unescaped_path)
    context["file_list"] = file_list
    context["page_name"] = unescaped_path
    context["page_path"] = breadcrumb_links_from_path(unescaped_path, music_dirs)


@@ 255,6 256,7 @@ def browse_file(context: dict, unescaped_path: str) -> dict:
            # A given track may have any or none of the above tags.
            pass

    context["cover_art"] = select_cover_art(unescaped_path)
    context["page_name"] = metadata["title"] or file_name
    context["escaped_path"] = quote(unescaped_path)
    context["unescaped_path"] = unescaped_path


@@ 360,6 362,17 @@ def init(

    # TODO: A more DRY way to handle checking for configs
    try:
        if c["config"]["cover_art"].lower() == "true":
            c["config"]["cover_art"] = True
        else:
            c["config"]["cover_art"] = False
    except KeyError:
        wrn(
            "No 'cover_art' value was found in the configuration file!  Defaulting to on..."
        )
        c["config"]["cover_art"] = True

    try:
        if c["config"]["holidays"].lower() == "true":
            c["config"]["holidays"] = True
        else:


@@ 1005,6 1018,45 @@ def search_files(q: str, only_audio: bool, only_video: bool) -> list:
    return hits


def select_cover_art(path: str) -> str:
    if not app.fidiConfig["config"]["cover_art"]:
        return None

    cover_art = None

    image_exts = ("jpg", "jpeg", "png")
    images = []

    if os.path.isfile(path):
        _dir = os.path.dirname(path)

    elif os.path.isdir(path):
        _dir = path

    for filename in os.listdir(_dir):
        for ext in image_exts:
            if filename.endswith(ext):
                images.append(filename)

    if len(images) == 1:
        cover_art = os.path.join(_dir, images[0])

    for img in images:

        _img = img.lower()
        if "cover" in _img or "folder" in _img or "front" in _img or "cover" in _img:
            cover_art = os.path.join(_dir, img)
            break

    if cover_art:
        return "/serve/" + quote(cover_art)

    elif images:
        return "/serve/" + quote(os.path.join(_dir, images[0]))

    wrn("No cover art found for dir: " + path)


def select_logo(config: dict, item: str, fakenow=None) -> str:
    # Don't spoil a user's custom settings
    if config["config"]["favicon_path"] != "/fidi.png":


@@ 1357,6 1409,12 @@ def serve_file(path):
        mimetype = "video/mp4"
    elif filename.endswith(".webm"):
        mimetype = "video/webm"
    elif filename.endswith(".jpg"):
        mimetype = "image/jpeg"
    elif filename.endswith(".jpeg"):
        mimetype = "image/jpeg"
    elif filename.endswith(".png"):
        mimetype = "image/png"
    else:
        return send_from_directory(dirname, filename)
    return send_from_directory(dirname, filename, mimetype=mimetype)

M mousikofidi/static/js/player.js => mousikofidi/static/js/player.js +22 -0
@@ 65,6 65,7 @@ var iconsEnabled = document.getElementById("icons-enabled");
var theaterViewButton = document.getElementById("video-theater-view");
var audioFollowCheckbox = document.getElementById("follow-track");
var audioFollowCheckboxMobile = document.getElementById("mobile-follow-track");
var coverArt = document.getElementById("cover-art");

function playAudio(targetArrow, dontPlay) {
    /*


@@ 737,6 738,24 @@ function theaterViewListener() {
}


function coverArtClickListener() {
    stat = this.getAttribute("data-stat");

    if (stat === "off") {
        this.style.width = "100%";
        this.setAttribute("data-stat", "full");

    } else if (stat === "full") {
        this.style.width = "50%";
        this.setAttribute("data-stat", "half");

    } else if (stat === "half") {
        this.style.width = "initial";
        this.setAttribute("data-stat", "off");
    }
}


function setUp() {
    /*
      MousikóFídi playlist player main entry point.


@@ 831,6 850,9 @@ function setUp() {
    if (theaterViewButton)
        theaterViewButton.addEventListener("click", theaterViewListener);

    if (coverArt)
        coverArt.addEventListener("click", coverArtClickListener);

}

window.onload = setUp();

M mousikofidi/static/js/player.min.js => mousikofidi/static/js/player.min.js +1 -1
@@ 1,1 1,1 @@
var audio=document.getElementById("audio");var audioNowPlayingTextP=document.getElementById("now-playing");var videoNowPlayingTextP=document.getElementById("video-now-playing");var nowPlayingNumDiv=document.getElementById("now-playing-num");var audioPlaybackEndedDiv=document.getElementById("audio-playback-ended");var videoPlaybackEndedDiv=document.getElementById("video-playback-ended");var videoNowPlayingNumDiv=document.getElementById("video-now-playing-num");var pageTitle=document.getElementById("title");var playArrows=document.getElementsByClassName("play-arrow");var playingTitleSpan=document.getElementById("playing-title");var videoPlayingTitleSpan=document.getElementById("video-playing-title");var playlist=document.getElementById("playlist");if(playlist){var tracks=playlist.getElementsByClassName("title")}var video=document.getElementById("video");var videoArrows=document.getElementsByClassName("video-arrow");var videoPlaylist=document.getElementById("video-playlist");if(videoPlaylist){var videoTracks=videoPlaylist.getElementsByClassName("video-title")}else{if(playlist){var videoTracks=playlist.getElementsByClassName("video-title")}}var prevBtn=document.getElementById("prev");var nextBtn=document.getElementById("next");var repeatBtn=document.getElementById("repeat");var shuffleBtn=document.getElementById("shuffle");var prevBtnMobile=document.getElementById("mobile-prev");var nextBtnMobile=document.getElementById("mobile-next");var repeatBtnMobile=document.getElementById("mobile-repeat");var shuffleBtnMobile=document.getElementById("mobile-shuffle");var randomOrderHolder=document.getElementById("randorder");var videoPrevBtn=document.getElementById("vid-prev");var videoNextBtn=document.getElementById("vid-next");var videoRepeatBtn=document.getElementById("vid-repeat");var videoShuffleBtn=document.getElementById("vid-shuffle");var videoPrevBtnMobile=document.getElementById("mobile-vid-prev");var videoNextBtnMobile=document.getElementById("mobile-vid-next");var videoRepeatBtnMobile=document.getElementById("mobile-vid-repeat");var videoShuffleBtnMobile=document.getElementById("mobile-vid-shuffle");var videoRandomOrderHolder=document.getElementById("vid-randorder");var params=new URLSearchParams(window.location.search);var single=document.getElementById("single");var singleLinkButton=document.getElementById("time-link");var audioLinkButton=document.getElementById("audio-time-link");var videoLinkButton=document.getElementById("video-time-link");var iconsEnabled=document.getElementById("icons-enabled");var theaterViewButton=document.getElementById("video-theater-view");var audioFollowCheckbox=document.getElementById("follow-track");var audioFollowCheckboxMobile=document.getElementById("mobile-follow-track");function playAudio(b,d){if(b){var h=b.getAttribute("data-browse")}else{return false}var n=h.replace("browse","serve");var f=pageTitle.getAttribute("data-sitename");var m=b.getAttribute("data-num");var i=b.getAttribute("data-title");var j="Now Playing: "+i+" | "+f;var e=shuffleBtn.getAttribute("data-stat");var l=shuffleBtnMobile.getAttribute("data-stat");var a=window.getComputedStyle(document.getElementsByClassName("mobile-hide")[0])["display"]==="none";var k;if(audio.src.endsWith(n)!==true){audio.src=n}if(typeof d==="undefined"){audio.play()}nowPlayingNumDiv.setAttribute("data-nowplaying-num",m);if(a===false){k=audioFollowCheckbox.checked===true}else{k=audioFollowCheckboxMobile.checked===true}if(k){var g=document.getElementById(b.id+"-target");g.scrollIntoView({block:"start",behavior:"smooth"})}if((e==="on")||(l==="on")){setRandomOrder("audio")}}function playAudioClickListener(){audioPlaybackEndedDiv.setAttribute("data-playback-ended","false");playAudio(this)}function playVideo(g,a){if(g){var f=g.getAttribute("data-browse")}else{return false}var h=f.replace("browse","serve");var e=videoShuffleBtn.getAttribute("data-stat");var d=videoShuffleBtnMobile.getAttribute("data-stat");var b=g.getAttribute("data-num");if(typeof a==="undefined"){video.src=h;video.play()}videoNowPlayingNumDiv.setAttribute("data-nowplaying-num",b);video.scrollIntoView({block:"start",behavior:"smooth"});if((e==="on")||(d==="on")){setRandomOrder("video")}}function playVideoClickListener(){videoPlaybackEndedDiv.setAttribute("data-playback-ended","false");playVideo(this)}function randInt(a){return Math.floor(Math.random()*a)}function setRandomOrder(e){if(e==="audio"){var b=playArrows;var f=randomOrderHolder.getAttribute("data-randorder");var g=randomOrderHolder}else{if(e==="video"){var b=videoArrows;var f=videoRandomOrderHolder.getAttribute("data-randorder");var g=videoRandomOrderHolder}}var h=randomizeTrackOrder(b.length,e);var d=randomStringFromArray(h);if(f==="none"){g.setAttribute("data-randorder",d)}else{if(f===d){while(f===d){var a=randomizeTrackOrder(b.length,e);d=randomStringFromArray(a)}}else{g.setAttribute("data-randorder",d)}}}function endedTrackListener(y,m){if(m==="audio"){var n=playArrows;var i=nowPlayingNumDiv.getAttribute("data-nowplaying-num");var e=randomOrderHolder;var v=audioPlaybackEndedDiv;var g=playAudio;var s=repeatBtn.getAttribute("data-stat");var w=repeatBtnMobile.getAttribute("data-stat");var a=((s=="one")||(w=="one"));var k=((s=="all")||(w=="all"));var u=shuffleBtn.getAttribute("data-stat");var x=shuffleBtnMobile.getAttribute("data-stat");var h=((u=="on")||(x=="on"))}else{if(m==="video"){var n=videoArrows;var i=videoNowPlayingNumDiv.getAttribute("data-nowplaying-num");var e=videoRandomOrderHolder;var v=videoPlaybackEndedDiv;var g=playVideo;var s=videoRepeatBtn.getAttribute("data-stat");var w=videoRepeatBtnMobile.getAttribute("data-stat");var j=((s=="on")||(w=="on"));var u=videoShuffleBtn.getAttribute("data-stat");var x=videoShuffleBtnMobile.getAttribute("data-stat");var h=((u=="on")||(x=="on"))}}var z=(v.getAttribute("data-playback-ended")==="true");var b=n.length-1;if(a){g(n[i])}else{if(h){if(z){return}else{var r=e.getAttribute("data-randorder");var o=r.split(",");var q=o.shift();if((o!="")&&(q!=="undefined")){g(n[q]);var p=randomStringFromArray(o);e.setAttribute("data-randorder",p)}else{if((k)&&(q==="undefined")){var d=randInt(b);g(n[d]);setRandomOrder(m)}else{var l=g(n[q]);if(k){setRandomOrder(m);var f=e.getAttribute("data-randorder");var t=f.split(",");g(n[t[0]])}else{v.setAttribute("data-playback-ended","true")}}}}}else{if(h===false){if(i<b){i++;g(n[i])}else{if(k){g(n[0])}else{if((a===false)&&k===false){}}}}}}}function endedAudioListener(){endedTrackListener(this,"audio")}function endedVideoListener(){endedTrackListener(this,"video")}function skipTrack(j,r){var f=j.getAttribute("data-cmd");if(r==="audio"){var o=playArrows;var e=nowPlayingNumDiv.getAttribute("data-nowplaying-num");var i=randomOrderHolder;var n=playAudio;var k=shuffleBtn.getAttribute("data-stat");var p=shuffleBtnMobile.getAttribute("data-stat");var q=tracks}else{if(r==="video"){var o=videoArrows;var e=videoNowPlayingNumDiv.getAttribute("data-nowplaying-num");var i=videoRandomOrderHolder;var n=playVideo;var k=videoShuffleBtn.getAttribute("data-stat");var p=videoShuffleBtnMobile.getAttribute("data-stat");var q=videoTracks}}var h=q.length-1;if((k==="on")||(p==="on")){var l=i.getAttribute("data-randorder");var g=l.split(",");if(g.length>0){var b=g.shift();var m=o[b];if(typeof(m)==="undefined"){var d=randInt(q.length);n(o[d]);setRandomOrder(r)}else{n(m);var a=randomStringFromArray(g);i.setAttribute("data-randorder",a)}}else{if(repeat==="all"){var d=randInt(q.length);n(o[d]);setRandomOrder(r)}}}else{if(k==="off"){if(f==="fwd"){if(e<h){e++;n(o[e])}else{n(o[0])}}else{if(f==="prev"){if(e>0){e--;n(o[e])}else{n(o[h])}}}}}}function skipAudioListener(){skipTrack(this,"audio")}function skipVideoListener(){skipTrack(this,"video")}function toggleRepeat(b){var a=b.getAttribute("data-stat");if(a==="off"){b.setAttribute("data-stat","one");b.textContent="Repeat One ";if(iconsEnabled){b.appendChild(document.createElement("i"));b.childNodes[1].classList.add("fas","fa-redo");b.style.paddingTop="9px";b.style.paddingRight="15px";b.style.paddingBottom="9px";b.style.paddingLeft="15px"}}else{if(a==="one"){b.setAttribute("data-stat","all");b.textContent="Repeat All";if(iconsEnabled){b.appendChild(document.createElement("span"));b.childNodes[1].classList.add("fa-stack");b.childNodes[1].appendChild(document.createElement("i"));b.childNodes[1].appendChild(document.createElement("i"));b.childNodes[1].childNodes[0].classList.add("fas","fa-redo","fa-stack-1x");b.childNodes[1].childNodes[1].classList.add("fas","fa-infinity","fa-stack-1x");b.childNodes[1].childNodes[1].style.fontSize="0.4em";b.style.marginBottom="0";b.style.paddingTop="5px";b.style.paddingRight="5px";b.style.paddingBottom="5px";b.style.paddingLeft="15px"}}else{if(a==="all"){b.setAttribute("data-stat","off");b.textContent="No Repeat";if(iconsEnabled){b.appendChild(document.createElement("span"));b.childNodes[1].classList.add("fa-stack");b.childNodes[1].appendChild(document.createElement("i"));b.childNodes[1].appendChild(document.createElement("i"));b.childNodes[1].childNodes[0].classList.add("fas","fa-redo","fa-stack-1x");b.childNodes[1].childNodes[1].classList.add("fas","fa-slash","fa-stack-1x");b.style.marginBottom="0";b.style.paddingTop="5px";b.style.paddingRight="5px";b.style.paddingBottom="5px";b.style.paddingLeft="15px"}}}}}function toggleRepeatListener(){toggleRepeat(this)}function randomizeTrackOrder(d,f){if(f==="audio"){var b=nowPlayingNumDiv.getAttribute("data-nowplaying-num")}else{if(f==="video"){var b=videoNowPlayingNumDiv.getAttribute("data-nowplaying-num")}}var a=0;var g=[];while(g.length<d-1){var e=randInt(d);while(e==b){e=randInt(d)}if(g.indexOf(e)===-1){g.push(e)}}return g}function randomStringFromArray(b){if(b==="none"){return}var a="";for(c=0;c<b.length;c++){a+=b[c];if(c<b.length-1){a+=","}}return a}function toggleShuffle(d,b){var a=d.getAttribute("data-stat");if(a==="off"){setRandomOrder(b);d.setAttribute("data-stat","on");d.textContent="Shuffle On ";if(iconsEnabled){d.appendChild(document.createElement("i"));d.childNodes[1].classList.add("fas","fa-random");d.style.paddingTop="9px";d.style.paddingRight="15px";d.style.paddingBottom="9px";d.style.paddingLeft="15px"}}else{if(a==="on"){d.setAttribute("data-stat","off");d.textContent="Shuffle Off";if(iconsEnabled){d.appendChild(document.createElement("span"));d.childNodes[1].classList.add("fa-stack");d.childNodes[1].appendChild(document.createElement("i"));d.childNodes[1].appendChild(document.createElement("i"));d.childNodes[1].childNodes[0].classList.add("fas","fa-random","fa-stack-1x");d.childNodes[1].childNodes[1].classList.add("fas","fa-slash","fa-stack-1x");d.style.marginBottom="0";d.style.paddingTop="5px";d.style.paddingRight="5px";d.style.paddingBottom="5px";d.style.paddingLeft="15px"}}}}function toggleShuffleAudioListener(){toggleShuffle(this,"audio")}function toggleShuffleVideoListener(){toggleShuffle(this,"video")}function paused(d,g,f){if(f==="audio"){var b=audioNowPlayingTextP;var a=nowPlayingNumDiv.getAttribute("data-nowplaying-num");var e=playArrows[a].getAttribute("data-title");var h=pageTitle.getAttribute("data-sitename")}else{if(f==="video"){var b=videoNowPlayingTextP;var a=videoNowPlayingNumDiv.getAttribute("data-nowplaying-num");var e=videoArrows[a].getAttribute("data-title")}}if(g==="playing"){if(f==="audio"){pageTitle.textContent="Now Playing: "+e+" | "+h}b.textContent="Now Playing: ";b.appendChild(document.createElement("span"));b.childNodes[1].onclick=function(){var i=document.getElementById(playArrows[a].id+"-target");i.scrollIntoView({block:"start",behavior:"smooth"})};b.childNodes[1].style.fontWeight="bold";b.childNodes[1].textContent=e}else{if(g==="paused"){if(f==="audio"){pageTitle.textContent="Paused: "+e+" | "+h}b.textContent="Paused: ";b.appendChild(document.createElement("span"));b.childNodes[1].onclick=function(){var i=document.getElementById(playArrows[a].id+"-target");i.scrollIntoView({block:"start",behavior:"smooth"})};b.childNodes[1].style.fontWeight="bold";b.childNodes[1].textContent=e}}}function playingAudioHandler(){paused(this,"playing","audio")}function pausedAudioHandler(){paused(this,"paused","audio")}function playingVideoHandler(){paused(this,"playing","video")}function pausedVideoHandler(){paused(this,"paused","video")}function giveLink(f){var d;var e;var h;var g;if(f==="audio"){g=audio}else{if(f==="video"){g=video}else{if(f==="single"){g=single}}}var b=window.location.protocol+"//"+window.location.host+window.location.pathname+"?t="+Math.floor(g.currentTime);if(f==="audio"){d=playArrows;e=nowPlayingNumDiv.getAttribute("data-nowplaying-num");h="&a="}else{if(f==="video"){d=videoArrows;e=videoNowPlayingNumDiv.getAttribute("data-nowplaying-num");h="&v="}}if(d){var a=d[e].getAttribute("id");b+=h+a}if(f==="video"){b+="#videoplayer"}var i=document.createElement("textarea");i.value=b;document.body.appendChild(i);i.select();document.execCommand("copy");document.body.removeChild(i);return b}function singleLinkListener(){giveLink("single")}function audioLinkListener(){giveLink("audio")}function videoLinkListener(){giveLink("video")}function seekTrack(){var a=params.get("a");var b=params.get("v");var d=params.get("t");if((a===null)&&(b===null)){single.currentTime=d;single.autoplay=true}else{if(a){playAudio(playArrows.namedItem(a));audio.currentTime=d;audio.autoplay=true}if(b){playVideo(videoArrows.namedItem(b));video.currentTime=d;video.autoplay=true}}}function toggletheaterView(d){var a=document.getElementsByTagName("body")[0];var e=((document.getElementById("current-theme").getAttribute("data-theme")==="/css/water/light.standalone")||(document.getElementById("current-theme").getAttribute("data-theme")==="/css/water/dark.standalone"));var b=d.getAttribute("data-stat")==="on";if(b){d.setAttribute("data-stat","off");d.textContent="Theater View: Off";if(e){a.style.maxWidth="800px"}if(iconsEnabled){d.appendChild(document.createElement("span"));d.childNodes[1].classList.add("fa-stack");d.childNodes[1].appendChild(document.createElement("i"));d.childNodes[1].appendChild(document.createElement("i"));d.childNodes[1].childNodes[0].classList.add("fas","fa-theater-masks","fa-stack-1x");d.childNodes[1].childNodes[1].classList.add("fas","fa-slash","fa-stack-1x");d.style.marginBottom="0";d.style.paddingTop="5px";d.style.paddingRight="5px";d.style.paddingBottom="5px";d.style.paddingLeft="15px"}}else{d.setAttribute("data-stat","on");d.textContent="Theater View: On ";if(e){a.style.maxWidth="100%"}if(iconsEnabled){d.appendChild(document.createElement("i"));d.childNodes[1].classList.add("fas","fa-theater-masks");d.style.paddingTop="9px";d.style.paddingRight="15px";d.style.paddingBottom="9px";d.style.paddingLeft="15px"}}window.location.href="#videoplayer"}function theaterViewListener(){toggletheaterView(this)}function setUp(){var i=0;if(nowPlayingNumDiv){var d=nowPlayingNumDiv.getAttribute("data-nowplaying-num")}var h=pageTitle.getAttribute("data-sitename");if(playArrows.length>0){var e=playArrows[0].getAttribute("data-title");var a="Paused: "+e+" | "+h}if(tracks){for(c=0;c<playArrows.length;c++){var f=playArrows.item(c);f.addEventListener("click",playAudioClickListener);f.setAttribute("data-num",c)}}if(audio){audio.src=playArrows[i].getAttribute("data-browse").replace("browse","serve");playingTitleSpan.onclick=function(){var j=document.getElementById(playArrows[i].id+"-target");j.scrollIntoView({block:"start",behavior:"smooth"})};playingTitleSpan.textContent=e;title.textContent=a;audio.addEventListener("ended",endedAudioListener);audio.addEventListener("playing",playingAudioHandler);audio.addEventListener("pause",pausedAudioHandler);prevBtn.addEventListener("click",skipAudioListener);nextBtn.addEventListener("click",skipAudioListener);repeatBtn.addEventListener("click",toggleRepeatListener);shuffleBtn.addEventListener("click",toggleShuffleAudioListener);prevBtnMobile.addEventListener("click",skipAudioListener);nextBtnMobile.addEventListener("click",skipAudioListener);repeatBtnMobile.addEventListener("click",toggleRepeatListener);shuffleBtnMobile.addEventListener("click",toggleShuffleAudioListener)}if(videoTracks){for(c=0;c<videoArrows.length;c++){var b=videoArrows.item(c);b.addEventListener("click",playVideoClickListener);b.setAttribute("data-num",c)}}if(videoArrows.length>0){var g=videoArrows[0].getAttribute("data-title")}if(video){video.src=videoArrows[i].getAttribute("data-browse").replace("browse","serve");videoPlayingTitleSpan.textContent=g;video.addEventListener("ended",endedVideoListener);video.addEventListener("playing",playingVideoHandler);video.addEventListener("pause",pausedVideoHandler);videoPrevBtn.addEventListener("click",skipVideoListener);videoNextBtn.addEventListener("click",skipVideoListener);videoRepeatBtn.addEventListener("click",toggleRepeatListener);videoShuffleBtn.addEventListener("click",toggleShuffleVideoListener);videoPrevBtnMobile.addEventListener("click",skipVideoListener);videoNextBtnMobile.addEventListener("click",skipVideoListener);videoRepeatBtnMobile.addEventListener("click",toggleRepeatListener);videoShuffleBtnMobile.addEventListener("click",toggleShuffleVideoListener)}if(singleLinkButton){singleLinkButton.addEventListener("click",singleLinkListener)}if(audioLinkButton){audioLinkButton.addEventListener("click",audioLinkListener)}if(videoLinkButton){videoLinkButton.addEventListener("click",videoLinkListener)}if(params.has("t")){seekTrack()}if(theaterViewButton){theaterViewButton.addEventListener("click",theaterViewListener)}}window.onload=setUp();
\ No newline at end of file
var audio=document.getElementById("audio");var audioNowPlayingTextP=document.getElementById("now-playing");var videoNowPlayingTextP=document.getElementById("video-now-playing");var nowPlayingNumDiv=document.getElementById("now-playing-num");var audioPlaybackEndedDiv=document.getElementById("audio-playback-ended");var videoPlaybackEndedDiv=document.getElementById("video-playback-ended");var videoNowPlayingNumDiv=document.getElementById("video-now-playing-num");var pageTitle=document.getElementById("title");var playArrows=document.getElementsByClassName("play-arrow");var playingTitleSpan=document.getElementById("playing-title");var videoPlayingTitleSpan=document.getElementById("video-playing-title");var playlist=document.getElementById("playlist");if(playlist){var tracks=playlist.getElementsByClassName("title")}var video=document.getElementById("video");var videoArrows=document.getElementsByClassName("video-arrow");var videoPlaylist=document.getElementById("video-playlist");if(videoPlaylist){var videoTracks=videoPlaylist.getElementsByClassName("video-title")}else{if(playlist){var videoTracks=playlist.getElementsByClassName("video-title")}}var prevBtn=document.getElementById("prev");var nextBtn=document.getElementById("next");var repeatBtn=document.getElementById("repeat");var shuffleBtn=document.getElementById("shuffle");var prevBtnMobile=document.getElementById("mobile-prev");var nextBtnMobile=document.getElementById("mobile-next");var repeatBtnMobile=document.getElementById("mobile-repeat");var shuffleBtnMobile=document.getElementById("mobile-shuffle");var randomOrderHolder=document.getElementById("randorder");var videoPrevBtn=document.getElementById("vid-prev");var videoNextBtn=document.getElementById("vid-next");var videoRepeatBtn=document.getElementById("vid-repeat");var videoShuffleBtn=document.getElementById("vid-shuffle");var videoPrevBtnMobile=document.getElementById("mobile-vid-prev");var videoNextBtnMobile=document.getElementById("mobile-vid-next");var videoRepeatBtnMobile=document.getElementById("mobile-vid-repeat");var videoShuffleBtnMobile=document.getElementById("mobile-vid-shuffle");var videoRandomOrderHolder=document.getElementById("vid-randorder");var params=new URLSearchParams(window.location.search);var single=document.getElementById("single");var singleLinkButton=document.getElementById("time-link");var audioLinkButton=document.getElementById("audio-time-link");var videoLinkButton=document.getElementById("video-time-link");var iconsEnabled=document.getElementById("icons-enabled");var theaterViewButton=document.getElementById("video-theater-view");var audioFollowCheckbox=document.getElementById("follow-track");var audioFollowCheckboxMobile=document.getElementById("mobile-follow-track");var coverArt=document.getElementById("cover-art");function playAudio(b,d){if(b){var h=b.getAttribute("data-browse")}else{return false}var n=h.replace("browse","serve");var f=pageTitle.getAttribute("data-sitename");var m=b.getAttribute("data-num");var i=b.getAttribute("data-title");var j="Now Playing: "+i+" | "+f;var e=shuffleBtn.getAttribute("data-stat");var l=shuffleBtnMobile.getAttribute("data-stat");var a=window.getComputedStyle(document.getElementsByClassName("mobile-hide")[0])["display"]==="none";var k;if(audio.src.endsWith(n)!==true){audio.src=n}if(typeof d==="undefined"){audio.play()}nowPlayingNumDiv.setAttribute("data-nowplaying-num",m);if(a===false){k=audioFollowCheckbox.checked===true}else{k=audioFollowCheckboxMobile.checked===true}if(k){var g=document.getElementById(b.id+"-target");g.scrollIntoView({block:"start",behavior:"smooth"})}if((e==="on")||(l==="on")){setRandomOrder("audio")}}function playAudioClickListener(){audioPlaybackEndedDiv.setAttribute("data-playback-ended","false");playAudio(this)}function playVideo(g,a){if(g){var f=g.getAttribute("data-browse")}else{return false}var h=f.replace("browse","serve");var e=videoShuffleBtn.getAttribute("data-stat");var d=videoShuffleBtnMobile.getAttribute("data-stat");var b=g.getAttribute("data-num");if(typeof a==="undefined"){video.src=h;video.play()}videoNowPlayingNumDiv.setAttribute("data-nowplaying-num",b);video.scrollIntoView({block:"start",behavior:"smooth"});if((e==="on")||(d==="on")){setRandomOrder("video")}}function playVideoClickListener(){videoPlaybackEndedDiv.setAttribute("data-playback-ended","false");playVideo(this)}function randInt(a){return Math.floor(Math.random()*a)}function setRandomOrder(e){if(e==="audio"){var b=playArrows;var f=randomOrderHolder.getAttribute("data-randorder");var g=randomOrderHolder}else{if(e==="video"){var b=videoArrows;var f=videoRandomOrderHolder.getAttribute("data-randorder");var g=videoRandomOrderHolder}}var h=randomizeTrackOrder(b.length,e);var d=randomStringFromArray(h);if(f==="none"){g.setAttribute("data-randorder",d)}else{if(f===d){while(f===d){var a=randomizeTrackOrder(b.length,e);d=randomStringFromArray(a)}}else{g.setAttribute("data-randorder",d)}}}function endedTrackListener(y,m){if(m==="audio"){var n=playArrows;var i=nowPlayingNumDiv.getAttribute("data-nowplaying-num");var e=randomOrderHolder;var v=audioPlaybackEndedDiv;var g=playAudio;var s=repeatBtn.getAttribute("data-stat");var w=repeatBtnMobile.getAttribute("data-stat");var a=((s=="one")||(w=="one"));var k=((s=="all")||(w=="all"));var u=shuffleBtn.getAttribute("data-stat");var x=shuffleBtnMobile.getAttribute("data-stat");var h=((u=="on")||(x=="on"))}else{if(m==="video"){var n=videoArrows;var i=videoNowPlayingNumDiv.getAttribute("data-nowplaying-num");var e=videoRandomOrderHolder;var v=videoPlaybackEndedDiv;var g=playVideo;var s=videoRepeatBtn.getAttribute("data-stat");var w=videoRepeatBtnMobile.getAttribute("data-stat");var j=((s=="on")||(w=="on"));var u=videoShuffleBtn.getAttribute("data-stat");var x=videoShuffleBtnMobile.getAttribute("data-stat");var h=((u=="on")||(x=="on"))}}var z=(v.getAttribute("data-playback-ended")==="true");var b=n.length-1;if(a){g(n[i])}else{if(h){if(z){return}else{var r=e.getAttribute("data-randorder");var o=r.split(",");var q=o.shift();if((o!="")&&(q!=="undefined")){g(n[q]);var p=randomStringFromArray(o);e.setAttribute("data-randorder",p)}else{if((k)&&(q==="undefined")){var d=randInt(b);g(n[d]);setRandomOrder(m)}else{var l=g(n[q]);if(k){setRandomOrder(m);var f=e.getAttribute("data-randorder");var t=f.split(",");g(n[t[0]])}else{v.setAttribute("data-playback-ended","true")}}}}}else{if(h===false){if(i<b){i++;g(n[i])}else{if(k){g(n[0])}else{if((a===false)&&k===false){}}}}}}}function endedAudioListener(){endedTrackListener(this,"audio")}function endedVideoListener(){endedTrackListener(this,"video")}function skipTrack(j,r){var f=j.getAttribute("data-cmd");if(r==="audio"){var o=playArrows;var e=nowPlayingNumDiv.getAttribute("data-nowplaying-num");var i=randomOrderHolder;var n=playAudio;var k=shuffleBtn.getAttribute("data-stat");var p=shuffleBtnMobile.getAttribute("data-stat");var q=tracks}else{if(r==="video"){var o=videoArrows;var e=videoNowPlayingNumDiv.getAttribute("data-nowplaying-num");var i=videoRandomOrderHolder;var n=playVideo;var k=videoShuffleBtn.getAttribute("data-stat");var p=videoShuffleBtnMobile.getAttribute("data-stat");var q=videoTracks}}var h=q.length-1;if((k==="on")||(p==="on")){var l=i.getAttribute("data-randorder");var g=l.split(",");if(g.length>0){var b=g.shift();var m=o[b];if(typeof(m)==="undefined"){var d=randInt(q.length);n(o[d]);setRandomOrder(r)}else{n(m);var a=randomStringFromArray(g);i.setAttribute("data-randorder",a)}}else{if(repeat==="all"){var d=randInt(q.length);n(o[d]);setRandomOrder(r)}}}else{if(k==="off"){if(f==="fwd"){if(e<h){e++;n(o[e])}else{n(o[0])}}else{if(f==="prev"){if(e>0){e--;n(o[e])}else{n(o[h])}}}}}}function skipAudioListener(){skipTrack(this,"audio")}function skipVideoListener(){skipTrack(this,"video")}function toggleRepeat(b){var a=b.getAttribute("data-stat");if(a==="off"){b.setAttribute("data-stat","one");b.textContent="Repeat One ";if(iconsEnabled){b.appendChild(document.createElement("i"));b.childNodes[1].classList.add("fas","fa-redo");b.style.paddingTop="9px";b.style.paddingRight="15px";b.style.paddingBottom="9px";b.style.paddingLeft="15px"}}else{if(a==="one"){b.setAttribute("data-stat","all");b.textContent="Repeat All";if(iconsEnabled){b.appendChild(document.createElement("span"));b.childNodes[1].classList.add("fa-stack");b.childNodes[1].appendChild(document.createElement("i"));b.childNodes[1].appendChild(document.createElement("i"));b.childNodes[1].childNodes[0].classList.add("fas","fa-redo","fa-stack-1x");b.childNodes[1].childNodes[1].classList.add("fas","fa-infinity","fa-stack-1x");b.childNodes[1].childNodes[1].style.fontSize="0.4em";b.style.marginBottom="0";b.style.paddingTop="5px";b.style.paddingRight="5px";b.style.paddingBottom="5px";b.style.paddingLeft="15px"}}else{if(a==="all"){b.setAttribute("data-stat","off");b.textContent="No Repeat";if(iconsEnabled){b.appendChild(document.createElement("span"));b.childNodes[1].classList.add("fa-stack");b.childNodes[1].appendChild(document.createElement("i"));b.childNodes[1].appendChild(document.createElement("i"));b.childNodes[1].childNodes[0].classList.add("fas","fa-redo","fa-stack-1x");b.childNodes[1].childNodes[1].classList.add("fas","fa-slash","fa-stack-1x");b.style.marginBottom="0";b.style.paddingTop="5px";b.style.paddingRight="5px";b.style.paddingBottom="5px";b.style.paddingLeft="15px"}}}}}function toggleRepeatListener(){toggleRepeat(this)}function randomizeTrackOrder(d,f){if(f==="audio"){var b=nowPlayingNumDiv.getAttribute("data-nowplaying-num")}else{if(f==="video"){var b=videoNowPlayingNumDiv.getAttribute("data-nowplaying-num")}}var a=0;var g=[];while(g.length<d-1){var e=randInt(d);while(e==b){e=randInt(d)}if(g.indexOf(e)===-1){g.push(e)}}return g}function randomStringFromArray(b){if(b==="none"){return}var a="";for(c=0;c<b.length;c++){a+=b[c];if(c<b.length-1){a+=","}}return a}function toggleShuffle(d,b){var a=d.getAttribute("data-stat");if(a==="off"){setRandomOrder(b);d.setAttribute("data-stat","on");d.textContent="Shuffle On ";if(iconsEnabled){d.appendChild(document.createElement("i"));d.childNodes[1].classList.add("fas","fa-random");d.style.paddingTop="9px";d.style.paddingRight="15px";d.style.paddingBottom="9px";d.style.paddingLeft="15px"}}else{if(a==="on"){d.setAttribute("data-stat","off");d.textContent="Shuffle Off";if(iconsEnabled){d.appendChild(document.createElement("span"));d.childNodes[1].classList.add("fa-stack");d.childNodes[1].appendChild(document.createElement("i"));d.childNodes[1].appendChild(document.createElement("i"));d.childNodes[1].childNodes[0].classList.add("fas","fa-random","fa-stack-1x");d.childNodes[1].childNodes[1].classList.add("fas","fa-slash","fa-stack-1x");d.style.marginBottom="0";d.style.paddingTop="5px";d.style.paddingRight="5px";d.style.paddingBottom="5px";d.style.paddingLeft="15px"}}}}function toggleShuffleAudioListener(){toggleShuffle(this,"audio")}function toggleShuffleVideoListener(){toggleShuffle(this,"video")}function paused(d,g,f){if(f==="audio"){var b=audioNowPlayingTextP;var a=nowPlayingNumDiv.getAttribute("data-nowplaying-num");var e=playArrows[a].getAttribute("data-title");var h=pageTitle.getAttribute("data-sitename")}else{if(f==="video"){var b=videoNowPlayingTextP;var a=videoNowPlayingNumDiv.getAttribute("data-nowplaying-num");var e=videoArrows[a].getAttribute("data-title")}}if(g==="playing"){if(f==="audio"){pageTitle.textContent="Now Playing: "+e+" | "+h}b.textContent="Now Playing: ";b.appendChild(document.createElement("span"));b.childNodes[1].onclick=function(){var i=document.getElementById(playArrows[a].id+"-target");i.scrollIntoView({block:"start",behavior:"smooth"})};b.childNodes[1].style.fontWeight="bold";b.childNodes[1].textContent=e}else{if(g==="paused"){if(f==="audio"){pageTitle.textContent="Paused: "+e+" | "+h}b.textContent="Paused: ";b.appendChild(document.createElement("span"));b.childNodes[1].onclick=function(){var i=document.getElementById(playArrows[a].id+"-target");i.scrollIntoView({block:"start",behavior:"smooth"})};b.childNodes[1].style.fontWeight="bold";b.childNodes[1].textContent=e}}}function playingAudioHandler(){paused(this,"playing","audio")}function pausedAudioHandler(){paused(this,"paused","audio")}function playingVideoHandler(){paused(this,"playing","video")}function pausedVideoHandler(){paused(this,"paused","video")}function giveLink(f){var d;var e;var h;var g;if(f==="audio"){g=audio}else{if(f==="video"){g=video}else{if(f==="single"){g=single}}}var b=window.location.protocol+"//"+window.location.host+window.location.pathname+"?t="+Math.floor(g.currentTime);if(f==="audio"){d=playArrows;e=nowPlayingNumDiv.getAttribute("data-nowplaying-num");h="&a="}else{if(f==="video"){d=videoArrows;e=videoNowPlayingNumDiv.getAttribute("data-nowplaying-num");h="&v="}}if(d){var a=d[e].getAttribute("id");b+=h+a}if(f==="video"){b+="#videoplayer"}var i=document.createElement("textarea");i.value=b;document.body.appendChild(i);i.select();document.execCommand("copy");document.body.removeChild(i);return b}function singleLinkListener(){giveLink("single")}function audioLinkListener(){giveLink("audio")}function videoLinkListener(){giveLink("video")}function seekTrack(){var a=params.get("a");var b=params.get("v");var d=params.get("t");if((a===null)&&(b===null)){single.currentTime=d;single.autoplay=true}else{if(a){playAudio(playArrows.namedItem(a));audio.currentTime=d;audio.autoplay=true}if(b){playVideo(videoArrows.namedItem(b));video.currentTime=d;video.autoplay=true}}}function toggletheaterView(d){var a=document.getElementsByTagName("body")[0];var e=((document.getElementById("current-theme").getAttribute("data-theme")==="/css/water/light.standalone")||(document.getElementById("current-theme").getAttribute("data-theme")==="/css/water/dark.standalone"));var b=d.getAttribute("data-stat")==="on";if(b){d.setAttribute("data-stat","off");d.textContent="Theater View: Off";if(e){a.style.maxWidth="800px"}if(iconsEnabled){d.appendChild(document.createElement("span"));d.childNodes[1].classList.add("fa-stack");d.childNodes[1].appendChild(document.createElement("i"));d.childNodes[1].appendChild(document.createElement("i"));d.childNodes[1].childNodes[0].classList.add("fas","fa-theater-masks","fa-stack-1x");d.childNodes[1].childNodes[1].classList.add("fas","fa-slash","fa-stack-1x");d.style.marginBottom="0";d.style.paddingTop="5px";d.style.paddingRight="5px";d.style.paddingBottom="5px";d.style.paddingLeft="15px"}}else{d.setAttribute("data-stat","on");d.textContent="Theater View: On ";if(e){a.style.maxWidth="100%"}if(iconsEnabled){d.appendChild(document.createElement("i"));d.childNodes[1].classList.add("fas","fa-theater-masks");d.style.paddingTop="9px";d.style.paddingRight="15px";d.style.paddingBottom="9px";d.style.paddingLeft="15px"}}window.location.href="#videoplayer"}function theaterViewListener(){toggletheaterView(this)}function coverArtClickListener(){stat=this.getAttribute("data-stat");if(stat==="off"){this.style.width="100%";this.setAttribute("data-stat","full")}else{if(stat==="full"){this.style.width="50%";this.setAttribute("data-stat","half")}else{if(stat==="half"){this.style.width="initial";this.setAttribute("data-stat","off")}}}}function setUp(){var i=0;if(nowPlayingNumDiv){var d=nowPlayingNumDiv.getAttribute("data-nowplaying-num")}var h=pageTitle.getAttribute("data-sitename");if(playArrows.length>0){var e=playArrows[0].getAttribute("data-title");var a="Paused: "+e+" | "+h}if(tracks){for(c=0;c<playArrows.length;c++){var f=playArrows.item(c);f.addEventListener("click",playAudioClickListener);f.setAttribute("data-num",c)}}if(audio){audio.src=playArrows[i].getAttribute("data-browse").replace("browse","serve");playingTitleSpan.onclick=function(){var j=document.getElementById(playArrows[i].id+"-target");j.scrollIntoView({block:"start",behavior:"smooth"})};playingTitleSpan.textContent=e;title.textContent=a;audio.addEventListener("ended",endedAudioListener);audio.addEventListener("playing",playingAudioHandler);audio.addEventListener("pause",pausedAudioHandler);prevBtn.addEventListener("click",skipAudioListener);nextBtn.addEventListener("click",skipAudioListener);repeatBtn.addEventListener("click",toggleRepeatListener);shuffleBtn.addEventListener("click",toggleShuffleAudioListener);prevBtnMobile.addEventListener("click",skipAudioListener);nextBtnMobile.addEventListener("click",skipAudioListener);repeatBtnMobile.addEventListener("click",toggleRepeatListener);shuffleBtnMobile.addEventListener("click",toggleShuffleAudioListener)}if(videoTracks){for(c=0;c<videoArrows.length;c++){var b=videoArrows.item(c);b.addEventListener("click",playVideoClickListener);b.setAttribute("data-num",c)}}if(videoArrows.length>0){var g=videoArrows[0].getAttribute("data-title")}if(video){video.src=videoArrows[i].getAttribute("data-browse").replace("browse","serve");videoPlayingTitleSpan.textContent=g;video.addEventListener("ended",endedVideoListener);video.addEventListener("playing",playingVideoHandler);video.addEventListener("pause",pausedVideoHandler);videoPrevBtn.addEventListener("click",skipVideoListener);videoNextBtn.addEventListener("click",skipVideoListener);videoRepeatBtn.addEventListener("click",toggleRepeatListener);videoShuffleBtn.addEventListener("click",toggleShuffleVideoListener);videoPrevBtnMobile.addEventListener("click",skipVideoListener);videoNextBtnMobile.addEventListener("click",skipVideoListener);videoRepeatBtnMobile.addEventListener("click",toggleRepeatListener);videoShuffleBtnMobile.addEventListener("click",toggleShuffleVideoListener)}if(singleLinkButton){singleLinkButton.addEventListener("click",singleLinkListener)}if(audioLinkButton){audioLinkButton.addEventListener("click",audioLinkListener)}if(videoLinkButton){videoLinkButton.addEventListener("click",videoLinkListener)}if(params.has("t")){seekTrack()}if(theaterViewButton){theaterViewButton.addEventListener("click",theaterViewListener)}if(coverArt){coverArt.addEventListener("click",coverArtClickListener)}}window.onload=setUp();
\ No newline at end of file

A mousikofidi/templates/cover-art.html => mousikofidi/templates/cover-art.html +3 -0
@@ 0,0 1,3 @@
<div class="center">
  <img data-stat="off" id="cover-art" src="{{ cover_art }}" title="The cover art for files in this directory.  Click to adjust size (up to three sizes).">
</div>

M mousikofidi/templates/dir_detail.html => mousikofidi/templates/dir_detail.html +4 -0
@@ 3,6 3,10 @@

  <h4 class="center mobile-big">{{ page_path|safe }}</h4>

  {% if cover_art %}
    {% include "cover-art.html" with context %}
  {% endif %}

  {% if item_type == "dir" %}
    {% include "directory_details.html" %}
  {% elif item_type == "audio" or item_type == "video" %}

M test_mousikofidi.py => test_mousikofidi.py +61 -4
@@ 44,6 44,7 @@ from mousikofidi import (
    paths_list,
    quote,
    request_context,
    select_cover_art,
    select_logo,
    title_slug,
)


@@ 279,6 280,9 @@ def test_browse_dir():
        "favicon_path": favicon,
        "icons": False,
        "logo_path": logo,
        "cover_art": "/serve/{}%2Fexample%2FMousikoFidi%20Sample%20Cover%20Art.png".format(
            escaped_sourcedir
        ),
        "music_dirs": [
            {
                "raw": "/home/username/music/flac",


@@ 534,6 538,9 @@ def test_browse_file():
        "unescaped_path": "{}/example".format(unescaped_sourcedir),
        "file_name": "example",
        "page_path": "",
        "cover_art": "/serve/{}%2Fexample%2FMousikoFidi%20Sample%20Cover%20Art.png".format(
            escaped_sourcedir
        ),
    }
    assert file_dict == expected_dict



@@ 544,7 551,9 @@ def test_config_to_string():
    assert (
        config_string
        == """config:
  cover_art: true
  favicon_path: /fidi.png
  holidays: true
  icons: false
  logo_path: /fidi.png
  music_dirs:


@@ 631,6 640,25 @@ def test_request_context():
        }


def test_select_cover_art_false():
    app.fidiConfig["config"]["cover_art"] = False
    example_dir = os.path.join(THIS_DIR, "example")
    real_flac = os.path.join(example_dir, "real.flac")
    cover_art = select_cover_art(real_flac)
    assert cover_art is None


def test_select_cover_art_true():
    app.fidiConfig["config"]["cover_art"] = True
    example_dir = os.path.join(THIS_DIR, "example")
    escaped_cover_art = quote(
        os.path.join(example_dir, "MousikoFidi Sample Cover Art.png")
    )
    real_flac = os.path.join(example_dir, "real.flac")
    cover_art = select_cover_art(real_flac)
    assert cover_art == "/serve/{}".format(escaped_cover_art)


def test_select_logo_no_holiday():
    c = {
        "config": {


@@ 958,6 986,7 @@ def test_init():
    c = init(use_config=os.path.join(THIS_DIR, "example", "fidi.yml"))
    assert c == {
        "config": {
            "cover_art": True,
            "favicon_path": "/fidi.png",
            "holidays": True,
            "icons": False,


@@ 2282,6 2311,7 @@ def test_dir_detail_not_found_real_with_plus_sign(client):

def test_file_detail_real_flac(client):
    example_dir_unescaped = os.path.join(THIS_DIR, "example", "real.flac")
    escaped = quote(example_dir_unescaped)
    dir_list = []
    dir_list.append(example_dir_unescaped)
    site_name = "COOL TEST SITE"


@@ 2295,7 2325,7 @@ def test_file_detail_real_flac(client):
    # Reset the config
    app.fidiConfig = app._fidiConfig.copy()
    assert rv.status == "200 OK"
    assert bytes(quote(example_dir_unescaped), "utf8") in rv.data
    assert bytes(escaped, "utf8") in rv.data
    assert bytes(example_dir_unescaped, "utf8") in rv.data
    assert b"Track: 34" in rv.data
    assert b"Released: 2019-08-08" in rv.data


@@ 2303,6 2333,12 @@ def test_file_detail_real_flac(client):
    assert bytes('"MousikóFídi Test Album"', "utf8") in rv.data
    assert bytes("MousikóFídi Test Album", "utf8") in rv.data
    assert bytes("MousikóFídi Test FLAC", "utf8") in rv.data
    assert bytes(
        '<img data-stat="off" id="cover-art" src="/serve/{}%2Fexample%2FMousikoFidi%20Sample%20Cover%20Art.png" title="The cover art for files in this directory.  Click to adjust size (up to three sizes).">'.format(
            escaped
        ),
        "utf8",
    )
    assert (
        bytes(
            '<audio id="single" controls src="/serve/{}">'.format(


@@ 2360,6 2396,7 @@ def test_file_detail_real_flac(client):

def test_file_detail_real_mp3(client):
    example_dir_unescaped = os.path.join(THIS_DIR, "example", "real.mp3")
    escaped = quote(example_dir_unescaped)
    dir_list = []
    dir_list.append(example_dir_unescaped)
    site_name = "COOL TEST SITE"


@@ 2373,7 2410,7 @@ def test_file_detail_real_mp3(client):
    # Reset the config
    app.fidiConfig = app._fidiConfig.copy()
    assert rv.status == "200 OK"
    assert bytes(quote(example_dir_unescaped), "utf8") in rv.data
    assert bytes(escaped, "utf8") in rv.data
    assert bytes(example_dir_unescaped, "utf8") in rv.data
    assert bytes("Genre: MousikóFídi Test", "utf8") in rv.data
    assert bytes('"MousikóFídi Test Album"', "utf8") in rv.data


@@ 2381,6 2418,12 @@ def test_file_detail_real_mp3(client):
    assert bytes("MousikóFídi Test Album", "utf8") in rv.data
    assert bytes("MousikóFídi Test Artist", "utf8") in rv.data
    assert bytes("MousikóFídi Test MP3", "utf8") in rv.data
    assert bytes(
        '<img data-stat="off" id="cover-art" src="/serve/{}%2Fexample%2FMousikoFidi%20Sample%20Cover%20Art.png" title="The cover art for files in this directory.  Click to adjust size (up to three sizes).">'.format(
            escaped
        ),
        "utf8",
    )
    assert (
        bytes(
            '<audio id="single" controls src="/serve/{}">'.format(


@@ 2445,6 2488,7 @@ def test_file_detail_real_mp3(client):

def test_file_detail_real_mp4(client):
    example_dir_unescaped = os.path.join(THIS_DIR, "example", "real.mp4")
    escaped = quote(example_dir_unescaped)
    dir_list = []
    dir_list.append(example_dir_unescaped)
    site_name = "COOL TEST SITE"


@@ 2462,7 2506,7 @@ def test_file_detail_real_mp4(client):
    app.fidiConfig = app._fidiConfig.copy()

    assert rv.status == "200 OK"
    assert bytes(quote(example_dir_unescaped), "utf8") in rv.data
    assert bytes(escaped, "utf8") in rv.data
    assert bytes(example_dir_unescaped, "utf8") in rv.data
    assert bytes("Genre: MousikóFídi Test Genre", "utf8") in rv.data
    assert bytes('"MousikóFídi Test MP4"', "utf8") in rv.data


@@ 2471,6 2515,12 @@ def test_file_detail_real_mp4(client):
    assert bytes("MousikóFídi Test Album", "utf8") in rv.data
    assert bytes("MousikóFídi Test Artist", "utf8") in rv.data
    assert bytes("MousikóFídi Test MP4", "utf8") in rv.data
    assert bytes(
        '<img data-stat="off" id="cover-art" src="/serve/{}%2Fexample%2FMousikoFidi%20Sample%20Cover%20Art.png" title="The cover art for files in this directory.  Click to adjust size (up to three sizes).">'.format(
            escaped
        ),
        "utf8",
    )
    assert bytes('<video id="single" controls>', "utf8") in rv.data
    assert b"Track: 34/100" in rv.data
    assert (


@@ 2537,6 2587,7 @@ def test_file_detail_real_mp4(client):

def test_file_detail_real_ogg(client):
    example_dir_unescaped = os.path.join(THIS_DIR, "example", "real.ogg")
    escaped = quote(example_dir_unescaped)
    dir_list = []
    dir_list.append(example_dir_unescaped)
    site_name = "COOL TEST SITE"


@@ 2550,7 2601,7 @@ def test_file_detail_real_ogg(client):
    # Reset the config
    app.fidiConfig = app._fidiConfig.copy()
    assert rv.status == "200 OK"
    assert bytes(quote(example_dir_unescaped), "utf8") in rv.data
    assert bytes(escaped, "utf8") in rv.data
    assert bytes(example_dir_unescaped, "utf8") in rv.data
    assert b"Track: 34" in rv.data
    assert b"Released: 2019-08-08" in rv.data


@@ 2558,6 2609,12 @@ def test_file_detail_real_ogg(client):
    assert bytes('"MousikóFídi Test Album"', "utf8") in rv.data
    assert bytes("MousikóFídi Test Album", "utf8") in rv.data
    assert bytes("MousikóFídi Test OGG", "utf8") in rv.data
    assert bytes(
        '<img data-stat="off" id="cover-art" src="/serve/{}%2Fexample%2FMousikoFidi%20Sample%20Cover%20Art.png" title="The cover art for files in this directory.  Click to adjust size (up to three sizes).">'.format(
            escaped
        ),
        "utf8",
    )
    assert (
        bytes(
            '<audio id="single" controls src="/serve/{}">'.format(