home · contact · privacy
Have basic player control as part of every page's head rather than only as playlist...
authorChristian Heller <c.heller@plomlompom.de>
Fri, 6 Dec 2024 15:54:53 +0000 (16:54 +0100)
committerChristian Heller <c.heller@plomlompom.de>
Fri, 6 Dec 2024 15:54:53 +0000 (16:54 +0100)
src/templates/_macros.tmpl
src/templates/file_data.tmpl
src/templates/files.tmpl
src/templates/playlist.tmpl
src/templates/yt_queries.tmpl
src/templates/yt_result.tmpl
src/templates/yt_results.tmpl
src/ytplom/http.py
src/ytplom/misc.py

index 8b851f5e6a6a2268084d2bb560ead387c9285516..8c407c1355bec304a1e80f7b5c4458da28757049 100644 (file)
@@ -1,14 +1,21 @@
 {% macro _link_if(cond, target, display_name = false ) %}{% if cond %}<a href="/{{target}}">{% endif %}{% if display_name %}{{display_name}}{% else %}{{target}}{% endif %}{% if cond %}</a>{% endif %}{% endmacro %}
 
 
-{% macro nav_head(page_names, selected="") %}
-<p>
+{% macro nav_head(page_names, redir_target, player_state, selected="") %}
+<form action="/player" method="POST">
+<input type="hidden" name="redir_target" value="{{redir_target}}" />
 {{ _link_if("playlist" != selected, page_names.playlist) }}
 ·
 {{ _link_if("files" != selected, page_names.files) }}
 ·
 {{ _link_if("yt_queries" != selected, page_names.yt_queries, "queries") }}
-</p>
+|
+<input type="submit" name="pause" value="{% if player_state.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 player_state.running %}stop{% else %}start{% endif %}">
+{% if player_state.running %}{% if player_state.paused %}PAUSED{% else %}PLAYING{% endif %}{% else %}STOPPED{% endif %}: {{player_state.title}}
+</form>
 <hr />
 {% endmacro %}
 
@@ -17,6 +24,9 @@
 <form action="/{{page_names.file}}/{{file.digest.b64}}" method="POST" />
 <input type="hidden" name="redir_target" value="{{redir_target}}" />
 <table>
+{% if playlist_view %}
+<tr><th colspan=2 class="screen_half_titles">current selection</th></tr>
+{% endif %}
 <tr><th>path:</th><td class="top_field">{% if playlist_view %}<a href="/{{page_names.file}}/{{file.digest.b64}}">{% endif %}{{file.rel_path}}{% if playlist_view %}</a>{% endif %}</td></tr>
 {% if not playlist_view %}
 <tr><th>present:</th><td>{% if file.present %}<a href="/{{page_names.download}}/{{file.yt_id}}">yes</a>{% else %}no{% endif %}</td></tr>
index 8df4bf01cd13f1f44660f96f8ae6b5902a5d87d7..305d3e9ed62f7614963e4cacdfd0fde99cd4f520 100644 (file)
@@ -9,6 +9,6 @@ td.tag_checkboxes { width: 1em; }
 
 
 {% block body %}
-{{ macros.nav_head(page_names) }}
+{{ macros.nav_head(page_names, redir_target, player_state) }}
 {{ macros.file_data_form(file, unused_tags, page_names, redir_target, flag_names) }}
 {% endblock %}
index 16ea4e2d2bc0416bb388c738ddc86f3358cee68e..2e5909cd40624492942880f23a5ea49ce20e7cc7 100644 (file)
@@ -2,7 +2,7 @@
 
 
 {% block body %}
-{{ macros.nav_head(page_names, "files") }}
+{{ macros.nav_head(page_names, redir_target, player_state, "files") }}
 <form method="GET">
 filter filename: <input name="filter_path" value="{{filter_path}}" />
 filter tags: <input name="filter_tags" value="{{filter_tags}}" />
index 63671f7a89af35a30d6aedb46cd2ddd9cabb5196..6207c335f235be76b67b17297da68d3d3051c644 100644 (file)
@@ -29,27 +29,16 @@ window.onload = keep_updated;
 
 
 {% block css %}
-#status { font-weight: bold; }
 td.screen_half { width: 50%; }
-tr.screen_half_titles>th { text-align: center; }
+th.screen_half_titles { text-align: center; }
 td.entry_buttons { width: 5em; }
 td.tag_checkboxes { width: 1em; }
 {% endblock %}
 
 
 {% block body %}
-{{ macros.nav_head(page_names, "playlist") }}
+{{ macros.nav_head(page_names, redir_target, player_state, "playlist") }}
 <table>
-<tr><td id="status" colspan=2>
-<form action="{{redir_target}}" 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">
-{% if running %}{% if pause %}PAUSED{% else %}PLAYING{% endif %}{% else %}STOPPED{% endif %}
-</form>
-</td></tr>
 <tr><td colspan=2>
 <form method="GET">
 filter filename: <input name="filter_path" value="{{filter_path}}" />
