aboutsummaryrefslogtreecommitdiffstats
path: root/youtube/templates
diff options
context:
space:
mode:
authorAstounds <kirito@disroot.org>2026-03-22 20:50:03 -0500
committerAstounds <kirito@disroot.org>2026-03-22 20:50:03 -0500
commit6a68f0664568cea6f9a12e8743f195fe0a41f3ce (patch)
tree4ad12a70811a4821c0cc9dc94c19c1ccf2bca808 /youtube/templates
parent84e1acaab8f7e4e7e36d19e3b6847a0ab6c33759 (diff)
downloadyt-local-6a68f0664568cea6f9a12e8743f195fe0a41f3ce.tar.lz
yt-local-6a68f0664568cea6f9a12e8743f195fe0a41f3ce.tar.xz
yt-local-6a68f0664568cea6f9a12e8743f195fe0a41f3ce.zip
Release v0.4.0 - HD Thumbnails, YouTube 2024+ Support, and yt-dlp Integrationv0.4.0
Major Features: - HD video thumbnails (hq720.jpg) with automatic fallback to lower qualities - HD channel avatars (240x240 instead of 88x88) - YouTube 2024+ lockupViewModel support for channel playlists - youtubei/v1/browse API integration for channel playlist tabs - yt-dlp integration for multi-language audio and subtitles Bug Fixes: - Fixed undefined `abort` import in playlist.py - Fixed undefined functions in proto.py (encode_varint, bytes_to_hex, succinct_encode) - Fixed missing `traceback` import in proto_debug.py - Fixed blurry playlist thumbnails using default.jpg instead of HD versions - Fixed channel playlists page using deprecated pbj=1 format Improvements: - Automatic thumbnail fallback system (hq720 → sddefault → hqdefault → mqdefault → default) - JavaScript thumbnail_fallback() handler for 404 errors - Better thumbnail quality across all pages (watch, channel, playlist, subscriptions) - Consistent HD avatar display for all channel items - Settings system automatically adds new settings without breaking user config Files Modified: - youtube/watch.py - HD thumbnails for related videos and playlist items - youtube/channel.py - HD thumbnails for channel playlists, youtubei API integration - youtube/playlist.py - HD thumbnails, fixed abort import - youtube/util.py - HD thumbnail URLs, avatar HD upgrade, prefix_url improvements - youtube/comments.py - HD video thumbnail - youtube/subscriptions.py - HD thumbnails, fixed abort import - youtube/yt_data_extract/common.py - lockupViewModel support, extract_lockup_view_model_info() - youtube/yt_data_extract/everything_else.py - HD playlist thumbnails - youtube/proto.py - Fixed undefined function references - youtube/proto_debug.py - Added traceback import - youtube/static/js/common.js - thumbnail_fallback() handler - youtube/templates/*.html - Added onerror handlers for thumbnail fallback - youtube/version.py - Bump to v0.4.0 Technical Details: - All thumbnail URLs now use hq720.jpg (1280x720) when available - Fallback handled client-side via JavaScript onerror handler - Server-side avatar upgrade via regex in util.prefix_url() - lockupViewModel parser extracts contentType, metadata, and first_video_id - Channel playlist tabs now use youtubei/v1/browse instead of deprecated pbj=1 - Settings version system ensures backward compatibility
Diffstat (limited to 'youtube/templates')
-rw-r--r--youtube/templates/base.html6
-rw-r--r--youtube/templates/channel.html4
-rw-r--r--youtube/templates/common_elements.html6
-rw-r--r--youtube/templates/watch.html42
4 files changed, 53 insertions, 5 deletions
diff --git a/youtube/templates/base.html b/youtube/templates/base.html
index 95207fa..dd7c628 100644
--- a/youtube/templates/base.html
+++ b/youtube/templates/base.html
@@ -26,6 +26,12 @@
// @license-end
</script>
{% endif %}
+ <script>
+ // @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
+ // Image prefix for thumbnails
+ let settings_img_prefix = "{{ settings.img_prefix or '' }}";
+ // @license-end
+ </script>
</head>
<body>
diff --git a/youtube/templates/channel.html b/youtube/templates/channel.html
index c43f488..2c0a1a2 100644
--- a/youtube/templates/channel.html
+++ b/youtube/templates/channel.html
@@ -81,10 +81,10 @@
<!-- new-->
<div id="links-metadata">
{% if current_tab in ('videos', 'shorts', 'streams') %}
- {% set sorts = [('1', 'views'), ('2', 'oldest'), ('3', 'newest'), ('4', 'newest - no shorts'),] %}
+ {% set sorts = [('3', 'newest'), ('4', 'newest - no shorts')] %}
<div id="number-of-results">{{ number_of_videos }} videos</div>
{% elif current_tab == 'playlists' %}
- {% set sorts = [('2', 'oldest'), ('3', 'newest'), ('4', 'last video added')] %}
+ {% set sorts = [('3', 'newest'), ('4', 'last video added')] %}
{% if items %}
<h2 class="page-number">Page {{ page_number }}</h2>
{% else %}
diff --git a/youtube/templates/common_elements.html b/youtube/templates/common_elements.html
index bacc513..bd43761 100644
--- a/youtube/templates/common_elements.html
+++ b/youtube/templates/common_elements.html
@@ -23,11 +23,11 @@
<a class="thumbnail-box" href="{{ info['url'] }}" title="{{ info['title'] }}">
<div class="thumbnail {% if info['type'] == 'channel' %} channel {% endif %}">
{% if lazy_load %}
- <img class="thumbnail-img lazy" alt="&#x20;" data-src="{{ info['thumbnail'] }}">
+ <img class="thumbnail-img lazy" alt="&#x20;" data-src="{{ info['thumbnail'] }}" onerror="thumbnail_fallback(this)">
{% elif info['type'] == 'channel' %}
- <img class="thumbnail-img channel" alt="&#x20;" src="{{ info['thumbnail'] }}">
+ <img class="thumbnail-img channel" alt="&#x20;" src="{{ info['thumbnail'] }}" onerror="thumbnail_fallback(this)">
{% else %}
- <img class="thumbnail-img" alt="&#x20;" src="{{ info['thumbnail'] }}">
+ <img class="thumbnail-img" alt="&#x20;" src="{{ info['thumbnail'] }}" onerror="thumbnail_fallback(this)">
{% endif %}
{% if info['type'] != 'channel' %}
diff --git a/youtube/templates/watch.html b/youtube/templates/watch.html
index 0991457..7432bde 100644
--- a/youtube/templates/watch.html
+++ b/youtube/templates/watch.html
@@ -85,6 +85,16 @@
<option value='{"type": "pair", "index": {{ loop.index0}}}' {{ 'selected' if loop.index0 == pair_idx and using_pair_sources else '' }} >{{ src_pair['quality_string'] }}</option>
{% endfor %}
</select>
+
+ {% if audio_tracks and audio_tracks|length > 1 %}
+ <select id="audio-language-select" autocomplete="off" title="Audio language">
+ {% for track in audio_tracks %}
+ <option value="{{ track.get('track_id', track['language']) }}" {{ 'selected' if loop.index0 == 0 else '' }}>
+ 🔊 {{ track['language_name'] }}{% if track.get('is_default') %} (Default){% endif %}
+ </option>
+ {% endfor %}
+ </select>
+ {% endif %}
{% endif %}
</div>
<input class="v-checkbox" name="video_info_list" value="{{ video_info }}" form="playlist-edit" type="checkbox">
@@ -246,6 +256,38 @@
let storyboard_url = {{ storyboard_url | tojson }};
// @license-end
</script>
+
+ <!-- Audio language selector handler -->
+ <script>
+ // @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
+ (function() {
+ 'use strict';
+ const audioSelect = document.getElementById('audio-language-select');
+ const qualitySelect = document.getElementById('quality-select');
+
+ if (audioSelect && qualitySelect) {
+ audioSelect.addEventListener('change', function() {
+ const selectedAudio = this.value;
+ const selectedQuality = qualitySelect.value;
+
+ // Parse current quality selection
+ let qualityData;
+ try {
+ qualityData = JSON.parse(selectedQuality);
+ } catch(e) {
+ return;
+ }
+
+ // Reload video with new audio language
+ const currentUrl = new URL(window.location.href);
+ currentUrl.searchParams.set('audio_lang', selectedAudio);
+ window.location.href = currentUrl.toString();
+ });
+ }
+ }());
+ // @license-end
+ </script>
+
<script src="/youtube.com/static/js/common.js"></script>
<script src="/youtube.com/static/js/transcript-table.js"></script>
{% if settings.use_video_player == 2 %}