From 2ade04273717807096a07b6eb132b7677917392d Mon Sep 17 00:00:00 2001 From: RblSb Date: Sat, 29 Feb 2020 14:01:12 +0300 Subject: Get youtube video title/duration with api --- src/client/players/Raw.hx | 18 ++++++++--- src/client/players/Youtube.hx | 71 ++++++++++++++++++++++++++++++++++--------- 2 files changed, 70 insertions(+), 19 deletions(-) (limited to 'src/client/players') diff --git a/src/client/players/Raw.hx b/src/client/players/Raw.hx index 1e5d245..44a33f2 100644 --- a/src/client/players/Raw.hx +++ b/src/client/players/Raw.hx @@ -5,6 +5,7 @@ import js.html.Element; import js.html.VideoElement; import js.Browser.document; import client.Main.ge; +import Types.VideoData; import Types.VideoItem; class Raw implements IPlayer { @@ -19,17 +20,24 @@ class Raw implements IPlayer { this.player = player; } - public function getRemoteDuration(src:String, callback:(duration:Float)->Void):Void { + public function getVideoData(url:String, callback:(data:VideoData)->Void):Void { + var title = url.substr(url.lastIndexOf('/') + 1); + final matchName = ~/^(.+)\./; + if (matchName.match(title)) title = matchName.matched(1); + else title = Lang.get("rawVideo"); + final video = document.createVideoElement(); - video.src = src; - // TODO catch errors on AddVideo and getRemoteVideoDuration + video.src = url; video.onerror = e -> { if (playerEl.contains(video)) playerEl.removeChild(video); - callback(0); + callback({duration: 0}); } video.onloadedmetadata = () -> { if (playerEl.contains(video)) playerEl.removeChild(video); - callback(video.duration); + callback({ + duration: video.duration, + title: title + }); } Utils.prepend(playerEl, video); } diff --git a/src/client/players/Youtube.hx b/src/client/players/Youtube.hx index cba3fc4..3e84950 100644 --- a/src/client/players/Youtube.hx +++ b/src/client/players/Youtube.hx @@ -1,10 +1,13 @@ package client.players; +import haxe.Json; +import haxe.Http; import js.html.Element; import js.Browser.document; import client.Main.ge; import js.youtube.Youtube as YtInit; import js.youtube.YoutubePlayer; +import Types.VideoData; import Types.VideoItem; using StringTools; @@ -13,6 +16,9 @@ class Youtube implements IPlayer { static final matchId = ~/v=([A-z0-9_-]+)/; static final matchShort = ~/youtu.be\/([A-z0-9_-]+)/; static final matchEmbed = ~/embed\/([A-z0-9_-]+)/; + static final apiUrl = "https://www.googleapis.com/youtube/v3/videos"; + static final urlTitleDuration = "?part=snippet,contentDetails&fields=items(snippet/title,contentDetails/duration)"; + static final apiKey = "AIzaSyDTk1OPRI9cDkAK_BKsBcv10DQCHse-QaA"; final main:Main; final player:Player; final playerEl:Element = ge("#ytapiplayer"); @@ -26,17 +32,10 @@ class Youtube implements IPlayer { } public static function isYoutube(url:String):Bool { - if (url.contains("youtu.be/")) { - return matchShort.match(url); - } - if (url.contains("youtube.com/embed/")) { - return matchEmbed.match(url); - } - if (!url.contains("youtube.com/")) return false; - return matchId.match(url); + return extractVideoId(url) != ""; } - function extractVideoId(url:String):String { + static function extractVideoId(url:String):String { if (url.contains("youtu.be/")) { matchShort.match(url); return matchShort.matched(1); @@ -45,13 +44,54 @@ class Youtube implements IPlayer { matchEmbed.match(url); return matchEmbed.matched(1); } - matchId.match(url); + if (!matchId.match(url)) return ""; return matchId.matched(1); } - public function getRemoteDuration(url:String, callback:(duration:Float)->Void):Void { + final matchHours = ~/([0-9]+)H/; + final matchMinutes = ~/([0-9]+)M/; + final matchSeconds = ~/([0-9]+)S/; + + function convertTime(duration:String):Float { + var total = 0; + final hours = matchHours.match(duration); + final minutes = matchMinutes.match(duration); + final seconds = matchSeconds.match(duration); + if (hours) total += Std.parseInt(matchHours.matched(1)) * 3600; + if (minutes) total += Std.parseInt(matchMinutes.matched(1)) * 60; + if (seconds) total += Std.parseInt(matchSeconds.matched(1)); + return total; + } + + public function getVideoData(url:String, callback:(data:VideoData)->Void):Void { + final id = extractVideoId(url); + final url = '$apiUrl$urlTitleDuration&id=$id&key=$apiKey'; + final http = new Http(url); + http.onData = data -> { + final json = Json.parse(data); + if (json.error != null) { + getRemoteDataFallback(url, callback); + return; + } + final item = json.items[0]; + if (item == null) { + callback({duration: 0}); + return; + } + final title:String = item.snippet.title; + final duration:String = item.contentDetails.duration; + callback({ + duration: convertTime(duration), + title: title + }); + } + http.onError = msg -> getRemoteDataFallback(url, callback); + http.request(); + } + + function getRemoteDataFallback(url:String, callback:(data:VideoData)->Void):Void { if (!YtInit.isLoadedAPI) { - YtInit.init(() -> getRemoteDuration(url, callback)); + YtInit.init(() -> getRemoteDataFallback(url, callback)); return; } final video = document.createDivElement(); @@ -67,12 +107,15 @@ class Youtube implements IPlayer { events: { onReady: e -> { if (playerEl.contains(video)) playerEl.removeChild(video); - callback(youtube.getDuration()); + callback({ + duration: youtube.getDuration() + }); }, onError: e -> { + // TODO message error codes trace('Error ${e.data}'); if (playerEl.contains(video)) playerEl.removeChild(video); - callback(0); + callback({duration: 0}); } } }); -- cgit v1.2.3