aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRblSb <msrblsb@gmail.com>2020-02-29 14:01:12 +0300
committerRblSb <msrblsb@gmail.com>2020-02-29 14:01:12 +0300
commit2ade04273717807096a07b6eb132b7677917392d (patch)
tree1598ad62bcb1f3c42b37edb7383df2704005bee5
parentec7e4b5ad120828f1464cf4186287d4928b462a8 (diff)
Get youtube video title/duration with api
-rw-r--r--res/client.js126
-rw-r--r--src/Types.hx5
-rw-r--r--src/client/IPlayer.hx3
-rw-r--r--src/client/Main.hx17
-rw-r--r--src/client/Player.hx8
-rw-r--r--src/client/players/Raw.hx18
-rw-r--r--src/client/players/Youtube.hx71
7 files changed, 175 insertions, 73 deletions
diff --git a/res/client.js b/res/client.js
index 14e7ca4..7b90a05 100644
--- a/res/client.js
+++ b/res/client.js
@@ -779,20 +779,16 @@ client_Main.prototype = {
if(!StringTools.startsWith(url,"http")) {
url = "" + protocol + "//" + url;
}
- var name = HxOverrides.substr(url,url.lastIndexOf("/") + 1,null);
- var matchName = new EReg("^(.+)\\.","");
- if(matchName.match(name)) {
- name = matchName.matched(1);
- } else {
- name = Lang.get("rawVideo");
- }
- this.player.getRemoteDuration(url,function(duration) {
- if(duration == 0) {
+ this.player.getVideoData(url,function(data) {
+ if(data.duration == 0) {
var tmp = Lang.get("addVideoError");
_gthis.serverMessage(4,tmp);
return;
}
- _gthis.send({ type : "AddVideo", addVideo : { item : { url : url, title : name, author : _gthis.personal.name, duration : duration, isTemp : isTemp}, atEnd : atEnd}});
+ if(data.title == null) {
+ data.title = Lang.get("rawVideo");
+ }
+ _gthis.send({ type : "AddVideo", addVideo : { item : { url : url, title : data.title, author : _gthis.personal.name, duration : data.duration, isTemp : isTemp}, atEnd : atEnd}});
callback();
return;
});
@@ -825,7 +821,7 @@ client_Main.prototype = {
var data = JSON.parse(e.data);
var t = data.type;
var t1 = t.charAt(0).toLowerCase() + HxOverrides.substr(t,1,null);
- haxe_Log.trace("Event: " + data.type,{ fileName : "src/client/Main.hx", lineNumber : 212, className : "client.Main", methodName : "onMessage", customParams : [data[t1]]});
+ haxe_Log.trace("Event: " + data.type,{ fileName : "src/client/Main.hx", lineNumber : 211, className : "client.Main", methodName : "onMessage", customParams : [data[t1]]});
switch(data.type) {
case "AddVideo":
this.player.addVideoItem(data.addVideo.item,data.addVideo.atEnd);
@@ -998,8 +994,9 @@ client_Main.prototype = {
}
var smilesWrap = window.document.querySelector("#smileswrap");
smilesWrap.onclick = function(e) {
+ var el = e.target;
var form = window.document.querySelector("#chatline");
- form.value += " " + e.target.title;
+ form.value += " " + el.title;
form.focus();
return;
};
@@ -1248,11 +1245,11 @@ client_Player.prototype = {
,setPlayer: function(player) {
this.player = player;
}
- ,getRemoteDuration: function(url,callback) {
+ ,getVideoData: function(url,callback) {
if(client_players_Youtube.isYoutube(url)) {
- new client_players_Youtube(this.main,this).getRemoteDuration(url,callback);
+ new client_players_Youtube(this.main,this).getVideoData(url,callback);
} else {
- new client_players_Raw(this.main,this).getRemoteDuration(url,callback);
+ new client_players_Raw(this.main,this).getVideoData(url,callback);
}
}
,setVideo: function(i) {
@@ -1551,22 +1548,29 @@ var client_players_Raw = function(main,player) {
};
client_players_Raw.__name__ = true;
client_players_Raw.prototype = {
- getRemoteDuration: function(src,callback) {
+ getVideoData: function(url,callback) {
var _gthis = this;
+ var title = HxOverrides.substr(url,url.lastIndexOf("/") + 1,null);
+ var matchName = new EReg("^(.+)\\.","");
+ if(matchName.match(title)) {
+ title = matchName.matched(1);
+ } else {
+ title = Lang.get("rawVideo");
+ }
var video = window.document.createElement("video");
- video.src = src;
+ video.src = url;
video.onerror = function(e) {
if(_gthis.playerEl.contains(video)) {
_gthis.playerEl.removeChild(video);
}
- callback(0);
+ callback({ duration : 0});
return;
};
video.onloadedmetadata = function() {
if(_gthis.playerEl.contains(video)) {
_gthis.playerEl.removeChild(video);
}
- callback(video.duration);
+ callback({ duration : video.duration, title : title});
return;
};
client_Utils.prepend(this.playerEl,video);
@@ -1630,6 +1634,9 @@ client_players_Raw.prototype = {
}
};
var client_players_Youtube = function(main,player) {
+ this.matchSeconds = new EReg("([0-9]+)S","");
+ this.matchMinutes = new EReg("([0-9]+)M","");
+ this.matchHours = new EReg("([0-9]+)H","");
this.isLoaded = false;
this.playerEl = window.document.querySelector("#ytapiplayer");
this.main = main;
@@ -1637,35 +1644,70 @@ var client_players_Youtube = function(main,player) {
};
client_players_Youtube.__name__ = true;
client_players_Youtube.isYoutube = function(url) {
+ return client_players_Youtube.extractVideoId(url) != "";
+};
+client_players_Youtube.extractVideoId = function(url) {
if(url.indexOf("youtu.be/") != -1) {
- return client_players_Youtube.matchShort.match(url);
+ client_players_Youtube.matchShort.match(url);
+ return client_players_Youtube.matchShort.matched(1);
}
if(url.indexOf("youtube.com/embed/") != -1) {
- return client_players_Youtube.matchEmbed.match(url);
+ client_players_Youtube.matchEmbed.match(url);
+ return client_players_Youtube.matchEmbed.matched(1);
}
- if(url.indexOf("youtube.com/") == -1) {
- return false;
+ if(!client_players_Youtube.matchId.match(url)) {
+ return "";
}
- return client_players_Youtube.matchId.match(url);
+ return client_players_Youtube.matchId.matched(1);
};
client_players_Youtube.prototype = {
- extractVideoId: function(url) {
- if(url.indexOf("youtu.be/") != -1) {
- client_players_Youtube.matchShort.match(url);
- return client_players_Youtube.matchShort.matched(1);
+ convertTime: function(duration) {
+ var total = 0;
+ var hours = this.matchHours.match(duration);
+ var minutes = this.matchMinutes.match(duration);
+ var seconds = this.matchSeconds.match(duration);
+ if(hours) {
+ total = Std.parseInt(this.matchHours.matched(1)) * 3600;
+ }
+ if(minutes) {
+ total += Std.parseInt(this.matchMinutes.matched(1)) * 60;
}
- if(url.indexOf("youtube.com/embed/") != -1) {
- client_players_Youtube.matchEmbed.match(url);
- return client_players_Youtube.matchEmbed.matched(1);
+ if(seconds) {
+ total += Std.parseInt(this.matchSeconds.matched(1));
}
- client_players_Youtube.matchId.match(url);
- return client_players_Youtube.matchId.matched(1);
+ return total;
+ }
+ ,getVideoData: function(url,callback) {
+ var _gthis = this;
+ var url1 = "" + client_players_Youtube.apiUrl + client_players_Youtube.urlTitleDuration + "&id=" + client_players_Youtube.extractVideoId(url) + "&key=" + client_players_Youtube.apiKey;
+ var http = new haxe_http_HttpJs(url1);
+ http.onData = function(data) {
+ var json = JSON.parse(data);
+ if(json.error != null) {
+ _gthis.getRemoteDataFallback(url1,callback);
+ return;
+ }
+ var item = json.items[0];
+ if(item == null) {
+ callback({ duration : 0});
+ return;
+ }
+ var title = item.snippet.title;
+ var tmp = _gthis.convertTime(item.contentDetails.duration);
+ callback({ duration : tmp, title : title});
+ return;
+ };
+ http.onError = function(msg) {
+ _gthis.getRemoteDataFallback(url1,callback);
+ return;
+ };
+ http.request();
}
- ,getRemoteDuration: function(url,callback) {
+ ,getRemoteDataFallback: function(url,callback) {
var _gthis = this;
if(!js_youtube_Youtube.isLoadedAPI) {
js_youtube_Youtube.init(function() {
- _gthis.getRemoteDuration(url,callback);
+ _gthis.getRemoteDataFallback(url,callback);
return;
});
return;
@@ -1673,19 +1715,18 @@ client_players_Youtube.prototype = {
var video = window.document.createElement("div");
video.id = "temp-videoplayer";
client_Utils.prepend(this.playerEl,video);
- this.youtube = new YT.Player(video.id,{ videoId : this.extractVideoId(url), playerVars : { modestbranding : 1, rel : 0, showinfo : 0}, events : { onReady : function(e) {
+ this.youtube = new YT.Player(video.id,{ videoId : client_players_Youtube.extractVideoId(url), playerVars : { modestbranding : 1, rel : 0, showinfo : 0}, events : { onReady : function(e) {
if(_gthis.playerEl.contains(video)) {
_gthis.playerEl.removeChild(video);
}
- var tmp = _gthis.youtube.getDuration();
- callback(tmp);
+ callback({ duration : _gthis.youtube.getDuration()});
return;
}, onError : function(e1) {
- haxe_Log.trace("Error " + e1.data,{ fileName : "src/client/players/Youtube.hx", lineNumber : 74, className : "client.players.Youtube", methodName : "getRemoteDuration"});
+ haxe_Log.trace("Error " + e1.data,{ fileName : "src/client/players/Youtube.hx", lineNumber : 116, className : "client.players.Youtube", methodName : "getRemoteDataFallback"});
if(_gthis.playerEl.contains(video)) {
_gthis.playerEl.removeChild(video);
}
- callback(0);
+ callback({ duration : 0});
return;
}}});
}
@@ -1701,7 +1742,7 @@ client_players_Youtube.prototype = {
this.video = window.document.createElement("div");
this.video.id = "videoplayer";
this.playerEl.appendChild(this.video);
- this.youtube = new YT.Player(this.video.id,{ videoId : this.extractVideoId(item.url), playerVars : { autoplay : 1, modestbranding : 1, rel : 0, showinfo : 0}, events : { onStateChange : function(e) {
+ this.youtube = new YT.Player(this.video.id,{ videoId : client_players_Youtube.extractVideoId(item.url), playerVars : { autoplay : 1, modestbranding : 1, rel : 0, showinfo : 0}, events : { onStateChange : function(e) {
switch(e.data) {
case -1:
_gthis.isLoaded = true;
@@ -2217,6 +2258,9 @@ client_Buttons.personalHistoryId = -1;
client_players_Youtube.matchId = new EReg("v=([A-z0-9_-]+)","");
client_players_Youtube.matchShort = new EReg("youtu.be/([A-z0-9_-]+)","");
client_players_Youtube.matchEmbed = new EReg("embed/([A-z0-9_-]+)","");
+client_players_Youtube.apiUrl = "https://www.googleapis.com/youtube/v3/videos";
+client_players_Youtube.urlTitleDuration = "?part=snippet,contentDetails&fields=items(snippet/title,contentDetails/duration)";
+client_players_Youtube.apiKey = "AIzaSyDTk1OPRI9cDkAK_BKsBcv10DQCHse-QaA";
js_youtube_Youtube.isLoadedAPI = false;
client_Main.main();
})(typeof window != "undefined" ? window : typeof global != "undefined" ? global : typeof self != "undefined" ? self : this);
diff --git a/src/Types.hx b/src/Types.hx
index 17b010b..8eda528 100644
--- a/src/Types.hx
+++ b/src/Types.hx
@@ -2,6 +2,11 @@ package;
import Client.ClientData;
+typedef VideoData = {
+ duration:Float,
+ ?title:String
+}
+
typedef Config = {
channelName:String,
maxLoginLength:Int,
diff --git a/src/client/IPlayer.hx b/src/client/IPlayer.hx
index a20b22b..4f29512 100644
--- a/src/client/IPlayer.hx
+++ b/src/client/IPlayer.hx
@@ -1,9 +1,10 @@
package client;
+import Types.VideoData;
import Types.VideoItem;
interface IPlayer {
- function getRemoteDuration(url:String, callback:(duration:Float)->Void):Void;
+ function getVideoData(url:String, callback:(data:VideoData)->Void):Void;
function loadVideo(item:VideoItem):Void;
function removeVideo():Void;
function play():Void;
diff --git a/src/client/Main.hx b/src/client/Main.hx
index d3271e9..c74a600 100644
--- a/src/client/Main.hx
+++ b/src/client/Main.hx
@@ -12,7 +12,9 @@ import js.Browser;
import js.Browser.document;
import js.lib.Date;
import Client.ClientData;
-import Types;
+import Types.VideoData;
+import Types.Config;
+import Types.WsEvent;
using StringTools;
using ClientTools;
@@ -156,23 +158,20 @@ class Main {
url = '$protocol//$host:$port$url';
}
if (!url.startsWith("http")) url = '$protocol//$url';
- var name = url.substr(url.lastIndexOf('/') + 1);
- final matchName = ~/^(.+)\./;
- if (matchName.match(name)) name = matchName.matched(1);
- else name = Lang.get("rawVideo");
- player.getRemoteDuration(url, (duration:Float) -> {
- if (duration == 0) {
+ player.getVideoData(url, (data:VideoData) -> {
+ if (data.duration == 0) {
serverMessage(4, Lang.get("addVideoError"));
return;
}
+ if (data.title == null) data.title = Lang.get("rawVideo");
send({
type: AddVideo, addVideo: {
item: {
url: url,
- title: name,
+ title: data.title,
author: personal.name,
- duration: duration,
+ duration: data.duration,
isTemp: isTemp
},
atEnd: atEnd
diff --git a/src/client/Player.hx b/src/client/Player.hx
index 7bd2f4e..4327e6c 100644
--- a/src/client/Player.hx
+++ b/src/client/Player.hx
@@ -5,6 +5,7 @@ import js.Browser.document;
import client.Main.ge;
import client.players.Raw;
import client.players.Youtube;
+import Types.VideoData;
import Types.VideoItem;
using StringTools;
@@ -80,11 +81,12 @@ class Player {
this.player = player;
}
- public function getRemoteDuration(url:String, callback:(duration:Float)->Void):Void {
+ public function getVideoData(url:String, callback:(data:VideoData)->Void):Void {
+ // TODO P2 reuse player objects
if (Youtube.isYoutube(url)) {
- new Youtube(main, this).getRemoteDuration(url, callback);
+ new Youtube(main, this).getVideoData(url, callback);
} else {
- new Raw(main, this).getRemoteDuration(url, callback);
+ new Raw(main, this).getVideoData(url, callback);
}
}
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});
}
}
});
send patches to the email below
yukais@pinapelz.com
include the subject [PATCH repo_name]
pinapelz.com
homepage