Skip to content

Instantly share code, notes, and snippets.

@1d10t
Last active March 23, 2018 11:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save 1d10t/1fd58475e95209d7ecfd15a9a3cc356a to your computer and use it in GitHub Desktop.
Save 1d10t/1fd58475e95209d7ecfd15a9a3cc356a to your computer and use it in GitHub Desktop.
vkontakte music m3u generating content script
/*
run in console at https://vk.com/audio
to download from wall, go to https://vk.com/wall[ID]?own=1&offset=[OFFSET]
wait for m3u file
use this autohotkey script https://gist.github.com/1d10t/6f8b151e50905449c63abc851dceb167
to download mp3 files
*/
(function(){
if(window.vk_m3u) return;
(function(t, e) {
"use strict";
function o(t) {
if (~t.indexOf("audio_api_unavailable")) {
var e = t.split("?extra=")[1].split("#"),
o = "" === e[1] ? "" : a(e[1]);
if (e = a(e[0]), "string" != typeof o || !e) return t;
o = o ? o.split(String.fromCharCode(9)) : [];
for (var s, r, n = o.length; n--;) {
if (r = o[n].split(String.fromCharCode(11)), s = r.splice(0, 1, e)[0], !l[s]) return t;
e = l[s].apply(null, r)
}
if (e && "http" === e.substr(0, 4)) return e
}
return t
}
function a(t) {
if (!t || t.length % 4 == 1) return !1;
for (var e, i, o = 0, a = 0, s = ""; i = t.charAt(a++);) i = r.indexOf(i), ~i && (e = o % 4 ? 64 * e + i : i, o++ % 4) && (s += String.fromCharCode(255 & e >> (-2 * o & 6)));
return s
}
function s(t, e) {
var i = t.length,
o = [];
if (i) {
var a = i;
for (e = Math.abs(e); a--;) e = (i * (a + 1) ^ e + a) % i, o[a] = e
}
return o
}
Object.defineProperty(e, "__esModule", {
value: !0
}), e.audioUnmaskSource = o;
var r = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMN0PQRSTUVWXYZO123456789+/=",
l = {
v: function(t) {
return t.split("").reverse().join("")
},
r: function(t, e) {
t = t.split("");
for (var i, o = r + r, a = t.length; a--;) i = o.indexOf(t[a]), ~i && (t[a] = o.substr(i - e, 1));
return t.join("")
},
s: function(t, e) {
var i = t.length;
if (i) {
var o = s(t, e),
a = 0;
for (t = t.split(""); ++a < i;) t[a] = t.splice(o[i - 1 - a], 1, t[a])[0];
t = t.join("")
}
return t
},
i: function(t, e) {
return l.s(t, e ^ vk.id)
},
x: function(t, e) {
var i = [];
return e = e.charCodeAt(0), each(t.split(""), function(t, o) {
i.push(String.fromCharCode(o.charCodeAt(0) ^ e))
}), i.join("")
}
}
})(0, window);
String.prototype.htmldecode = function(){
if(!window.htmldecode_textarea) window.htmldecode_textarea = document.createElement('textarea');
window.htmldecode_textarea.innerHTML = this;
return window.htmldecode_textarea.value;
}
function ubtoa(str){
return window.btoa(encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, function(match, p1) {
return String.fromCharCode('0x' + p1);
}));
}
function m3u_generate(list){
var keys = Object.keys(list);
var data = "#EXTM3U\n"+keys.map(function(key){
var value = list[key];
return '#EXTINF:'+value[3]+','+value[1]+' - '+value[2]+"\n"+value[4]+"\n";
}).join('');
return data;
}
function get_file(data, filename, mime){
if(!mime) mime = 'application/octet-stream';
if(!window.URL || !window.Blob){
window.open('data:'+mime+';base64,' + encodeURIComponent(ubtoa(data)));
return;
}
var
url = window.URL.createObjectURL(new Blob([data], {type: mime})),
a = document.createElement('a')
;
a.href = url;
a.download = filename;
a.click();
setTimeout(function(){
a.remove();
window.URL.revokeObjectURL(url);
}, 1000);
}
function m3u_download(list, filename){
if(!filename) filename = 'vkontakte-'+(new Date).toISOString().replace(/[^\w\d]/g, '-');
else filename = filename.replace(/[^\w\dа-яА-ЯёЁ\(\)\[\]\- ]/g, '_');
get_file(
m3u_generate(list),
filename+'.m3u',
'audio/mpegURL'
);
}
function vk_clear_url_cache(user_id){
var re = new RegExp('^au\\.'+(user_id?''+user_id+'_':''));
for(var k in localStorage) if(re.test(k)) console.log('remove url cache', k), localStorage.removeItem(k);
}
function vk_full_id(element){
if(typeof(element.length) == 'undefined') return element.dataset.fullId;
var audio_arr = element;
return audio_arr[AudioUtils.AUDIO_ITEM_INDEX_OWNER_ID]+'_'+audio_arr[AudioUtils.AUDIO_ITEM_INDEX_ID];
}
function vk_storage_key(audio_arr){
return 'au.'+vk_full_id(audio_arr);
}
function vk_audio_data(element, onurl, nonetwork){
var audio_arr = typeof(element.length) == 'undefined' ? AudioUtils.getAudioFromEl(element) : element;
if(audio_arr[AudioUtils.AUDIO_ITEM_INDEX_URL]){
audio_arr[AudioUtils.AUDIO_ITEM_INDEX_URL] = window.audioUnmaskSource(audio_arr[AudioUtils.AUDIO_ITEM_INDEX_URL]);
onurl(element, audio_arr);
return audio_arr;
}
var url = localStorage.getItem(vk_storage_key(audio_arr));
if(url){
audio_arr[AudioUtils.AUDIO_ITEM_INDEX_URL] = url;
onurl(element, audio_arr);
return audio_arr;
}
if(nonetwork){
onurl(element, audio_arr);
return audio_arr;
}
ap._ensureHasURL(audio_arr, function(t) {
audio_arr[AudioUtils.AUDIO_ITEM_INDEX_URL] = window.audioUnmaskSource(t[AudioUtils.AUDIO_ITEM_INDEX_URL]);
if(audio_arr[AudioUtils.AUDIO_ITEM_INDEX_URL]) localStorage.setItem(vk_storage_key(audio_arr), audio_arr[AudioUtils.AUDIO_ITEM_INDEX_URL]);
onurl(element, audio_arr);
});
return audio_arr;
}
function vk_audio_list_discover(list, onend, bulk){
if(typeof(bulk) == 'undefined') bulk = true;
var list_done = [];
var skip = 0;
var period = 2000;
var error_sleep = 80*1000;
var list_chunk_size = 10;
var list = [].map.call(list, function(element){ return element; }); // convert nodelist to array
var requested = list.length;
var busy = false;
var ct = setInterval(function(){
if(busy) return;
if(skip){ skip--; return; }
if(!requested){
clearInterval(ct);
onend(list_done);
return;
}
busy = true;
//console.log('requested', requested);
if(bulk){
var
elements = [],
add_num = Math.min(list_chunk_size, list.length)
;
while(elements.length < add_num && list.length){
var element = list.shift();
//console.log(element);
vk_audio_data(element, function(e, audio_arr){
if(audio_arr[AudioUtils.AUDIO_ITEM_INDEX_URL]){
list_done.push(audio_arr);
requested--;
return;
}
elements.push(e);
}, true);
};
if(!elements.length){
clearInterval(ct);
onend(list_done);
return;
}
var fullIds = elements.map(vk_full_id).join(',');
ajax.post("al_audio.php", {
act: "reload_audio",
al: 1,
ids: fullIds
}, {
onDone: function(sub_list, a) {
//console.log(sub_list, a);
if(sub_list){
while(sub_list.length){
var audio_arr = sub_list.shift();
if(audio_arr[AudioUtils.AUDIO_ITEM_INDEX_URL]){
vk_audio_data(audio_arr, function(e, audio_arr){
if(audio_arr[AudioUtils.AUDIO_ITEM_INDEX_URL]) localStorage.setItem(vk_storage_key(audio_arr), audio_arr[AudioUtils.AUDIO_ITEM_INDEX_URL]);
list_done.push(audio_arr);
requested--;
}, true);
}else{
console.log('no url in', audio_arr);
for(var i=0; i<elements.length; i++){
if(vk_full_id(audio_arr) == vk_full_id(elements[i])){
list.push(elements[i]);
break;
}
}
}
}
}else{
while(elements.length) list.push(elements.shift());
skip = Math.round(error_sleep/period);
return;
}
busy = false;
}
});
}else{
var element = list.shift();
vk_audio_data(element, function(element, audio_arr){
if(audio_arr[AudioUtils.AUDIO_ITEM_INDEX_URL]){
list_done.push(audio_arr);
requested--;
}else{
list.push(element);
skip = Math.round(error_sleep/period);
return;
}
busy = false;
});
}
}, period);
}
function vk_playlists(){
var ps = clone(ap.getPlaylists());
var rows_wrap = window.wide_column || document.querySelector('.audio_page__audio_rows');
if(rows_wrap) ps.unshift({_title: 'Записи со страницы '+location, _list: rows_wrap.querySelectorAll('.audio_row')});
ps = ps.map(function(pl){
var p = {_title: 'Временный плейлист', _list: []};
if(pl._ref) pl = pl._ref;
p._list = pl._list;
if(pl._title) p._title = pl._title;
return p;
});
return ps;
}
function vk_choose_playlist(chosen){
var ps = vk_playlists();
//console.log(ps);
var s = [];
for(var i=0; i<ps.length; i++){
s.push(''+i+') '+ps[i]._title+' ('+ps[i]._list.length+' записей)');
}
s = s.join("\n");
if(chosen === undefined) chosen = prompt(s, 0);
if(chosen === null || !ps[chosen]) return;
return ps[chosen];
}
function vk_m3u(chosen, onend){
var keylist = {};
var playlist = vk_choose_playlist(chosen);
if(!playlist) return;
vk_audio_list_discover(playlist._list, function(list){
while(list.length){
var audio_arr = list.shift();
var key = vk_full_id(audio_arr);
if(keylist[key]) return;
keylist[key] = [
key,
audio_arr[AudioUtils.AUDIO_ITEM_INDEX_PERFORMER].htmldecode(),
audio_arr[AudioUtils.AUDIO_ITEM_INDEX_TITLE].htmldecode(),
audio_arr[AudioUtils.AUDIO_ITEM_INDEX_DURATION],
audio_arr[AudioUtils.AUDIO_ITEM_INDEX_URL]
];
}
m3u_download(keylist, playlist._title);
if(onend) onend();
}, true)
}
function vk_load_wall(){
return setInterval(function(){ if(wall_more_link.style.display=='block') wall_more_link.click(); }, 100);
}
var ap = getAudioPlayer();
['vk_m3u', 'vk_clear_url_cache', 'vk_playlists'].map(function(fn){ window[fn] = eval('('+fn+')') });
})();
// example 1: choose playlist by kbd and download it
/*
window.vk_m3u(
undefined, // choose playlist in prompt
undefined // no function on end
);
*/
// example 2: all friends from https://vk.com/audios
/*
var friends = {}, queue;
(function reload_friends_list(){
document.querySelector('.audio_more_friends_btn').click();
setTimeout(function(){
queue = [].map.call(document.querySelectorAll('.audio_friends_list .audio_friend'), function(fe, i){
return fe;
}).filter(function(fe){
return !friends[fe.dataset.id];
});
if(!queue.length){
reload_friends_list();
return;
}
var busy = false;
var load_interval = setInterval(function(){
if(busy) return;
busy = true;
var fe = queue.shift();
fe.click();
friends[fe.dataset.id] = true;
vk_clear_url_cache(
//fe.dataset.id
);
setTimeout(function(){
window.vk_m3u(ap.getPlaylists().length, reload_friends_list);
}, 10*1000);
}, 1000);
}, 5000);
})();
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment