Skip to content

Instantly share code, notes, and snippets.

@siliconbrain
Last active January 28, 2017 18:55
Show Gist options
  • Save siliconbrain/3e186a74a62e94196a158d1452b9e6d9 to your computer and use it in GitHub Desktop.
Save siliconbrain/3e186a74a62e94196a158d1452b9e6d9 to your computer and use it in GitHub Desktop.
Tampermokey script for displaying music policy information for music videos on YouTube
// ==UserScript==
// @name YouTube music policy display
// @namespace http://tampermonkey.net/
// @version 0.1
// @description Show music policy info for music videos
// @author siliconbrain
// @match https://www.youtube.com/*
// @grant none
// ==/UserScript==
function ajax(url, success, error) {
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (this.readyState == 4) {
if (this.status >= 200 && this.status < 300) {
if (success) success(this.responseText);
} else {
if (error) error(this.status, this.responseText);
}
}
};
xhr.open('GET', url, true);
xhr.send();
return xhr;
}
function getMusicPolicyInfoElement() {
var id = 'musicPolicyInfo';
var musicPolicyInfoElement = document.querySelector('#' + id);
if (!musicPolicyInfoElement) {
musicPolicyInfoElement = document.createElement('div');
musicPolicyInfoElement.id = 'musicPolicyInfo';
musicPolicyInfoElement.innerHTML = 'Determining availability...';
document.querySelector('#watch-headline-title').append(musicPolicyInfoElement);
}
return musicPolicyInfoElement;
}
function videoTitleToQuery(title) {
return title
.replace(/\bft\b/gi, 'feat')
.replace(/[\[\(](audio|lyric|music|official|video|\s)+[\]\)]/gi, '')
.replace(/[^\w\d\u00C0-\u017F]/g, ' ');
}
function getWords(str) {
return str
.replace(/[^\w\d\u00C0-\u017F]/g, ' ')
.trim()
.replace(/ (?= )/g, '')
.split(' ');
}
function symmetricDifference(setA, setB) {
var all = setA.concat(setB);
return all.reduce((set, val) => (setA.indexOf(val) >= 0 && setB.indexOf(val) >= 0) ? set : set.concat([val]), []);
}
function bestMatch(query, tracks) {
if (tracks.length == 1) return tracks[0];
var queryWords = getWords(query).map(w => w.toLowerCase());
var tracksWords = tracks.map(track => getWords(track.artist).concat(getWords(track.title)).map(w => w.toLowerCase()));
var diffs = tracksWords.map(trackWords => symmetricDifference(queryWords, trackWords));
var ranks = diffs.map(d => d.length);
var best = ranks.reduce((cur, val, idx) => val < cur.val ? {idx: idx, val: val} : cur, {idx: 0, val: Infinity});
console.log('bestMatch', queryWords, tracksWords, diffs, best);
return tracks[best.idx];
}
function loadMusicPolicy(player) {
if (player.getCurrentVideoConfig().args.vmap.match(/ytpwatch.music/) || document.querySelector('meta[itemprop="genre"][content="Music"]')) {
var q = videoTitleToQuery(player.getVideoData().title);
console.info('Music policy query string:', q);
ajax(`https://www.youtube.com/audioswap_ajax?action_get_tracks=1&s=ad_supported_music&q=${encodeURI(q)}`, function(resp) {
var musicPolicyInfoElement = getMusicPolicyInfoElement();
resp = JSON.parse(resp);
var tracks = resp.tracks;
console.info('Music policy query results:', tracks);
if (tracks.length > 0) {
var track = bestMatch(q, tracks);
var trackName = `${track.title} by ${track.artist}`;
ajax(`https://www.youtube.com/audioswap_ajax?action_get_track_details=1&asset_id=${track.asset_id}&isrc=${track.isrc}`, function(resp) {
resp = JSON.parse(resp);
if (resp.is_available) {
if (resp.sr_policy.restrictions) {
musicPolicyInfoElement.innerHTML = `© ${trackName} is blocked in ${resp.sr_policy.restrictions.blocked_terr_names.length} countries.`;
} else {
musicPolicyInfoElement.innerHTML = `✓ ${trackName} is viewable worldwide.`;
}
} else {
musicPolicyInfoElement.innerHTML = `✗ ${trackName} is not available for playback.`;
}
if (tracks.length > 1) musicPolicyInfoElement.innerHTML += ` (best of ${tracks.length} results)`;
});
} else {
musicPolicyInfoElement.innerHTML = `⚠ Track info not found.`;
}
});
}
}
function addPlayerEventListener(player, event, name, handler) {
window[name] = handler;
player.addEventListener(event, name);
}
(function() {
'use strict';
var player = yt.player.getPlayerByElement('player-api');
addPlayerEventListener(player, 'onReady', 'playerReadyHandlerForMusicPolicy', function() {
var lastVideoId = player.getVideoData().video_id;
addPlayerEventListener(player, 'onStateChange', 'playerStateChangeHandlerForMusicPolicy', function(state) {
var videoId = player.getVideoData().video_id;
if (state == 1 && lastVideoId != videoId) {
lastVideoId = videoId;
loadMusicPolicy(player);
}
});
if (lastVideoId) loadMusicPolicy(player);
});
//window.THE_PLAYER = player; // for debugging
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment