~hristoast/mousikofidi

909c279b027336b521f5f15ccac2eb4466fde3c2 — Hristos N. Triantafillou 8 months ago 97f4ae2 0.13
Expand javascript tests
M example/real.flac => example/real.flac +0 -0

M example/real.mp3 => example/real.mp3 +0 -0

M example/real.ogg => example/real.ogg +0 -0

M mousikofidi.py => mousikofidi.py +45 -1
@@ 1057,4 1057,48 @@ def settings_edit():

@app.route("/test-js")
def test_js():
    return render_template("test_js.html")
    _audio_list = []
    _video_list = []
    audio_list = []
    video_list = []
    example_dir = os.path.join(os.getcwd(), "example")

    if os.path.isdir(example_dir):

        for a in (
            "fake.flac",
            "fake.mp3",
            "fake.ogg",
            "real.flac",
            "real.mp3",
            "real.ogg",
        ):
            path = os.path.join(example_dir, a)
            m = get_metadata_dict(path)
            d = file_dict(path, m, "audio")
            _audio_list.append(d)
            _audio_list.append(d)

        for v in ("fake.mp4", "fake.webm", "real.mp4", "real.webm"):
            path = os.path.join(example_dir, v)
            m = get_metadata_dict(path)
            d = file_dict(path, m, "video")
            _video_list.append(d)
            _video_list.append(d)

    if _audio_list:
        audio_list = make_unique_slugs(_audio_list)

    if _video_list:
        video_list = make_unique_slugs(_video_list)

    c = request_context(app.fidiConfig)
    c.update(
        {
            "page_name": "Javascript Tests Page!",
            "item_list": audio_list,
            "video_list": video_list,
            "single_file_e": audio_list[0]["escaped_path"],
        }
    )
    return render_template("test_js.html", **c)

M static/css/fidi.css => static/css/fidi.css +4 -0
@@ 224,6 224,10 @@ input.X {
    color: green;
}

.hidden {
    display: none;
}

