// ==UserScript==
// @name get_iplayer helper
// @namespace http://tampermonkey.net/
// @include http://www.bbc.co.uk/*
// @include https://www.bbc.co.uk/*
// @version 0.3
// @description Adds bright pink buttons to every program in BBC's iPlayer website (https://www.bbc.co.uk/iplayer) that allows quick linking to open source downloader get_iplayer Web PVR Manager (available at https://github.com/get-iplayer/get_iplayer/wiki/installation)
// @author Jake Lewis ( no relation to Phil ).
// @supportURL [email protected]
// @connect bbc.co.uk
// @connect localhost
// @license GPL version 3 or any later version; http://www.gnu.org/copyleft/gpl.html
// @require http://code.jquery.com/jquery-latest.min.js
// @grant GM.setValue
// @grant GM.getValue
// @grant GM.listValues
// @grant GM.deleteValue
// ==/UserScript==
//There are three types of pages this script is designed to work on:
// catagory pages such as https://www.bbc.co.uk/iplayer/categories/arts/featured
// episodes pages such as https://www.bbc.co.uk/iplayer/episodes/b006m86d
// episode pages such as https://www.bbc.co.uk/iplayer/episode/b0c0bt44/eastenders-15012019
(function() {
'use strict';
//variables that can be passed to get_iplayer's Web PVR Manager
var recordDirectory = ""; // the default. Do not edit here - change it in cookies below so it survives updates to this script
var localhostPort = "1935"//the default. Do not edit here - change it in cookies below so it survives updates to this script
var fps25 = 0;//the default. Do not edit here - change it in cookies below so it survives updates to this script
var force = 0;//the default. Do not edit here - change it in cookies below so it survives updates to this script
var modes = "best";//the default. Do not edit here - change it in cookies below so it survives updates to this script
var subtitles = 0;// the default. Do not edit here - change it in cookies below so it survives updates to this script
var thumb = 0;// the default. Do not edit here - change it in cookies below so it survives updates to this script
var sortType = "featured"; // the default - change this via the bbc webpage
$(document).ready(function() {
trace( "A helper script to be used with get_iplayer: https://github.com/get-iplayer/get_iplayer/wiki/installation ");
trace( "Bugs to [email protected]. Be sure to include: OS, Browser type, the bbc URL, and a good description of the issue. ");
(async () => {
trace("You can change these settings below in the script:")
// ---------------------- COOKIES --------------------
//changes to the first line in each section will be saved over any future updates to this script.
//await GM.setValue("recordDirectory", "B:\\TV\\BBC");// <-----EDIT AND ENABLE THIS TO RECORD IN A CUSTOM DIRECTORY----->
//or
//await GM.deleteValue("recordDirectory");//disable above and enable this to return to default (a desktop folder?)
recordDirectory = await GM.getValue("recordDirectory", "");
trace("recordDirectory: "+recordDirectory+ " Edit this in the script's COOKIE section");
//await GM.setValue("localhostPort", "1936"); //edit and enable this if you have changed your localhost port - unlikely.
//or
//await GM.deleteValue("localhostPort");//disable above and enable this to return to default port of 1935
localhostPort = await GM.getValue("localhostPort", "1935");
trace("localhostPort: "+localhostPort);
//await GM.setValue("fps25", "1");//enable this to record 25fps
//or
//await GM.deleteValue("fps25");//disable above and enable this to return to default of 50 fps
fps25 = await GM.getValue("fps25", "0");
trace("fps25: "+fps25);
//await GM.setValue("force", "1");//enable this force overwrites
//or
//await GM.deleteValue("force"); //disable above and enable this to return to default of not forcing
force = await GM.getValue("force", "0");
trace("force: "+force);
//await GM.setValue("modes", "best");//edit and enable this to lower quality
//or
//await GM.deleteValue("modes");//disable above and enable this to return to default of best
modes = await GM.getValue("modes", "best");
trace("modes: "+modes);
//await GM.setValue("subtitles", "1");//enable this to request subtitles
//or
//await GM.deleteValue("subtitles");//disable above and enable this to return to default of no subtitles
subtitles = await GM.getValue("subtitles", "0");
trace("subtitles: "+subtitles);
//await GM.setValue("thumb", "1");//enable this to request thumbnails
//or
//await GM.deleteValue("thumb"); //disable above and enable this to return to default of no thumbnails
thumb = await GM.getValue("thumb", "0");
trace("thumb: "+thumb);
// save the sortType - do NOT edit here - change it using the 'Change sort:" gui on bbc page https://www.bbc.co.uk/iplayer/categories/
var url = window.location.href;
if(url.includes("www.bbc.co.uk/iplayer/categories/")){
sortType = url.substr(url.lastIndexOf("/")+1);
switch (sortType){
case "featured":
case "a-z":
case "most-recent":
await GM.setValue("sortType", sortType);
break;
default: sortType = "featured";
}
}else{
sortType = await GM.getValue("sortType", sortType);
}
/*var keys = await GM.listValues();
for (var i = 0; i < keys.length; i++){
trace(keys[i]+" "+ await GM.getValue(keys[i]));
}*/
parsePage();
})();//async
});
function parsePage(){
//on all pages change the sort type
var catNav = document.querySelectorAll('div.tvip-cat-container')[0];
if(catNav!=null){
var cats = catNav.querySelectorAll('a.typo');
for( i = 0; i < cats.length; i++){
var cat = cats[i];
cat.href = cat.href.replace("featured", sortType);
trace(i+" "+cat.innerText+" "+cat.href);
}
}
var categoryString = ""; // not in use - work in progress as catagory is not available in a single episode page
var nameString = "";
var isCategoriesPage = true;
//on an episodes page
var headerElement = document.querySelector('h1.hero-header__title');
if(headerElement!=null){
if(window.location.href.includes("www.bbc.co.uk/iplayer/episodes/")){
isCategoriesPage = false;
nameString = headerElement.innerText;
//catElement = document.querySelector('div.hero-header__label');
//if(catElement != null){
// categoryString = "\\"+ makeDirectorySafeName(catElement.innerText);}
}
}
//on an individual programme/episode page
if(window.location.href.includes("www.bbc.co.uk/iplayer/episode/")){
var nameElement = document.querySelector('span.typo');
if(nameElement != null) nameString = nameElement.innerText;
var singleElement = document.querySelector('div.playback-content');
//trace("singleElement.length:"+singleElement.length);
if(singleElement!=null ){
singleElement.insertBefore(createButtons(location.href,"\\" + makeDirectorySafeName(nameString), nameString), singleElement.children[0]);
}
isCategoriesPage = false;
//Mmm, problem here that catagory is not available in an episode page.
}
//on all pages
var targetElements = document.querySelectorAll('div.content-item');
// trace("targetElements.length:"+targetElements.length);
for (var i = 0; i < targetElements.length; i++) {
var targetElement = targetElements[i];
//trace(i+" "+ targetElement);
var content_item__link = targetElement.querySelector('a.content-item__link');
if(content_item__link != null){
// var catElement = content_item__link.querySelector('span.typo');//may not be stable!
// if(catElement != null){
// if(isCategoriesPage){
// categoryString = "\\"+ makeDirectorySafeName(catElement.innerText);}
// }
var titleElement = content_item__link.querySelector('div.content-item__title');
if( titleElement != null ){
if(isCategoriesPage){
nameString = titleElement.innerText;
if(nameString.endsWith("...") && titleElement.querySelector('span.tvip-hide')!=null){ //bbc uses this to hide the end of long titles
nameString = nameString.substring(0, nameString.length-3);
}
}
}
targetElement.insertBefore(createButtons(content_item__link, categoryString+ "\\" + makeDirectorySafeName(nameString), nameString), content_item__link);
}else{
// a 'This Episode' element in episodes page
content_item__link = targetElement.querySelector('span.content-item__link');
if(content_item__link!=null){
if(content_item__link.innerText.includes('This Episode')){
targetElement.insertBefore(createButtons(location.href,"\\" + makeDirectorySafeName(nameString), nameString), content_item__link);}
}
}
if(isCategoriesPage){
categoryString = "";
nameString = "";
}
}//targetElements
}
function createButtons(videoURL, directory, searchTerm){
var buttonSpan = document.createElement("span");
buttonSpan.appendChild( createButton(videoURL, directory, "", "Add QuickURL to Queue", 'pvr_queue') );
buttonSpan.appendChild( createButton('', directory, searchTerm, "Search Get_iPlayer ", 'search_progs'));
// trace(directory+"\\"+searchTerm+" "+videoURL);
return buttonSpan;
}
function createButton(videoURL, directory, searchTerm, label, nextPage){
var addButton = document.createElement("button");
addButton.appendChild(document.createTextNode(label));
//addButton.style.width = "170px";
//addButton.style.left = "15%";
addButton.style.backgroundColor = "#F54997";
addButton.style.color = "white";
addButton.style.textAlign = "center";
addButton.style.padding = "2px 5px";
addButton.style.margin = "0px 5px";
addButton.style.fontSize = "9px";
addButton.style.border = "3px";
addButton.style.cursor = "pointer";
addButton.style.borderRadius = "2px";
//addButton.style.fontFamily = "Roboto, Arial, sans-serif";
addButton.style.textDecoration = "none";
//our data
addButton.videoURL = videoURL;
addButton.directory = directory;
addButton.onclick = function buttonClick(evt){
trace("buttonClick() "+evt.target.videoURL);
post('http://localhost:'+localhostPort+'/', {
'SEARCH':searchTerm,
'SEARCHFIELDS':'name',
'PROGTYPES': 'tv',
'URL': evt.target.videoURL,
'OUTPUT': recordDirectory+evt.target.directory,
'NEXTPAGE': nextPage,
'FORCE:':force,
'FPS25': fps25,
'MODES': modes,
'SUBTITLES':subtitles,
'THUMB':thumb
}
);
};
return addButton;
}
function trace(str){
console.log("get_iplayer helper: "+str);
}
function post(path, params, method) {
method = method || "post"; // Set method to post by default if not specified.
var form = document.createElement("form");
form.setAttribute("method", method);
form.setAttribute("action", path);
form.setAttribute("enctype", "multipart/form-data");
form.setAttribute("target", "_blank");//disable this for easier debugging
for(var key in params) {
if(params.hasOwnProperty(key)) {
var hiddenField = document.createElement("input");
hiddenField.setAttribute("type", "hidden");
hiddenField.setAttribute("name", key);
hiddenField.setAttribute("value", params[key]);
form.appendChild(hiddenField);
}
}
document.body.appendChild(form);
form.submit();
}
var safeCharRegex = /[<>/\|?*]/g;
function makeDirectorySafeName(inString){
//get_iplayer can't write to directories with this character in the name!
inString = inString.replace("’","'"); //at least looks similar.
//remove Windows illegal directory characters
inString = inString.replace(":", ";");//at least looks similar
inString = inString.replace('"', "'");//at least looks similar.
return inString.replace(safeCharRegex, '_');
}
})();