Данная страница будет полезной для тех, кто решил взять заказ на парсер аудио-треков VK и резко понял, что ничего не понял.
Знакомо?
Если да — то вы пытались парсить мобильную версию сайта и успешно доставали ссылки. Неверные ссылки. Ссылки на 25-секундный голос, сообщающий что все идет не по плану.
Если нет — вам стоит попробовать.
А вот это верный вопрос! Дело в том, что перед воспроизведением записи, вк натравливает на такой url заготовленные js-скрипты. В общем-то ничего сложного — несколько переворотов строк, побитовые сдвиги, даже одно побитовое отрицание. И все это сжато компрессором.
Честно говоря, раньше искать функции, отвечающие за это дело, было сложнее. Судя по всему во Вконтакте завелись кроты)) Иначе как блин объяснить то, что они подписали, буквально повесили вывеску на самом нужном месте:
Ладно, ладно, все мы рабы сборщиков…
В обоих случаях
Думаю, при надобности с PHP на другой язык перевести код будет уже проще.
Статья написана с целью снизить кол-во человекоминут в мире, затрачиваемых на эту задачу.
P.s: Актуальное решение всегда можно будет найти здесь: gist.github.com/in4in-dev/09f32f313f11b2c10778d9e2ffe7e60e
P.s2: Пользователь ImIeee также обновляет свое решение в репозитории github.com/vodka2/vkaudio (тут вы найдете решение на Python)
В чем проблема
Знакомо?
https://m.vk.com/mp3/audio_api_unavailable.mp3?extra=AeL2rMfFyZzlD3HkyvfnvNvLx1KOqw5UDfuXCOTvttm4ts1OBJnYELvHyxvODI9fnM9YztD5A3iOyI14sxv2mNiXt3iTzdLInduXzvG9C2uVr3b5mezinfj2lJbpDhGYC25rDxbwsOPQmg1eu2Pbyxr3ntPowNLhDMrrDs8XnKu2sOuOyO8XzMf1otDmBtL6BNvllNjZx3aZuLHpq3aOBvvhzenJnZKTzKnMuwfKBI4TquffrtzKv2nymMyVDu1LzJnuwMLxwMm/BeTcserWlun3ExLVBG#AqSZntu
Если да — то вы пытались парсить мобильную версию сайта и успешно доставали ссылки. Неверные ссылки. Ссылки на 25-секундный голос, сообщающий что все идет не по плану.
Если нет — вам стоит попробовать.
Как получить верный URL
А вот это верный вопрос! Дело в том, что перед воспроизведением записи, вк натравливает на такой url заготовленные js-скрипты. В общем-то ничего сложного — несколько переворотов строк, побитовые сдвиги, даже одно побитовое отрицание. И все это сжато компрессором.
Честно говоря, раньше искать функции, отвечающие за это дело, было сложнее. Судя по всему во Вконтакте завелись кроты)) Иначе как блин объяснить то, что они подписали, буквально повесили вывеску на самом нужном месте:
Ладно, ладно, все мы рабы сборщиков…
Без лишних слов, актуальный код
Декодер на JavaScript
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
}
Буква в букву декодер на PHP
global $n, $i, $id;
$n = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMN0PQRSTUVWXYZO123456789+/=";
$id = 123456789; //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;
}
В обоих случаях
s("https://m.vk.com/mp3/audio_api_unavailable.mp3?extra=encodeextraurl");
Думаю, при надобности с PHP на другой язык перевести код будет уже проще.
Статья написана с целью снизить кол-во человекоминут в мире, затрачиваемых на эту задачу.
P.s: Актуальное решение всегда можно будет найти здесь: gist.github.com/in4in-dev/09f32f313f11b2c10778d9e2ffe7e60e
P.s2: Пользователь ImIeee также обновляет свое решение в репозитории github.com/vodka2/vkaudio (тут вы найдете решение на Python)
XanderBass
Поменяют и спрячут алгоритм теперь после этой публикации.
Taraflex
Зато автор публикации получит новый заказ на доработку парсера )))
catanfa
предлагаю In4in завести github репозиторий и обновлять свой декодер вслед за вк, в случае изменений со стороны вк.
In4in Автор
gist.github.com/in4in-dev/09f32f313f11b2c10778d9e2ffe7e60e
Идея хорошая
In4in Автор
Не думаю, что из-за статьи будут что-то менять. В конце концов, они и не прячут декодер — просто скрывают таким образом музыку от обывателя.
riky
ровно год назад была статья на эту тему.
интересно за это время сильно изменился механизм?
habr.com/post/340810
In4in Автор
Сравнивал вскользь недавно.
kto-to_tam
На сколько понимаю, они этим самым проверяют локаль пользователя… и в плейлисте появляется то и дело — «Аудиозапись your_favorite_music недоступна для прослушивания в Вашем регионе.»
Но можно же, в теории, позаимствовать айди товарища из «нужной» страны… Хотя вроде там более замароченно.
In4in Автор
Думаю, за это отвечает другой механизм и на такие аудио даже ссылки не выдает. К сожалению, мне такие записи не попадались и как это обойти — ответить трудно. Попробую зайти через впн глянуть.
SandroSmith
Именно ВПН и позволяет обойти «ваш регион».
Точнее, если у туннеля выход в Европе — DMCA(или кто там у них) блюдётся. Если в России — слушай на здоровье.
kto-to_tam
А у меня, к сожалению, такое встречается постоянно… если не пользуюсь русским прокси.
Именно поэтому перестал пользоваться вк музыкой как таковой… проще уж из других источников слушать, чем слушать трэк через три.
megahertz
А никто ничего не прячет, похожий на base64 декодер подогнанный под свои нужды
jimmyjonezz
Всегда есть возможность использовать telegram бота…
mastacamp
главное успеть скачать всю свою музыку) я успел) автору большой респект!!!
ilyamodder
А зачем? Можно же просто взять ID официального приложения и пользоваться API для аудио как раньше.
Rast1234
Там не просто, надо еще прикинуться, например, андроидом и по-хитрому получить несколтко токенов, чтобы это сработало. На гитхабе видел реализацию, но у меня что-то пошло не так.
ImIeee
Не эту реализацию случайно — github.com/vodka2/vk-audio-token? Если эту, то можно было создать Issue, кроме того, не так давно я добавил примеры использования полученных токенов. Если другую, можете, если не трудно, написать ссылку? Вообще, на мой взгляд, использование API намного удобнее, чем парсинг сайта.
Rast1234
Реализация ваша, да. Спасибо за нее :)
Я просто ради интереса решил переписать на шарпе, поэтому issue не помогут. Токены получаю от гугла и от вк, но что-то делаю не так — vk api всегда возвращает тот самый 25-секундный семпл. Хочу разобраться и запилить экспортер всего-и-вся-из-вк, но все руки не доходят.
ImIeee
Сложно сказать, не видя кода, но, возможно, вы делаете запрос к API с другим User-Agent. В принципе, я мог бы посмотреть ваш код, если бы вы выложили его на Github, всё-таки идея хорошая.
Rast1234
Если не справлюсь, напишу вам) все-таки интересно и самому поковыряться
nokimaro
После того как появилась платная подписка на музыку, сделали завязку на google play, и для полноценной работы нужно проходить доп. валидацию с использованием android_id (device_id) при которой api токен меняется на такой же токен с доп. правами, в частности с правами на доступ к audio api, при том что документацию по audio api с сайта вк выпилили.
ImIeee
Официальный клиент ВК для Android может работать и без валидации, правда, там другие методы API.
Legomegger
Значит ли это что сейчас опять появятся на пару недель over 9000 приложений музыки в AppStore?
In4in Автор
Как ответила мне одна девушка, «У меня целых три таких приложения и я жму там одну кнопочку, а ты тут столько строк какой-то фигни написал»)
Skerrigan
«Глаза» то у девушки хоть большие?
navion
Даже Google сейчас выпиливает плагины для скачивания музыки из VK.
serg_deep
.
dimka11
Такие приложения разве не нарушают условия соглашений?
DevFish
Красивый код на php)
kolyan222
Подозреваю, что это шифрование ссылок сделано только для того, что бы у правообладателей не было претензий к сервису.
namikiri
А если для себя решил написать, то страница полезной не будет?
ImIeee
Давно уже поддерживаю аналогичный код на Github и на Тостере. Даже скрипт для обратного шифрования есть.
In4in Автор
Добавил к статье :)