.initialsize {
    font-size: initial;
    font-weight: initial;

M static/css/fidi.min.css => static/css/fidi.min.css +1 -1
@@ 1,1 1,1 @@
audio{margin-top:25px;width:100%}div#player{background-color:#333;border-top-left-radius:4px;border-top-right-radius:4px;box-shadow:4px 4px 2px 2px rgba(0,0,0,0.2);padding-bottom:10px;position:-webkit-sticky;position:sticky;bottom:0;z-index:4}div#player audio{width:95%}p#now-playing{color:#fff;margin:0 auto;margin-bottom:-10px;padding-top:12px}div#videoplayer{margin:0 auto;width:100%}video{margin-top:25px;width:100% !important;height:auto !important}footer{font-size:.5em;margin-top:25px}div#player button{display:inline-block}form#playlistctl input{display:inline-block}form#theme-picker label select{margin:0 auto}nav{height:50px;margin-bottom:0;padding-bottom:0;position:-webkit-sticky;position:sticky;top:0;z-index:34}nav ul{margin-bottom:0;margin-top:0;list-style-type:none;overflow:hidden;background-color:#333;padding-left:0;display:inline-block;width:100%}nav ul li{float:left}nav ul li#logo{float:right}nav ul li#logo a#logo{padding:0}nav ul li#logo a#logo{-webkit-transition:none;transition:none;float:right;color:darkgray}nav ul li#logo a#logo:hover{background-color:#333}nav ul li a{display:block;color:white;text-align:center;padding:14px 16px;text-decoration:none}nav ul li a:hover{-webkit-transition:background-color .5s ease;transition:background-color .5s ease;background-color:#111}nav ul li a img{margin-top:9px;margin-right:9px;height:32px;width:32px}a:hover{text-decoration:none}div#content{min-height:315px;margin-top:20px}div#top-link{z-index:16;float:right;position:-webkit-sticky;position:sticky;bottom:30px;margin-right:10px}div#top-link a{z-index:16;width:0;height:0;border-left:25px solid transparent;border-right:25px solid transparent;border-bottom:25px solid grey}input#bulk-add{margin:0 auto;margin-bottom:25px}select#to-load{margin:0 auto;margin-bottom:10px}div.anchor{bottom:100px;position:relative}div.play-arrow{width:0;height:0;border-top:15px solid transparent;border-bottom:15px solid transparent;border-left:15px solid green;float:left;margin-left:14px;margin-top:5px}input.plus{color:#41adff;font-size:1.9em;margin:0 0 0 10px;padding:0;background:none !important;width:20px}input.plus-btn{color:#41adff;font-size:1.9em;margin:0 auto}input.X{margin:0 0 0 20px;padding:0;font-size:1.4em;background:none !important}.center{text-align:center}.bold{font-weight:bold}.green{color:green}.initialsize{font-size:initial;font-weight:initial}.red{color:red}@media(min-width:481px) and (max-width:767px),(min-width:320px) and (max-width:480px){.mobile-big{font-size:1.5em}.mobile-hide{display:none}.mobile{padding:0}}
\ No newline at end of file
audio{margin-top:25px;width:100%}div#player{background-color:#333;border-top-left-radius:4px;border-top-right-radius:4px;box-shadow:4px 4px 2px 2px rgba(0,0,0,0.2);padding-bottom:10px;position:-webkit-sticky;position:sticky;bottom:0;z-index:4}div#player audio{width:95%}p#now-playing{color:#fff;margin:0 auto;margin-bottom:-10px;padding-top:12px}div#videoplayer{margin:0 auto;width:100%}video{margin-top:25px;width:100% !important;height:auto !important}footer{font-size:.5em;margin-top:25px}div#player button{display:inline-block}form#playlistctl input{display:inline-block}form#theme-picker label select{margin:0 auto}nav{height:50px;margin-bottom:0;padding-bottom:0;position:-webkit-sticky;position:sticky;top:0;z-index:34}nav ul{margin-bottom:0;margin-top:0;list-style-type:none;overflow:hidden;background-color:#333;padding-left:0;display:inline-block;width:100%}nav ul li{float:left}nav ul li#logo{float:right}nav ul li#logo a#logo{padding:0}nav ul li#logo a#logo{-webkit-transition:none;transition:none;float:right;color:darkgray}nav ul li#logo a#logo:hover{background-color:#333}nav ul li a{display:block;color:white;text-align:center;padding:14px 16px;text-decoration:none}nav ul li a:hover{-webkit-transition:background-color .5s ease;transition:background-color .5s ease;background-color:#111}nav ul li a img{margin-top:9px;margin-right:9px;height:32px;width:32px}a:hover{text-decoration:none}div#content{min-height:315px;margin-top:20px}div#top-link{z-index:16;float:right;position:-webkit-sticky;position:sticky;bottom:30px;margin-right:10px}div#top-link a{z-index:16;width:0;height:0;border-left:25px solid transparent;border-right:25px solid transparent;border-bottom:25px solid grey}input#bulk-add{margin:0 auto;margin-bottom:25px}select#to-load{margin:0 auto;margin-bottom:10px}div.anchor{bottom:100px;position:relative}div.play-arrow{width:0;height:0;border-top:15px solid transparent;border-bottom:15px solid transparent;border-left:15px solid green;float:left;margin-left:14px;margin-top:5px}input.plus{color:#41adff;font-size:1.9em;margin:0 0 0 10px;padding:0;background:none !important;width:20px}input.plus-btn{color:#41adff;font-size:1.9em;margin:0 auto}input.X{margin:0 0 0 20px;padding:0;font-size:1.4em;background:none !important}.center{text-align:center}.bold{font-weight:bold}.green{color:green}.hidden{display:none}.initialsize{font-size:initial;font-weight:initial}.red{color:red}@media(min-width:481px) and (max-width:767px),(min-width:320px) and (max-width:480px){.mobile-big{font-size:1.5em}.mobile-hide{display:none}.mobile{padding:0}}
\ No newline at end of file

M static/js/player.js => static/js/player.js +10 -9
@@ 50,12 50,11 @@ var singleLinkButton = document.getElementById("time-link");
var audioLinkButton = document.getElementById("audio-time-link");
var videoLinkButton = document.getElementById("video-time-link");

function playAudio(targetArrow) {
function playAudio(targetArrow, dontPlay) {
    /*
      Play the selected track.
    */
    var browse = targetArrow.getAttribute("data-browse");
    var dataNowPlaying = targetArrow.getAttribute("data-nowplaying");
    var serve = browse.replace("browse", "serve");
    var siteName = pageTitle.getAttribute("data-sitename");
    var thisTrackNum = targetArrow.getAttribute("data-num");


@@ 63,9 62,9 @@ function playAudio(targetArrow) {
    var playingTextTitle = "Now Playing: " + title + " | " + siteName;
    var shuffle = shuffleBtn.getAttribute("data-stat");

    audio.setAttribute("data-nowplaying", dataNowPlaying);
    audio.src = serve;
    audio.play();
    if (typeof dontPlay === 'undefined')
        audio.play();
    nowPlayingNumDiv.setAttribute("data-nowplaying-num", thisTrackNum);
    playingTitleSpan.textContent = title;
    pageTitle.textContent = playingTextTitle;


@@ 79,19 78,19 @@ function playAudioClickListener() {
    playAudio(this);
}

function playVideo(targetArrow) {
function playVideo(targetArrow, dontPlay) {
    /*
      Play the selected track.
    */
    var browse = targetArrow.getAttribute("data-browse");
    var dataNowPlaying = targetArrow.getAttribute("data-videonowplaying");
    var serve = browse.replace("browse", "serve");
    var shuffle = videoShuffleBtn.getAttribute("data-stat");
    var thisTrackNum = targetArrow.getAttribute("data-num");

    video.setAttribute("data-nowplaying", dataNowPlaying);
    video.src = serve;
    video.play();
    if (typeof dontPlay === 'undefined') {
        video.src = serve;
        video.play();
    }
    videoNowPlayingNumDiv.setAttribute("data-nowplaying-num", thisTrackNum);

    if (shuffle === "on") {


@@ 456,6 455,8 @@ function giveLink(playerType) {

    // Clean up the ad hoc text area
    document.body.removeChild(textArea);

    return urlToGive;
}

function singleLinkListener() {

M static/js/player.min.js => static/js/player.min.js +1 -1
@@ 1,1 1,1 @@
var audio=document.getElementById("audio");var audioNowPlayingTextP=document.getElementById("now-playing");var nowPlayingNumDiv=document.getElementById("now-playing-num");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 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 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 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");function playAudio(a){var f=a.getAttribute("data-browse");var e=a.getAttribute("data-nowplaying");var j=f.replace("browse","serve");var d=pageTitle.getAttribute("data-sitename");var i=a.getAttribute("data-num");var g=a.getAttribute("data-title");var h="Now Playing: "+g+" | "+d;var b=shuffleBtn.getAttribute("data-stat");audio.setAttribute("data-nowplaying",e);audio.src=j;audio.play();nowPlayingNumDiv.setAttribute("data-nowplaying-num",i);playingTitleSpan.textContent=g;pageTitle.textContent=h;if(b==="on"){setRandomOrder("audio")}}function playAudioClickListener(){playAudio(this)}function playVideo(e){var d=e.getAttribute("data-browse");var f=e.getAttribute("data-videonowplaying");var g=d.replace("browse","serve");var b=videoShuffleBtn.getAttribute("data-stat");var a=e.getAttribute("data-num");video.setAttribute("data-nowplaying",f);video.src=g;video.play();videoNowPlayingNumDiv.setAttribute("data-nowplaying-num",a);if(b==="on"){setRandomOrder("video")}}function playVideoClickListener(){playVideo(this)}function randInt(a){return Math.floor(Math.random()*Math.floor(a))}function setRandomOrder(f){if(f==="audio"){var b=playArrows;var g=randomOrderHolder.getAttribute("data-randorder");var h=randomOrderHolder;var e=tracks}else{if(f==="video"){var b=videoArrows;var g=videoRandomOrderHolder.getAttribute("data-randorder");var h=videoRandomOrderHolder;var e=videoTracks}}var i=randomizeTrackOrder(e.length,f);var d=randomStringFromArray(i);if(g==="none"){h.setAttribute("data-randorder",d)}else{if(g===d){while(g===d){var a=randomizeTrackOrder(e.length,f);d=randomStringFromArray(a)}}else{h.setAttribute("data-randorder",d)}}}function endedTrackListener(n,i){if(i==="audio"){var o=playArrows;var f=nowPlayingNumDiv.getAttribute("data-nowplaying-num");var j=randomOrderHolder;var m=playAudio;var d=repeatBtn.getAttribute("data-stat");var k=shuffleBtn.getAttribute("data-stat")}else{if(i==="video"){var o=videoArrows;var f=videoNowPlayingNumDiv.getAttribute("data-nowplaying-num");var j=videoRandomOrderHolder;var m=playVideo;var d=videoRepeatBtn.getAttribute("data-stat");var k=videoShuffleBtn.getAttribute("data-stat")}}var h=o.length-1;if(d==="one"){m(o[f])}else{if(k==="on"){var l=j.getAttribute("data-randorder");var g=l.split(",");if(g!=""){var b=g.shift();m(o[b]);var a=randomStringFromArray(g);j.setAttribute("data-randorder",a)}else{if(d==="all"){var e=randInt(h);m(o[e]);setRandomOrder(i)}else{}}}else{if(k==="off"){if(f<h){f++;m(o[f])}else{if(d==="all"){m(o[0])}else{if(d==="off"){}}}}}}}function endedAudioListener(){endedTrackListener(this,"audio")}function endedVideoListener(){endedTrackListener(this,"video")}function skipTrack(j,q){var f=j.getAttribute("data-cmd");if(q==="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=tracks}else{if(q==="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=videoTracks}}var h=p.length-1;if(k==="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(p.length);n(o[d]);setRandomOrder(q)}else{n(m);var a=randomStringFromArray(g);i.setAttribute("data-randorder",a)}}else{if(repeat==="all"){var d=randInt(p.length);n(o[d]);setRandomOrder(q)}}}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"}else{if(a==="one"){b.setAttribute("data-stat","all");b.textContent="Repeat All"}else{if(a==="all"){b.setAttribute("data-stat","off");b.textContent="No Repeat"}}}}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"}else{if(a==="on"){d.setAttribute("data-stat","off");d.textContent="Shuffle Off"}}}function toggleShuffleAudioListener(){toggleShuffle(this,"audio")}function toggleShuffleVideoListener(){toggleShuffle(this,"video")}function paused(b,e){var a=nowPlayingNumDiv.getAttribute("data-nowplaying-num");var d=playArrows[a].getAttribute("data-title");var f=pageTitle.getAttribute("data-sitename");if(e==="playing"){pageTitle.textContent="Now Playing: "+d+" | "+f;audioNowPlayingTextP.textContent="Now Playing: ";audioNowPlayingTextP.appendChild(document.createElement("span"));audioNowPlayingTextP.childNodes[1].style.fontWeight="bold";audioNowPlayingTextP.childNodes[1].textContent=d}else{if(e==="paused"){pageTitle.textContent="Paused: "+d+" | "+f;audioNowPlayingTextP.textContent="Paused: ";audioNowPlayingTextP.appendChild(document.createElement("span"));audioNowPlayingTextP.childNodes[1].style.fontWeight="bold";audioNowPlayingTextP.childNodes[1].textContent=d}}}function playingAudioHandler(){paused(this,"playing")}function pausedAudioHandler(){paused(this,"paused")}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)}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 setUp(){var h=0;if(nowPlayingNumDiv){var d=nowPlayingNumDiv.getAttribute("data-nowplaying-num")}var g=pageTitle.getAttribute("data-sitename");if(playArrows.length>0){var e=playArrows[0].getAttribute("data-title");var a="Paused: "+e+" | "+g}if(tracks){for(c=0;c<tracks.length;c++){var f=playArrows.item(c);f.addEventListener("click",playAudioClickListener);f.setAttribute("data-num",c)}}if(audio){audio.src=playArrows[h].getAttribute("data-browse").replace("browse","serve");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)}if(videoTracks){for(c=0;c<videoTracks.length;c++){var b=videoArrows.item(c);b.addEventListener("click",playVideoClickListener);b.setAttribute("data-num",c)}}if(video){video.src=videoArrows[h].getAttribute("data-browse").replace("browse","serve");video.addEventListener("ended",endedVideoListener);videoPrevBtn.addEventListener("click",skipVideoListener);videoNextBtn.addEventListener("click",skipVideoListener);videoRepeatBtn.addEventListener("click",toggleRepeatListener);videoShuffleBtn.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()}}window.onload=setUp();
\ No newline at end of file
var audio=document.getElementById("audio");var audioNowPlayingTextP=document.getElementById("now-playing");var nowPlayingNumDiv=document.getElementById("now-playing-num");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 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 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 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");function playAudio(a,b){var f=a.getAttribute("data-browse");var j=f.replace("browse","serve");var e=pageTitle.getAttribute("data-sitename");var i=a.getAttribute("data-num");var g=a.getAttribute("data-title");var h="Now Playing: "+g+" | "+e;var d=shuffleBtn.getAttribute("data-stat");audio.src=j;if(typeof b==="undefined"){audio.play()}nowPlayingNumDiv.setAttribute("data-nowplaying-num",i);playingTitleSpan.textContent=g;pageTitle.textContent=h;if(d==="on"){setRandomOrder("audio")}}function playAudioClickListener(){playAudio(this)}function playVideo(f,a){var e=f.getAttribute("data-browse");var g=e.replace("browse","serve");var d=videoShuffleBtn.getAttribute("data-stat");var b=f.getAttribute("data-num");if(typeof a==="undefined"){video.src=g;video.play()}videoNowPlayingNumDiv.setAttribute("data-nowplaying-num",b);if(d==="on"){setRandomOrder("video")}}function playVideoClickListener(){playVideo(this)}function randInt(a){return Math.floor(Math.random()*Math.floor(a))}function setRandomOrder(f){if(f==="audio"){var b=playArrows;var g=randomOrderHolder.getAttribute("data-randorder");var h=randomOrderHolder;var e=tracks}else{if(f==="video"){var b=videoArrows;var g=videoRandomOrderHolder.getAttribute("data-randorder");var h=videoRandomOrderHolder;var e=videoTracks}}var i=randomizeTrackOrder(e.length,f);var d=randomStringFromArray(i);if(g==="none"){h.setAttribute("data-randorder",d)}else{if(g===d){while(g===d){var a=randomizeTrackOrder(e.length,f);d=randomStringFromArray(a)}}else{h.setAttribute("data-randorder",d)}}}function endedTrackListener(n,i){if(i==="audio"){var o=playArrows;var f=nowPlayingNumDiv.getAttribute("data-nowplaying-num");var j=randomOrderHolder;var m=playAudio;var d=repeatBtn.getAttribute("data-stat");var k=shuffleBtn.getAttribute("data-stat")}else{if(i==="video"){var o=videoArrows;var f=videoNowPlayingNumDiv.getAttribute("data-nowplaying-num");var j=videoRandomOrderHolder;var m=playVideo;var d=videoRepeatBtn.getAttribute("data-stat");var k=videoShuffleBtn.getAttribute("data-stat")}}var h=o.length-1;if(d==="one"){m(o[f])}else{if(k==="on"){var l=j.getAttribute("data-randorder");var g=l.split(",");if(g!=""){var b=g.shift();m(o[b]);var a=randomStringFromArray(g);j.setAttribute("data-randorder",a)}else{if(d==="all"){var e=randInt(h);m(o[e]);setRandomOrder(i)}else{}}}else{if(k==="off"){if(f<h){f++;m(o[f])}else{if(d==="all"){m(o[0])}else{if(d==="off"){}}}}}}}function endedAudioListener(){endedTrackListener(this,"audio")}function endedVideoListener(){endedTrackListener(this,"video")}function skipTrack(j,q){var f=j.getAttribute("data-cmd");if(q==="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=tracks}else{if(q==="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=videoTracks}}var h=p.length-1;if(k==="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(p.length);n(o[d]);setRandomOrder(q)}else{n(m);var a=randomStringFromArray(g);i.setAttribute("data-randorder",a)}}else{if(repeat==="all"){var d=randInt(p.length);n(o[d]);setRandomOrder(q)}}}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"}else{if(a==="one"){b.setAttribute("data-stat","all");b.textContent="Repeat All"}else{if(a==="all"){b.setAttribute("data-stat","off");b.textContent="No Repeat"}}}}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"}else{if(a==="on"){d.setAttribute("data-stat","off");d.textContent="Shuffle Off"}}}function toggleShuffleAudioListener(){toggleShuffle(this,"audio")}function toggleShuffleVideoListener(){toggleShuffle(this,"video")}function paused(b,e){var a=nowPlayingNumDiv.getAttribute("data-nowplaying-num");var d=playArrows[a].getAttribute("data-title");var f=pageTitle.getAttribute("data-sitename");if(e==="playing"){pageTitle.textContent="Now Playing: "+d+" | "+f;audioNowPlayingTextP.textContent="Now Playing: ";audioNowPlayingTextP.appendChild(document.createElement("span"));audioNowPlayingTextP.childNodes[1].style.fontWeight="bold";audioNowPlayingTextP.childNodes[1].textContent=d}else{if(e==="paused"){pageTitle.textContent="Paused: "+d+" | "+f;audioNowPlayingTextP.textContent="Paused: ";audioNowPlayingTextP.appendChild(document.createElement("span"));audioNowPlayingTextP.childNodes[1].style.fontWeight="bold";audioNowPlayingTextP.childNodes[1].textContent=d}}}function playingAudioHandler(){paused(this,"playing")}function pausedAudioHandler(){paused(this,"paused")}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 setUp(){var h=0;if(nowPlayingNumDiv){var d=nowPlayingNumDiv.getAttribute("data-nowplaying-num")}var g=pageTitle.getAttribute("data-sitename");if(playArrows.length>0){var e=playArrows[0].getAttribute("data-title");var a="Paused: "+e+" | "+g}if(tracks){for(c=0;c<tracks.length;c++){var f=playArrows.item(c);f.addEventListener("click",playAudioClickListener);f.setAttribute("data-num",c)}}if(audio){audio.src=playArrows[h].getAttribute("data-browse").replace("browse","serve");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)}if(videoTracks){for(c=0;c<videoTracks.length;c++){var b=videoArrows.item(c);b.addEventListener("click",playVideoClickListener);b.setAttribute("data-num",c)}}if(video){video.src=videoArrows[h].getAttribute("data-browse").replace("browse","serve");video.addEventListener("ended",endedVideoListener);videoPrevBtn.addEventListener("click",skipVideoListener);videoNextBtn.addEventListener("click",skipVideoListener);videoRepeatBtn.addEventListener("click",toggleRepeatListener);videoShuffleBtn.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()}}window.onload=setUp();
\ No newline at end of file

