From 7a0110f5e565633f62b0feefc65e9e57ecc823fe Mon Sep 17 00:00:00 2001 From: Christian Heller Date: Wed, 4 Dec 2024 17:24:00 +0100 Subject: [PATCH] Show reduced file data form/table in playlist view. --- src/templates/_base.tmpl | 3 +- src/templates/_macros.tmpl | 41 ++++++++++++++++++++++++ src/templates/file_data.tmpl | 34 ++------------------ src/templates/files.tmpl | 2 +- src/templates/playlist.tmpl | 55 +++++++++++++++++--------------- src/ytplom/http.py | 29 ++++++++++------- src/ytplom/misc.py | 62 +++++++++++++++--------------------- 7 files changed, 117 insertions(+), 109 deletions(-) diff --git a/src/templates/_base.tmpl b/src/templates/_base.tmpl index 3f9edf4..d87faeb 100644 --- a/src/templates/_base.tmpl +++ b/src/templates/_base.tmpl @@ -10,8 +10,7 @@ diff --git a/src/templates/_macros.tmpl b/src/templates/_macros.tmpl index aa6ed50..89838d8 100644 --- a/src/templates/_macros.tmpl +++ b/src/templates/_macros.tmpl @@ -11,3 +11,44 @@


{% endmacro %} + + +{% macro file_data_form(file, unused_tags, page_names, flag_names=[], playlist_view=false) %} +
+ + + +{% if not playlist_view %} + +{% endif %} + + + + + +{% if not playlist_view %} + + + + +{% endif %} +
path:{% if playlist_view %}{% endif %}{{file.rel_path}}{% if playlist_view %}{% endif %}
present:{% if file.present %}yes{% else %}no{% endif %}
YouTube ID:{{file.yt_id}}
tags + +{% for tag in file.tags %} + +{% endfor %} + + +{% for tag in unused_tags %} + +{% endfor %} + +
{{tag}}
add:
+
flags: +{% for flag_name in flag_names %} +{{ flag_name }}:
+{% endfor %} +
+ +
+{% endmacro %} diff --git a/src/templates/file_data.tmpl b/src/templates/file_data.tmpl index b5a45b9..482f8ea 100644 --- a/src/templates/file_data.tmpl +++ b/src/templates/file_data.tmpl @@ -2,41 +2,13 @@ {% block css %} -td { width: 100%; } +td.top_field { width: 100%; } td.flags { text-align: right; } +td.tag_checkboxes { width: 1em; } {% endblock %} {% block body %} {{ macros.nav_head(page_names) }} -
- - - - - - - - - - - - -
path:{{file.rel_path}}
YouTube ID:{{file.yt_id}}
present:{% if file.present %}yes{% else %}no{% endif %}
flags: -{% for flag_name in flag_names %} -{{ flag_name }}:
-{% endfor %} -
tags -{% for tag in file.tags %} - {{tag}}
-{% endfor %} - - -{% for tag in unused_tags %} - -{% endfor %} - -
- -
+{{ macros.file_data_form(file, unused_tags, page_names, flag_names) }} {% endblock %} diff --git a/src/templates/files.tmpl b/src/templates/files.tmpl index f8286e5..c4c452d 100644 --- a/src/templates/files.tmpl +++ b/src/templates/files.tmpl @@ -15,7 +15,7 @@ show absent: sizeactionstagspath {% for file in files %} -{{ file.size | round(3) }} +{{ file.size | round(1) }} {% for tag in file.tags %}{{tag}} {%endfor %} {{file.rel_path}} diff --git a/src/templates/playlist.tmpl b/src/templates/playlist.tmpl index e82aff1..c602362 100644 --- a/src/templates/playlist.tmpl +++ b/src/templates/playlist.tmpl @@ -29,50 +29,53 @@ window.onload = keep_updated; {% block css %} -#status { text-align: center; font-weight: bold; } -th { text-align: center; } -td.history { width: 50%; } +#status { font-weight: bold; } +td.screen_half { width: 50%; } +tr.screen_half_titles>th { text-align: center; } td.entry_buttons { width: 5em; } +td.tag_checkboxes { width: 1em; } {% endblock %} -{% macro playlist_entries(files_w_idx, reverse) %} - - -{% for idx, file in files_w_idx %} - - - - -{% endfor %} -
- - - -{{ file.rel_path }}
- -{% endmacro %} - - {% block body %} {{ macros.nav_head(page_names, "playlist") }} - + -{{ playlist_entries(prev_files_w_idx, reverse=true) }} -{{ playlist_entries(next_files_w_idx, reverse=false) }} + + +
-{% if running %}{% if pause %}PAUSED{% else %}PLAYING{% endif %}{% else %}STOPPED{% endif %}:
-{{ current_video.rel_path }}
+{% if running %}{% if pause %}PAUSED{% else %}PLAYING{% endif %}{% else %}STOPPED{% endif %} +
pastfuture
current selectionplaylist
+{{ macros.file_data_form(current_file, unused_tags, page_names, playlist_view=true) }} + +
+ +{% for idx, file in files_w_idx %} + + + +{% endfor %} +
+{% if file.digest == current_file.digest %} +PLAYING +{% else %} + + + +{% endif %} +{{ file.rel_path }}
+
{% endblock %} diff --git a/src/ytplom/http.py b/src/ytplom/http.py index d61b75c..b0aea64 100644 --- a/src/ytplom/http.py +++ b/src/ytplom/http.py @@ -28,7 +28,7 @@ _TemplateContext: TypeAlias = dict[ None | bool | FilesWithIndex | _PageNames | _FilterStr | Path | PlayerUpdateId | QueryText | QuotaCost | UrlStr | 'VideoFile' | YoutubeId - | 'YoutubeVideo' | list[FlagName] | list['Tag'] | list['VideoFile'] + | 'YoutubeVideo' | list[FlagName] | set['Tag'] | list['VideoFile'] | list['YoutubeVideo'] | list['YoutubeQuery'] ] @@ -151,9 +151,7 @@ class _TaskHandler(BaseHTTPRequestHandler): file.save(conn) conn.commit() file.ensure_absence_if_deleted() - self._redirect(Path('/') - .joinpath(PAGE_NAMES['file']) - .joinpath(digest.b64)) + self._redirect(Path(postvars['redir'][0])) def _receive_yt_query(self, query_txt: QueryText) -> None: with DbConn() as conn: @@ -273,11 +271,11 @@ class _TaskHandler(BaseHTTPRequestHandler): def _send_file_data(self, digest: Hash) -> None: with DbConn() as conn: file = VideoFile.get_one(conn, digest) - all_tags = VideoFile.get_all_tags(conn) - self._send_rendered_template( - _NAME_TEMPLATE_FILE_DATA, - {'file': file, 'flag_names': list(FILE_FLAGS), - 'unused_tags': [t for t in all_tags if t not in file.tags]}) + unused_tags = file.unused_tags(conn) + self._send_rendered_template(_NAME_TEMPLATE_FILE_DATA, + {'file': file, + 'flag_names': list(FILE_FLAGS), + 'unused_tags': unused_tags}) def _send_files_index(self, params: dict[str, list[str]]) -> None: filter_path = _FilterStr(params.get('filter_path', [''])[0]) @@ -312,11 +310,18 @@ class _TaskHandler(BaseHTTPRequestHandler): def _send_playlist(self) -> None: if self.server.player.empty: self.server.player.load_files() + current_file, unused_tags = None, set() + if self.server.player.current_file_digest: + with DbConn() as conn: + current_file = VideoFile.get_one( + conn, self.server.player.current_file_digest) + unused_tags = current_file.unused_tags(conn) self._send_rendered_template( _NAME_TEMPLATE_PLAYLIST, {'last_update': self.server.player.last_update, 'running': self.server.player.is_running, 'paused': self.server.player.is_paused, - 'current_video': self.server.player.current_file, - 'prev_files_w_idx': self.server.player.prev_files_w_idx, - 'next_files_w_idx': self.server.player.next_files_w_idx}) + 'current_file': current_file, + 'unused_tags': unused_tags, + 'files_w_idx': list(enumerate(self.server.player.files)) + }) diff --git a/src/ytplom/misc.py b/src/ytplom/misc.py index d0b55e8..438a8cd 100644 --- a/src/ytplom/misc.py +++ b/src/ytplom/misc.py @@ -278,7 +278,6 @@ class VideoFile(DbData): f'{self.yt_id}|{self.last_update}|{self.tags_str}') def _renew_last_update(self): - print("DEBUG calling_renew_last_update", self.rel_path) self.last_update = DatetimeStr(datetime.now().strftime(TIMESTAMP_FMT)) self._hash_on_last_update = hash(self) @@ -297,12 +296,11 @@ class VideoFile(DbData): raise NotFoundException(f'no entry for file to Youtube ID {yt_id}') return cls._from_table_row(row) - @classmethod - def get_all_tags(cls, conn: BaseDbConn) -> set[Tag]: - """Return all tags used among VideoFiles.""" + def unused_tags(self, conn: BaseDbConn) -> set[Tag]: + """Return tags used among other VideoFiles, not in self.""" tags = set() - for file in cls.get_all(conn): - for tag in file.tags: + for file in self.get_all(conn): + for tag in [t for t in file.tags if t not in self.tags]: tags.add(tag) return tags @@ -423,11 +421,11 @@ class Player: """Collect files in PATH_DOWNLOADS DB-known and of legal extension.""" with DbConn() as conn: known_files = {f.full_path: f for f in VideoFile.get_all(conn)} - self._files = [known_files[p] for p in PATH_DOWNLOADS.iterdir() - if p in known_files - and p.is_file() - and p.suffix[1:] in LEGAL_EXTENSIONS] - shuffle(self._files) + self.files = [known_files[p] for p in PATH_DOWNLOADS.iterdir() + if p in known_files + and p.is_file() + and p.suffix[1:] in LEGAL_EXTENSIONS] + shuffle(self.files) self._idx = 0 def _signal_update(self) -> None: @@ -439,7 +437,7 @@ class Player: config=True) self._monitor_kill() self._mpv.observe_property('pause', lambda a, b: self._signal_update()) - for path in [f.full_path for f in self._files]: + for path in [f.full_path for f in self.files]: self._mpv.command('loadfile', path, 'append') @self._mpv.event_callback('start-file') @@ -471,28 +469,18 @@ class Player: @property def empty(self) -> bool: """Return if playlist empty.""" - return 0 == len(self._files) + return 0 == len(self.files) @property - def current_file(self) -> Optional[VideoFile]: - """Return what we assume is the currently playing file.""" - if not self._files: - return None - return self._files[self._idx] + def current_file_digest(self) -> Optional[Hash]: + """Return .digest of what we assume is the currently playing file. - @property - def _files_w_idx(self) -> FilesWithIndex: - return list(enumerate(self._files)) - - @property - def prev_files_w_idx(self) -> FilesWithIndex: - """List 'past' files of playlist.""" - return list(reversed(self._files_w_idx[:self._idx])) - - @property - def next_files_w_idx(self) -> FilesWithIndex: - """List 'coming' files of playlist.""" - return self._files_w_idx[self._idx + 1:] + We don't return the actual file object because we cannot guarantee its + data's up-to-date-ness, it being cached from the last .load_files call. + """ + if not self.files: + return None + return self.files[self._idx].digest @property def is_running(self) -> bool: @@ -528,7 +516,7 @@ class Player: def next(self) -> None: """Move player to next item in playlist.""" - if self._idx < len(self._files) - 1: + if self._idx < len(self.files) - 1: self._idx += 1 self._play_at_index() @@ -543,16 +531,16 @@ class Player: or (upwards and start_idx == self._idx + 1) or ((not upwards) and start_idx == self._idx - 1) or (upwards and start_idx < 1) - or ((not upwards) and start_idx > len(self._files) - 2)): + or ((not upwards) and start_idx > len(self.files) - 2)): return i0, i1 = start_idx, start_idx + (-1 if upwards else 1) if self._mpv: # NB: a functional playlist-move would do this in a single step, # but for some reason I don't seem to get it to do anything - path = self._files[i1].full_path + path = self.files[i1].full_path self._mpv.command('playlist-remove', i1) self._mpv.command('loadfile', path, 'insert-at', i0) - self._files[i0], self._files[i1] = self._files[i1], self._files[i0] + self.files[i0], self.files[i1] = self.files[i1], self.files[i0] def reload(self) -> None: """Close MPV, re-read (and re-shuffle) filenames, then re-start MPV.""" @@ -563,9 +551,9 @@ class Player: def inject_and_play(self, file: VideoFile) -> None: """Inject file after current title, then jump to it.""" - if self._files: + if self.files: self._idx += 1 - self._files.insert(self._idx, file) + self.files.insert(self._idx, file) if self._mpv: self._mpv.command('loadfile', file.full_path, 'insert-at', self._idx) -- 2.30.2