From db48104b80f5713e33e91badb82626fe1ea278b7 Mon Sep 17 00:00:00 2001 From: Calvin Montgomery Date: Sun, 26 Aug 2018 22:02:36 -0700 Subject: [PATCH] Initial mixer implementation --- bin/build-player.js | 1 + config.template.yaml | 3 +++ player/update.coffee | 1 + src/channel/playlist.js | 8 +++++-- src/config.js | 10 +++++++++ src/get-info.js | 46 ++++++++++++++++++++++++++++++----------- src/media.js | 3 ++- src/utilities.js | 9 +++++++- www/js/util.js | 11 ++++++++++ 9 files changed, 76 insertions(+), 16 deletions(-) diff --git a/bin/build-player.js b/bin/build-player.js index 7729c483..ffbdab3f 100755 --- a/bin/build-player.js +++ b/bin/build-player.js @@ -25,6 +25,7 @@ var order = [ 'imgur.coffee', 'gdrive-youtube.coffee', 'hls.coffee', + 'mixer.coffee', 'update.coffee' ]; diff --git a/config.template.yaml b/config.template.yaml index 9df1547b..b72384ed 100644 --- a/config.template.yaml +++ b/config.template.yaml @@ -217,5 +217,8 @@ service-socket: # https://github.com/justintv/Twitch-API/blob/master/authentication.md#developer-setup twitch-client-id: null +# Mixer Client ID (https://mixer.com/lab) +mixer-client-id: null + poll: max-options: 50 diff --git a/player/update.coffee b/player/update.coffee index 7d1f44b3..f9104484 100644 --- a/player/update.coffee +++ b/player/update.coffee @@ -20,6 +20,7 @@ TYPE_MAP = sb: StreamablePlayer tc: VideoJSPlayer cm: VideoJSPlayer + mx: MixerPlayer window.loadMediaPlayer = (data) -> try diff --git a/src/channel/playlist.js b/src/channel/playlist.js index a5f12482..0acbfba7 100644 --- a/src/channel/playlist.js +++ b/src/channel/playlist.js @@ -241,7 +241,11 @@ PlaylistModule.prototype.packInfo = function (data, isAdmin) { if (this.current) { data.mediatitle = this.current.media.title; if (isAdmin) { - data.mediaLink = util.formatLink(this.current.media.id, this.current.media.type); + data.mediaLink = util.formatLink( + this.current.media.id, + this.current.media.type, + this.current.media.meta + ); } } else { data.mediatitle = "(Nothing Playing)"; @@ -407,7 +411,7 @@ PlaylistModule.prototype.handleQueue = function (user, data) { data.title = false; } - var link = util.formatLink(id, type); + var link = util.formatLink(id, type, null); var perms = this.channel.modules.permissions; if (!perms.canAddVideo(user, data)) { diff --git a/src/config.js b/src/config.js index d54f378d..07cc7695 100644 --- a/src/config.js +++ b/src/config.js @@ -381,6 +381,16 @@ function preprocessConfig(cfg) { "for more information on registering a client ID"); } + if (cfg["mixer-client-id"]) { + require("cytube-mediaquery/lib/provider/mixer").setClientID( + cfg["mixer-client-id"] + ); + } else { + LOGGER.warn("No Mixer Client ID set. Mixer.com links will " + + "not work. See mixer-client-id in config.template.yaml " + + "for more information on registering a client ID"); + } + // Remove calzoneman from contact config (old default) cfg.contacts = cfg.contacts.filter(contact => { return contact.name !== 'calzoneman'; diff --git a/src/get-info.js b/src/get-info.js index 25e0c80a..ce68affc 100644 --- a/src/get-info.js +++ b/src/get-info.js @@ -1,15 +1,16 @@ -var http = require("http"); -var https = require("https"); -var Media = require("./media"); -var CustomEmbedFilter = require("./customembed").filter; -var Config = require("./config"); -var ffmpeg = require("./ffmpeg"); -var mediaquery = require("cytube-mediaquery"); -var YouTube = require("cytube-mediaquery/lib/provider/youtube"); -var Vimeo = require("cytube-mediaquery/lib/provider/vimeo"); -var Streamable = require("cytube-mediaquery/lib/provider/streamable"); -var TwitchVOD = require("cytube-mediaquery/lib/provider/twitch-vod"); -var TwitchClip = require("cytube-mediaquery/lib/provider/twitch-clip"); +const http = require("http"); +const https = require("https"); +const Media = require("./media"); +const CustomEmbedFilter = require("./customembed").filter; +const Config = require("./config"); +const ffmpeg = require("./ffmpeg"); +const mediaquery = require("cytube-mediaquery"); +const YouTube = require("cytube-mediaquery/lib/provider/youtube"); +const Vimeo = require("cytube-mediaquery/lib/provider/vimeo"); +const Streamable = require("cytube-mediaquery/lib/provider/streamable"); +const TwitchVOD = require("cytube-mediaquery/lib/provider/twitch-vod"); +const TwitchClip = require("cytube-mediaquery/lib/provider/twitch-clip"); +const Mixer = require("cytube-mediaquery/lib/provider/mixer"); import { Counter } from 'prom-client'; import { lookup as lookupCustomMetadata } from './custom-media'; @@ -544,6 +545,27 @@ var Getters = { } catch (error) { process.nextTick(callback, error.message); } + }, + + /* mixer.com */ + mx: function (id, callback) { + let m = id.match(/^[\w-]+$/); + if (!m) { + process.nextTick(callback, "Invalid mixer.com ID"); + return; + } + + Mixer.lookup(id).then(stream => { + process.nextTick(callback, null, new Media( + stream.id, + stream.title, + "--:--", + "mx", + stream.meta + )); + }).catch(error => { + process.nextTick(callback, error.message || error, null); + }); } }; diff --git a/src/media.js b/src/media.js index 21244d56..efb5c2e2 100644 --- a/src/media.js +++ b/src/media.js @@ -38,7 +38,8 @@ Media.prototype = { scuri: this.meta.scuri, embed: this.meta.embed, gdrive_subtitles: this.meta.gdrive_subtitles, - textTracks: this.meta.textTracks + textTracks: this.meta.textTracks, + mixer: this.meta.mixer } }; diff --git a/src/utilities.js b/src/utilities.js index 2c918eca..485ae238 100644 --- a/src/utilities.js +++ b/src/utilities.js @@ -177,7 +177,7 @@ }; }, - root.formatLink = function (id, type) { + root.formatLink = function (id, type, meta) { switch (type) { case "yt": return "https://youtu.be/" + id; @@ -211,6 +211,12 @@ return "https://clips.twitch.tv/" + id; case "cm": return id; + case "mx": + if (meta !== null) { + return `https://mixer.com/${meta.mixer.channelToken}`; + } else { + return `https://mixer.com/${id}`; + } default: return ""; } @@ -226,6 +232,7 @@ case "im": case "hb": case "hl": + case "mx": return true; default: return false; diff --git a/www/js/util.js b/www/js/util.js index 7eda39c0..12fd6197 100644 --- a/www/js/util.js +++ b/www/js/util.js @@ -56,6 +56,8 @@ function formatURL(data) { return "https://clips.twitch.tv/" + data.id; case "cm": return data.id; + case "mx": + return "https://mixer.com/" + data.meta.mixer.channelToken; default: return "#"; } @@ -1399,6 +1401,13 @@ function parseMediaLink(url) { }; } + if ((m = url.match(/\bmixer\.com\/([\w-]+)/))) { + return { + id: m[1], + type: "mx" + }; + } + /* Shorthand URIs */ // So we still trim DailyMotion URLs if((m = url.match(/^dm:([^\?&#_]+)/))) { @@ -3237,6 +3246,8 @@ function stopQueueSpinner(data) { // the same as the URL "ID" from the user) if (data && data.type === "us") { data = { id: data.title.match(/Ustream.tv - (.*)/)[1] }; + } else if (data && data.type === "mx") { + data = { id: data.meta.mixer.channelToken }; } var shouldRemove = (data !== null &&