M static/js/tests.js => static/js/tests.js +263 -4
@@ 23,13 23,19 @@ var results = document.getElementById("__results");
var audioRandomOrderHolder = document.getElementById("randorder");
var videoRandomOrderHolder = document.getElementById("vid-randorder");

var audioArrows = document.getElementById("playlist");
var audioArrows = document.getElementsByClassName("play-arrow");
var audioShuffleButton = document.getElementById("shuffle");
var audioTracks = audioArrows.getElementsByClassName("title");
var playlist = document.getElementById("playlist");
var audioTracks = playlist.getElementsByClassName("title");

var videoArrows = document.getElementById("video-playlist");
var videoArrows = document.getElementsByClassName("video-arrow");
var videoShuffleButton = document.getElementById("vid-shuffle");
var videoTracks = videoArrows.getElementsByClassName("video-title");
var videoPlaylist = document.getElementById("video-playlist");
if (videoPlaylist) {
    var videoTracks = videoPlaylist.getElementsByClassName("video-title");
} else if (playlist) {
    var videoTracks = playlist.getElementsByClassName("video-title");
}

var repeatButton = document.getElementById("repeat");



@@ 490,6 496,199 @@ function testToggleShuffleVideo() {
    return true;
}

function testPlayAudio() {
    console.log("Begin: testPlayAudio()");

    var realFlac = audioArrows[6];
    var realMp3 = audioArrows[8];
    var realOgg = audioArrows[10];

    playAudio(realFlac, "Don't play!");

    var nowPlaying1 = nowPlayingNumDiv.getAttribute("data-nowplaying-num");
    var title1 = pageTitle.textContent;
    var titleSpan1 = playingTitleSpan.textContent;

    playAudio(realMp3, "Don't play!");

    var nowPlaying2 = nowPlayingNumDiv.getAttribute("data-nowplaying-num");
    var title2 = pageTitle.textContent;
    var titleSpan2 = playingTitleSpan.textContent;

    playAudio(realOgg, "Don't play!");

    var nowPlaying3 = nowPlayingNumDiv.getAttribute("data-nowplaying-num");
    var title3 = pageTitle.textContent;
    var titleSpan3 = playingTitleSpan.textContent;

    console.log("nowPlaying1: " + nowPlaying1);
    console.log("nowPlaying2: " + nowPlaying2);
    console.log("nowPlaying3: " + nowPlaying3);

    console.log("title1: " + title1);
    console.log("title2: " + title2);
    console.log("title3: " + title3);

    console.log("titleSpan1: " + titleSpan1);
    console.log("titleSpan2: " + titleSpan2);
    console.log("titleSpan3: " + titleSpan3);

    if (nowPlaying1 != 6) {
        console.log("TEST FAILED");
        console.log("nowPlaying1 did equal '6'!!");
        console.log("End: testPlayAudio()");
        return false;
    }

    if (nowPlaying2 != 8) {
        console.log("TEST FAILED");
        console.log("nowPlaying2 did equal '8'!!");
        console.log("End: testPlayAudio()");
        return false;
    }

    if (nowPlaying3 != 10) {
        console.log("TEST FAILED");
        console.log("nowPlaying3 did equal '10'!!");
        console.log("End: testPlayAudio()");
        return false;
    }

    if (title1.split("|")[0] != "Now Playing: MousikóFídi Test FLAC ") {
        console.log("TEST FAILED");
        console.log("title1.split("|")[0] did equal 'MousikóFídi Test FLAC '!!");
        console.log("End: testPlayAudio()");
        return false;
    }

    if (title2.split("|")[0] != "Now Playing: MousikóFídi Test MP3 ") {
        console.log("TEST FAILED");
        console.log("title1.split("|")[0] did equal 'MousikóFídi Test MP3 '!!");
        console.log("End: testPlayAudio()");
        return false;
    }

    if (title3.split("|")[0] != "Now Playing: MousikóFídi Test OGG ") {
        console.log("TEST FAILED");
        console.log("title1.split("|")[0] did equal 'MousikóFídi Test OGG '!!");
        console.log("End: testPlayAudio()");
        return false;
    }

    if (titleSpan1 != "MousikóFídi Test FLAC") {
        console.log("TEST FAILED");
        console.log("titleSpan1 did equal 'MousikóFídi Test FLAC'!!");
        console.log("End: testPlayAudio()");
        return false;
    }

    if (titleSpan2 != "MousikóFídi Test MP3") {
        console.log("TEST FAILED");
        console.log("titleSpan2 did equal 'MousikóFídi Test MP3'!!");
        console.log("End: testPlayAudio()");
        return false;
    }

    if (titleSpan3 != "MousikóFídi Test OGG") {
        console.log("TEST FAILED");
        console.log("titleSpan3 did equal 'MousikóFídi Test OGG'!!");
        console.log("End: testPlayAudio()");
        return false;
    }

    console.log("End: testPlayAudio()");
    return true;
}

