Skip to content

Commit

Permalink
Raw youtube fallback for unavailable videos
Browse files Browse the repository at this point in the history
Also:
- fix `tryLocalIp` replacement (NAT workaround)
- improve proxy headers a bit
- use json2object fork for better generated diffs
  • Loading branch information
RblSb committed Apr 28, 2024
1 parent 8679f8e commit f545e96
Show file tree
Hide file tree
Showing 13 changed files with 1,527 additions and 488 deletions.
13 changes: 7 additions & 6 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,19 @@
"res/client.js": true
},
"[haxe]": {
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.organizeImports": "explicit",
"source.fixAll": "explicit"
}
"editor.formatOnSave": true,
"editor.formatOnPaste": false
},
"editor.codeActionsOnSave": {
"source.sortImports": "explicit",
"source.fixAll": "explicit"
},
"[html]": {
"editor.formatOnSave": true,
"editor.defaultFormatter": "vscode.html-language-features"
},
"[css]": {
"editor.formatOnSave": true,
"editor.defaultFormatter": "HookyQR.beautify"
"editor.defaultFormatter": "vscode.css-language-features"
},
}
3 changes: 2 additions & 1 deletion build-server.hxml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
--library hxnodejs
--library hxnodejs-ws
--library json2object
--library json2object:git:https://github.com/RblSb/json2object.git
-D junsafe_compiler_cache
# Client libs for completion
--library youtubeIFramePlayer:git:https://github.com/okawa-h/youtubeIFramePlayer-externs.git
--library hls.js-extern:git:https://github.com/grosmar/hls.js-haxe-extern.git
Expand Down
1,532 changes: 1,114 additions & 418 deletions build/server.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion hxformat.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
},
"methodChain": {
"rules": []
},
}
},
"emptyLines": {
"beforeDocCommentEmptyLines": "ignore",
Expand Down
109 changes: 83 additions & 26 deletions res/client.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions src/Types.hx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package;

import Client.ClientData;
import utils.YoutubeUtils.YouTubeVideoInfo;

typedef VideoDataRequest = {
url:String,
Expand Down Expand Up @@ -204,6 +205,10 @@ typedef WsEvent = {
},
?dump:{
data:String
},
?getYoutubeVideoInfo:{
url:String,
?response:YouTubeVideoInfo
}
}

Expand Down Expand Up @@ -242,4 +247,5 @@ enum abstract WsEventType(String) {
var UpdatePlaylist;
var TogglePlaylistLock;
var Dump;
var GetYoutubeVideoInfo;
}
12 changes: 11 additions & 1 deletion src/client/Main.hx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import js.html.Event;
import js.html.InputElement;
import js.html.KeyboardEvent;
import js.html.MouseEvent;
import js.html.URL;
import js.html.VideoElement;
import js.html.WebSocket;

Expand Down Expand Up @@ -387,7 +388,13 @@ class Main {

public function tryLocalIp(url:String):String {
if (host == globalIp) return url;
return url.replace(globalIp, host);
try {
final url = new URL(url);
url.hostname = url.hostname.replace(globalIp, host);
return '$url';
} catch (e) {
return url;
}
}

function onMessage(e):Void {
Expand Down Expand Up @@ -557,6 +564,9 @@ class Main {

case Dump:
Utils.saveFile("dump.json", ApplicationJson, data.dump.data);

case GetYoutubeVideoInfo:
// handled by event listeners like `JsApi.once`
}
}

Expand Down
4 changes: 4 additions & 0 deletions src/client/Player.hx
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,10 @@ class Player {
setItemElementType(el, videoList.getItem(pos).isTemp);
}

public function getCurrentItem():VideoItem {
return videoList.currentItem;
}

function setPlayer(newPlayer:IPlayer):Void {
if (player != newPlayer) {
if (player != null) {
Expand Down
65 changes: 43 additions & 22 deletions src/client/players/Youtube.hx
Original file line number Diff line number Diff line change
Expand Up @@ -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)";
Expand All @@ -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/;
Expand Down Expand Up @@ -256,11 +239,49 @@ 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);
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, 320, 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;
Expand Down
Loading

0 comments on commit f545e96

Please sign in to comment.