aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRblSb <msrblsb@gmail.com>2020-03-08 03:20:52 +0300
committerRblSb <msrblsb@gmail.com>2020-03-08 03:20:52 +0300
commit4df4f2d023d7c2413fb5d6bf9597ce409c3354be (patch)
tree9385e57e234e3c27ba1ce3433c63df38a92c3702
parentc6709732e858d111a75d14f8b9a132c58487f8d8 (diff)
Youtube playlists and api key in config
-rw-r--r--default-config.json1
-rw-r--r--res/client.js108
-rw-r--r--res/index.html2
-rw-r--r--src/Types.hx4
-rw-r--r--src/client/Main.hx12
-rw-r--r--src/client/players/Youtube.hx83
6 files changed, 173 insertions, 37 deletions
diff --git a/default-config.json b/default-config.json
index 37c3861..6d0a99e 100644
--- a/default-config.json
+++ b/default-config.json
@@ -7,6 +7,7 @@
"totalVideoLimit": 0,
"userVideoLimit": 0,
"templateUrl": "https://youtube.com/watch?v=iY1QHpp6iEE",
+ "youtubeApiKey": "AIzaSyDTk1OPRI9cDkAK_BKsBcv10DQCHse-QaA",
"permissions": {
"guest": ["writeChat", "addVideo", "removeVideo", "changeOrder", "requestLeader", "rewind"],
"user": ["guest"],
diff --git a/res/client.js b/res/client.js
index 721babb..240d382 100644
--- a/res/client.js
+++ b/res/client.js
@@ -921,7 +921,10 @@ client_Main.prototype = {
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, isIframe : false}, atEnd : atEnd}});
+ if(data.url == null) {
+ data.url = url;
+ }
+ _gthis.send({ type : "AddVideo", addVideo : { item : { url : data.url, title : data.title, author : _gthis.personal.name, duration : data.duration, isTemp : isTemp, isIframe : false}, atEnd : atEnd}});
callback();
return;
});
@@ -970,7 +973,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 : 257, className : "client.Main", methodName : "onMessage", customParams : [data[t1]]});
+ haxe_Log.trace("Event: " + data.type,{ fileName : "src/client/Main.hx", lineNumber : 258, className : "client.Main", methodName : "onMessage", customParams : [data[t1]]});
switch(data.type) {
case "AddVideo":
this.player.addVideoItem(data.addVideo.item,data.addVideo.atEnd);
@@ -1237,7 +1240,10 @@ client_Main.prototype = {
}
this.ws.send(JSON.stringify(data));
}
- ,serverMessage: function(type,text) {
+ ,serverMessage: function(type,text,isText) {
+ if(isText == null) {
+ isText = true;
+ }
var msgBuf = window.document.querySelector("#messagebuffer");
var div = window.document.createElement("div");
var time = "[" + new Date().toTimeString().split(" ")[0] + "] ";
@@ -1256,7 +1262,11 @@ client_Main.prototype = {
break;
case 4:
div.className = "server-whisper";
- div.textContent = time + text;
+ if(isText) {
+ div.textContent = time + text;
+ } else {
+ div.innerHTML = time + text;
+ }
break;
default:
}
@@ -1384,6 +1394,9 @@ client_Main.prototype = {
,getTemplateUrl: function() {
return this.config.templateUrl;
}
+ ,getYoutubeApiKey: function() {
+ return this.config.youtubeApiKey;
+ }
,escapeRegExp: function(regex) {
var _this_r = new RegExp("([.*+?^${}()|[\\]\\\\])","g".split("u").join(""));
return regex.replace(_this_r,"\\$1");
@@ -1907,10 +1920,15 @@ var client_players_Youtube = function(main,player) {
this.playerEl = window.document.querySelector("#ytapiplayer");
this.main = main;
this.player = player;
+ client_players_Youtube.apiKey = main.getYoutubeApiKey();
};
client_players_Youtube.__name__ = true;
client_players_Youtube.isYoutube = function(url) {
- return client_players_Youtube.extractVideoId(url) != "";
+ if(client_players_Youtube.extractVideoId(url) == "") {
+ return client_players_Youtube.extractPlaylistId(url) != "";
+ } else {
+ return true;
+ }
};
client_players_Youtube.extractVideoId = function(url) {
if(url.indexOf("youtu.be/") != -1) {
@@ -1926,6 +1944,12 @@ client_players_Youtube.extractVideoId = function(url) {
}
return client_players_Youtube.matchId.matched(1);
};
+client_players_Youtube.extractPlaylistId = function(url) {
+ if(!client_players_Youtube.matchPlaylist.match(url)) {
+ return "";
+ }
+ return client_players_Youtube.matchPlaylist.matched(1);
+};
client_players_Youtube.prototype = {
convertTime: function(duration) {
var total = 0;
@@ -1945,30 +1969,78 @@ client_players_Youtube.prototype = {
}
,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);
+ var id = client_players_Youtube.extractVideoId(url);
+ if(id == "") {
+ this.getPlaylistVideoData(url,callback);
+ return;
+ }
+ var http = new haxe_http_HttpJs("" + client_players_Youtube.videosUrl + client_players_Youtube.urlTitleDuration + "&id=" + id + "&key=" + client_players_Youtube.apiKey);
http.onData = function(data) {
var json = JSON.parse(data);
if(json.error != null) {
- _gthis.getRemoteDataFallback(url1,callback);
+ _gthis.youtubeApiError(json.error);
+ _gthis.getRemoteDataFallback(url,callback);
return;
}
- var item = json.items[0];
- if(item == null) {
+ var items = json.items;
+ if(items == null || items.length == 0) {
callback({ duration : 0});
return;
}
- var title = item.snippet.title;
- var tmp = _gthis.convertTime(item.contentDetails.duration);
- callback({ duration : tmp, title : title});
+ var _g = 0;
+ while(_g < items.length) {
+ var item = items[_g];
+ ++_g;
+ var title = item.snippet.title;
+ var tmp = _gthis.convertTime(item.contentDetails.duration);
+ callback({ duration : tmp, title : title, url : url});
+ }
return;
};
http.onError = function(msg) {
- _gthis.getRemoteDataFallback(url1,callback);
+ _gthis.getRemoteDataFallback(url,callback);
return;
};
http.request();
}
+ ,getPlaylistVideoData: function(url,callback) {
+ var _gthis = this;
+ var http = new haxe_http_HttpJs("" + client_players_Youtube.playlistUrl + client_players_Youtube.urlVideoId + "&maxResults=50&playlistId=" + client_players_Youtube.extractPlaylistId(url) + "&key=" + client_players_Youtube.apiKey);
+ http.onData = function(data) {
+ var json = JSON.parse(data);
+ if(json.error != null) {
+ _gthis.youtubeApiError(json.error);
+ callback({ duration : 0});
+ return;
+ }
+ var items = json.items;
+ if(items == null || items.length == 0) {
+ callback({ duration : 0});
+ return;
+ }
+ var loadNextItem = null;
+ loadNextItem = function() {
+ var loadNextItem1 = "youtu.be/" + items.shift().snippet.resourceId.videoId;
+ _gthis.getVideoData(loadNextItem1,function(data1) {
+ callback(data1);
+ if(items.length > 0) {
+ loadNextItem();
+ }
+ return;
+ });
+ };
+ loadNextItem();
+ return;
+ };
+ http.onError = function(msg) {
+ callback({ duration : 0});
+ return;
+ };
+ http.request();
+ }
+ ,youtubeApiError: function(error) {
+ this.main.serverMessage(4,"Error " + error.code + ": " + error.message,false);
+ }
,getRemoteDataFallback: function(url,callback) {
var _gthis = this;
if(!js_youtube_Youtube.isLoadedAPI) {
@@ -1989,7 +2061,7 @@ client_players_Youtube.prototype = {
callback({ duration : tmp});
return;
}, onError : function(e1) {
- haxe_Log.trace("Error " + e1.data,{ fileName : "src/client/players/Youtube.hx", lineNumber : 117, className : "client.players.Youtube", methodName : "getRemoteDataFallback"});
+ haxe_Log.trace("Error " + e1.data,{ fileName : "src/client/players/Youtube.hx", lineNumber : 170, className : "client.players.Youtube", methodName : "getRemoteDataFallback"});
if(_gthis.playerEl.contains(video)) {
_gthis.playerEl.removeChild(video);
}
@@ -2700,9 +2772,11 @@ 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.matchPlaylist = new EReg("youtube\\.com.*list=([A-z0-9_-]+)","");
+client_players_Youtube.videosUrl = "https://www.googleapis.com/youtube/v3/videos";
+client_players_Youtube.playlistUrl = "https://www.googleapis.com/youtube/v3/playlistItems";
client_players_Youtube.urlTitleDuration = "?part=snippet,contentDetails&fields=items(snippet/title,contentDetails/duration)";
-client_players_Youtube.apiKey = "AIzaSyDTk1OPRI9cDkAK_BKsBcv10DQCHse-QaA";
+client_players_Youtube.urlVideoId = "?part=snippet&fields=items(snippet/resourceId/videoId)";
js_youtube_Youtube.isLoadedAPI = false;
client_Main.main();
})(typeof window != "undefined" ? window : typeof global != "undefined" ? global : typeof self != "undefined" ? self : this);
diff --git a/res/index.html b/res/index.html
index 8ad141b..254e4bc 100644
--- a/res/index.html
+++ b/res/index.html
@@ -1,5 +1,5 @@
<!DOCTYPE html>
-<html lang="ru"><head>
+<html><head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<style class="vjs-styles-defaults">
.video-js {
diff --git a/src/Types.hx b/src/Types.hx
index a98c7a1..2501cc4 100644
--- a/src/Types.hx
+++ b/src/Types.hx
@@ -4,7 +4,8 @@ import Client.ClientData;
typedef VideoData = {
duration:Float,
- ?title:String
+ ?title:String,
+ ?url:String
}
typedef Config = {
@@ -16,6 +17,7 @@ typedef Config = {
totalVideoLimit:Int,
userVideoLimit:Int,
templateUrl:String,
+ youtubeApiKey:String,
permissions:{
guest:Array<Permission>,
user:Array<Permission>,
diff --git a/src/client/Main.hx b/src/client/Main.hx
index 1552d38..918a81a 100644
--- a/src/client/Main.hx
+++ b/src/client/Main.hx
@@ -182,10 +182,11 @@ class Main {
return;
}
if (data.title == null) data.title = Lang.get("rawVideo");
+ if (data.url == null) data.url = url;
send({
type: AddVideo, addVideo: {
item: {
- url: url,
+ url: data.url,
title: data.title,
author: personal.name,
duration: data.duration,
@@ -502,7 +503,7 @@ class Main {
ws.send(Json.stringify(data));
}
- function serverMessage(type:Int, ?text:String):Void {
+ public function serverMessage(type:Int, ?text:String, isText = true):Void {
final msgBuf = ge("#messagebuffer");
final div = document.createDivElement();
final time = "[" + new Date().toTimeString().split(" ")[0] + "] ";
@@ -518,7 +519,8 @@ class Main {
div.textContent = time + text + " " + Lang.get("entered");
case 4:
div.className = "server-whisper";
- div.textContent = time + text;
+ if (isText) div.textContent = time + text;
+ else div.innerHTML = time + text;
default:
}
msgBuf.appendChild(div);
@@ -650,6 +652,10 @@ class Main {
return config.templateUrl;
}
+ public function getYoutubeApiKey():String {
+ return config.youtubeApiKey;
+ }
+
function escapeRegExp(regex:String):String {
return ~/([.*+?^${}()|[\]\\])/g.replace(regex, "\\$1");
}
diff --git a/src/client/players/Youtube.hx b/src/client/players/Youtube.hx
index 15eb014..f582ba7 100644
--- a/src/client/players/Youtube.hx
+++ b/src/client/players/Youtube.hx
@@ -16,9 +16,12 @@ 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 matchPlaylist = ~/youtube\.com.*list=([A-z0-9_-]+)/;
+ static final videosUrl = "https://www.googleapis.com/youtube/v3/videos";
+ static final playlistUrl = "https://www.googleapis.com/youtube/v3/playlistItems";
static final urlTitleDuration = "?part=snippet,contentDetails&fields=items(snippet/title,contentDetails/duration)";
- static final apiKey = "AIzaSyDTk1OPRI9cDkAK_BKsBcv10DQCHse-QaA";
+ static final urlVideoId = "?part=snippet&fields=items(snippet/resourceId/videoId)";
+ static var apiKey:String;
final main:Main;
final player:Player;
final playerEl:Element = ge("#ytapiplayer");
@@ -29,10 +32,11 @@ class Youtube implements IPlayer {
public function new(main:Main, player:Player) {
this.main = main;
this.player = player;
+ apiKey = main.getYoutubeApiKey();
}
public static function isYoutube(url:String):Bool {
- return extractVideoId(url) != "";
+ return extractVideoId(url) != "" || extractPlaylistId(url) != "";
}
static function extractVideoId(url:String):String {
@@ -48,6 +52,11 @@ class Youtube implements IPlayer {
return matchId.matched(1);
}
+ static function extractPlaylistId(url:String):String {
+ if (!matchPlaylist.match(url)) return "";
+ return matchPlaylist.matched(1);
+ }
+
final matchHours = ~/([0-9]+)H/;
final matchMinutes = ~/([0-9]+)M/;
final matchSeconds = ~/([0-9]+)S/;
@@ -64,32 +73,76 @@ class Youtube implements IPlayer {
}
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);
+ var id = extractVideoId(url);
+ if (id == "") {
+ getPlaylistVideoData(url, callback);
+ return;
+ }
+ final dataUrl = '$videosUrl$urlTitleDuration&id=$id&key=$apiKey';
+ final http = new Http(dataUrl);
http.onData = data -> {
final json = Json.parse(data);
if (json.error != null) {
+ youtubeApiError(json.error);
getRemoteDataFallback(url, callback);
return;
}
- final item = json.items[0];
- if (item == null) {
+ final items:Array<Dynamic> = json.items;
+ if (items == null || items.length == 0) {
callback({duration: 0});
return;
}
- final title:String = item.snippet.title;
- final duration:String = item.contentDetails.duration;
- // TODO duration is PT0S for streams
- callback({
- duration: convertTime(duration),
- title: title
- });
+ for (item in items) {
+ final title:String = item.snippet.title;
+ final duration:String = item.contentDetails.duration;
+ // TODO duration is PT0S for streams
+ callback({
+ duration: convertTime(duration),
+ title: title,
+ url: url
+ });
+ }
}
http.onError = msg -> getRemoteDataFallback(url, callback);
http.request();
}
+ function getPlaylistVideoData(url:String, callback:(data:VideoData)->Void):Void {
+ final id = extractPlaylistId(url);
+ final dataUrl = '$playlistUrl$urlVideoId&maxResults=50&playlistId=$id&key=$apiKey';
+ final http = new Http(dataUrl);
+ http.onData = data -> {
+ final json = Json.parse(data);
+ if (json.error != null) {
+ youtubeApiError(json.error);
+ callback({duration: 0});
+ return;
+ }
+ final items:Array<Dynamic> = json.items;
+ if (items == null || items.length == 0) {
+ callback({duration: 0});
+ return;
+ }
+ function loadNextItem():Void {
+ final item = items.shift();
+ final id:String = item.snippet.resourceId.videoId;
+ getVideoData('youtu.be/$id', data -> {
+ callback(data);
+ if (items.length > 0) loadNextItem();
+ });
+ }
+ loadNextItem();
+ }
+ http.onError = msg -> callback({duration: 0});
+ http.request();
+ }
+
+ function youtubeApiError(error:Dynamic):Void {
+ final code:Int = error.code;
+ final msg:String = error.message;
+ main.serverMessage(4, 'Error $code: $msg', false);
+ }
+
function getRemoteDataFallback(url:String, callback:(data:VideoData)->Void):Void {
if (!YtInit.isLoadedAPI) {
YtInit.init(() -> getRemoteDataFallback(url, callback));
send patches to the email below
yukais@pinapelz.com
include the subject [PATCH repo_name]
pinapelz.com
homepage