function testPlayVideo() {
    console.log("Begin: testPlayVideo()");

    var realMp4 = audioArrows[16];
    var realWebm = audioArrows[18];

    playVideo(realMp4, "Don't play!");

    var nowPlaying1 = videoNowPlayingNumDiv.getAttribute("data-nowplaying-num");

    playVideo(realWebm, "Don't play!");

    var nowPlaying2 = videoNowPlayingNumDiv.getAttribute("data-nowplaying-num");

    console.log("nowPlaying1: " + nowPlaying1);
    console.log("nowPlaying2: " + nowPlaying2);

    if (nowPlaying1 != 4) {
        console.log("TEST FAILED");
        console.log("nowPlaying1 did equal '4'!!");
        console.log("End: testPlayAudio()");
        return false;
    }

    if (nowPlaying2 != 6) {
        console.log("TEST FAILED");
        console.log("nowPlaying2 did equal '6'!!");
        console.log("End: testPlayAudio()");
        return false;
    }

    console.log("End: testPlayVideo()");
    return true;
}

function testGiveLinkAudio() {
    console.log("Begin: testGiveLinkAudio()");

    var audioLink = giveLink("audio");

    console.log("audioLink: " + audioLink);

    if (audioLink.endsWith("?t=0&a=mousikófíditestogg0") === false) {
        console.log("TEST FAILED");
        console.log("audioLink.endsWith(\"?t=0&a=mousikófíditestogg0\") did not equal 'true'!!");
        console.log("End: testGiveLinkAudio()");
        return false;
    }

    console.log("End: testGiveLinkAudio()");
    return true;
}

function testGiveLinkVideo() {
    console.log("Begin: testGiveLinkVideo()");

    var videoLink = giveLink("video");

    console.log("videoLink: " + videoLink);

    if (videoLink.endsWith("?t=0&v=realwebm0#videoplayer") === false) {
        console.log("TEST FAILED");
        console.log("videoLink.endsWith(\"?t=0&v=realwebm0#videoplayer\") did not equal 'true'!!");
        console.log("End: testGiveLinkVideo()");
        return false;
    }

    console.log("End: testGiveLinkVideo()");
    return true;
}

function testGiveLinkSingle() {
    console.log("Begin: testGiveLinkSingle()");

    var singleLink = giveLink("single");

    console.log("singleLink: " + singleLink);

    if (singleLink.endsWith("?t=0") === false) {
        console.log("TEST FAILED");
        console.log("singleLink.endsWith(\"?t=0\") did not equal 'true'!!");
        console.log("End: testGiveLinkSingle()");
        return false;
    }

    console.log("End: testGiveLinkSingle()");
    return true;
}

//
// Test Entrypoint
//


@@ 610,6 809,66 @@ function testFidiJs() {
        fail += 1;
    }

    var result9 = testPlayAudio();
    if (result9) {
        passed.appendChild(document.createElement("div"));
        passed.childNodes[pass].textContent = "PASS: testPlayAudio()";
        pass += 1;

    } else {
        failed.appendChild(document.createElement("div"));
        failed.childNodes[fail].textContent = "FAIL: testPlayAudio()";
        fail += 1;
    }

    var result10 = testPlayVideo();
    if (result10) {
        passed.appendChild(document.createElement("div"));
        passed.childNodes[pass].textContent = "PASS: testPlayVideo()";
        pass += 1;

    } else {
        failed.appendChild(document.createElement("div"));
        failed.childNodes[fail].textContent = "FAIL: testPlayVideo()";
        fail += 1;
    }

    var result11 = testGiveLinkAudio();
    if (result11) {
        passed.appendChild(document.createElement("div"));
        passed.childNodes[pass].textContent = "PASS: testGiveLinkAudio()";
        pass += 1;

    } else {
        failed.appendChild(document.createElement("div"));
        failed.childNodes[fail].textContent = "FAIL: testGiveLinkAudio()";
        fail += 1;
    }

    var result12 = testGiveLinkVideo();
    if (result12) {
        passed.appendChild(document.createElement("div"));
        passed.childNodes[pass].textContent = "PASS: testGiveLinkVideo()";
        pass += 1;

    } else {
        failed.appendChild(document.createElement("div"));
        failed.childNodes[fail].textContent = "FAIL: testGiveLinkVideo()";
        fail += 1;
    }

    var result13 = testGiveLinkSingle();
    if (result13) {
        passed.appendChild(document.createElement("div"));
        passed.childNodes[pass].textContent = "PASS: testGiveLinkSingle()";
        pass += 1;

    } else {
        failed.appendChild(document.createElement("div"));
        failed.childNodes[fail].textContent = "FAIL: testGiveLinkSingle()";
        fail += 1;
    }

    results.textContent = "--  Passed: " + pass + ", Failed: " + fail + " --";
    console.log("END: MousikóFídi Javascript Test Suite");
}

M templates/audio_player.html => templates/audio_player.html +1 -1
@@ 2,7 2,7 @@
  <p id="now-playing" title="The status of the current track.">Paused: <span class="bold" id="playing-title" title="The title of the current track."></span></p>
  <div data-nowplaying-num="0" id="now-playing-num"></div>
  <div data-randorder="none" id="randorder"></div>
  <audio{% if autoplay %} autoplay{% endif %}{% if preload_audio %} preload="auto"{% endif %} id="audio" controls data-nowplaying="none">
  <audio{% if autoplay %} autoplay{% endif %}{% if preload_audio %} preload="auto"{% endif %} id="audio" controls>
    Your browser does not support the <code>audio</code> element.
  </audio>
  <button data-cmd="prev" id="prev" title="Click to skip to the previous track in the list.">Previous</button>

