Данная страница будет полезной для тех, кто решил взять заказ на парсер аудио-треков VK и резко понял, что ничего не понял.
В чем проблема
Знакомо?
https://m.vk.com/mp3/audio_api_unavailable.mp3?extra=AeL2rMfFyZzlD3HkyvfnvNvLx1KOqw5UDfuXCOTvttm4ts1OBJnYELvHyxvODI9fnM9YztD5A3iOyI14sxv2mNiXt3iTzdLInduXzvG9C2uVr3b5mezinfj2lJbpDhGYC25rDxbwsOPQmg1eu2Pbyxr3ntPowNLhDMrrDs8XnKu2sOuOyO8XzMf1otDmBtL6BNvllNjZx3aZuLHpq3aOBvvhzenJnZKTzKnMuwfKBI4TquffrtzKv2nymMyVDu1LzJnuwMLxwMm/BeTcserWlun3ExLVBG#AqSZntu
Если да — то вы пытались парсить мобильную версию сайта и успешно доставали ссылки. Неверные ссылки. Ссылки на 25-секундный голос, сообщающий что все идет не по плану.
Если нет — вам стоит попробовать.
Как получить верный URL
А вот это верный вопрос! Дело в том, что перед воспроизведением записи, вк натравливает на такой url заготовленные js-скрипты. В общем-то ничего сложного — несколько переворотов строк, побитовые сдвиги, даже одно побитовое отрицание. И все это сжато компрессором.
Честно говоря, раньше искать функции, отвечающие за это дело, было сложнее. Судя по всему во Вконтакте завелись кроты)) Иначе как блин объяснить то, что они подписали, буквально повесили вывеску на самом нужном месте:
Ладно, ладно, все мы рабы сборщиков…
Без лишних слов, актуальный код
var id = 0; //Ваш userid
var n = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMN0PQRSTUVWXYZO123456789+/=",
i = {
v: function(e) {
return e.split("").reverse().join("")
},
r: function(e, t) {
e = e.split("");
for (var i, o = n + n, s = e.length; s--;) i = o.indexOf(e[s]), ~i && (e[s] = o.substr(i - t, 1));
return e.join("")
},
s: function(e, t) {
var n = e.length;
if (n) {
var i = r(e, t),
o = 0;
for (e = e.split(""); ++o < n;) e[o] = e.splice(i[n - 1 - o], 1, e[o])[0];
e = e.join("")
}
return e
},
i: function(e, t) {
return i.s(e, t ^ id)
},
x: function(e, t) {
var n = [];
return t = t.charCodeAt(0), each(e.split(""), function(e, i) {
n.push(String.fromCharCode(i.charCodeAt(0) ^ t))
}), n.join("")
}
};
function o() {
return window.wbopen && ~(window.open + "").indexOf("wbopen")
}
function s(e) {
if (!o() && ~e.indexOf("audio_api_unavailable")) {
var t = e.split("?extra=")[1].split("#"),
n = "" === t[1] ? "" : a(t[1]);
if (t = a(t[0]), "string" != typeof n || !t) return e;
n = n ? n.split(String.fromCharCode(9)) : [];
for (var s, r, l = n.length; l--;) {
if (r = n[l].split(String.fromCharCode(11)), s = r.splice(0, 1, t)[0], !i[s]) return e;
t = i[s].apply(null, r)
}
if (t && "http" === t.substr(0, 4)) return t
}
return e
}
function a(e) {
if (!e || e.length % 4 == 1) return !1;
for (var t, i, o = 0, s = 0, a = ""; i = e.charAt(s++);) i = n.indexOf(i), ~i && (t = o % 4 ? 64 * t + i : i, o++ % 4) && (a += String.fromCharCode(255 & t >> (-2 * o & 6)));
return a
}
function r(e, t) {
var n = e.length,
i = [];
if (n) {
var o = n;
for (t = Math.abs(t); o--;) t = (n * (o + 1) ^ t + o) % n, i[o] = t
}
return i
}
global $n, $i, $id;
$n = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMN0PQRSTUVWXYZO123456789+/=";
$id = 150032691; //user_id
$i = [
'v' => function($e) {
return strrev($e);
},
'r' => function($e, $t){
global $n;
$e = str_split($e);
for ($o = $n . $n, $s = count($e); $s--;){
$i = stripos($o, $e[$s]);
if(~$i){
$e[$s] = substr($o, $i - $t, 1);
}
}
return implode("", $e);
},
's' => function($e, $t) {
$n = strlen($e);
if ($n) {
$i = r($e, $t);
$o = 0;
$e = str_split($e);
for (; ++$o < $n;){
$p = array_splice($e, $i[$n - 1 - $o], 1, $e[$o]);
$e[$o] = $p[0];
}
$e = implode("", $e);
}
return $e;
},
'i' => function($e, $t){
global $i, $id;
$k = $i['s'];
return $k($e, $t ^ $id);
},
];
function o() {
return false;
}
function a($e){
global $n;
if (!$e || strlen($e) % 4 == 1) {
return !1;
}
$s = 0;
for ($o = 0, $a = "";$s < strlen($e);) {
$i = $e[$s++];
$i = strpos($n, $i);
if ($i !== false) {
$t = ($o % 4) ? 64 * $t + $i : $i;
if ($o++ % 4) {
$a .= chr(255 & $t >> (-2 * $o & 6));
}
}
}
return $a;
}
function r($e, $t) {
$n = strlen($e);
$i = [];
if ($n) {
$o = $n;
$t = abs($t);
for (; $o--;){
$t = ($n * ($o + 1) ^ $t + $o) % $n;
$i[$o] = $t;
}
}
return $i;
}
function s($e){
global $i;
if (!o() && strpos($e, "audio_api_unavailable") !== false) {
$t = explode("?extra=", $e);
$t = $t[1];
$t = explode("#", $t);
$n = ("" === $t[1]) ? "" : a($t[1]);
$t = a($t[0]);
if (!is_string($n) || !$t){ return $e;}
$n = $n ? explode(chr(9), $n) : [];
for ($l = count($n); $l--;) {
$r = explode(chr(11), $n[$l]);
$s = array_splice($r, 0, 1, $t);
$s = $s[0];
if (!$i[$s]){ return $e; }
$t = $i[$s](...$r);
}
if ($t && "http" === substr($t, 0, 4)){ return $t;}
}
return $e;
}
function bcmod($k, $i){
for(;$k >= $i; $k -= $i){}
return $k;
}
В обоих случаях
s("https://m.vk.com/mp3/audio_api_unavailable.mp3?extra=encodeextraurl");
Думаю, при надобности с PHP на другой язык перевести код будет уже проще.
Статья написана с целью снизить кол-во человекоминут в мире, затрачиваемых на эту задачу.
Автор: In4in