@@ -57,7 +46,6 @@ filter tags: <input name="filter_tags" value="{{filter_tags}}" />
 <input type="submit" value="filter" />
 </form>
 </td></tr>
-<tr class="screen_half_titles"><th>current selection</th><th>playlist</th></tr>
 <tr>
 <td class="screen_half">
 {% if current_file %}
@@ -67,6 +55,7 @@ filter tags: <input name="filter_tags" value="{{filter_tags}}" />
 <td class="screen_half">
 <form action="{{redir_target}}" method="POST">
 <table>
+<tr><th colspan=2 class="screen_half_titles"><form action="{{redir_target}}" method="POST">playlist <input type="submit" name="reload" value="reload"></form></th></tr>
 {% for idx, file in files_w_idx %}
 <tr>
 <td class="entry_buttons">
index 9ef271d0ae28d55e199f73955a36692318704b57..477b7b27172e7794b8d5480bc6861e84820013bd 100644 (file)
@@ -2,7 +2,7 @@
 
 
 {% block body %}
-{{ macros.nav_head(page_names, "yt_queries") }}
+{{ macros.nav_head(page_names, redir_target, player_state, "yt_queries") }}
 <p>quota: {{quota_count}}/100000</p>
 <form action="/{{page_names.yt_queries}}" method="POST" />
 <input name="query" />
index 73ffbab3dfda38dc1ccbc85702f6db3f828a2c12..65372467cc7136956ffc5ce2d8df8e894c0c4ff9 100644 (file)
@@ -2,7 +2,7 @@
 
 
 {% block body %}
-{{ macros.nav_head(page_names) }}
+{{ macros.nav_head(page_names, redir_target, player_state) }}
 <table>
 <tr><th>title:</th><td>{{video_data.title}}</td></tr>
 <tr><th>thumbnail:</th><td><img src="/{{page_names.thumbnails}}/{{video_data.id_}}.jpg" /></td></tr>
index 872d461b3a088be6bb1529fab0be49c6914781b3..c3fa0347b2193793b28da7ed39b9cda495ca7464 100644 (file)
@@ -2,7 +2,7 @@
 
 
 {% block body %}
-{{ macros.nav_head(page_names) }}
+{{ macros.nav_head(page_names, redir_target, player_state) }}
 <p>query: {{query}}</p>
 <table>
 {% for video in videos %}
index 2b85490cafba259153d640bda24ea4efeeb8c843..1ea2bc202e30fa84fb966fcf6f251972c6097d34 100644 (file)
@@ -25,11 +25,12 @@ from ytplom.primitives import NotFoundException, PATH_APP_DATA
 _ColorStr = NewType('_ColorStr', str)
 _PageNames: TypeAlias = dict[str, Path]
 _ReqDict: TypeAlias = dict[str, list[str]]
+_PlayerState: TypeAlias = dict[str, bool | Path | str]
 _TemplateContext: TypeAlias = dict[
         str,
         None | bool
-        | _ColorStr | FilesWithIndex | _PageNames | FilterStr | Path
-        | PlayerUpdateId | QueryText | QuotaCost | UrlStr | 'VideoFile'
+        | _ColorStr | FilesWithIndex | _PlayerState | _PageNames | FilterStr
+        | Path | PlayerUpdateId | QueryText | QuotaCost | UrlStr | 'VideoFile'
         | YoutubeId | 'YoutubeVideo' | list[FlagName] | set['Tag']
         | list['VideoFile'] | list['YoutubeVideo'] | list['YoutubeQuery']
 ]