M templates/base.html => templates/base.html +1 -0
@@ 115,6 115,7 @@
    {% else %}
      <script src="/js/player.min.js"></script>
    {% endif %}
    {% block extra_js %}{% endblock %}

  </body>
</html>

M templates/test_js.html => templates/test_js.html +36 -90
@@ 1,103 1,49 @@
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title id="title" data-sitename="MousikóFídi Javascript Test Page">MousikóFídi Javascript Test Page</title>
{% extends 'base.html' %}
{% block content %}

    <style>
     .center {
       text-align: center;
     }
  <div class="hidden">
    {% include "item_table.html" with context %}
    {% include "audio_player.html" with context %}
    {% include "video_player.html" with context %}
    <audio id="single"{% if autoplay %} autoplay{% endif %} controls src="/serve/{{ single_file_e }}">
      Your browser does not support the <code>audio</code> element.
    </audio>
  </div>

     .hidden {
       display: none;
     }
    </style>
  <h1 class="center">{{ page_name }}</h1>

  </head>
  <body>
  <p class="center">Tests begin below:</p>

    <h1 class="center">MousikóFídi Javascript Test Page</h1>
  <div data-nowplaying-num="0" id="now-playing-num"></div>
  <div data-randorder="none" id="randorder"></div>

    <p class="center">Tests begin below:</p>
  <div data-nowplaying-num="0" id="video-now-playing-num"></div>
  <div data-randorder="none" id="vid-randorder"></div>

    <div data-nowplaying-num="0" id="now-playing-num"></div>
    <div data-randorder="none" id="randorder"></div>
  <p class="hidden" id="now-playing" title="The status of the current track.">Paused: <span class="bold" id="playing-title" title="The title of the current track."></span></p>
  <!-- <audio class="hidden" data-nowplaying="none" id="audio"></audio> -->

    <div data-nowplaying-num="0" id="video-now-playing-num"></div>
    <div data-randorder="none" id="vid-randorder"></div>
  <button class="hidden" data-cmd="prev" id="prev" title="Click to skip to the previous track in the list.">Previous</button>
  <button class="hidden" data-cmd="fwd" id="next" title="Click to skip to the next track in the list.">Next</button>
  <button class="hidden" data-stat="off" id="repeat" title="Click to toggle between no repeat, repeat one track, and repeat all tracks.">No Repeat</button>
  <button class="hidden" data-stat="off" id="shuffle" title="Click to toggle between a shuffled track order on and off.">Shuffle Off</button>

    <div class="hidden" id="playlist">
      <div class="title"><div class="play-arrow" data-browse="/browse/something">Audio</div></div>
      <div class="title"><div class="play-arrow" data-browse="/browse/something">Audio</div></div>
      <div class="title"><div class="play-arrow" data-browse="/browse/something">Audio</div></div>
      <div class="title"><div class="play-arrow" data-browse="/browse/something">Audio</div></div>
      <div class="title"><div class="play-arrow" data-browse="/browse/something">Audio</div></div>
      <div class="title"><div class="play-arrow" data-browse="/browse/something">Audio</div></div>
      <div class="title"><div class="play-arrow" data-browse="/browse/something">Audio</div></div>
      <div class="title"><div class="play-arrow" data-browse="/browse/something">Audio</div></div>
      <div class="title"><div class="play-arrow" data-browse="/browse/something">Audio</div></div>
      <div class="title"><div class="play-arrow" data-browse="/browse/something">Audio</div></div>
      <div class="title"><div class="play-arrow" data-browse="/browse/something">Audio</div></div>
      <div class="title"><div class="play-arrow" data-browse="/browse/something">Audio</div></div>
      <div class="title"><div class="play-arrow" data-browse="/browse/something">Audio</div></div>
      <div class="title"><div class="play-arrow" data-browse="/browse/something">Audio</div></div>
      <div class="title"><div class="play-arrow" data-browse="/browse/something">Audio</div></div>
      <div class="title"><div class="play-arrow" data-browse="/browse/something">Audio</div></div>
      <div class="title"><div class="play-arrow" data-browse="/browse/something">Audio</div></div>
      <div class="title"><div class="play-arrow" data-browse="/browse/something">Audio</div></div>
      <div class="title"><div class="play-arrow" data-browse="/browse/something">Audio</div></div>
      <div class="title"><div class="play-arrow" data-browse="/browse/something">Audio</div></div>
    </div>
  <!-- <video class="hidden" id="video"></video> -->

    <div class="hidden" id="video-playlist">
      <div class="video-title"><div class="video-arrow" data-browse="/browse/something">Video</div></div>
      <div class="video-title"><div class="video-arrow" data-browse="/browse/something">Video</div></div>
      <div class="video-title"><div class="video-arrow" data-browse="/browse/something">Video</div></div>
      <div class="video-title"><div class="video-arrow" data-browse="/browse/something">Video</div></div>
      <div class="video-title"><div class="video-arrow" data-browse="/browse/something">Video</div></div>
      <div class="video-title"><div class="video-arrow" data-browse="/browse/something">Video</div></div>
      <div class="video-title"><div class="video-arrow" data-browse="/browse/something">Video</div></div>
      <div class="video-title"><div class="video-arrow" data-browse="/browse/something">Video</div></div>
      <div class="video-title"><div class="video-arrow" data-browse="/browse/something">Video</div></div>
      <div class="video-title"><div class="video-arrow" data-browse="/browse/something">Video</div></div>
      <div class="video-title"><div class="video-arrow" data-browse="/browse/something">Video</div></div>
      <div class="video-title"><div class="video-arrow" data-browse="/browse/something">Video</div></div>
      <div class="video-title"><div class="video-arrow" data-browse="/browse/something">Video</div></div>
      <div class="video-title"><div class="video-arrow" data-browse="/browse/something">Video</div></div>
      <div class="video-title"><div class="video-arrow" data-browse="/browse/something">Video</div></div>
      <div class="video-title"><div class="video-arrow" data-browse="/browse/something">Video</div></div>
      <div class="video-title"><div class="video-arrow" data-browse="/browse/something">Video</div></div>
      <div class="video-title"><div class="video-arrow" data-browse="/browse/something">Video</div></div>
      <div class="video-title"><div class="video-arrow" data-browse="/browse/something">Video</div></div>
      <div class="video-title"><div class="video-arrow" data-browse="/browse/something">Video</div></div>
      <div class="video-title"><div class="video-arrow" data-browse="/browse/something">Video</div></div>
    </div>
  <button class="hidden" data-cmd="prev" id="vid-prev" title="Click to skip to the previous track in the list.">Previous</button>
  <button class="hidden" data-cmd="fwd" id="vid-next" title="Click to skip to the next track in the list.">Next</button>
  <button class="hidden" data-stat="off" id="vid-repeat" title="Click to toggle between no repeat, repeat one track, and repeat all tracks.">No Repeat</button>  
  <button class="hidden" data-stat="off" id="vid-shuffle" title="Click to toggle between a shuffled track order on and off.">Shuffle Off</button>

    <p class="hidden" id="now-playing" title="The status of the current track.">Paused: <span class="bold" id="playing-title" title="The title of the current track."></span></p>
    <!-- <audio class="hidden" data-nowplaying="none" id="audio"></audio> -->
  <!-- The below three elements are not required or used by the js that's being tested. -->
  <div id="__failed"></div>
  <div id="__passed"></div>
  <div id="__results"></div>

    <button class="hidden" data-cmd="prev" id="prev" title="Click to skip to the previous track in the list.">Previous</button>
    <button class="hidden" data-cmd="fwd" id="next" title="Click to skip to the next track in the list.">Next</button>
    <button class="hidden" data-stat="off" id="repeat" title="Click to toggle between no repeat, repeat one track, and repeat all tracks.">No Repeat</button>
    <button class="hidden" data-stat="off" id="shuffle" title="Click to toggle between a shuffled track order on and off.">Shuffle Off</button>
  <h3 class="center"><a href="{{ url_for('.index') }}">Get me outta here!</a></h3>

    <!-- <video class="hidden" id="video"></video> -->
{% endblock %}

    <button class="hidden" data-cmd="prev" id="vid-prev" title="Click to skip to the previous track in the list.">Previous</button>
    <button class="hidden" data-cmd="fwd" id="vid-next" title="Click to skip to the next track in the list.">Next</button>
    <button class="hidden" data-stat="off" id="vid-repeat" title="Click to toggle between no repeat, repeat one track, and repeat all tracks.">No Repeat</button>  
    <button class="hidden" data-stat="off" id="vid-shuffle" title="Click to toggle between a shuffled track order on and off.">Shuffle Off</button>

    <!-- The below three elements are not required or used by the js that's being tested. -->
    <div id="__failed"></div>
    <div id="__passed"></div>
    <div id="__results"></div>

    <p class="center"><a href="{{ url_for('.index') }}">Get me outta here!</a></p>

    <script src="/static/js/player.js"></script>
    <script src="/static/js/tests.js"></script>

  </body>
