Last active
March 23, 2018 11:17
-
-
Save 1d10t/1fd58475e95209d7ecfd15a9a3cc356a to your computer and use it in GitHub Desktop.
vkontakte music m3u generating content script
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
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