@@ -54,6 +55,7 @@ PAGE_NAMES: _PageNames = {
     'files': Path('files'),
     'last_update': Path('last_playlist_update.json'),
     'missing': Path('missing.json'),
+    'player': Path('player'),
     'playlist': Path('playlist'),
     'thumbnails': Path('thumbnails'),
     'yt_result': Path('yt_result'),
@@ -130,10 +132,11 @@ class _TaskHandler(BaseHTTPRequestHandler):
         page_name = Path(toks_url[1] if len(toks_url) > 1 else '')
         body_length = int(self.headers['content-length'])
         postvars = _ReqMap(self.rfile.read(body_length).decode())
-        # postvars = parse_qs(self.rfile.read(body_length).decode())
-        if PAGE_NAMES['playlist'] == page_name:
-            self._receive_player_command(postvars.single_key, url.query)
-        if PAGE_NAMES['files'] == page_name:
+        if PAGE_NAMES['player'] == page_name:
+            self._receive_player_command(postvars.as_dict)
+        elif PAGE_NAMES['playlist'] == page_name:
+            self._receive_playlist_command(postvars.single_key, url.query)
+        elif PAGE_NAMES['files'] == page_name:
             self._receive_files_command(postvars)
         elif PAGE_NAMES['file'] == page_name:
             self._receive_file_data(Hash.from_b64(toks_url[2]),
@@ -141,16 +144,19 @@ class _TaskHandler(BaseHTTPRequestHandler):
         elif PAGE_NAMES['yt_queries'] == page_name:
             self._receive_yt_query(QueryText(postvars.single_value('query')))
 
-    def _receive_player_command(self, command: str, params_str: str) -> None:
-        if 'pause' == command:
+    def _receive_player_command(self, postvars: _ReqDict) -> None:
+        if 'pause' in postvars.keys():
             self.server.player.toggle_pause()
-        elif 'prev' == command:
+        elif 'prev' in postvars.keys():
             self.server.player.prev()
-        elif 'next' == command:
+        elif 'next' in postvars.keys():
             self.server.player.next()
-        elif 'stop' == command:
+        elif 'stop' in postvars.keys():
             self.server.player.toggle_run()
-        elif 'reload' == command:
+        self._redirect(Path(postvars['redir_target'][0]))
+
+    def _receive_playlist_command(self, command: str, params_str: str) -> None:
+        if 'reload' == command:
             self.server.player.clear()
         elif command.startswith('jump_'):
             self.server.player.jump_to(int(command.split('_')[1]))
@@ -224,9 +230,16 @@ class _TaskHandler(BaseHTTPRequestHandler):
                                 tmpl_ctx: _TemplateContext
                                 ) -> None:
         tmpl = self.server.jinja.get_template(str(tmpl_name))
+        tmpl_ctx['redir_target'] = Path(self.path)
         tmpl_ctx['background_color'] = _ColorStr(
                 self.server.config.background_color)
         tmpl_ctx['page_names'] = PAGE_NAMES
+        tmpl_ctx['player_state'] = {
+                'running': self.server.player.is_running,
+                'paused': self.server.player.is_paused,
+                'title': (self.server.player.current_file_cached.rel_path
+                          if self.server.player.current_file_cached
+                          else 'none')}
         html = tmpl.render(**tmpl_ctx)
         self._send_http(bytes(html, 'utf8'))
 
@@ -302,13 +315,11 @@ class _TaskHandler(BaseHTTPRequestHandler):
         with DbConn() as conn:
             file = VideoFile.get_one(conn, digest)
             unused_tags = file.unused_tags(conn)
-        redir_target = Path('/').joinpath(PAGE_NAMES['file']).joinpath(
-                file.digest.b64)
-        self._send_rendered_template(_NAME_TEMPLATE_FILE_DATA,
-                                     {'file': file,
-                                      'flag_names': list(FILE_FLAGS),
-                                      'unused_tags': unused_tags,
-                                      'redir_target': redir_target})
+        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: _ReqMap) -> None:
         filter_path = FilterStr(params.single_value('filter_path'))
@@ -323,9 +334,7 @@ class _TaskHandler(BaseHTTPRequestHandler):
                 {'files': files,
                  'filter_path': filter_path,
                  'filter_tags': filter_tags,
-                 'show_absent': show_absent,
-                 'redir_target': Path(
-                     f'/{PAGE_NAMES["files"]}?{params.as_str}')})
+                 'show_absent': show_absent})
 
     def _send_missing_json(self) -> None:
         with DbConn() as conn:
@@ -347,9 +356,9 @@ class _TaskHandler(BaseHTTPRequestHandler):
             self.server.player.load_files_and_start(filter_path, filter_tags)
         current_file, unused_tags = None, set()
         with DbConn() as conn:
-            if self.server.player.current_file_digest:
+            if self.server.player.current_file_cached:
                 current_file = VideoFile.get_one(
-                        conn, self.server.player.current_file_digest)
+                        conn, self.server.player.current_file_cached.digest)
                 unused_tags = current_file.unused_tags(conn)
         self._send_rendered_template(
                 _NAME_TEMPLATE_PLAYLIST,
@@ -359,8 +368,6 @@ class _TaskHandler(BaseHTTPRequestHandler):
                  'current_file': current_file,
                  'filter_path': filter_path,
                  'filter_tags': filter_tags,
-                 'redir_target': Path(
-                     f'/{PAGE_NAMES["playlist"]}?{params.as_str}'),
                  'unused_tags': unused_tags,
                  'files_w_idx': list(enumerate(self.server.player.files))
                  })
index 45299bf13d550c75fcce55b676c26bb6e7f1ab85..4bd492dfed2596d8bb92a8c4f0287f7b15d1490e 100644 (file)
@@ -495,15 +495,11 @@ class Player:
         return 0 == len(self.files)
 
     @property
-    def current_file_digest(self) -> Optional[Hash]:
-        """Return .digest of what we assume is the currently playing file.
-
-        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.
-        """
+    def current_file_cached(self) -> Optional[VideoFile]:
+        """Return cached version of the currently playing file."""
         if not self.files:
             return None
-        return self.files[self._idx].digest
+        return self.files[self._idx]
 
     @property
     def is_running(self) -> bool: