Skip to content

Commit

Permalink
fix: add proper HTML and JSON output
Browse files Browse the repository at this point in the history
  • Loading branch information
mgoltzsche committed Feb 20, 2024
1 parent 468e215 commit 34d6bd7
Show file tree
Hide file tree
Showing 7 changed files with 145 additions and 9 deletions.
3 changes: 2 additions & 1 deletion MANIFEST.in
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
include README.md
include beetsplug/webm3u/config_default.yaml
include beetsplug/webm3u/templates/*.html
include beetsplug/webm3u/static/**
6 changes: 3 additions & 3 deletions beetsplug/webm3u/__init__.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
from flask import Flask
from flask import Flask, render_template
from beets.plugins import BeetsPlugin
from beets.ui import Subcommand, decargs
from optparse import OptionParser
from beetsplug.web import ReverseProxied
from beetsplug.webm3u.routes import bp


class PlaylistServerPlugin(BeetsPlugin):
class WebM3UPlugin(BeetsPlugin):
def __init__(self):
super().__init__()
self.config.add(
Expand Down Expand Up @@ -63,7 +63,7 @@ def create_app():

@app.route('/')
def home():
return '<html><body><ul><li><a href="playlists">Playlists</a></li><li><a href="media">Audio files</a></ul></body></html>'
return render_template('index.html')

app.register_blueprint(bp)

Expand Down
65 changes: 60 additions & 5 deletions beetsplug/webm3u/routes.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
import os
from flask import Flask, Blueprint, send_from_directory, send_file, abort
from flask import Flask, Blueprint, send_from_directory, send_file, abort, render_template, request, jsonify
from beets import config
from pathlib import Path

MIMETYPE_HTML = 'text/html'
MIMETYPE_JSON = 'application/json'

bp = Blueprint('webm3u_bp', __name__, template_folder='templates')

@bp.route('/playlists/', defaults={'path': ''})
@bp.route('/playlists/<path:path>')
def index_page(path):
def playlists(path):
root_dir = config['webm3u']['playlist_dir'].get()
if not root_dir:
root_dir = config['smartplaylist']['playlist_dir'].get()
Expand All @@ -19,12 +22,64 @@ def index_page(path):
# TODO: transform item URIs within playlist
return send_file(abs_path)
else:
# Generate html/json directory listing
return 'playlist dir'
#return send_from_directory(root_dir, path, as_attachment=True)
pl = _playlists(abs_path)
dirs = _directories(abs_path)
mimetypes = (MIMETYPE_JSON, MIMETYPE_HTML)
mimetype = request.accept_mimetypes.best_match(mimetypes, MIMETYPE_JSON)
if mimetype == MIMETYPE_HTML:
return render_template('playlists.html',
path=path,
playlists=pl,
directories=dirs,
humanize=_humanize_size,
)
else:
return jsonify({
'directories': [{'name': d} for d in dirs],
'playlists': pl,
})

@bp.route('/music/', defaults={'path': ''})
@bp.route('/music/<path:path>')
def music(path):
root_dir = config['directory'].get()
return send_from_directory(root_dir, path)

def _playlists(dir):
l = [f for f in os.listdir(dir) if _is_playlist(dir, f)]
l.sort()
return [_playlist_dto(dir, f) for f in l]

def _playlist_dto(dir, filename):
st = os.stat(os.path.join(dir, filename))
return {
'name': Path(filename).stem,
'path': filename,
'size': st.st_size,
}

def _is_playlist(dir, filename):
f = os.path.join(dir, filename)
return os.path.isfile(f) and (f.endswith('.m3u') or f.endswith('.m3u8'))

def _directories(dir):
l = [d for d in os.listdir(dir) if os.path.isdir(_join(dir, d))]
l.sort()
return l

def _join(dir, filename):
return os.path.join(dir, filename)

def _check_path(root_dir, path):
path = os.path.normpath(path)
root_dir = os.path.normpath(root_dir)
if path != root_dir and not path.startswith(root_dir+os.sep):
raise Exception('request path {} is outside the root directory {}'.format(path, root_dir))

def _humanize_size(num):
suffix = 'B'
for unit in ("", "Ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi"):
if abs(num) < 1024.0:
return f"{num:3.1f}{unit}{suffix}"
num /= 1024.0
return f"{num:.1f}Yi{suffix}"
23 changes: 23 additions & 0 deletions beetsplug/webm3u/static/style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
body {
font-family: Verdana, sans-serif;
font-size: 1.2em;
line-height: 1.5em;
}
ul, li {
margin: 0;
padding: 0;
list-style-type: none;
}
li a {
display: block;
padding: 0.5em 1em;
}
li a span {
font-size: 0.7em
}
li:nth-child(odd) {
background-color: #fafafa;
}
li a:hover, li a:active {
background: #eeeeee;
}
21 changes: 21 additions & 0 deletions beetsplug/webm3u/templates/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Beets music library</title>
<link rel="stylesheet" type="text/css" href= "{{ url_for('static',filename='style.css') }}">
</head>
<body>
<h1>Beets music library</h1>

<p>
<a href="javascript:history.back()">&#129176; back</a>
</p>

<ul>
<li><a href="playlists/">Playlists</a></li>
<li><a href="music/">Audio files</a></li>
</ul>
</body>
</html>
34 changes: 34 additions & 0 deletions beetsplug/webm3u/templates/playlists.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Playlists</title>
<link rel="stylesheet" type="text/css" href= "{{ url_for('static',filename='style.css') }}">
</head>
<body>
<h1>Playlists</h1>

<p>
<a href="javascript:history.back()">&#129176; back</a>
</p>

<ul>
{% if path %}
<li>
<a href="../">..</a>
</li>
{% endif %}
{% for dir in directories %}
<li>
<a href="{{ dir }}/">&#128193; {{ dir }}</a>
</li>
{% endfor %}
{% for playlist in playlists %}
<li>
<a href="{{ playlist.path }}">&#127925; {{ playlist.name }} <span>({{ humanize(playlist.size) }})</span></a>
</li>
{% endfor %}
</ul>
</body>
</html>
2 changes: 2 additions & 0 deletions example_beets_config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ smartplaylist:
playlists:
- name: all.m3u8
query: ''
- name: subdir/another.m3u8
query: ''

ytimport:
directory: /data/ytimport

0 comments on commit 34d6bd7

Please sign in to comment.