~hristoast/mousikofidi

2ec73849bd353d2f080a68aacb13543f5bbe0279 — Hristos N. Triantafillou 8 months ago 14c147b 0.12
Allow overwriting saved playlists with a confirmation (#48)

I've also greatly expanded tests.
2 files changed, 1001 insertions(+), 17 deletions(-)

M mousikofidi.py
M test_mousikofidi.py
M mousikofidi.py => mousikofidi.py +23 -8
@@ 589,10 589,10 @@ this User's Guide entry</a> for more information.</p>"""
            if "delete" in request.form:
                if os.path.isfile(full_path):
                    flash(
                        """<form action="/playlist/load/%2Fdelete-confirm" class="center" id="playlistctl" method="post">
                        """<p><form action="/playlist/load/%2Fdelete-confirm" class="center" id="playlistctl" method="post">
  <input class="center red" id="really-delete" name="really-delete" title="Verify to delete the selected playlist file." value="Really delete '{0}'?" type="submit" />
  <input id="to-load" name="to-load" type="hidden" value="{0}">
</form>""".format(
</form></p>""".format(
                            to_load
                        )
                    )


@@ 660,7 660,13 @@ this User's Guide entry</a> for more information.</p>"""

    elif cmd == "save":
        allowed_chars = (" ", "_", "+")
        bulk_paths = ast.literal_eval(request.form["bulk-list"])
        bulk_list = request.form.get("bulk-list")
        if bulk_list:
            bulk_paths = ast.literal_eval(bulk_list)
        else:
            bulk_paths = ast.literal_eval(
                urllib.parse.unquote(request.form.get("to-save"))
            )
        playlist_content = []
        playlist_dir = context["playlist_dir"]
        raw_file_name = request.form["file-name"]


@@ 676,12 682,21 @@ this User's Guide entry</a> for more information.</p>"""
            return context

        if os.path.isfile(full_path_file_name):
            flash(
                """<p class="bold center red">A playlist with the name '{}' already exists!</p>""".format(
                    cleaned_file_name
            if "save" in request.form:

                flash(
                    """<p><form action="/playlist/save/%2Fsave-confirm" class="center" id="playlistctl" method="post">
  <input class="center red" id="really-save" name="really-save" title="Verify overwrite selected playlist file." value="Overwrite Existing playlist '{0}'?" type="submit" />
  <input id="file-name" name="file-name" type="hidden" value="{0}">
  <input id="to-save" name="to-save" type="hidden" value='{1}'>
</form></p>""".format(
                        cleaned_file_name, quote(str(context["user_playlist"]))
                    )
                )
            )
            return context
                return context

            elif "really-save" in request.form:
                pass

        for p in bulk_paths:
            playlist_content.append(p)

M test_mousikofidi.py => test_mousikofidi.py +978 -9
@@ 570,11 570,11 @@ def test_handle_playlist_cmd_add_multi():
        example_dir = os.path.join(THIS_DIR, "example")
        c = init(use_config=os.path.join(example_dir, "fidi.yml"))

        f = os.path.join(THIS_DIR, "example", "real.flac")
        f2 = os.path.join(THIS_DIR, "example", "real.mp3")
        f3 = os.path.join(THIS_DIR, "example", "real.ogg")
        f4 = os.path.join(THIS_DIR, "example", "fake.mp4")
        f5 = os.path.join(THIS_DIR, "example", "fake.webm")
        f = os.path.join(example_dir, "real.flac")
        f2 = os.path.join(example_dir, "real.mp3")
        f3 = os.path.join(example_dir, "real.ogg")
        f4 = os.path.join(example_dir, "fake.mp4")
        f5 = os.path.join(example_dir, "fake.webm")

        d = request_context(c)
        d2 = handle_playlist_cmd("add", f, d)


@@ 2077,12 2077,981 @@ def test_playlist_empty(client):
    assert bytes("</form>", "utf8") not in rv.data


# TODO: Playlists and playlist detail tests.  Also check for the right buttons on each page.
def test_playlist_with_audio_and_video(client):
    example_dir = os.path.join(THIS_DIR, "example")
    url = "/playlist"

    with app.test_client() as tc:

        f = os.path.join(example_dir, "real.flac")
        f2 = os.path.join(example_dir, "real.mp3")
        f3 = os.path.join(example_dir, "real.mp4")
        f4 = os.path.join(example_dir, "real.ogg")
        f5 = os.path.join(example_dir, "fake.mp4")
        f6 = os.path.join(example_dir, "fake.webm")

        with tc.session_transaction() as sess:
            sess["user_playlist"] = [f, f2, f3, f4, f5, f6]

        rv = tc.get(url)

    assert (
        bytes(
            '<form  action="/playlist/clear/%2Fall" class="center" id="playlistctl" method="post">',
            "utf8",
        )
        in rv.data
    )
    assert (
        bytes(
            '<input class="center" id="clear" name="clear" title="Remove all tracks from your playlist." value="Clear Playlist" type="submit" />',
            "utf8",
        )
        in rv.data
    )
    assert (
        bytes(
            '<form action="/playlist/save/%2Fsave" class="center" id="playlistctl" method="post">',
            "utf8",
        )
        in rv.data
    )
    assert (
        bytes(
            '<input class="center" id="save" name="save" title="Save this playlist as a .m3u file.  Note that doing so will reload the page, stopping any playback." value="Save Playlist" type="submit" />',
            "utf8",
        )
        in rv.data
    )
    assert (
        bytes(
            '<input id="file-name" name="file-name" type="text" placeholder="Playlist name" title="File name for the playlist to be saved.  Only alphanumeric charatcers, spaces, underscores, and plus signs are allowed." required/>',
            "utf8",
        )
        in rv.data
    )
    assert (
        bytes(
            '<input id="item-list" name="bulk-list" type="hidden" value="[&#39;{0}/real.flac&#39;, &#39;{0}/real.mp3&#39;, &#39;{0}/real.mp4&#39;, &#39;{0}/real.ogg&#39;, &#39;{0}/fake.mp4&#39;, &#39;{0}/fake.webm&#39;]">'.format(
                example_dir
            ),
            "utf8",
        )
        in rv.data
    )
    assert bytes('<h4 class="center">Audio Tracks</h4>', "utf8") in rv.data
    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" title="Click to play this track."></div>'.format(
                quote(example_dir), example_dir
            ),
            "utf8",
        )
        in rv.data
    )
    assert (
        bytes(
            '<a class="mobile-big" href="/browse/{}%2Freal.flac">'.format(
                quote(example_dir)
            ),
            "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(
            '<form action="/playlist/rm/{}%2Freal.flac" class="center" method="post">'.format(
                quote(example_dir)
            ),
            "utf8",
        )
        in rv.data
    )
    assert (
        bytes('<input class="bold red X" type="submit" value="X">', "utf8") in rv.data
    )
    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" title="Click to play this track."></div>'.format(
                quote(example_dir), example_dir
            ),
            "utf8",
        )
        in rv.data
    )
    assert (
        bytes(
            '<a class="mobile-big" href="/browse/{}%2Freal.mp3">'.format(
                quote(example_dir)
            ),
            "utf8",
        )
        in rv.data
    )
    assert (
        bytes(
            '<form action="/playlist/rm/{}%2Freal.mp3" class="center" method="post">'.format(
                quote(example_dir)
            ),
            "utf8",
        )
        in rv.data
    )
    assert (
        bytes(
            '<div class="play-arrow video-arrow" data-browse="/browse/{0}%2Freal.mp4" data-num="0" data-path="{1}/real.mp4" data-title="MousikóFídi Test MP4" title="Click to play this track."></div>'.format(
                quote(example_dir), example_dir
            ),
            "utf8",
        )
        in rv.data
    )
    assert (
        bytes(
            '<a class="video-title" href="/browse/{}%2Freal.mp4">'.format(
                quote(example_dir)
            ),
            "utf8",
        )
        in rv.data
    )
    assert (
        bytes(
            '<form action="/playlist/rm/{}%2Freal.mp4" class="center" method="post">'.format(
                quote(example_dir)
            ),
            "utf8",
        )
        in rv.data
    )
    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" title="Click to play this track."></div>'.format(
                quote(example_dir), example_dir
            ),
            "utf8",
        )
        in rv.data
    )
    assert (
        bytes(
            '<a class="mobile-big" href="/browse/{}%2Freal.ogg">'.format(
                quote(example_dir)
            ),
            "utf8",
        )
        in rv.data
    )
    assert (
        bytes(
            '<form action="/playlist/rm/{}%2Freal.ogg" class="center" method="post">'.format(
                quote(example_dir)
            ),
            "utf8",
        )
        in rv.data
    )
    assert (
        bytes(
            '<div class="play-arrow video-arrow" data-browse="/browse/{0}%2Ffake.mp4" data-num="0" data-path="{1}/fake.mp4" data-title="fake.mp4" title="Click to play this track."></div>'.format(
                quote(example_dir), example_dir
            ),
            "utf8",
        )
        in rv.data
    )
    assert (
        bytes(
            '<a class="video-title" href="/browse/{}%2Ffake.mp4">'.format(
                quote(example_dir)
            ),
            "utf8",
        )
        in rv.data
    )
    assert (
        bytes(
            '<form action="/playlist/rm/{}%2Ffake.mp4" class="center" method="post">'.format(
                quote(example_dir)
            ),
            "utf8",
        )
        in rv.data
    )
    assert (
        bytes(
            '<div class="play-arrow video-arrow" data-browse="/browse/{0}%2Ffake.webm" data-num="0" data-path="{1}/fake.webm" data-title="fake.webm" title="Click to play this track."></div>'.format(
                quote(example_dir), example_dir
            ),
            "utf8",
        )
        in rv.data
    )
    assert (
        bytes(
            '<a class="video-title" href="/browse/{}%2Ffake.webm">'.format(
                quote(example_dir)
            ),
            "utf8",
        )
        in rv.data
    )
    assert (
        bytes(
            '<form action="/playlist/rm/{}%2Ffake.webm" class="center" method="post">'.format(
                quote(example_dir)
            ),
            "utf8",
        )
        in rv.data
    )
    assert bytes('<div class="center" id="player">', "utf8") in rv.data
    assert (
        bytes(
            '<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>',
            "utf8",
        )
        in rv.data
    )
    assert (
        bytes('<div data-nowplaying-num="0" id="now-playing-num"></div>', "utf8")
        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>", "utf8") in rv.data
    assert (
        bytes(
            '<button data-cmd="prev" id="prev" title="Click to skip to the previous track in the list.">Previous</button>',
            "utf8",
        )
        in rv.data
    )
    assert (
        bytes(
            '<button data-cmd="fwd" id="next" title="Click to skip to the next track in the list.">Next</button>',
            "utf8",
        )
        in rv.data
    )
    assert (
        bytes(
            '<button data-stat="off" id="repeat" title="Click to toggle between no repeat, repeat one track, and repeat all tracks.">No Repeat</button>',
            "utf8",
        )
        in rv.data
    )
    assert (
        bytes(
            '<button data-stat="off" id="shuffle" title="Click to toggle between a shuffled track order on and off.">Shuffle Off</button>',
            "utf8",
        )
        in rv.data
    )
    assert (
        bytes('<div data-nowplaying-num="0" id="video-now-playing-num"></div>', "utf8")
        in rv.data
    )
    assert (
        bytes('<div data-randorder="none" id="vid-randorder"></div>', "utf8") in rv.data
    )
    assert bytes('<div id="videoplayer" class="center">', "utf8") in rv.data
    assert bytes('<video id="video" controls>', "utf8") in rv.data
    assert bytes("<source>", "utf8") in rv.data
    assert bytes("</video>", "utf8") in rv.data
    assert (
        bytes(
            '<button data-cmd="prev" id="vid-prev" title="Click to skip to the previous track in the list.">Previous</button>',
            "utf8",
        )
        in rv.data
    )
    assert (
        bytes(
            '<button data-cmd="fwd" id="vid-next" title="Click to skip to the next track in the list.">Next</button>',
            "utf8",
        )
        in rv.data
    )
    assert (
        bytes(
            '<button data-stat="off" id="vid-repeat" title="Click to toggle between no repeat, repeat one track, and repeat all tracks.">No Repeat</button>',
            "utf8",
        )
        in rv.data
    )
    assert (
        bytes(
            '<button data-stat="off" id="vid-shuffle" title="Click to toggle between a shuffled track order on and off.">Shuffle Off</button>',
            "utf8",
        )
        in rv.data
    )
    assert bytes('<div id="top"></div>', "utf8") in rv.data
    assert (
        bytes(
            '<div id="top-link"><a class="bold" href="#top" title="Click this triangle to navigate back to the top of the current page without reloading it."></a></div>',
            "utf8",
        )
        in rv.data
    )


def test_playlist_with_audio_no_video(client):
    example_dir = os.path.join(THIS_DIR, "example")
    url = "/playlist"

    with app.test_client() as tc:

        f = os.path.join(example_dir, "real.flac")
        f2 = os.path.join(example_dir, "real.mp3")
        f3 = os.path.join(example_dir, "real.ogg")

        with tc.session_transaction() as sess:
            sess["user_playlist"] = [f, f2, f3]

        rv = tc.get(url)

    for line in rv.data.decode().split("\n"):
        print(line)

    assert (
        bytes(
            '<form  action="/playlist/clear/%2Fall" class="center" id="playlistctl" method="post">',
            "utf8",
        )
        in rv.data
    )
    assert (
        bytes(
            '<input class="center" id="clear" name="clear" title="Remove all tracks from your playlist." value="Clear Playlist" type="submit" />',
            "utf8",
        )
        in rv.data
    )
    assert (
        bytes(
            '<form action="/playlist/save/%2Fsave" class="center" id="playlistctl" method="post">',
            "utf8",
        )
        in rv.data
    )
    assert (
        bytes(
            '<input class="center" id="save" name="save" title="Save this playlist as a .m3u file.  Note that doing so will reload the page, stopping any playback." value="Save Playlist" type="submit" />',
            "utf8",
        )
        in rv.data
    )
    assert (
        bytes(
            '<input id="file-name" name="file-name" type="text" placeholder="Playlist name" title="File name for the playlist to be saved.  Only alphanumeric charatcers, spaces, underscores, and plus signs are allowed." required/>',
            "utf8",
        )
        in rv.data
    )
    assert (
        bytes(
            '<input id="item-list" name="bulk-list" type="hidden" value="[&#39;{0}/real.flac&#39;, &#39;{0}/real.mp3&#39;, &#39;{0}/real.ogg&#39;]">'.format(
                example_dir
            ),
            "utf8",
        )
        in rv.data
    )
    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" title="Click to play this track."></div>'.format(
                quote(example_dir), example_dir
            ),
            "utf8",
        )
        in rv.data
    )
    assert (
        bytes(
            '<a class="mobile-big" href="/browse/{}%2Freal.flac">'.format(
                quote(example_dir)
            ),
            "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(
            '<form action="/playlist/rm/{}%2Freal.flac" class="center" method="post">'.format(
                quote(example_dir)
            ),
            "utf8",
        )
        in rv.data
    )
    assert (
        bytes('<input class="bold red X" type="submit" value="X">', "utf8") in rv.data
    )
    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" title="Click to play this track."></div>'.format(
                quote(example_dir), example_dir
            ),
            "utf8",
        )
        in rv.data
    )
    assert (
        bytes(
            '<a class="mobile-big" href="/browse/{}%2Freal.mp3">'.format(
                quote(example_dir)
            ),
            "utf8",
        )
        in rv.data
    )
    assert (
        bytes(
            '<form action="/playlist/rm/{}%2Freal.mp3" class="center" method="post">'.format(
                quote(example_dir)
            ),
            "utf8",
        )
        in rv.data
    )
    assert (
        bytes(
            '<div class="play-arrow video-arrow" data-browse="/browse/{0}%2Freal.mp4" data-num="0" data-path="{1}/real.mp4" data-title="MousikóFídi Test MP4" title="Click to play this track."></div>'.format(
                quote(example_dir), example_dir
            ),
            "utf8",
        )
        not in rv.data
    )
    assert (
        bytes(
            '<a class="video-title" href="/browse/{}%2Freal.mp4">'.format(
                quote(example_dir)
            ),
            "utf8",
        )
        not in rv.data
    )
    assert (
        bytes(
            '<form action="/playlist/rm/{}%2Freal.mp4" class="center" method="post">'.format(
                quote(example_dir)
            ),
            "utf8",
        )
        not in rv.data
    )
    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" title="Click to play this track."></div>'.format(
                quote(example_dir), example_dir
            ),
            "utf8",
        )
        in rv.data
    )
    assert (
        bytes(
            '<a class="mobile-big" href="/browse/{}%2Freal.ogg">'.format(
                quote(example_dir)
            ),
            "utf8",
        )
        in rv.data
    )
    assert (
        bytes(
            '<form action="/playlist/rm/{}%2Freal.ogg" class="center" method="post">'.format(
                quote(example_dir)
            ),
            "utf8",
        )
        in rv.data
    )
    assert (
        bytes(
            '<div class="play-arrow video-arrow" data-browse="/browse/{0}%2Ffake.mp4" data-num="0" data-path="{1}/fake.mp4" data-title="fake.mp4" title="Click to play this track."></div>'.format(
                quote(example_dir), example_dir
            ),
            "utf8",
        )
        not in rv.data
    )
    assert (
        bytes(
            '<a class="video-title" href="/browse/{}%2Ffake.mp4">'.format(
                quote(example_dir)
            ),
            "utf8",
        )
        not in rv.data
    )
    assert (
        bytes(
            '<form action="/playlist/rm/{}%2Ffake.mp4" class="center" method="post">'.format(
                quote(example_dir)
            ),
            "utf8",
        )
        not in rv.data
    )
    assert (
        bytes(
            '<div class="play-arrow video-arrow" data-browse="/browse/{0}%2Ffake.webm" data-num="0" data-path="{1}/fake.webm" data-title="fake.webm" title="Click to play this track."></div>'.format(
                quote(example_dir), example_dir
            ),
            "utf8",
        )
        not in rv.data
    )
    assert (
        bytes(
            '<a class="video-title" href="/browse/{}%2Ffake.webm">'.format(
                quote(example_dir)
            ),
            "utf8",
        )
        not in rv.data
    )
    assert (
        bytes(
            '<form action="/playlist/rm/{}%2Ffake.webm" class="center" method="post">'.format(
                quote(example_dir)
            ),
            "utf8",
        )
        not in rv.data
    )
    assert bytes('<div class="center" id="player">', "utf8") in rv.data
    assert (
        bytes(
            '<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>',
            "utf8",
        )
        in rv.data
    )
    assert (
        bytes('<div data-nowplaying-num="0" id="now-playing-num"></div>', "utf8")
        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>", "utf8") in rv.data
    assert (
        bytes(
            '<button data-cmd="prev" id="prev" title="Click to skip to the previous track in the list.">Previous</button>',
            "utf8",
        )
        in rv.data
    )
    assert (
        bytes(
            '<button data-cmd="fwd" id="next" title="Click to skip to the next track in the list.">Next</button>',
            "utf8",
        )
        in rv.data
    )
    assert (
        bytes(
            '<button data-stat="off" id="repeat" title="Click to toggle between no repeat, repeat one track, and repeat all tracks.">No Repeat</button>',
            "utf8",
        )
        in rv.data
    )
    assert (
        bytes(
            '<button data-stat="off" id="shuffle" title="Click to toggle between a shuffled track order on and off.">Shuffle Off</button>',
            "utf8",
        )
        in rv.data
    )
    assert (
        bytes('<div data-nowplaying-num="0" id="video-now-playing-num"></div>', "utf8")
        not in rv.data
    )
    assert (
        bytes('<div data-randorder="none" id="vid-randorder"></div>', "utf8")
        not in rv.data
    )
    assert bytes('<div id="videoplayer" class="center">', "utf8") not in rv.data
    assert bytes('<video id="video" controls>', "utf8") not in rv.data
    assert bytes("<source>", "utf8") not in rv.data
    assert bytes("</video>", "utf8") not in rv.data
    assert (
        bytes(
            '<button data-cmd="prev" id="vid-prev" title="Click to skip to the previous track in the list.">Previous</button>',
            "utf8",
        )
        not in rv.data
    )
    assert (
        bytes(
            '<button data-cmd="fwd" id="vid-next" title="Click to skip to the next track in the list.">Next</button>',
            "utf8",
        )
        not in rv.data
    )
    assert (
        bytes(
            '<button data-stat="off" id="vid-repeat" title="Click to toggle between no repeat, repeat one track, and repeat all tracks.">No Repeat</button>',
            "utf8",
        )
        not in rv.data
    )
    assert (
        bytes(
            '<button data-stat="off" id="vid-shuffle" title="Click to toggle between a shuffled track order on and off.">Shuffle Off</button>',
            "utf8",
        )
        not in rv.data
    )
    assert bytes('<div id="top"></div>', "utf8") in rv.data
    assert (
        bytes(
            '<div id="top-link"><a class="bold" href="#top" title="Click this triangle to navigate back to the top of the current page without reloading it."></a></div>',
            "utf8",
        )
        in rv.data
    )


def test_playlist_no_audio_with_video(client):
    example_dir = os.path.join(THIS_DIR, "example")
    url = "/playlist"

    with app.test_client() as tc:

        f = os.path.join(example_dir, "real.mp4")
        f2 = os.path.join(example_dir, "fake.mp4")
        f3 = os.path.join(example_dir, "fake.webm")

        with tc.session_transaction() as sess:
            sess["user_playlist"] = [f, f2, f3]

        rv = tc.get(url)

    assert (
        bytes(
            '<form  action="/playlist/clear/%2Fall" class="center" id="playlistctl" method="post">',
            "utf8",
        )
        in rv.data
    )
    assert (
        bytes(
            '<input class="center" id="clear" name="clear" title="Remove all tracks from your playlist." value="Clear Playlist" type="submit" />',
            "utf8",
        )
        in rv.data
    )
    assert (
        bytes(
            '<form action="/playlist/save/%2Fsave" class="center" id="playlistctl" method="post">',
            "utf8",
        )
        in rv.data
    )
    assert (
        bytes(
            '<input class="center" id="save" name="save" title="Save this playlist as a .m3u file.  Note that doing so will reload the page, stopping any playback." value="Save Playlist" type="submit" />',
            "utf8",
        )
        in rv.data
    )
    assert (
        bytes(
            '<input id="file-name" name="file-name" type="text" placeholder="Playlist name" title="File name for the playlist to be saved.  Only alphanumeric charatcers, spaces, underscores, and plus signs are allowed." required/>',
            "utf8",
        )
        in rv.data
    )
    assert (
        bytes(
            '<input id="item-list" name="bulk-list" type="hidden" value="[&#39;{0}/real.mp4&#39;, &#39;{0}/fake.mp4&#39;, &#39;{0}/fake.webm&#39;]">'.format(
                example_dir
            ),
            "utf8",
        )
        in rv.data
    )
    assert bytes('<h4 class="center">Audio Tracks</h4>', "utf8") not in rv.data
    assert bytes('<h4 class="center">Files:</h4>', "utf8") not in rv.data
    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" title="Click to play this track."></div>'.format(
                quote(example_dir), example_dir
            ),
            "utf8",
        )
        not in rv.data
    )
    assert (
        bytes(
            '<a class="mobile-big" href="/browse/{}%2Freal.flac">'.format(
                quote(example_dir)
            ),
            "utf8",
        )
        not in rv.data
    )
    assert bytes("MousikóFídi Test MP4", "utf8") in rv.data
    assert bytes("MousikóFídi Test Album", "utf8") in rv.data
    assert (
        bytes(
            '<form action="/playlist/rm/{}%2Freal.flac" class="center" method="post">'.format(
                quote(example_dir)
            ),
            "utf8",
        )
        not in rv.data
    )
    assert (
        bytes('<input class="bold red X" type="submit" value="X">', "utf8") in rv.data
    )
    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" title="Click to play this track."></div>'.format(
                quote(example_dir), example_dir
            ),
            "utf8",
        )
        not in rv.data
    )
    assert (
        bytes(
            '<a class="mobile-big" href="/browse/{}%2Freal.mp3">'.format(
                quote(example_dir)
            ),
            "utf8",
        )
        not in rv.data
    )
    assert (
        bytes(
            '<form action="/playlist/rm/{}%2Freal.mp3" class="center" method="post">'.format(
                quote(example_dir)
            ),
            "utf8",
        )
        not in rv.data
    )
    assert (
        bytes(
            '<div class="play-arrow video-arrow" data-browse="/browse/{0}%2Freal.mp4" data-num="0" data-path="{1}/real.mp4" data-title="MousikóFídi Test MP4" title="Click to play this track."></div>'.format(
                quote(example_dir), example_dir
            ),
            "utf8",
        )
        in rv.data
    )
    assert (
        bytes(
            '<a class="video-title" href="/browse/{}%2Freal.mp4">'.format(
                quote(example_dir)
            ),
            "utf8",
        )
        in rv.data
    )
    assert (
        bytes(
            '<form action="/playlist/rm/{}%2Freal.mp4" class="center" method="post">'.format(
                quote(example_dir)
            ),
            "utf8",
        )
        in rv.data
    )
    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" title="Click to play this track."></div>'.format(
                quote(example_dir), example_dir
            ),
            "utf8",
        )
        not in rv.data
    )
    assert (
        bytes(
            '<a class="mobile-big" href="/browse/{}%2Freal.ogg">'.format(
                quote(example_dir)
            ),
            "utf8",
        )
        not in rv.data
    )
    assert (
        bytes(
            '<form action="/playlist/rm/{}%2Freal.ogg" class="center" method="post">'.format(
                quote(example_dir)
            ),
            "utf8",
        )
        not in rv.data
    )
    assert (
        bytes(
            '<div class="play-arrow video-arrow" data-browse="/browse/{0}%2Ffake.mp4" data-num="0" data-path="{1}/fake.mp4" data-title="fake.mp4" title="Click to play this track."></div>'.format(
                quote(example_dir), example_dir
            ),
            "utf8",
        )
        in rv.data
    )
    assert (
        bytes(
            '<a class="video-title" href="/browse/{}%2Ffake.mp4">'.format(
                quote(example_dir)
            ),
            "utf8",
        )
        in rv.data
    )
    assert (
        bytes(
            '<form action="/playlist/rm/{}%2Ffake.mp4" class="center" method="post">'.format(
                quote(example_dir)
            ),
            "utf8",
        )
        in rv.data
    )
    assert (
        bytes(
            '<div class="play-arrow video-arrow" data-browse="/browse/{0}%2Ffake.webm" data-num="0" data-path="{1}/fake.webm" data-title="fake.webm" title="Click to play this track."></div>'.format(
                quote(example_dir), example_dir
            ),
            "utf8",
        )
        in rv.data
    )
    assert (
        bytes(
            '<a class="video-title" href="/browse/{}%2Ffake.webm">'.format(
                quote(example_dir)
            ),
            "utf8",
        )
        in rv.data
    )
    assert (
        bytes(
            '<form action="/playlist/rm/{}%2Ffake.webm" class="center" method="post">'.format(
                quote(example_dir)
            ),
            "utf8",
        )
        in rv.data
    )
    assert bytes('<div class="center" id="player">', "utf8") not in rv.data
    assert (
        bytes(
            '<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>',
            "utf8",
        )
        not in rv.data
    )
    assert (
        bytes('<div data-nowplaying-num="0" id="now-playing-num"></div>', "utf8")
        not in rv.data
    )
    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>", "utf8") not in rv.data
    assert (
        bytes(
            '<button data-cmd="prev" id="prev" title="Click to skip to the previous track in the list.">Previous</button>',
            "utf8",
        )
        not in rv.data
    )
    assert (
        bytes(
            '<button data-cmd="fwd" id="next" title="Click to skip to the next track in the list.">Next</button>',
            "utf8",
        )
        not in rv.data
    )
    assert (
        bytes(
            '<button data-stat="off" id="repeat" title="Click to toggle between no repeat, repeat one track, and repeat all tracks.">No Repeat</button>',
            "utf8",
        )
        not in rv.data
    )
    assert (
        bytes(
            '<button data-stat="off" id="shuffle" title="Click to toggle between a shuffled track order on and off.">Shuffle Off</button>',
            "utf8",
        )
        not in rv.data
    )
    assert (
        bytes('<div data-nowplaying-num="0" id="video-now-playing-num"></div>', "utf8")
        in rv.data
    )
    assert (
        bytes('<div data-randorder="none" id="vid-randorder"></div>', "utf8") in rv.data
    )
    assert bytes('<div id="videoplayer" class="center">', "utf8") in rv.data
    assert bytes('<video id="video" controls>', "utf8") in rv.data
    assert bytes("<source>", "utf8") in rv.data
    assert bytes("</video>", "utf8") in rv.data
    assert (
        bytes(
            '<button data-cmd="prev" id="vid-prev" title="Click to skip to the previous track in the list.">Previous</button>',
            "utf8",
        )
        in rv.data
    )
    assert (
        bytes(
            '<button data-cmd="fwd" id="vid-next" title="Click to skip to the next track in the list.">Next</button>',
            "utf8",
        )
        in rv.data
    )
    assert (
        bytes(
            '<button data-stat="off" id="vid-repeat" title="Click to toggle between no repeat, repeat one track, and repeat all tracks.">No Repeat</button>',
            "utf8",
        )
        in rv.data
    )
    assert (
        bytes(
            '<button data-stat="off" id="vid-shuffle" title="Click to toggle between a shuffled track order on and off.">Shuffle Off</button>',
            "utf8",
        )
        in rv.data
    )
    assert bytes('<div id="top"></div>', "utf8") in rv.data
    assert (
        bytes(
            '<div id="top-link"><a class="bold" href="#top" title="Click this triangle to navigate back to the top of the current page without reloading it."></a></div>',
            "utf8",
        )
        in rv.data
    )

# TODO: Work out how to test multipe page requests with sessions
# def test_playlist_not_empty(client):
#     pass

# def test_playlistctl_add(client):
#     pass