</html>
{% block extra_js %}
  <script src="/static/js/tests.js"></script> 
{% endblock %}

M test_mousikofidi.py => test_mousikofidi.py +102 -64
@@ 59,7 59,7 @@ def client():
        yield client


def test_audio_dict():
def test_audio_dict_flac():
    example_dir_unescaped = os.path.join(THIS_DIR, "example")
    example_dir_escaped = quote(example_dir_unescaped)
    f = os.path.join(THIS_DIR, "example", "real.flac")


@@ 70,14 70,58 @@ def test_audio_dict():
        "album": "MousikóFídi Test Album",
        "artist": "MousikóFídi Test Artist",
        "genre": "MousikóFídi Test",
        "title": "MousikóFídi Test Title",
        "title": "MousikóFídi Test FLAC",
        "track": "34",
        "type": "audio",
        "tracktotal": None,
        "file_name": "real.flac",
        "escaped_path": "{}%2Freal.flac".format(example_dir_escaped),
        "unescaped_path": "{}/real.flac".format(example_dir_unescaped),
        "slug": "mousikófíditesttitle",
        "slug": "mousikófíditestflac",
    }


def test_audio_dict_mp3():
    example_dir_unescaped = os.path.join(THIS_DIR, "example")
    example_dir_escaped = quote(example_dir_unescaped)
    f = os.path.join(THIS_DIR, "example", "real.mp3")
    m = get_metadata_dict(f)
    d = file_dict(f, m, "audio")

    assert d == {
        "album": "MousikóFídi Test Album",
        "artist": "MousikóFídi Test Artist",
        "genre": "MousikóFídi Test",
        "title": "MousikóFídi Test MP3",
        "track": "34",
        "type": "audio",
        "tracktotal": "1",
        "file_name": "real.mp3",
        "escaped_path": "{}%2Freal.mp3".format(example_dir_escaped),
        "unescaped_path": "{}/real.mp3".format(example_dir_unescaped),
        "slug": "mousikófíditestmp3",
    }


def test_audio_dict_ogg():
    example_dir_unescaped = os.path.join(THIS_DIR, "example")
    example_dir_escaped = quote(example_dir_unescaped)
    f = os.path.join(THIS_DIR, "example", "real.ogg")
    m = get_metadata_dict(f)
    d = file_dict(f, m, "audio")

    assert d == {
        "album": "MousikóFídi Test Album",
        "artist": "MousikóFídi Test Artist",
        "genre": "MousikóFídi Test",
        "title": "MousikóFídi Test OGG",
        "track": "34",
        "type": "audio",
        "tracktotal": None,
        "file_name": "real.ogg",
        "escaped_path": "{}%2Freal.ogg".format(example_dir_escaped),
        "unescaped_path": "{}/real.ogg".format(example_dir_unescaped),
        "slug": "mousikófíditestogg",
    }




@@ 89,7 133,7 @@ def test_audio_metadata_fake_flac():
def test_audio_metadata_real_flac():
    real = file_metadata(os.path.join(THIS_DIR, "example", "real.flac"))
    assert real == {
        "TITLE": "MousikóFídi Test Title",
        "TITLE": "MousikóFídi Test FLAC",
        "ARTIST": "MousikóFídi Test Artist",
        "ALBUM": "MousikóFídi Test Album",
        "COMMENT": "FLAC",


@@ 107,7 151,7 @@ def test_audio_metadata_fake_mp3():
def test_audio_metadata_real_mp3():
    real = file_metadata(os.path.join(THIS_DIR, "example", "real.mp3"))
    assert real == {
        "TIT2": "MousikóFídi Test Title",
        "TIT2": "MousikóFídi Test MP3",
        "TPE1": "MousikóFídi Test Artist",
        "TALB": "MousikóFídi Test Album",
        "COMM": "MP3",


@@ 126,7 170,7 @@ def test_audio_metadata_fake_ogg():
def test_audio_metadata_real_ogg():
    real = file_metadata(os.path.join(THIS_DIR, "example", "real.ogg"))
    assert real == {
        "TITLE": "MousikóFídi Test Title",
        "TITLE": "MousikóFídi Test OGG",
        "ARTIST": "MousikóFídi Test Artist",
        "ALBUM": "MousikóFídi Test Album",
        "COMMENT": "OGG",


@@ 324,26 368,26 @@ def test_browse_dir():
                "album": "MousikóFídi Test Album",
                "artist": "MousikóFídi Test Artist",
                "genre": "MousikóFídi Test",
                "title": "MousikóFídi Test Title",
                "title": "MousikóFídi Test FLAC",
                "track": "34",
                "tracktotal": None,
                "file_name": "real.flac",
                "escaped_path": "{}%2Fexample%2Freal.flac".format(escaped_sourcedir),
                "unescaped_path": "{}/example/real.flac".format(unescaped_sourcedir),
                "slug": "mousikófíditesttitle",
                "slug": "mousikófíditestflac",
            },
            {
                "type": "audio",
                "album": "MousikóFídi Test Album",
                "artist": "MousikóFídi Test Artist",
                "genre": "MousikóFídi Test",
                "title": "MousikóFídi Test Title",
                "title": "MousikóFídi Test MP3",
                "track": "34",
                "tracktotal": "1",
                "file_name": "real.mp3",
                "escaped_path": "{}%2Fexample%2Freal.mp3".format(escaped_sourcedir),
                "unescaped_path": "{}/example/real.mp3".format(unescaped_sourcedir),
                "slug": "mousikófíditesttitle0",
                "slug": "mousikófíditestmp3",
            },
            {
                "type": "video",


@@ 363,13 407,13 @@ def test_browse_dir():
                "album": "MousikóFídi Test Album",
                "artist": "MousikóFídi Test Artist",
                "genre": "MousikóFídi Test",
                "title": "MousikóFídi Test Title",
                "title": "MousikóFídi Test OGG",
                "track": "34",
                "tracktotal": None,
                "file_name": "real.ogg",
                "escaped_path": "{}%2Fexample%2Freal.ogg".format(escaped_sourcedir),
                "unescaped_path": "{}/example/real.ogg".format(unescaped_sourcedir),
                "slug": "mousikófíditesttitle1",
                "slug": "mousikófíditestogg",
            },
        ],
    }


@@ 762,7 806,7 @@ def test_get_metadata_dict_real_audio():
        "artist": "MousikóFídi Test Artist",
        "date": "2019-08-08",
        "genre": "MousikóFídi Test",
        "title": "MousikóFídi Test Title",
        "title": "MousikóFídi Test FLAC",
        "track": "34",
        "tracktotal": None,
    }


