From: Christian Heller <c.heller@plomlompom.de> Date: Sun, 24 Nov 2024 17:55:31 +0000 (+0100) Subject: Replace install.py by a short shell script. X-Git-Url: https://plomlompom.com/repos/%7B%7Bprefix%7D%7D/%7B%7Bdb.prefix%7D%7D/%7B%7B%20web_path%20%7D%7D/static/day?a=commitdiff_plain;h=e7c42fa1b4826c32839bf16bf5f38b3c0bdde692;p=ytplom Replace install.py by a short shell script. --- diff --git a/install.py b/install.py deleted file mode 100755 index 991ef5f..0000000 --- a/install.py +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/env python3 -'''Ensure expected directories, files for app to work exist.''' -from shutil import copyfile -from os import makedirs, scandir -from os.path import basename, join as path_join -from ytplom.misc import PATH_APP_DATA, PATH_MIGRATIONS, PATH_TEMPLATES - -for path in (PATH_APP_DATA, PATH_TEMPLATES, PATH_MIGRATIONS): - print(f'ensuring {path}') - makedirs(path) -for path_dir in (PATH_MIGRATIONS, PATH_TEMPLATES): - for entry in scandir(basename(path_dir)): - target_path = path_join(path_dir, basename(entry.path)) - print(f'copying {entry.path} to {target_path}') - copyfile(entry.path, target_path) -print('installation finished') diff --git a/install.sh b/install.sh new file mode 100755 index 0000000..0661178 --- /dev/null +++ b/install.sh @@ -0,0 +1,7 @@ +#!/usr/bin/sh +set -e +set -x + +PATH_APP_SHARE=~/.local/share/ytplom +mkdir -p "${PATH_APP_SHARE}" +cp -r ./install_to_share/* "${PATH_APP_SHARE}/" diff --git a/install_to_share/migrations/init_0.sql b/install_to_share/migrations/init_0.sql new file mode 100644 index 0000000..5b45769 --- /dev/null +++ b/install_to_share/migrations/init_0.sql @@ -0,0 +1,32 @@ +CREATE TABLE yt_queries ( + id TEXT PRIMARY KEY, + text TEXT NOT NULL, + retrieved_at TEXT NOT NULL +); +CREATE TABLE yt_videos ( + id TEXT PRIMARY KEY, + title TEXT NOT NULL, + description TEXT NOT NULL, + published_at TEXT NOT NULL, + duration TEXT NOT NULL, + definition TEXT NOT NULL +); +CREATE TABLE yt_query_results ( + query_id TEXT NOT NULL, + video_id TEXT NOT NULL, + PRIMARY KEY (query_id, video_id), + FOREIGN KEY (query_id) REFERENCES yt_queries(id), + FOREIGN KEY (video_id) REFERENCES yt_videos(id) +); +CREATE TABLE quota_costs ( + id TEXT PRIMARY KEY, + timestamp TEXT NOT NULL, + cost INT NOT NULL +); +CREATE TABLE files ( + rel_path TEXT PRIMARY KEY, + yt_id TEXT NOT NULL DEFAULT "", + flags INTEGER NOT NULL DEFAULT 0, + FOREIGN KEY (yt_id) REFERENCES yt_videos(id) +); + diff --git a/install_to_share/templates/_base.tmpl b/install_to_share/templates/_base.tmpl new file mode 100644 index 0000000..8839067 --- /dev/null +++ b/install_to_share/templates/_base.tmpl @@ -0,0 +1,20 @@ +{% import '_macros.tmpl' as macros %} +<!DOCTYPE html> +<html> +<head> +<meta charset="UTF-8"> +<script> +{% block script %} +{% endblock %} +</script> +<style> +body { background-color: #aaaa00; } +{% block css %} +{% endblock %} +</style> +</head> +<body> +{% block body %} +{% endblock %} +</body> +</html> diff --git a/install_to_share/templates/_macros.tmpl b/install_to_share/templates/_macros.tmpl new file mode 100644 index 0000000..12b28df --- /dev/null +++ b/install_to_share/templates/_macros.tmpl @@ -0,0 +1,13 @@ +{% macro _link_if(cond, target) %}{% if cond %}<a href="/{{target}}">{% endif %}{{target}}{% if cond %}</a>{% endif %}{% endmacro %} + + +{% macro nav_head(selected="") %} +<p> +{{ _link_if("playlist" != selected, "playlist") }} +· +{{ _link_if("videos" != selected, "videos") }} +· +{{ _link_if("queries" != selected, "queries") }} +</p> +<hr /> +{% endmacro %} diff --git a/install_to_share/templates/playlist.tmpl b/install_to_share/templates/playlist.tmpl new file mode 100644 index 0000000..58c2b5b --- /dev/null +++ b/install_to_share/templates/playlist.tmpl @@ -0,0 +1,61 @@ +{% extends '_base.tmpl' %} + + +{% block script %} +const RELOAD_INTERVAL_S = 10; +const PATH_LAST_UPDATE = '/_last_playlist_update.json'; +const MSG_SERVER_DOWN = 'Server seems to be unavailable.'; +const MSG_ERR_UNKNOWN = 'Unknown error checking ' + PATH_LAST_UPDATE; +const last_update = '{{last_update}}'; +async function keep_updated() { + try { + const response = await fetch(PATH_LAST_UPDATE); + const data = await response.json(); + if (data.last_update != last_update) { + location.reload(); + } + } catch(error) { + const status = document.getElementById('status'); + if (error instanceof TypeError && !error.response) { + status.innerText = MSG_SERVER_DOWN; + } else { + status.innerText = MSG_ERR_UNKNOWN; + } + } + setTimeout(keep_updated, RELOAD_INTERVAL_S * 1000); +} +window.onload = keep_updated; +{% endblock %} + + +{% block css %} +table { width: 100%; } +#status { text-align: center; font-weight: bold; } +td.history { width: 50%; } +{% endblock %} + + +{% block body %} +{{ macros.nav_head("playlist") }} +<table> +<tr><td id="status" colspan=2> +{% if running %}{% if pause %}PAUSED{% else %}PLAYING{% endif %}{% else %}STOPPED{% endif %}:<br /> +{{ current_title }}<br /> +<form action="/playlist" method="POST"> +<input type="submit" name="pause" autofocus value="{% if paused %}resume{% else %}pause{% endif %}"> +<input type="submit" name="prev" value="prev"> +<input type="submit" name="next" value="next"> +<input type="submit" name="stop" value="{% if running %}stop{% else %}start{% endif %}"> +<input type="submit" name="reload" value="reload"> +</form> +</td></tr> +{% for prev_title, next_title in tuples %} +<tr><td class="history"> +{{ prev_title }} +</td><td class="history"> +{{ next_title }} +</td></tr> +{% endfor %} +</table> +{% endblock %} + diff --git a/install_to_share/templates/queries.tmpl b/install_to_share/templates/queries.tmpl new file mode 100644 index 0000000..457f80e --- /dev/null +++ b/install_to_share/templates/queries.tmpl @@ -0,0 +1,22 @@ +{% extends '_base.tmpl' %} + + +{% block body %} +{{ macros.nav_head("queries") }} +<p>quota: {{quota_count}}/100000</p> +<form action="/queries" method="POST" /> +<input name="query" /> +</form> +<table> +<tr> +<th>retrieved at</th> +<th>query</th> +</tr> +{% for query in queries %} +<tr> +<td>{{query.retrieved_at[:19]}}</td> +<td><a href="/query/{{query.id_}}">{{query.text}}</a></td> +</tr> +{% endfor %} +</table> +{% endblock %} diff --git a/install_to_share/templates/results.tmpl b/install_to_share/templates/results.tmpl new file mode 100644 index 0000000..131d14e --- /dev/null +++ b/install_to_share/templates/results.tmpl @@ -0,0 +1,23 @@ +{% extends '_base.tmpl' %} + + +{% block body %} +{{ macros.nav_head() }} +<p>query: {{query}}</p> +<table> +{% for video in videos %} +<tr> +<td> +<a href="/yt_video/{{video.id_}}"><img src="/thumbnails/{{video.id_}}.jpg" /></a> +</td> +<td> +{{video.definition}}<br /> +{{video.duration}} +</td> +<td> +<b><a href="/yt_video/{{video.id_}}">{{video.title}}</a></b> · {{video.description}} +</td> +</tr> +{% endfor %} +</table> +{% endblock %} diff --git a/install_to_share/templates/video.tmpl b/install_to_share/templates/video.tmpl new file mode 100644 index 0000000..54d005f --- /dev/null +++ b/install_to_share/templates/video.tmpl @@ -0,0 +1,17 @@ +{% extends '_base.tmpl' %} + + +{% block body %} +{{ macros.nav_head() }} +<table> +<tr><th>path:</th><td>{{file.rel_path}}</td></tr> +<tr><th>YouTube ID:</th><td><a href="/yt_video/{{file.yt_id}}">{{file.yt_id}}</a></tr> +<tr><th>present:</th><td>{% if file.present %}<a href="/dl/{{file.yt_id}}">yes</a>{% else %}no{% endif %}</td></tr> +</table> +<form action="/video/{{file.yt_id}}" method="POST" /> +{% for flag_name in flag_names %} +{{ flag_name }}: <input type="checkbox" name="{{flag_name}}" {% if file.flag_set(flag_name) %}checked {% endif %} /><br /> +{% endfor %} +<input type="submit" /> +</form> +{% endblock %} diff --git a/install_to_share/templates/videos.tmpl b/install_to_share/templates/videos.tmpl new file mode 100644 index 0000000..5cbf47f --- /dev/null +++ b/install_to_share/templates/videos.tmpl @@ -0,0 +1,12 @@ +{% extends '_base.tmpl' %} + + +{% block body %} +{{ macros.nav_head("videos") }} +<p>downloaded videos:</p> +<ul> +{% for video_id, path in videos %} +<li><a href="/video/{{video_id}}">{{ path }}</a> +{% endfor %} +</ul> +{% endblock %} diff --git a/install_to_share/templates/yt_video.tmpl b/install_to_share/templates/yt_video.tmpl new file mode 100644 index 0000000..1ecb258 --- /dev/null +++ b/install_to_share/templates/yt_video.tmpl @@ -0,0 +1,23 @@ +{% extends '_base.tmpl' %} + + +{% block body %} +{{ macros.nav_head() }} +<table> +<tr><th>title:</th><td>{{video_data.title}}</td></tr> +<tr><th>thumbnail:</th><td><img src="/thumbnails/{{video_data.id_}}.jpg" /></td></tr> +<tr><th>description:</th><td>{{video_data.description}}</td></tr> +<tr><th>duration:</th><td>{{video_data.duration}}</td></tr> +<tr><th>definition:</th><td>{{video_data.definition}}</td></tr> +<tr><th>YouTube ID:</th><td>{{video_data.id_}} (<a href="{{youtube_prefix}}{{video_data.id_}}">watch</a>)</td></tr> +<tr><th>download:</th><td>{% if is_temp %}working on it{% else %}<a href="/dl/{{video_data.id_}}">{{ file_path if file_path else "please do" }}</a>{% endif %}</td></tr> +<tr> +<th>linked queries:</th> +<td> +<ul> +{% for query in queries %}<li><a href="/query/{{query.id_}}">{{query.text}}</a>{% endfor %} +</ul> +</td> +</tr> +</table> +{% endblock %} diff --git a/migrations/init_0.sql b/migrations/init_0.sql deleted file mode 100644 index 5b45769..0000000 --- a/migrations/init_0.sql +++ /dev/null @@ -1,32 +0,0 @@ -CREATE TABLE yt_queries ( - id TEXT PRIMARY KEY, - text TEXT NOT NULL, - retrieved_at TEXT NOT NULL -); -CREATE TABLE yt_videos ( - id TEXT PRIMARY KEY, - title TEXT NOT NULL, - description TEXT NOT NULL, - published_at TEXT NOT NULL, - duration TEXT NOT NULL, - definition TEXT NOT NULL -); -CREATE TABLE yt_query_results ( - query_id TEXT NOT NULL, - video_id TEXT NOT NULL, - PRIMARY KEY (query_id, video_id), - FOREIGN KEY (query_id) REFERENCES yt_queries(id), - FOREIGN KEY (video_id) REFERENCES yt_videos(id) -); -CREATE TABLE quota_costs ( - id TEXT PRIMARY KEY, - timestamp TEXT NOT NULL, - cost INT NOT NULL -); -CREATE TABLE files ( - rel_path TEXT PRIMARY KEY, - yt_id TEXT NOT NULL DEFAULT "", - flags INTEGER NOT NULL DEFAULT 0, - FOREIGN KEY (yt_id) REFERENCES yt_videos(id) -); - diff --git a/templates/_base.tmpl b/templates/_base.tmpl deleted file mode 100644 index 8839067..0000000 --- a/templates/_base.tmpl +++ /dev/null @@ -1,20 +0,0 @@ -{% import '_macros.tmpl' as macros %} -<!DOCTYPE html> -<html> -<head> -<meta charset="UTF-8"> -<script> -{% block script %} -{% endblock %} -</script> -<style> -body { background-color: #aaaa00; } -{% block css %} -{% endblock %} -</style> -</head> -<body> -{% block body %} -{% endblock %} -</body> -</html> diff --git a/templates/_macros.tmpl b/templates/_macros.tmpl deleted file mode 100644 index 12b28df..0000000 --- a/templates/_macros.tmpl +++ /dev/null @@ -1,13 +0,0 @@ -{% macro _link_if(cond, target) %}{% if cond %}<a href="/{{target}}">{% endif %}{{target}}{% if cond %}</a>{% endif %}{% endmacro %} - - -{% macro nav_head(selected="") %} -<p> -{{ _link_if("playlist" != selected, "playlist") }} -· -{{ _link_if("videos" != selected, "videos") }} -· -{{ _link_if("queries" != selected, "queries") }} -</p> -<hr /> -{% endmacro %} diff --git a/templates/playlist.tmpl b/templates/playlist.tmpl deleted file mode 100644 index 58c2b5b..0000000 --- a/templates/playlist.tmpl +++ /dev/null @@ -1,61 +0,0 @@ -{% extends '_base.tmpl' %} - - -{% block script %} -const RELOAD_INTERVAL_S = 10; -const PATH_LAST_UPDATE = '/_last_playlist_update.json'; -const MSG_SERVER_DOWN = 'Server seems to be unavailable.'; -const MSG_ERR_UNKNOWN = 'Unknown error checking ' + PATH_LAST_UPDATE; -const last_update = '{{last_update}}'; -async function keep_updated() { - try { - const response = await fetch(PATH_LAST_UPDATE); - const data = await response.json(); - if (data.last_update != last_update) { - location.reload(); - } - } catch(error) { - const status = document.getElementById('status'); - if (error instanceof TypeError && !error.response) { - status.innerText = MSG_SERVER_DOWN; - } else { - status.innerText = MSG_ERR_UNKNOWN; - } - } - setTimeout(keep_updated, RELOAD_INTERVAL_S * 1000); -} -window.onload = keep_updated; -{% endblock %} - - -{% block css %} -table { width: 100%; } -#status { text-align: center; font-weight: bold; } -td.history { width: 50%; } -{% endblock %} - - -{% block body %} -{{ macros.nav_head("playlist") }} -<table> -<tr><td id="status" colspan=2> -{% if running %}{% if pause %}PAUSED{% else %}PLAYING{% endif %}{% else %}STOPPED{% endif %}:<br /> -{{ current_title }}<br /> -<form action="/playlist" method="POST"> -<input type="submit" name="pause" autofocus value="{% if paused %}resume{% else %}pause{% endif %}"> -<input type="submit" name="prev" value="prev"> -<input type="submit" name="next" value="next"> -<input type="submit" name="stop" value="{% if running %}stop{% else %}start{% endif %}"> -<input type="submit" name="reload" value="reload"> -</form> -</td></tr> -{% for prev_title, next_title in tuples %} -<tr><td class="history"> -{{ prev_title }} -</td><td class="history"> -{{ next_title }} -</td></tr> -{% endfor %} -</table> -{% endblock %} - diff --git a/templates/queries.tmpl b/templates/queries.tmpl deleted file mode 100644 index 457f80e..0000000 --- a/templates/queries.tmpl +++ /dev/null @@ -1,22 +0,0 @@ -{% extends '_base.tmpl' %} - - -{% block body %} -{{ macros.nav_head("queries") }} -<p>quota: {{quota_count}}/100000</p> -<form action="/queries" method="POST" /> -<input name="query" /> -</form> -<table> -<tr> -<th>retrieved at</th> -<th>query</th> -</tr> -{% for query in queries %} -<tr> -<td>{{query.retrieved_at[:19]}}</td> -<td><a href="/query/{{query.id_}}">{{query.text}}</a></td> -</tr> -{% endfor %} -</table> -{% endblock %} diff --git a/templates/results.tmpl b/templates/results.tmpl deleted file mode 100644 index 131d14e..0000000 --- a/templates/results.tmpl +++ /dev/null @@ -1,23 +0,0 @@ -{% extends '_base.tmpl' %} - - -{% block body %} -{{ macros.nav_head() }} -<p>query: {{query}}</p> -<table> -{% for video in videos %} -<tr> -<td> -<a href="/yt_video/{{video.id_}}"><img src="/thumbnails/{{video.id_}}.jpg" /></a> -</td> -<td> -{{video.definition}}<br /> -{{video.duration}} -</td> -<td> -<b><a href="/yt_video/{{video.id_}}">{{video.title}}</a></b> · {{video.description}} -</td> -</tr> -{% endfor %} -</table> -{% endblock %} diff --git a/templates/video.tmpl b/templates/video.tmpl deleted file mode 100644 index 54d005f..0000000 --- a/templates/video.tmpl +++ /dev/null @@ -1,17 +0,0 @@ -{% extends '_base.tmpl' %} - - -{% block body %} -{{ macros.nav_head() }} -<table> -<tr><th>path:</th><td>{{file.rel_path}}</td></tr> -<tr><th>YouTube ID:</th><td><a href="/yt_video/{{file.yt_id}}">{{file.yt_id}}</a></tr> -<tr><th>present:</th><td>{% if file.present %}<a href="/dl/{{file.yt_id}}">yes</a>{% else %}no{% endif %}</td></tr> -</table> -<form action="/video/{{file.yt_id}}" method="POST" /> -{% for flag_name in flag_names %} -{{ flag_name }}: <input type="checkbox" name="{{flag_name}}" {% if file.flag_set(flag_name) %}checked {% endif %} /><br /> -{% endfor %} -<input type="submit" /> -</form> -{% endblock %} diff --git a/templates/videos.tmpl b/templates/videos.tmpl deleted file mode 100644 index 5cbf47f..0000000 --- a/templates/videos.tmpl +++ /dev/null @@ -1,12 +0,0 @@ -{% extends '_base.tmpl' %} - - -{% block body %} -{{ macros.nav_head("videos") }} -<p>downloaded videos:</p> -<ul> -{% for video_id, path in videos %} -<li><a href="/video/{{video_id}}">{{ path }}</a> -{% endfor %} -</ul> -{% endblock %} diff --git a/templates/yt_video.tmpl b/templates/yt_video.tmpl deleted file mode 100644 index 1ecb258..0000000 --- a/templates/yt_video.tmpl +++ /dev/null @@ -1,23 +0,0 @@ -{% extends '_base.tmpl' %} - - -{% block body %} -{{ macros.nav_head() }} -<table> -<tr><th>title:</th><td>{{video_data.title}}</td></tr> -<tr><th>thumbnail:</th><td><img src="/thumbnails/{{video_data.id_}}.jpg" /></td></tr> -<tr><th>description:</th><td>{{video_data.description}}</td></tr> -<tr><th>duration:</th><td>{{video_data.duration}}</td></tr> -<tr><th>definition:</th><td>{{video_data.definition}}</td></tr> -<tr><th>YouTube ID:</th><td>{{video_data.id_}} (<a href="{{youtube_prefix}}{{video_data.id_}}">watch</a>)</td></tr> -<tr><th>download:</th><td>{% if is_temp %}working on it{% else %}<a href="/dl/{{video_data.id_}}">{{ file_path if file_path else "please do" }}</a>{% endif %}</td></tr> -<tr> -<th>linked queries:</th> -<td> -<ul> -{% for query in queries %}<li><a href="/query/{{query.id_}}">{{query.text}}</a>{% endfor %} -</ul> -</td> -</tr> -</table> -{% endblock %} diff --git a/ytplom/misc.py b/ytplom/misc.py index 9e46c82..647ad39 100644 --- a/ytplom/misc.py +++ b/ytplom/misc.py @@ -82,9 +82,6 @@ QUOTA_COST_YOUTUBE_DETAILS = QuotaCost(1) # local expectations TIMESTAMP_FMT = '%Y-%m-%d %H:%M:%S.%f' LEGAL_EXTENSIONS = {'webm', 'mp4', 'mkv'} -VIDEO_FLAGS: dict[FlagName, FlagsInt] = { - FlagName('delete'): FlagsInt(1 << 62) -} # tables to create database with EXPECTED_DB_VERSION = 0 @@ -93,6 +90,12 @@ PATH_MIGRATIONS = PathStr(path_join(PATH_APP_DATA, 'migrations')) PATH_DB_SCHEMA = PathStr(path_join(PATH_MIGRATIONS, f'init_{EXPECTED_DB_VERSION}.sql')) +# other +NAME_INSTALLER = 'install.sh' +VIDEO_FLAGS: dict[FlagName, FlagsInt] = { + FlagName('delete'): FlagsInt(1 << 62) +} + class NotFoundException(Exception): """Raise on expected data missing, e.g. DB fetches finding nothing.""" @@ -126,7 +129,7 @@ class DatabaseConnection: if not isdir(path_db_dir): raise NotFoundException( f'cannot find {path_db_dir} as directory to put DB ' - 'into, did you run install.py?') + f'into, did you run {NAME_INSTALLER}?') with sql_connect(self._path) as conn: with open(PATH_DB_SCHEMA, 'r', encoding='utf8') as f: conn.executescript(f.read())