aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Types.hx4
-rw-r--r--src/client/Main.hx12
-rw-r--r--src/client/players/Youtube.hx83
3 files changed, 80 insertions, 19 deletions
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