@@ 1663,7 1707,9 @@ def test_dir_detail_found(client):
    assert b"fake.ogg" in rv.data
    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 Title", "utf8") in rv.data
    assert bytes("MousikóFídi Test FLAC", "utf8") in rv.data
    assert bytes("MousikóFídi Test MP3", "utf8") in rv.data
    assert bytes("MousikóFídi Test OGG", "utf8") in rv.data
    assert b"34" in rv.data
    assert (
        bytes(


@@ 1714,9 1760,7 @@ def test_dir_detail_found(client):
        in rv.data
    )
    assert bytes('<div data-randorder="none" id="randorder"></div>', "utf8") in rv.data
    assert (
        bytes('<audio id="audio" controls data-nowplaying="none">', "utf8") in rv.data
    )
    assert bytes('<audio id="audio" controls>', "utf8") in rv.data
    assert bytes("</audio>", "utf8") in rv.data
    assert (
        bytes(


@@ 1856,10 1900,9 @@ def test_file_detail_real_flac(client):
    assert b"Track: 34" in rv.data
    assert b"Released: 2019-08-08" in rv.data
    assert bytes("Genre: MousikóFídi Test", "utf8") in rv.data
    assert bytes('"MousikóFídi Test Title"', "utf8") in rv.data
    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 Title", "utf8") in rv.data
    assert bytes("MousikóFídi Test FLAC", "utf8") in rv.data
    assert (
        bytes(
            '<audio id="single" controls src="/serve/{}">'.format(


@@ 1880,7 1923,7 @@ def test_file_detail_real_flac(client):
    )
    assert (
        bytes(
            '<title id="title" data-sitename="{0}">MousikóFídi Test Title | {0}</title>'.format(
            '<title id="title" data-sitename="{0}">MousikóFídi Test FLAC | {0}</title>'.format(
                site_name
            ),
            "utf8",


@@ 1907,12 1950,11 @@ def test_file_detail_real_mp3(client):
    assert bytes(quote(example_dir_unescaped), "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 Title"', "utf8") in rv.data
    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 Album", "utf8") in rv.data
    assert bytes("MousikóFídi Test Artist", "utf8") in rv.data
    assert bytes("MousikóFídi Test Title", "utf8") in rv.data
    assert bytes("MousikóFídi Test MP3", "utf8") in rv.data
    assert (
        bytes(
            '<audio id="single" controls src="/serve/{}">'.format(


@@ 1933,7 1975,7 @@ def test_file_detail_real_mp3(client):
    )
    assert (
        bytes(
            '<title id="title" data-sitename="{0}">MousikóFídi Test Title | {0}</title>'.format(
            '<title id="title" data-sitename="{0}">MousikóFídi Test MP3 | {0}</title>'.format(
                site_name
            ),
            "utf8",


@@ 2020,10 2062,9 @@ def test_file_detail_real_ogg(client):
    assert b"Track: 34" in rv.data
    assert b"Released: 2019-08-08" in rv.data
    assert bytes("Genre: MousikóFídi Test", "utf8") in rv.data
    assert bytes('"MousikóFídi Test Title"', "utf8") in rv.data
    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 Title", "utf8") in rv.data
    assert bytes("MousikóFídi Test OGG", "utf8") in rv.data
    assert (
        bytes(
            '<audio id="single" controls src="/serve/{}">'.format(


@@ 2044,7 2085,7 @@ def test_file_detail_real_ogg(client):
    )
    assert (
        bytes(
            '<title id="title" data-sitename="{0}">MousikóFídi Test Title | {0}</title>'.format(
            '<title id="title" data-sitename="{0}">MousikóFídi Test OGG | {0}</title>'.format(
                site_name
            ),
            "utf8",


@@ 2149,7 2190,7 @@ def test_playlist_with_audio_and_video(client):
    assert bytes('<h4 class="center">Video Tracks</h4>', "utf8") in rv.data
    assert (
        bytes(
            '<div class="play-arrow" data-browse="/browse/{0}%2Freal.flac" data-num="0" data-path="{1}/real.flac" data-title="MousikóFídi Test Title" id="mousikófíditesttitle" title="Click to play this track."></div>'.format(
            '<div class="play-arrow" data-browse="/browse/{0}%2Freal.flac" data-num="0" data-path="{1}/real.flac" data-title="MousikóFídi Test FLAC" id="mousikófíditestflac" title="Click to play this track."></div>'.format(
                quote(example_dir), example_dir
            ),
            "utf8",


@@ 2165,7 2206,9 @@ def test_playlist_with_audio_and_video(client):
        )
        in rv.data
    )
    assert bytes("MousikóFídi Test Title", "utf8") in rv.data
    assert bytes("MousikóFídi Test FLAC", "utf8") in rv.data
    assert bytes("MousikóFídi Test MP3", "utf8") in rv.data
    assert bytes("MousikóFídi Test OGG", "utf8") in rv.data
    assert bytes("MousikóFídi Test Album", "utf8") in rv.data
    assert (
        bytes(


@@ 2181,7 2224,7 @@ def test_playlist_with_audio_and_video(client):
    )
    assert (
        bytes(
            '<div class="play-arrow" data-browse="/browse/{0}%2Freal.mp3" data-num="0" data-path="{1}/real.mp3" data-title="MousikóFídi Test Title" id="mousikófíditesttitle0" title="Click to play this track."></div>'.format(
            '<div class="play-arrow" data-browse="/browse/{0}%2Freal.mp3" data-num="0" data-path="{1}/real.mp3" data-title="MousikóFídi Test MP3" id="mousikófíditestmp3" title="Click to play this track."></div>'.format(
                quote(example_dir), example_dir
            ),
            "utf8",


@@ 2235,7 2278,7 @@ def test_playlist_with_audio_and_video(client):
    )
    assert (
        bytes(
            '<div class="play-arrow" data-browse="/browse/{0}%2Freal.ogg" data-num="0" data-path="{1}/real.ogg" data-title="MousikóFídi Test Title" id="mousikófíditesttitle1" title="Click to play this track."></div>'.format(
            '<div class="play-arrow" data-browse="/browse/{0}%2Freal.ogg" data-num="0" data-path="{1}/real.ogg" data-title="MousikóFídi Test OGG" id="mousikófíditestogg" title="Click to play this track."></div>'.format(
                quote(example_dir), example_dir
            ),
            "utf8",


@@ 2327,9 2370,7 @@ def test_playlist_with_audio_and_video(client):
        in rv.data
    )
    assert bytes('<div data-randorder="none" id="randorder"></div>', "utf8") in rv.data
    assert (
        bytes('<audio id="audio" controls data-nowplaying="none">', "utf8") in rv.data
    )
    assert bytes('<audio id="audio" controls>', "utf8") in rv.data
    assert bytes("</audio>", "utf8") in rv.data
    assert (
        bytes(


@@ 2470,7 2511,7 @@ def test_playlist_with_audio_no_video(client):
    assert bytes('<h4 class="center">Files:</h4>', "utf8") in rv.data
    assert (
        bytes(
            '<div class="play-arrow" data-browse="/browse/{0}%2Freal.flac" data-num="0" data-path="{1}/real.flac" data-title="MousikóFídi Test Title" id="mousikófíditesttitle" title="Click to play this track."></div>'.format(
            '<div class="play-arrow" data-browse="/browse/{0}%2Freal.flac" data-num="0" data-path="{1}/real.flac" data-title="MousikóFídi Test FLAC" id="mousikófíditestflac" title="Click to play this track."></div>'.format(
                quote(example_dir), example_dir
            ),
            "utf8",


@@ 2486,7 2527,9 @@ def test_playlist_with_audio_no_video(client):
        )
        in rv.data
    )
    assert bytes("MousikóFídi Test Title", "utf8") in rv.data
    assert bytes("MousikóFídi Test FLAC", "utf8") in rv.data
    assert bytes("MousikóFídi Test MP3", "utf8") in rv.data
    assert bytes("MousikóFídi Test OGG", "utf8") in rv.data
    assert bytes("MousikóFídi Test Album", "utf8") in rv.data
    assert (
        bytes(


@@ 2502,7 2545,7 @@ def test_playlist_with_audio_no_video(client):
    )
    assert (
        bytes(
            '<div class="play-arrow" data-browse="/browse/{0}%2Freal.mp3" data-num="0" data-path="{1}/real.mp3" data-title="MousikóFídi Test Title" id="mousikófíditesttitle0" title="Click to play this track."></div>'.format(
            '<div class="play-arrow" data-browse="/browse/{0}%2Freal.mp3" data-num="0" data-path="{1}/real.mp3" data-title="MousikóFídi Test MP3" id="mousikófíditestmp3" title="Click to play this track."></div>'.format(
                quote(example_dir), example_dir
            ),
            "utf8",


@@ 2556,7 2599,7 @@ def test_playlist_with_audio_no_video(client):
    )
    assert (
        bytes(
            '<div class="play-arrow" data-browse="/browse/{0}%2Freal.ogg" data-num="0" data-path="{1}/real.ogg" data-title="MousikóFídi Test Title" id="mousikófíditesttitle1" title="Click to play this track."></div>'.format(
            '<div class="play-arrow" data-browse="/browse/{0}%2Freal.ogg" data-num="0" data-path="{1}/real.ogg" data-title="MousikóFídi Test OGG" id="mousikófíditestogg" title="Click to play this track."></div>'.format(
                quote(example_dir), example_dir
            ),
            "utf8",


@@ 2648,9 2691,7 @@ def test_playlist_with_audio_no_video(client):
        in rv.data
    )
    assert bytes('<div data-randorder="none" id="randorder"></div>', "utf8") in rv.data
    assert (
        bytes('<audio id="audio" controls data-nowplaying="none">', "utf8") in rv.data
    )
    assert bytes('<audio id="audio" controls>', "utf8") in rv.data
    assert bytes("</audio>", "utf8") in rv.data
    assert (
        bytes(


@@ 2974,10 3015,7 @@ def test_playlist_no_audio_with_video(client):
    assert (
        bytes('<div data-randorder="none" id="randorder"></div>', "utf8") not in rv.data
    )
    assert (
        bytes('<audio id="audio" controls data-nowplaying="none">', "utf8")
        not in rv.data
    )
    assert bytes('<audio id="audio" controls>', "utf8") not in rv.data
    assert bytes("</audio>", "utf8") not in rv.data
    assert (
        bytes(


@@ 3143,10 3181,10 @@ def test_playlist_detail_real_with_bad(client):
        )
        in rv.data
    )
    assert bytes('<div class="anchor" id="mousikófíditesttitle">', "utf8") in rv.data
    assert bytes('<div class="anchor" id="mousikófíditestflac">', "utf8") in rv.data
    assert (
        bytes(
            '<div class="play-arrow" data-browse="/browse/{q}%2Freal.flac" data-num="0" data-path="{u}/real.flac" data-title="MousikóFídi Test Title" id="mousikófíditesttitle" title="Click to play this track."></div>'.format(
            '<div class="play-arrow" data-browse="/browse/{q}%2Freal.flac" data-num="0" data-path="{u}/real.flac" data-title="MousikóFídi Test FLAC" id="mousikófíditestflac" title="Click to play this track."></div>'.format(
                q=qmdir, u=mdir
            ),
            "utf8",


@@ 3159,12 3197,14 @@ def test_playlist_detail_real_with_bad(client):
        )
        in rv.data
    )
    assert bytes("\n                  MousikóFídi Test Title\n", "utf8") in rv.data
    assert bytes("\n                  MousikóFídi Test FLAC\n", "utf8") in rv.data
    assert bytes("\n                  MousikóFídi Test MP3\n", "utf8") in rv.data
    assert bytes("\n                  MousikóFídi Test OGG\n", "utf8") in rv.data
    assert bytes("\n              MousikóFídi Test\n", "utf8") in rv.data
    assert bytes('<div class="anchor" id="mousikófíditesttitle0">', "utf8") in rv.data
    assert bytes('<div class="anchor" id="mousikófíditestmp3">', "utf8") in rv.data
    assert (
        bytes(
            '<div class="play-arrow" data-browse="/browse/{q}%2Freal.mp3" data-num="0" data-path="{u}/real.mp3" data-title="MousikóFídi Test Title" id="mousikófíditesttitle0" title="Click to play this track."></div>'.format(
            '<div class="play-arrow" data-browse="/browse/{q}%2Freal.mp3" data-num="0" data-path="{u}/real.mp3" data-title="MousikóFídi Test MP3" id="mousikófíditestmp3" title="Click to play this track."></div>'.format(
                q=qmdir, u=mdir
            ),
            "utf8",


@@ 3179,10 3219,10 @@ def test_playlist_detail_real_with_bad(client):
    )
    assert bytes("\n              MousikóFídi Test Album\n", "utf8") in rv.data
    assert bytes("\n              MousikóFídi Test Artist\n", "utf8") in rv.data
    assert bytes('<div class="anchor" id="mousikófíditesttitle1">', "utf8") in rv.data
    assert bytes('<div class="anchor" id="mousikófíditestogg">', "utf8") in rv.data
    assert (
        bytes(
            '<div class="play-arrow" data-browse="/browse/{q}%2Freal.ogg" data-num="0" data-path="{u}/real.ogg" data-title="MousikóFídi Test Title" id="mousikófíditesttitle1" title="Click to play this track."></div>'.format(
            '<div class="play-arrow" data-browse="/browse/{q}%2Freal.ogg" data-num="0" data-path="{u}/real.ogg" data-title="MousikóFídi Test OGG" id="mousikófíditestogg" title="Click to play this track."></div>'.format(
                q=qmdir, u=mdir
            ),
            "utf8",


@@ 3207,9 3247,7 @@ def test_playlist_detail_real_with_bad(client):
        in rv.data
    )
    assert bytes('<div data-randorder="none" id="randorder"></div>', "utf8") in rv.data
    assert (
        bytes('<audio id="audio" controls data-nowplaying="none">', "utf8") in rv.data
    )
    assert bytes('<audio id="audio" controls>', "utf8") in rv.data
    assert bytes("</audio>", "utf8") in rv.data
    assert (
        bytes(


@@ 3314,10 3352,10 @@ def test_playlist_detail_real(client):
        )
        in rv.data
    )
    assert bytes('<div class="anchor" id="mousikófíditesttitle">', "utf8") in rv.data
    assert bytes('<div class="anchor" id="mousikófíditestflac">', "utf8") in rv.data
    assert (
        bytes(
            '<div class="play-arrow" data-browse="/browse/{q}%2Freal.flac" data-num="0" data-path="{u}/real.flac" data-title="MousikóFídi Test Title" id="mousikófíditesttitle" title="Click to play this track."></div>'.format(
            '<div class="play-arrow" data-browse="/browse/{q}%2Freal.flac" data-num="0" data-path="{u}/real.flac" data-title="MousikóFídi Test FLAC" id="mousikófíditestflac" title="Click to play this track."></div>'.format(
                q=qmdir, u=mdir
            ),
            "utf8",


@@ 3330,12 3368,12 @@ def test_playlist_detail_real(client):
        )
        in rv.data
    )
    assert bytes("\n                  MousikóFídi Test Title\n", "utf8") in rv.data
    assert bytes("\n                  MousikóFídi Test FLAC\n", "utf8") in rv.data
    assert bytes("\n              MousikóFídi Test\n", "utf8") in rv.data
    assert bytes('<div class="anchor" id="mousikófíditesttitle0">', "utf8") in rv.data
    assert bytes('<div class="anchor" id="mousikófíditestmp3">', "utf8") in rv.data
    assert (
        bytes(
            '<div class="play-arrow" data-browse="/browse/{q}%2Freal.mp3" data-num="0" data-path="{u}/real.mp3" data-title="MousikóFídi Test Title" id="mousikófíditesttitle0" title="Click to play this track."></div>'.format(
            '<div class="play-arrow" data-browse="/browse/{q}%2Freal.mp3" data-num="0" data-path="{u}/real.mp3" data-title="MousikóFídi Test MP3" id="mousikófíditestmp3" title="Click to play this track."></div>'.format(
                q=qmdir, u=mdir
            ),
            "utf8",


@@ 3348,12 3386,14 @@ def test_playlist_detail_real(client):
        )
        in rv.data
    )
    assert bytes("\n                  MousikóFídi Test MP3\n", "utf8") in rv.data
    assert bytes("\n                  MousikóFídi Test OGG\n", "utf8") in rv.data
    assert bytes("\n              MousikóFídi Test Album\n", "utf8") in rv.data
    assert bytes("\n              MousikóFídi Test Artist\n", "utf8") in rv.data
    assert bytes('<div class="anchor" id="mousikófíditesttitle1">', "utf8") in rv.data
    assert bytes('<div class="anchor" id="mousikófíditestogg">', "utf8") in rv.data
    assert (
        bytes(
            '<div class="play-arrow" data-browse="/browse/{q}%2Freal.ogg" data-num="0" data-path="{u}/real.ogg" data-title="MousikóFídi Test Title" id="mousikófíditesttitle1" title="Click to play this track."></div>'.format(
            '<div class="play-arrow" data-browse="/browse/{q}%2Freal.ogg" data-num="0" data-path="{u}/real.ogg" data-title="MousikóFídi Test OGG" id="mousikófíditestogg" title="Click to play this track."></div>'.format(
                q=qmdir, u=mdir
            ),
            "utf8",


@@ 3378,9 3418,7 @@ def test_playlist_detail_real(client):
        in rv.data
    )
    assert bytes('<div data-randorder="none" id="randorder"></div>', "utf8") in rv.data
    assert (
        bytes('<audio id="audio" controls data-nowplaying="none">', "utf8") in rv.data
    )
    assert bytes('<audio id="audio" controls>', "utf8") in rv.data
    assert bytes("</audio>", "utf8") in rv.data
    assert (
        bytes(