Greasy Fork is available in English.
Grab radio stream from 101.ru
// ==UserScript== // @name Grab Radio 101.ru // @namespace https://github.com/AlekPet/ // @version 0.3.1 // @description Grab radio stream from 101.ru // @copyright 2018, AlekPet (https://github.com/AlekPet) // @author AlekPet // @license MIT; https://opensource.org/licenses/MIT // @match http*://101.ru/* // @icon data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAEIElEQVRIS+1Vf0zUZRj/PMcdx4FgtWzi8Ec6RNwqlxJII6RftmNm4VotQREtWJZpDDA2Gg3Eu7A1clISP7MthjJhTijdWrr+yLA1QR1Xo4aMtuAQwfR7P7h72vNl73Xc2fyr/urd3n2/977v9/k8n+f5fN4jZmb8i4P+B7hbdf+bErnOX+CBzD0UW1rEq+w7SJu4zY3Wk7iB+Xi7ZyOGrriQk3mdtpbGc7U9ku6WdfB+gIGz5RQ7Byewyp5PAy19rLEZboqGxpF4tmAJdTTf5H5HFKpsRiIiiPiCn/8EGgLghDA4V9bDCdaHMDqk4VeHH9sOrqQTrbf40mAkhIEKXlY7yJevjQLmKTycHMX208cNpS9v4A++qadzZYf5iRWpFMYgybadzu/v5UXPrcbokBtDDh/ybUl0vO###UHlASKDwaAz+O7HG5z//rforc/C0oWxeO2TVuQ++Si+uNiN1zOzsSFxfSiAE0m2fLrUdIE1jsJtvwkuWJCVt5BOHnNxv8OM96qg90DKIwBNpxxoqEiF0RiBXfXNyHtqHY71daEoaxMylj82CzDb5LdoHA9gRWMJx2evQcumblzne7CrIx3DjhnkWV36/sHDHjaYPfh5eBoUdQt1nT/R2aMZnPFIAlW0d3PtmTZCzDiKrZu5xlryNwPJSmjLnJmZgcfj0ae6SdS6lEeGKpPRaITJZNKnDL/fD5/PF4gV5gPZlOl2u+H1enUwKYd8KCCyJ0FlTanIYrHogPJbvpOzMvUzwXdRKAM5LAEVOwUiwSIiInRAeVcs5GxwUrraQi87xcDlcumH5bcEUUACIuUILp3ZbA7YQMqqGIcx8Din+Gz2x7j6w029oZa1iVzQvh6x982aS4EpFQnY5LSXX6n6GtWFa5GevIRUeVSP5jAYLGvlP65pSPtsB2AikoDDV6e5psiJ+DX3g+LisDTRh93lE4ToMezbbeE9efF4qbIHF0cu6+rZ+2IaV2/J1c2o90WVyK+5uX9nHWKeTkPk8kU4ktVF81KS+IVDqVye+zttrViGnG2WgAc+PzHJDZ2/oM2+mrfbTpP9zTT44ca7nY3o2luOBXH3zjo+uAfCYGzEhfSmnfjt+1G077+C52tT+MPicSppWIzFD5pR+IYPHb1j9MxGjadmJtFcs5ILar+iA4XrEL9gHoq//BRtRfswPyqGRAhzALwT03zGWhfogTDYbE/hQyVOKjmagGWJBqqsMvJHjWN6OVJS3dxqS+Z8ew/1jQwQosfxzpbHuSrnVZ3pHVWk1CH1Fw+IVOUpUzKSoVQk8pSmKpUpIcgZ+T5MRUpryo0iOZFrsKMlmDKVBBBQpZxgzyhPhfkg1Gyaps0xjyQhmctQjORdklBXhawrsDv+ZSoGUh41g10smSsm8lQllKdaV4n+BTVI+QRe6RsxAAAAAElFTkSuQmCC // @run-at document-end // @grant GM_setValue // @grant GM_getValue // @grant GM_addStyle // @require https://code.jquery.com/jquery-3.1.0.min.js // ==/UserScript== GM_addStyle(` #radio_box { position: fixed; top: 5%; left: 50%; margin-left: -300px; width: 600px; background: silver; border: 1px solid silver; z-index: 9999; box-shadow: 4px 4px 8px silver; } #names { background: white; text-align: center; padding: 3px; } .menu_radios > li { display: inline-block; background: #737171; padding: 0 3px; border: 1px solid; margin: 0 2px; color: white; font-size: 0.7em; box-shadow: 2px 2px 5px silver; cursor: pointer; user-select: none; } .menu_radios > li:hover { background: #4c1a1a; } div#outputs { padding: 5px; background: moccasin; text-align: center; max-height: 500px; overflow-y: auto; } .selactive{ background: #4c1a1a !important; } .main_title, .main_title_small { padding: 5px; border: 1px solid; font-size: 1.3em; background: #949292; color: white; text-align: center; font-family: cursive; } .main_title_small{ font-size: 0.9em; background: #4a3737; margin: 15px 0; } .box_inner > ul li, #outputs > ul li { display: inline-block; padding: 10px; border: 1px solid; margin: 10px; background: #949292; color: white; cursor: pointer; zoom: 0.5; box-shadow: 8px 8px 20px black; } @-moz-document url-prefix() { .box_inner > ul li, #outputs > ul li { width: 170px; word-wrap: break-word; } li audio { transform: translate(-60px,0) scale(0.6); } } #foot { text-align: center; padding: 5px; background: dimgray; border-top: 1px solid white; } div#box_codes { position: fixed; top: 5%; left: 6%; background: #d2cccc; border: 1px solid silver; text-align: center; padding: 5px; opacity: 0.8; display:none; } textarea#texta { width: 520px; height: 400px; } .box_inner { display: none; } .box_radio { background: #504f4f; margin-bottom: 2px; color: white; cursor:pointer; } .title_ganre { background: #6f293f; } .textarea_info { background: darkgray; color: white; padding: 3px; } .textarea_info > div{ float: right; margin-right: 5px; color: yellow; cursor: pointer; } `); (function() { 'use strict'; var canavas_img = false, radios_count = 0, radios_image_load = 0, debug = true, RadioObj = null function loadStorage(){ let RadioObj_tmp = GM_getValue('RadioObj'); RadioObj = (RadioObj_tmp) ? JSON.parse(GM_getValue('RadioObj')) : { options: {}, allRadio:{} }; if(debug) console.log(RadioObj) return (RadioObj.hasOwnProperty("allRadio") && Object.keys(RadioObj.allRadio).length)?true:false } function saveToStorage(){ try{ var save_data = JSON.stringify(RadioObj); if(save_data.length>0 && save_data !== null && save_data !=="" && save_data !== undefined){ GM_setValue('RadioObj', save_data); if(debug) console.log("Сохраненно: ",RadioObj); } }catch(e){ console.log(e); } } function ajax(urls){ return $.ajax( { url: urls, async: false, xhrFields: { withCredentials: true}, success: function(data){ return data }, error: function(){ return "error" } }).responseText; } function getListGenres(data){ let html = data, output ={}, liEl = $(html).find("div.content__main > ul li"), liElLenght = liEl.length liEl.each(function(index, el){ if(index != liElLenght-1) { let name = $(this).find("a").text().trim(), link = '//101.ru'+$(this).find("a").attr("href") output[name]=({name: name, link: link}) } }) return output } function getListRadios(data){ for(let x in data) { let elements = ajax(data[x].link), html = $(elements); if(!data[x].hasOwnProperty("radio")) data[x].radio = []; if(!data[x].hasOwnProperty("clear")) data[x].clear = []; $(html).find(".content__main > div.grid.grid_size_m > li").each(function(index,el){ let name = $(this).find("a.grid__title > span").text(), href = $(this).find("a.grid__title").attr("href"), image = $(this).find("link").attr("href"), json = getJson(href.slice(href.lastIndexOf("/")+1,href.length), true); let linksR = []; if(!json.includes("Канал не найден")){ let jsonP = JSON.parse(json); jsonP = jsonP.r###lt for(let s = 0; s < jsonP.playlist.length; s++){ let file = jsonP.playlist[s].file, cut = file.slice(0, file.lastIndexOf("?")); linksR.push(cut) } } if(json.includes("Канал не найден")){ data[x].clear.push({name:name,link:href,image:image, json:json}) } else { data[x].radio.push({name:name,link:href,image:image, json:linksR}) radios_count++ } }); } return data } function getJson(id, bo){ let urls = bo ? "//101.ru/api/channel/getServers/"+id+"/channel/AAC/64/?dataFormat=html5" : "//101.ru/api/channel/getServers/"+id+"/channel/MP3/128/", otvet = ajax(urls) if(otvet.includes("Канал не поддерживает формат AAC")){ otvet = getJson(id, false); } return otvet } function panel_v1(obj){ let div = $("<div id='radio_box'>"+ "<div class='main_title'>Radio List 101.ru</div>"+ "<div id='outputs'>Пустой список!</div>"+ "<div id='foot'><button onclick=\"$(\'#box_codes\').toggle(\'slow\')\">Получить код</button></div>"+ "<div id='box_codes'><textarea id='texta' spellcheck='false'></textarea></div>"+ "</div>"), outuptCode = ``, past = $(div).find("#outputs").empty(); for(let o in obj){ // Main genres let genre = obj[o], divA = $("<div class='box_radio'></div>"), divB = $("<div class='title_ganre'></div>").text(genre.name).click(function(event){ event.stopPropagation(); $(this).next(".box_inner").toggle('slow'); }), divC = $("<div class='box_inner'></div>"), ul = $("<ul>"), text = "" for(let i=0;i<genre.radio.length;i++){ outuptCode += `{\n` let radio = genre.radio[i] text += '<li><a href="'+radio.link+'" class="noajax" data-tooltip-block="#topchan82">'+ '<div class="cover logo" style="background-color: #eeeeee"><img src="'+radio.image+'" alt="'+radio.name+'"></div>'+ '<div class="h3 caps htitle">'+radio.name+'</div>'+ '</a>'; outuptCode += `"title":"${radio.name}",\n"artist":"${genre.name} - 101.ru",\n"poster":"${radio.image}",` if(canavas_img) outuptCode += `\n"canvas":"${radio.canvasik}",\n` for(let s = 0 ; s<radio.json.length;s++){ text +='<div>'+radio.json[s]+'</div><audio controls preload="none"><source src="'+radio.json[s]+'" type="audio/mpeg"></source></audio>'; outuptCode += `"mp3":"${radio.json[s]}"` if(s < radio.json.length-1) outuptCode += `,\n` } outuptCode += `\n},\n` // if(i < genre.radio.length-1) outuptCode += `\n},\n` text +='</li>'; } $(ul).html(text) divC.append(ul) divA.append(divB,divC) past.append(divA) } $("body").append(div) $("#texta").val(outuptCode) } function panelv2_menu(obj){ let div = $("<div id='radio_box'>"+ "<div class='main_title'>Radio List 101.ru</div>"+ "<div id='names'><ul class='menu_radios'></ul></div>"+ "<div id='outputs'>Пусто, выберите элемент!</div>"+ "<div id='foot'><button onclick=\"$(\'#box_codes\').toggle(\'slow\')\">Получить код</button></div>"+ "<div id='box_codes'>"+ "<div class='textarea_info'><span>None info</span><div onclick=\"$(\'#box_codes\').toggle(\'slow\')\">X</div></div>"+ "<textarea id='texta' spellcheck='false'></textarea>"+ "</div>"+ "</div>"), ul_menu = $(div).find(".menu_radios"), // All radios _liAll = $("<li>").text("Все").attr("title","Все").click(function(){ $(".menu_radios > li.selactive").removeClass() $(this).addClass("selactive") $("#outputs").empty(); let outuptCode = "", counts = 0 for(let o in obj){ let genre = obj[o] counts+= genre.radio.length $("#outputs").append($("<div class='main_title_small'>").text(o)) outuptCode = loadRadioSelected(genre, outuptCode) } $("#texta").val(outuptCode) $("body").find(".textarea_info > span").text(`Количество радиостанций: ${counts} (Все)`) }) ul_menu.append(_liAll) // Make list ganres radios and ouput 1 ganres for(let o in obj){ let genre = obj[o], _li = $("<li>").text(o).attr("title",o).click(function(){ $(".menu_radios > li.selactive").removeClass() $(this).addClass("selactive") $("#outputs").empty(); let outuptCode = "" outuptCode = loadRadioSelected(genre, outuptCode) $("#texta").val(outuptCode) $("body").find(".textarea_info > span").text(`Количество радиостанций: ${genre.radio.length} (${o})`) }) ul_menu.append(_li) } $("body").append(div) // Load default $(".menu_radios > li.selactive").removeClass() $(ul_menu).find("li:eq(1)").addClass("selactive") $("#outputs").empty(); let outuptCode = "" outuptCode = loadRadioSelected(obj["Лучшие станции"], outuptCode) $("#texta").val(outuptCode) $("body").find(".textarea_info > span").text(`Количество радиостанций: ${obj["Лучшие станции"].radio.length} (Лучшие станции)`) } function loadRadioSelected(genre, outuptCode){ let ul = $("<ul>"), text = "" for(let i=0;i<genre.radio.length;i++){ outuptCode += '{\n' let radio = genre.radio[i] text += '<li><a href="'+radio.link+'" class="noajax" data-tooltip-block="#topchan82">'+ '<div class="cover logo" style="background-color: #eeeeee"><img src="'+radio.image+'" alt="'+radio.name+'" width="440px"></div>'+ '<div class="h3 caps htitle">'+radio.name+'</div>'+ '</a>'; outuptCode += '"title":"'+radio.name+'",\n"artist":"'+genre.name+' - 101.ru",\n"poster":"'+radio.image+'",\n' if(canavas_img) outuptCode += '"canvas":"'+radio.canvasik+'",\n' for(let s = 0 ; s<radio.json.length;s++){ text +='<div>'+radio.json[s]+'</div><audio controls preload="none"><source src="'+radio.json[s]+'" type="audio/mpeg"></source></audio>'; outuptCode += '"mp3":"'+radio.json[s]+'"' if(s < radio.json.length-1) outuptCode += ',\n' } outuptCode += '\n}' if(i<genre.radio.length-1)outuptCode +=',\n' text +='</li>'; } $(ul).html(text) $("#outputs").append(ul) return outuptCode } function returnCanvas(params){ let canvas = document.createElement("canvas"), ctx = null, img = new Image(), src = params.src, text = params.text, color = params.color, gradient = params.gradient || [], stroke = params.stroke || false, shadow = params.shadow || [] if(text.includes(" ")){ text = text.split(" ") } img.crossOrigin = "Anonymous"; if(src.length && canvas.getContext('2d')){ ctx = canvas.getContext("2d") img.onload = function(){ if(debug) console.log("Load image: ", src) let w = canvas.width = this.width, h = canvas.height = this.height; ctx.drawImage(img, 0, 0); if(color == null && gradient.length){ color = ctx.createLinearGradient(0,0,w,0); for(let col=0;col<gradient.length;col++) color.addColorStop(gradient[col].proc,gradient[col].color); } ctx.font="20px Verdana"; ctx.textAlign = 'center'; if(shadow.length) { ctx.shadowColor = shadow[0]; ctx.shadowBlur = shadow[1]; ctx.shadowOffsetX = ctx.shadowOffsetY= shadow[2]; } if(stroke){ ctx.strokeStyle = color if(Object.prototype.toString.call(text) == "[object Array]"){ for(let i=0;i<text.length;i++) ctx.strokeText(text[i], w/2, h/text.length+i*20+text.length) } else { ctx.strokeText(text,w/2,h/2); } } else { ctx.fillStyle = color if(Object.prototype.toString.call(text) == "[object Array]"){ for(let i=0;i<text.length;i++) ctx.fillText(text[i], w/2, h/text.length+i*20+text.length) } else { ctx.fillText(text,w/2,h/2); } } if(debug) console.log(canvas.toDataURL("image/png")) params.radio.canvasik = canvas.toDataURL("image/png") radios_image_load++ return canvas.toDataURL("image/png") } img.onerror = function(){ params.radio.canvasik = src return src } img.src= src } } function convertToCanvas(obj){ for(let o in obj){ // Main genres let genre = obj[o] for(let i=0;i<genre.radio.length;i++){ let radio = genre.radio[i], canvasik canvasik = returnCanvas({ src: "."+radio.image.slice(radio.image.indexOf("/",7),radio.image.length), text: radio.name, color: null, gradient: [{proc: 0, color: "black"}, {proc: 0.5, color: "red"}, {proc: 1, color: "black"}], stroke: false, shadow: ["black",10,20], radio: radio }); } } return obj } function OBJLengthEmpty(obj){ return Object.keys(obj).length == 0 ? true : false } function init(){ let interval = null,listGanres,listRadios,makePanelObject listGanres = getListGenres(ajax("//101.ru/radio-top")) if(OBJLengthEmpty(listGanres)){ throw Error("Список жанров пуст!") return false } if(debug) console.log("Жанры полученны!",listGanres) listRadios = getListRadios(listGanres) if(OBJLengthEmpty(listRadios)){ throw Error("Список радиостанций пуст!") return false } makePanelObject = (canavas_img)? convertToCanvas(listRadios): listRadios if(canavas_img && OBJLengthEmpty(makePanelObject)){ throw Error("Список радиостанций, с canvas'ом пуст!") return false } if(debug) console.log("Список радиостанций получен!", "Найдено:", radios_count) if(canavas_img){ interval = setInterval(function(){ if(radios_image_load == radios_count){ if(debug) console.log("Loading images from canvas completed! Count:", radios_image_load) clearInterval(interval) //panel(makePanelObject) if(!RadioObj.hasOwnProperty("allRadio")) RadioObj.allRadio = {}; RadioObj.allRadio = makePanelObject saveToStorage() panelv2_menu(makePanelObject) } else { if(debug) console.log("Loading images from canvas:", radios_image_load,"/",radios_count) } }, 2000) } else { // panel(makePanelObject) if(!RadioObj.hasOwnProperty("allRadio")) RadioObj.allRadio = {}; RadioObj.allRadio = makePanelObject saveToStorage() panelv2_menu(makePanelObject) } } function grabAgain(){ if(confirm("Начать грабить 101.ru?")){ canavas_img = confirm("Внимание:\nПеревести все изображения радиостанций в canvas?\n") init() } } if(loadStorage()){ if(confirm("Загрузить сохраненные радио, с прошлого раза?")){ if(confirm("Внимание:\nДобавить canvas в коды?\n")){ if(RadioObj.hasOwnProperty("allRadio") && RadioObj.allRadio.hasOwnProperty("Лучшие станции") && RadioObj.allRadio["Лучшие станции"].hasOwnProperty("radio") && RadioObj.allRadio["Лучшие станции"].radio[0].hasOwnProperty("canvasik")){ canavas_img = true } else { alert("Внимание:\nПоле с изображением в canvas не найдено!\nЗагрузка не возможна, начните грабить заново с canvas'ом!") canavas_img = false } } panelv2_menu(RadioObj.allRadio) } else { grabAgain() } } else { grabAgain() } })();