Skip to content

Instantly share code, notes, and snippets.

@taylorsmcclure
Created March 25, 2020 22:35
Show Gist options
  • Save taylorsmcclure/d2afe3977a645c7de494687dc5174a95 to your computer and use it in GitHub Desktop.
Save taylorsmcclure/d2afe3977a645c7de494687dc5174a95 to your computer and use it in GitHub Desktop.
plugdj-youtube-fix
// ==UserScript==
// @name Plug.dj YT API Key workaround
// @namespace https://plug.dj?refuid=4613422
// @version 1.3.0
// @author WiBla ([email protected])
// @description This script will add a button next to "import/create playlist" that allows you to add videos without searching for them
// @downloadURL https://gist.github.com/WiBla/ad1aa9a98949c624cd2886c1a25b5feb/raw/8d83fc7bb1ac77f8ff9494023991e21e5599ec56/yt-workaround.user.js
// @updateURL https://gist.github.com/WiBla/ad1aa9a98949c624cd2886c1a25b5feb/raw/8d83fc7bb1ac77f8ff9494023991e21e5599ec56/yt-workaround.user.js
// @include *://plug.dj/*
// @include *://*.plug.dj/*
// @exclude *://*.plug.dj/_/*
// @exclude *://*.plug.dj/@/*
// @exclude *://*.plug.dj/!/*
// @exclude *://*.plug.dj/about
// @exclude *://*.plug.dj/ba
// @exclude *://*.plug.dj/forgot-password
// @exclude *://*.plug.dj/founders
// @exclude *://*.plug.dj/giftsub/*
// @exclude *://*.plug.dj/jobs
// @exclude *://*.plug.dj/legal
// @exclude *://*.plug.dj/merch
// @exclude *://*.plug.dj/partners
// @exclude *://*.plug.dj/plot
// @exclude *://*.plug.dj/privacy
// @exclude *://*.plug.dj/purchase
// @exclude *://*.plug.dj/subscribe
// @exclude *://*.plug.dj/team
// @exclude *://*.plug.dj/terms
// @exclude *://*.plug.dj/press
// @grant none
// @run-at document-end
// ==/UserScript==
/* global $, gapi */
(function() {
'use strict';
// Because plug.dj hides the interface while loading, this is necessary
// We can't just use document.readyState ($.ready)
function $$(selector) {return document.querySelectorAll(selector);}
function loadScript(URL) {
// Check if DOM is ready
if (!$$('.loading-box.d-none').length || !$$('.logout').length) {
setTimeout(function(){loadScript();}, 200);
}
else init();
}
function autoReload() {
// if not completely loaded, call again until loaded
if (!$$('#video').length && !$$('.spinner').length) setTimeout(autoReload, 200);
else if ($$('#video').length) {
setTimeout(function(){location.reload();}, 60*1000);
}
}
loadScript();
autoReload();
function init() {
// ADD YOUR OWN KEY HERE
window.gapi.client.setApiKey('INSERT_OWN_KEY_HERE');
var pl = {}, media = {};
function convert_time(duration) {
var a = duration.match(/\d+/g);
if (duration.indexOf('M') >= 0 && duration.indexOf('H') == -1 && duration.indexOf('S') == -1) {
a = [0, a[0], 0];
}
if (duration.indexOf('H') >= 0 && duration.indexOf('M') == -1) {
a = [a[0], 0, a[1]];
}
if (duration.indexOf('H') >= 0 && duration.indexOf('M') == -1 && duration.indexOf('S') == -1) {
a = [a[0], 0, 0];
}
duration = 0;
if (a.length == 3) {
duration = duration + parseInt(a[0]) * 3600;
duration = duration + parseInt(a[1]) * 60;
duration = duration + parseInt(a[2]);
}
if (a.length == 2) {
duration = duration + parseInt(a[0]) * 60;
duration = duration + parseInt(a[1]);
}
if (a.length == 1) {
duration = duration + parseInt(a[0]);
}
return duration
}
function completeMedia() {
$.ajax({
url: `https://www.googleapis.com/youtube/v3/videos?id=${media.cid}&key=${gapi.config.get().client.apiKey}&part=snippet,contentDetails`,
type: 'GET',
success: (data) => {
media.author = data.items[0].snippet.title.split('-');
// Video's title contains a "-" so parse it
/* if (media.author.length) {
media.title = media.author[1].trim();
media.author = media.author[0].trim();
} else { // Otherwise, use the channel's name as author..
media.title = media.author[1].trim();
media.author = data.items[0].snippet.channelTitle;
} */
// Fix added for when videos are not formatted with hyphons
media.title = media.author[0];
media.author = data.items[0].snippet.channelTitle;
media.image = data.items[0].snippet.thumbnails.default.url;
media.duration = convert_time(data.items[0].contentDetails.duration);
media.format = 1;
media.id = -1;
addMedia();
},
error: () => alert('YT API didn\'t reply, is your key still valid?')
});
}
function addMedia() {
$.ajax({
url: `/_/playlists/${pl.id}/media/insert`,
type: 'POST',
data: JSON.stringify({
media: [media],
"append": false
}),
contentType: 'application/json',
success: () => alert('Media added! You might need a refresh to see it.'),
error: (err) => {
if (err.responseJSON.status === 'maxItems') {
alert('This playlist is full!');
} else alert('Sorry, the media couldn\'t be added.');
}
});
}
function extractCID(cid) {
return cid.replace(/(?:https?:)?(?:\/\/)?(?:[0-9A-Z-]+\.)?(?:youtu\.be\/|youtube(?:-nocookie)?\.com\/\S*?[^\w\s-])((?!videoseries)[\w-]{11})(?=[^\w-]|$)(?![?=&+%\w.-]*(?:['"][^<>]*>|<\/a>))[?=&+%\w.-]*/gi, '$1');
}
function askCID() {
media.cid = prompt('Video\'s link:');
media.cid = extractCID(media.cid);
completeMedia(media);
}
let found = false;
function findPlaylist() {
if (found) return askCID();
$.ajax({
url: '/_/playlists',
success: (data) => {
pl.name = prompt('In which playlist do you wish to add the song?\nName must be exactly the same');
if (!!pl.name === false) return;
data.data.forEach((playlist, i, a) => {
if (playlist.name === pl.name) {
if (playlist.count === 200) {
alert(`${pl.name} is full!`);
} else {
pl.id = playlist.id;
found = true;
askCID();
}
}
if (i + 1 >= a.length && !found) {
if (confirm(`${pl.name} couldn't be found. Do you whish to add the live in "${playlist.name}"?`)) {
pl.id = playlist.id;
askCID();
}
}
});
}
});
}
var $grabBtn = $(`<div id="playlist-import" class="button" title="CTRL + Click to change playlist">
<i class="fa fa-plus-circle"></i>
<span>YT Grab+</span>
</div>`);
$grabBtn.click(function(event) {
found = event.ctrlKey ? false : found;
findPlaylist();
});
$('.playlist-buttons-import-create').append($grabBtn);
}
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment