Add HLS support to multi-audio

This commit is contained in:
2026-04-05 14:56:51 -05:00
parent 62a028968e
commit f0649be5de
19 changed files with 2256 additions and 164 deletions

View File

@@ -8,7 +8,7 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta http-equiv="Content-Security-Policy" content="default-src 'self' 'unsafe-inline' 'unsafe-eval'; media-src 'self' blob: {{ app_url }}/* data: https://*.googlevideo.com; {{ "img-src 'self' https://*.googleusercontent.com https://*.ggpht.com https://*.ytimg.com;" if not settings.proxy_images else "" }}">
<meta http-equiv="Content-Security-Policy" content="default-src 'self' 'unsafe-inline' 'unsafe-eval' blob:; media-src 'self' blob: {{ app_url }}/* data: https://*.googlevideo.com; img-src 'self' https://*.googleusercontent.com https://*.ggpht.com https://*.ytimg.com; connect-src 'self' https://*.googlevideo.com; font-src 'self' data:; worker-src 'self' blob:;">
<title>{{ page_title }}</title>
<link title="YT Local" href="/youtube.com/opensearch.xml" rel="search" type="application/opensearchdescription+xml">
<link href="/youtube.com/static/favicon.ico" type="image/x-icon" rel="icon">

View File

@@ -3,13 +3,13 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta http-equiv="Content-Security-Policy" content="default-src 'self' 'unsafe-inline'; media-src 'self' https://*.googlevideo.com; {{ "img-src 'self' https://*.googleusercontent.com https://*.ggpht.com https://*.ytimg.com;" if not settings.proxy_images else "" }}">
<meta http-equiv="Content-Security-Policy" content="default-src 'self' 'unsafe-inline' 'unsafe-eval'; media-src 'self' blob: https://*.googlevideo.com; img-src 'self' https://*.googleusercontent.com https://*.ggpht.com https://*.ytimg.com; connect-src 'self' https://*.googlevideo.com; font-src 'self' data:;">
<title>{{ title }}</title>
<link href="/youtube.com/static/favicon.ico" type="image/x-icon" rel="icon">
{% if settings.use_video_player == 2 %}
<!-- plyr -->
<link href="/youtube.com/static/modules/plyr/plyr.css" rel="stylesheet">
<!--/ plyr -->
<!-- /plyr -->
{% endif %}
<style>
body {
@@ -37,9 +37,6 @@
<body>
<video id="js-video-player" controls autofocus onmouseleave="{{ title }}"
oncontextmenu="{{ title }}" onmouseenter="{{ title }}" title="{{ title }}">
{% if uni_sources %}
<source src="{{ uni_sources[uni_idx]['url'] }}" type="{{ uni_sources[uni_idx]['type'] }}" data-res="{{ uni_sources[uni_idx]['quality'] }}">
{% endif %}
{% for source in subtitle_sources %}
{% if source['on'] %}
<track label="{{ source['label'] }}" src="{{ source['url'] }}" kind="subtitles" srclang="{{ source['srclang'] }}" default>
@@ -47,28 +44,66 @@
<track label="{{ source['label'] }}" src="{{ source['url'] }}" kind="subtitles" srclang="{{ source['srclang'] }}">
{% endif %}
{% endfor %}
{% if uni_sources %}
{% for source in uni_sources %}
<source src="{{ source['url'] }}" type="{{ source['type'] }}" title="{{ source['quality_string'] }}">
{% endfor %}
{% endif %}
</video>
{% if js_data %}
<script>
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
data = {{ js_data|tojson }};
// @license-end
</script>
{% endif %}
<script>
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
let storyboard_url = {{ storyboard_url | tojson }};
let hls_manifest_url = {{ hls_manifest_url | tojson }};
let hls_unavailable = {{ hls_unavailable | tojson }};
let playback_mode = {{ playback_mode | tojson }};
let pair_sources = {{ pair_sources | tojson }};
let pair_idx = {{ pair_idx | tojson }};
// @license-end
</script>
{% if settings.use_video_player == 2 %}
{% set hls_should_work = (playback_mode == 'hls' or playback_mode == 'auto') and not hls_unavailable %}
{% set use_dash = not hls_should_work %}
{% if not use_dash %}
<script src="/youtube.com/static/js/hls.min.js"
integrity="sha512-CSVqc4a7tn+tizDNt+eDoVn2fXYAwMDpCLrwGlWrOktNfZQ9gp4dKKScElMeRlrIifhliXs0a06BLaUgmMlCUw=="
crossorigin="anonymous"></script>
{% endif %}
<script src="/youtube.com/static/js/common.js"></script>
{% if settings.use_video_player == 0 %}
<!-- Native player -->
{% if use_dash %}
<script src="/youtube.com/static/js/watch.dash.js"></script>
{% else %}
<script src="/youtube.com/static/js/watch.hls.js"></script>
{% endif %}
{% elif settings.use_video_player == 1 %}
<!-- Native player with hotkeys -->
<script src="/youtube.com/static/js/hotkeys.js"></script>
{% if use_dash %}
<script src="/youtube.com/static/js/watch.dash.js"></script>
{% else %}
<script src="/youtube.com/static/js/watch.hls.js"></script>
{% endif %}
{% elif settings.use_video_player == 2 %}
<!-- plyr -->
<script src="/youtube.com/static/modules/plyr/plyr.min.js"
integrity="sha512-l6ZzdXpfMHRfifqaR79wbYCEWjLDMI9DnROvb+oLkKq6d7MGroGpMbI7HFpicvmAH/2aQO+vJhewq8rhysrImw=="
crossorigin="anonymous"></script>
<script src="/youtube.com/static/js/plyr-start.js"></script>
{% if use_dash %}
<script src="/youtube.com/static/js/plyr.dash.start.js"></script>
{% else %}
<script src="/youtube.com/static/js/plyr.hls.start.js"></script>
{% endif %}
<!-- /plyr -->
{% elif settings.use_video_player == 1 %}
<script src="/youtube.com/static/js/hotkeys.js"></script>
{% endif %}
{% if use_dash %}
<script src="/youtube.com/static/js/av-merge.js"></script>
{% endif %}
</body>
</html>

View File

@@ -29,6 +29,11 @@
<td data-label="License"><a href="http://www.gnu.org/licenses/agpl-3.0.html">AGPL-3.0 or later</a></td>
<td data-label="Source"><a href="/youtube.com/static/js/common.js">common.js</a></td>
</tr>
<tr>
<td data-label="File"><a href="/youtube.com/static/js/hls.min.js">hls.min.js</a></td>
<td data-label="License"><a href="https://spdx.org/licenses/BSD-3-Clause.html">BSD-3-Clause</a></td>
<td data-label="Source"><a href="https://github.com/video-dev/hls.js/tree/v1.6.15/src">hls.js v1.6.15 source</a></td>
</tr>
<tr>
<td data-label="File"><a href="/youtube.com/static/js/hotkeys.js">hotkeys.js</a></td>
<td data-label="License"><a href="http://www.gnu.org/licenses/agpl-3.0.html">AGPL-3.0 or later</a></td>
@@ -40,9 +45,24 @@
<td data-label="Source"><a href="/youtube.com/static/js/playlistadd.js">playlistadd.js</a></td>
</tr>
<tr>
<td data-label="File"><a href="/youtube.com/static/js/plyr-start.js">plyr-start.js</a></td>
<td data-label="File"><a href="/youtube.com/static/js/plyr.dash.start.js">plyr.dash.start.js</a></td>
<td data-label="License"><a href="http://www.gnu.org/licenses/agpl-3.0.html">AGPL-3.0 or later</a></td>
<td data-label="Source"><a href="/youtube.com/static/js/plyr-start.js">plyr-start.js</a></td>
<td data-label="Source"><a href="/youtube.com/static/js/plyr.dash.start.js">plyr.dash.start.js</a></td>
</tr>
<tr>
<td data-label="File"><a href="/youtube.com/static/js/plyr.hls.start.js">plyr.hls.start.js</a></td>
<td data-label="License"><a href="http://www.gnu.org/licenses/agpl-3.0.html">AGPL-3.0 or later</a></td>
<td data-label="Source"><a href="/youtube.com/static/js/plyr.hls.start.js">plyr.hls.start.js</a></td>
</tr>
<tr>
<td data-label="File"><a href="/youtube.com/static/js/sponsorblock.js">sponsorblock.js</a></td>
<td data-label="License"><a href="http://www.gnu.org/licenses/agpl-3.0.html">AGPL-3.0 or later</a></td>
<td data-label="Source"><a href="/youtube.com/static/js/sponsorblock.js">sponsorblock.js</a></td>
</tr>
<tr>
<td data-label="File"><a href="/youtube.com/static/js/storyboard-preview.js">storyboard-preview.js</a></td>
<td data-label="License"><a href="http://www.gnu.org/licenses/agpl-3.0.html">AGPL-3.0 or later</a></td>
<td data-label="Source"><a href="/youtube.com/static/js/storyboard-preview.js">storyboard-preview.js</a></td>
</tr>
<tr>
<td data-label="File"><a href="/youtube.com/static/modules/plyr/plyr.min.js">plyr.min.js</a></td>
@@ -55,9 +75,14 @@
<td data-label="Source"><a href="/youtube.com/static/js/transcript-table.js">transcript-table.js</a></td>
</tr>
<tr>
<td data-label="File"><a href="/youtube.com/static/js/watch.js">watch.js</a></td>
<td data-label="File"><a href="/youtube.com/static/js/watch.dash.js">watch.dash.js</a></td>
<td data-label="License"><a href="http://www.gnu.org/licenses/agpl-3.0.html">AGPL-3.0 or later</a></td>
<td data-label="Source"><a href="/youtube.com/static/js/watch.js">watch.js</a></td>
<td data-label="Source"><a href="/youtube.com/static/js/watch.dash.js">watch.dash.js</a></td>
</tr>
<tr>
<td data-label="File"><a href="/youtube.com/static/js/watch.hls.js">watch.hls.js</a></td>
<td data-label="License"><a href="http://www.gnu.org/licenses/agpl-3.0.html">AGPL-3.0 or later</a></td>
<td data-label="Source"><a href="/youtube.com/static/js/watch.hls.js">watch.hls.js</a></td>
</tr>
</tbody>
</table>

View File

@@ -9,7 +9,7 @@
<!-- plyr -->
<link href="/youtube.com/static/modules/plyr/plyr.css" rel="stylesheet">
<link href="/youtube.com/static/modules/plyr/custom_plyr.css" rel="stylesheet">
<!--/ plyr -->
<!-- /plyr -->
{% endif %}
{% endblock style %}
@@ -23,22 +23,9 @@
{% endif %}
</span>
</div>
{% elif (uni_sources.__len__() == 0 or live) and hls_formats.__len__() != 0 %}
<div class="live-url-choices">
<span>Copy a url into your video player:</span>
<ol>
{% for fmt in hls_formats %}
<li class="url-choice"><div class="url-choice-label">{{ fmt['video_quality'] }}: </div><input class="url-choice-copy" value="{{ fmt['url'] }}" readonly onclick="this.select();"></li>
{% endfor %}
</ol>
</div>
{% else %}
<figure class="sc-video">
<video id="js-video-player" playsinline controls {{ 'autoplay' if settings.autoplay_videos }}>
{% if uni_sources %}
<source src="{{ uni_sources[uni_idx]['url'] }}" type="{{ uni_sources[uni_idx]['type'] }}" data-res="{{ uni_sources[uni_idx]['quality'] }}">
{% endif %}
{% for source in subtitle_sources %}
{% if source['on'] %}
<track label="{{ source['label'] }}" src="{{ source['url'] }}" kind="subtitles" srclang="{{ source['srclang'] }}" default>
@@ -46,7 +33,18 @@
<track label="{{ source['label'] }}" src="{{ source['url'] }}" kind="subtitles" srclang="{{ source['srclang'] }}">
{% endif %}
{% endfor %}
{% if uni_sources %}
{% for source in uni_sources %}
<source src="{{ source['url'] }}" type="{{ source['type'] }}" title="{{ source['quality_string'] }}">
{% endfor %}
{% endif %}
</video>
{% if hls_unavailable and not uni_sources %}
<div class="playability-error">
<span>Error: HLS streams unavailable. Video may not play without JavaScript fallback.</span>
</div>
{% endif %}
</figure>
{% endif %}
@@ -76,16 +74,25 @@
<div class="external-player-controls">
<input class="speed" id="speed-control" type="text" title="Video speed">
{% if settings.use_video_player < 2 %}
<!-- Native player quality selector -->
<select id="quality-select" autocomplete="off">
<option value="-1" selected>Auto</option>
<!-- Quality options will be populated by HLS -->
</select>
{% else %}
<select id="quality-select" autocomplete="off" style="display: none;">
<!-- Quality options will be populated by HLS -->
</select>
{% endif %}
{% if settings.use_video_player != 2 %}
<select id="quality-select" autocomplete="off">
{% for src in uni_sources %}
<option value='{"type": "uni", "index": {{ loop.index0 }}}' {{ 'selected' if loop.index0 == uni_idx and not using_pair_sources else '' }} >{{ src['quality_string'] }}</option>
{% endfor %}
{% for src_pair in pair_sources %}
<option value='{"type": "pair", "index": {{ loop.index0}}}' {{ 'selected' if loop.index0 == pair_idx and using_pair_sources else '' }} >{{ src_pair['quality_string'] }}</option>
{% if audio_tracks|length > 1 %}
<select id="audio-track-select" autocomplete="off">
{% for track in audio_tracks %}
<option value="{{ track['id'] }}" {{ 'selected' if track['is_default'] else '' }}>{{ track['name'] }}</option>
{% endfor %}
</select>
{% endif %}
{% endif %}
</div>
<input class="v-checkbox" name="video_info_list" value="{{ video_info }}" form="playlist-edit" type="checkbox">
@@ -244,26 +251,64 @@
</div>
<script src="/youtube.com/static/js/av-merge.js"></script>
<script src="/youtube.com/static/js/watch.js"></script>
<script>
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
let storyboard_url = {{ storyboard_url | tojson }};
let hls_manifest_url = {{ hls_manifest_url | tojson }};
let hls_unavailable = {{ hls_unavailable | tojson }};
let playback_mode = {{ playback_mode | tojson }};
let pair_sources = {{ pair_sources | tojson }};
let pair_idx = {{ pair_idx | tojson }};
// @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 %}
{% set hls_should_work = (playback_mode == 'hls' or playback_mode == 'auto') and not hls_unavailable %}
{% set use_dash = not hls_should_work %}
{% if use_dash %}
<script src="/youtube.com/static/js/av-merge.js"></script>
{% else %}
<script src="/youtube.com/static/js/hls.min.js"
integrity="sha512-CSVqc4a7tn+tizDNt+eDoVn2fXYAwMDpCLrwGlWrOktNfZQ9gp4dKKScElMeRlrIifhliXs0a06BLaUgmMlCUw=="
crossorigin="anonymous"></script>
{% endif %}
{% if settings.use_video_player == 0 %}
<!-- Native player (no hotkeys) -->
{% if use_dash %}
<script src="/youtube.com/static/js/watch.dash.js"></script>
{% else %}
<script src="/youtube.com/static/js/watch.hls.js"></script>
{% endif %}
{% elif settings.use_video_player == 1 %}
<!-- Native player with hotkeys -->
<script src="/youtube.com/static/js/hotkeys.js"></script>
{% if use_dash %}
<script src="/youtube.com/static/js/watch.dash.js"></script>
{% else %}
<script src="/youtube.com/static/js/watch.hls.js"></script>
{% endif %}
{% elif settings.use_video_player == 2 %}
<!-- plyr -->
<script src="/youtube.com/static/modules/plyr/plyr.min.js"
integrity="sha512-l6ZzdXpfMHRfifqaR79wbYCEWjLDMI9DnROvb+oLkKq6d7MGroGpMbI7HFpicvmAH/2aQO+vJhewq8rhysrImw=="
crossorigin="anonymous"></script>
<script src="/youtube.com/static/js/plyr-start.js"></script>
{% if use_dash %}
<script src="/youtube.com/static/js/plyr.dash.start.js"></script>
{% else %}
<script src="/youtube.com/static/js/plyr.hls.start.js"></script>
{% endif %}
<!-- /plyr -->
{% elif settings.use_video_player == 1 %}
<script src="/youtube.com/static/js/hotkeys.js"></script>
{% endif %}
<!-- Storyboard Preview Thumbnails -->
{% if settings.use_video_player != 2 %}
<script src="/youtube.com/static/js/storyboard-preview.js"></script>
{% endif %}
{% if settings.use_comments_js %} <script src="/youtube.com/static/js/comments.js"></script> {% endif %}
{% if settings.use_sponsorblock_js %} <script src="/youtube.com/static/js/sponsorblock.js"></script> {% endif %}
{% endblock main %}