diff options
| author | RblSb <msrblsb@gmail.com> | 2024-04-28 07:23:25 +0300 |
|---|---|---|
| committer | RblSb <msrblsb@gmail.com> | 2024-04-28 21:51:50 +0300 |
| commit | 9d844bbf3ac6be327325b13a91a6b33f73c49c1d (patch) | |
| tree | 52108f2300ca84decf33a1e7b3552e81166ba5ac /src/client/players | |
| parent | 8679f8edcb6d2f3142db30848c640aed6fe883b8 (diff) | |
Raw youtube fallback for unavailable videos
Also:
- fix `tryLocalIp` replacement (NAT workaround)
- improve proxy headers a bit
- use json2object fork for better generated diffs
Diffstat (limited to 'src/client/players')
| -rw-r--r-- | src/client/players/Youtube.hx | 69 |
1 files changed, 47 insertions, 22 deletions
diff --git a/src/client/players/Youtube.hx b/src/client/players/Youtube.hx index a728012..5308b63 100644 --- a/src/client/players/Youtube.hx +++ b/src/client/players/Youtube.hx @@ -10,15 +10,11 @@ import js.Browser.document; import js.html.Element; import js.youtube.Youtube as YtInit; import js.youtube.YoutubePlayer; +import utils.YoutubeUtils; using StringTools; class Youtube implements IPlayer { - final matchId = ~/youtube\.com.*v=([A-z0-9_-]+)/; - final matchShort = ~/youtu\.be\/([A-z0-9_-]+)/; - final matchShorts = ~/youtube\.com\/shorts\/([A-z0-9_-]+)/; - final matchEmbed = ~/youtube\.com\/embed\/([A-z0-9_-]+)/; - final matchPlaylist = ~/youtube\.com.*list=([A-z0-9_-]+)/; final videosUrl = "https://www.googleapis.com/youtube/v3/videos"; final playlistUrl = "https://www.googleapis.com/youtube/v3/playlistItems"; final urlTitleDuration = "?part=snippet,contentDetails&fields=items(snippet/title,contentDetails/duration)"; @@ -41,25 +37,12 @@ class Youtube implements IPlayer { return extractVideoId(url) != "" || extractPlaylistId(url) != ""; } - public function extractVideoId(url:String):String { - if (matchId.match(url)) { - return matchId.matched(1); - } - if (matchShort.match(url)) { - return matchShort.matched(1); - } - if (matchShorts.match(url)) { - return matchShorts.matched(1); - } - if (matchEmbed.match(url)) { - return matchEmbed.matched(1); - } - return ""; + public function extractVideoId(url:String) { + return YoutubeUtils.extractVideoId(url); } - function extractPlaylistId(url:String):String { - if (!matchPlaylist.match(url)) return ""; - return matchPlaylist.matched(1); + public function extractPlaylistId(url:String) { + return YoutubeUtils.extractPlaylistId(url); } final matchHours = ~/([0-9]+)H/; @@ -256,11 +239,53 @@ class Youtube implements IPlayer { }, onPlaybackRateChange: e -> { player.onRateChange(); + }, + onError: e -> { + // TODO message error codes + trace('Error ${e.data}'); + rawSourceFallback(item.url); } } }); } + function rawSourceFallback(url:String):Void { + JsApi.once(GetYoutubeVideoInfo, event -> { + final data = event.getYoutubeVideoInfo; + final info = data.response; + final format = getBestStreamFormat(info) ?? { + trace("format not found in response info:"); + trace(info); + return; + }; + final item = player.getCurrentItem(); + item.url = format.url; + player.refresh(); + }); + main.send({ + type: GetYoutubeVideoInfo, + getYoutubeVideoInfo: { + url: url + } + }); + } + + function getBestStreamFormat(info:YouTubeVideoInfo):Null<YoutubeVideoFormat> { + info.formats ??= []; + info.adaptiveFormats ??= []; + final formats = info.adaptiveFormats.concat(info.formats); + final qPriority = [1080, 720, 480, 360, 240]; + for (q in qPriority) { + final quality = '${q}p'; + for (format in formats) { + if (format.audioQuality == null) continue; // no sound + if (format.width == null) continue; // no video + if (format.qualityLabel == quality) return format; + } + } + return null; + } + public function removeVideo():Void { if (video == null) return; isLoaded = false; |
