Как быстро и просто скачать плейлист с Вконтакте

[ Версия для печати ]
Добавить в Facebook Добавить в Twitter Добавить в Вконтакте Добавить в Одноклассники
  [ ОТВЕТИТЬ ] [ НОВАЯ ТЕМА ]
VampirBFW
31.10.2017 - 10:59
Статус: Offline


Поварствующий радиоуправляемый сисадмин

Регистрация: 20.02.10
Сообщений: 9895
11
Как все начиналось

Дело было вечером, делать было нечего… Точнее, я просто хотел загрузить аудиокнигу перед парами и тут меня ждал сюрприз. Кэш в кейт мобайле отключили. Как так? Что делать? Конечно же писать свое приложение с кэшем и аудиозаписями. Но для начала нужно понять, как вк превращает ссылки вида audio%user_id%_%track_id% в прямые ссылки на mp3. Что из этого вышло приложения я не написал и как скачать определенный плейлист можно прочитать под катом.

Это сообщение отредактировал VampirBFW - 31.10.2017 - 11:15
 
[^]
Yap
[x]



Продам слона

Регистрация: 10.12.04
Сообщений: 1488
 
[^]
VampirBFW
31.10.2017 - 10:59
Статус: Offline


Поварствующий радиоуправляемый сисадмин

Регистрация: 20.02.10
Сообщений: 9895
Дебажим js

Начинаем с очевидного — открываем вкладку аудиозаписей и смотрим код. Видим onclick на кнопке у каждой аудиозаписи:

onclick="return getAudioPlayer().toggleAudio(this, event)"

Открываем audioplayer.js, включаем Pretty print и ищем функцию toggleAudio().

toggleAudio()
AudioPlayer.prototype.toggleAudio = function(t, e) {
if (vk && vk.widget && !vk.id && window.Widgets)
return Widgets.oauth(),
!1;
if (domClosest("_audio_row__tt", e.target))
return cancelEvent(e);
var i = domClosest("_audio_row", t)
, o = AudioUtils.getAudioFromEl(i, !0);
if (window.getSelection && window.getSelection().rangeCount) {
var a = window.getSelection().getRangeAt(0);
if (a && a.startOffset != a.endOffset)
return !1
}
if (e && hasClass(e.target, "mem_link"))
return nav.go(attr(e.target, "href"), e, {
navigateToUploader: !0
}),
cancelEvent(e);
if (hasClass(e.target, "_audio_row__title_inner") && o.lyrics && !o.isInAttach)
return AudioUtils.toggleAudioLyrics(i, o),
cancelEvent(e);
if (hasClass(e.target, "audio_row__performer"))
return checkEvent(e) || vk.widget ? !0 : (AudioUtils.audioSearchPerformer(e.target, o.performer, e),
cancelEvent(e));
var s = cur.cancelClick || e && (hasClass(e.target, "audio_lyrics") || domClosest("_audio_duration_wrap", e.target) || domClosest("_audio_inline_player", e.target) || domClosest("audio_performer", e.target));
if (cur._sliderMouseUpNowEl && cur._sliderMouseUpNowEl == geByClass1("audio_inline_player_progress", i) && (s = !0),
delete cur.cancelClick,
delete cur._sliderMouseUpNowEl,
s)
return !0;
if (AudioUtils.isClaimedAudio(o) || o.isReplaceable) {
var r = AudioUtils.getAudioExtra(o)
, l = r.claim;
if (l)
return void (hasClass(i, "no_actions") || o.isInEditBox || showAudioClaimWarning(o, l, AudioUtils.replaceWithOriginal.bind(AudioUtils, i, o)))
}
if (o.isPlaying)
this.pause();
else {
var n = AudioUtils.getContextPlaylist(i);
this.play(o.fullId, n.playlist, o.context || n.context),
cur.audioPage && cur.audioPage.onUserAction(o, n.playlist)
}
AudioUtils.onRowOver(i, !1, !0)
}


Ставим брейкпоинт на первую инструкцию и нажимаем на кнопку. Входим в режим отладки и начинаем выполнять код по шагам.

Видим, что переменная o через несколько шагов содержит кучу полезной информации: исполнитель, название, хэши, всякие айди. Но не содержит главного свойства — url.
Идем дальше, выходим из toggleAudio(), попадаем в файл common.js в функцию, работающую с эвентами. Ага, значит ссылку мы получим асинхронно, надо бы посматривать на сетевую активность, что ж, шагаем дальше. Через n шагов замечаем, что во вкладке network появляется интересный запрос:

Request URL:https://vk.com/al_audio.php
Request Method:POST

Form Data:
act:reload_audio
al:1
ids: список id вида %user_id%_%track_id%, которые нужно обновить

И не менее интересный ответ:

4089188939145<!><!>0<!>6854<!>0<!><!json>[[456239119,%my_id%,"https:\/\/vk.com\/mp3\/audio_api_unavailable.mp3?extra=ofvLohaZvtDKnOPmEtHWl2rJCLLMrJiZy1i4D3blohn4AZLflLqZtMn3utbJmeTrCdq2Be1LyJ1HDvqTBKnUne8YrJfzzKrVENKXzL9JmMHgEgz3u3nbDwfuBMDiywLJBOrfl2fQwJDRmvrFzwDbwtGWvwThDxy6lxLHt1KOlvDODhbTAgjOzffOzdvTBOvOms9nvO9Ix1bxrNqUwgnfAfLWnwfLDLb0CLLxAvCVr2r4ExbHzhPTlKS2p3zcodu3yxm4Ea#CWS1mZi","Сон смешного человека ","Ф.М. Достоевский",4705,0,0,"",0,2,"","[]","6adb4186ee0c1d3ad0\/5102a312745ae505a7\/08eb0e4bd407e74e76\/d313ec4b6051942649\/","",[]],[456239118,%my_id%,"https:\/\/vk.com\/mp3\/audio_api_unavailable.mp3?extra=AdbkuuLOywjuou0Zme1yrdzJsI9Tm2qYvIO2AJaWnMnIztKOzgLxmMfbu3rgyJ8Tme5MBNrKlMLpChPIBLLFngjvu3zZAxztuOXJztfgrK9vq1rznLCYDJznBMrMCMT4rO9PytD3oc5kAhyYm1jMmZeZlxqZsKfWyKO9DNGUmvfuBtfOudjXrvbmyZLVltvICvPIver5zg5Zm2jWmJvWsue5nuXWzgPnBZq6l2n3x30OCgCVC2SVmxjqzvD6Egrlnc1zyq#CWSYmdC","автостопом в москву","црвених цветова",359,0,0,"",0,18,"","[]","57c59cffa93d47effa\/836d457cff34e02fa0\/6374a8e457c763a8c6\/96db3ddc8c210b1fb0\/","",[]],[456239117,%my_id%,"https:\/\/vk.com\/mp3\/audio_api_unavailable.mp3?extra=AgDYnY1TmwmOm2vTos5Ylu9Juwzkugv4zMzZyJbVlKjcqI9LB2vdzhe6DufVqY9KA1uZy3bfnhm4AgDOAwHIzMDztMTxsLjHn2K9veXuttvKq2fxogTWxY1fzJvumJrADLDlCdnLAv8UAfPiB2zxEKTrttLTrtK2ntrLCLnOww5rtI1Rq2vzsgr2vMnYp1P5BeOOx3rIEs8WBI10yLntCNzOCKrLBtznBMzRC29ewMOOC3uTueuYl29OztnWDhCXoffz#CWSYntC","Sal sér hon standa (Völuspá, 64-66)","Nytt Land",272,0,0,"",0,82,"","[]","4881448c55978a3374\/40a707901f551a4572\/778fe59467e6a629a9\/02a308905303098496\/","https:\/\/pp.userapi.com\/c837628\/v837628453\/829d0\/kLoB-0G_r78.jpg,https:\/\/pp.userapi.com\/c837628\/v837628453\/829cf\/C39pJ5b-t-w.jpg",80],[456239116,%my_id%,"https:\/\/vk.com\/mp3\/audio_api_unavailable.mp3?extra=l1yUmI1MCc8Vsxq2qxHYoM1Ku2i9C1y\/EdzWzZfADhrpDgGYrwvJwwTRtZzHDwL3A2HZqKXXrOfHtZDVDKzZn1zIrKLJD3PVBKqOzxLylKDjvZuYqKf5qLG3rhn4nJnHs1rlt1PUy29mCvLuuxD6DJHJAtGXvNfjrMzkt29Wme93mKuWze55x1PotO01lMqZnuHfzJLgBM1Jluzqogvkr3KYs1fNmtn6qODYyx0XnxDZDNnvvO9Lsgn0tdrKDc9Kowm2#CWSOmJy","After Dark "," Mr.Kitty",351,0,0,"",0,18,"","[]","353d934506a14abed5\/5745fb63e4e5f4abb4\/2ed8c9b81df35317d7\/01404a5db986cf16b8\/","",[]],[456239115,%my_id%,"https:\/\/vk.com\/mp3\/audio_api_unavailable.mp3?extra=mJfWyY1SBMm\/m1HYDc5YzgO5BwvdndC5nZDyvNzWyMvsEgfwyMvmsJzXm2fqEhq5mJvXvw50qIO4xZKTEefVsxq3yMfkltLpnJvWzfDrCZHgywiXEgzZqwntsJvMn21Nss9psKDkBKHKlY1LzI1vlJPyEuu3l3nyEhjsBNuWAhrlq3rezZfxmJn4A2zwtZbowhq3B1CWlZe4ytHZnhzhu19Lt29fvJDkCfLOzgvewI43rtjWmd1YBKLysOe2uMfKztbr#CWSZmJG","Storm","Godspeed You! Black Emperor",1352,0,0,"",0,34,"","[]","81b9d46c10d9df8d03\/5299d303c627944df7\/5ec696a0453d27253e\/ce7a1e0600cff40c53\/","",[]]]<!><!bool><!>7212f741260c90ab47

Понимаем, что это json, распаковываем

Это сообщение отредактировал VampirBFW - 31.10.2017 - 11:01

Как быстро и просто скачать плейлист с Вконтакте
 
[^]
VampirBFW
31.10.2017 - 11:01
Статус: Offline


Поварствующий радиоуправляемый сисадмин

Регистрация: 20.02.10
Сообщений: 9895
Отлично, теперь у нас есть хоть какая-то ссылка, но выглядит она не очень рабочей, что делать дальше?

Расшифровываем ссылку

Шагаем по скрипту дальше и понимаем, что ничего не выходит, на каком-то этапе ссылка просто превращается из audio_api_unavailable в ссылку на mp3. Значит где-то что-то происходит!
Но где именно? В одной из функций setUrl() вызывается функция с говорящим именем audioUnmaskSource()

Код функции
function i() {
return window.wbopen && ~(window.open + "").indexOf("wbopen")
}
function o(t) {
if (!i() && ~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--; )
o[a] = (e += e * (a + i) / e) % i | 0
}
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
},
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("")
}
}
}


Ставим брейкпоинт на o(t) и смотрим, что приходит и что уходит. t — наша ссылка вида audio_api..., в ?extra= содержатся два параметра. Насколько я понял, один содержит зашифрованную ссылку, а второй — это что-то вроде ключа. Можно зареверсить алгоритм, понять, как именно он все это шифрует, а можно просто вызвать o('https://...audio_api_...'). Так я и решил сделать, и получил на выходе прямую ссылку на mp3

Получаем зашифрованные ссылки

Расшифровывать ссылки научились, метод для получения зашифрованной ссылки знаем. Как же нам теперь получить айди, которые нужно передать методу, возвращающему зашифрованные ссылки? Идем смотреть сетевую активность. Как мы поняли ранее, взаимодействие с audio API происходит через al_audio.php. Ставим фильтр на данный запрос, загружаем страницу с аудиозаписями заново и видим уже новый запрос

Request URL:https://vk.com/al_audio.php
Request Method:POST
Status Code:200
Form Data:
access_hash:
act:load_section
al:1
claim:0
offset:30
owner_id:my_id
playlist_id:-1
type:playlist

И в ответ получаем большой json в том же виде, что и раньше, который содержит данные о плейлисте. Поле offset отвечает за смещение, начиная с которого, мы будем получать данные о плейлисте. Кроме того, ответ содержит полезные данные: поля hasMore и nextOffset.

Собираем все вместе

Мы знаем как получить данные о плейлисте, как получить зашифрованные ссылки и как их расшифровать. Осталось собрать все воедино


Вот так легко и просто можно скачать всю нужную Вам музыку.

как это сделал савелий журавлев.

Это сообщение отредактировал VampirBFW - 31.10.2017 - 11:02
 
[^]
Rents
31.10.2017 - 11:01
31
Статус: Offline


Дворянин в 0,5 поколении

Регистрация: 31.01.09
Сообщений: 681
я конечно понимаю,что ТС админ.Но если ты хотел таким чайникам,как я,подсобить,то я понял только слова "вечером" и "аудиокнига".
 
[^]
Chasm
31.10.2017 - 11:02
8
Статус: Offline


Optimus Prime

Регистрация: 29.10.13
Сообщений: 1114
А можно я не буду это делать? Пожалуйста.
 
[^]
marlaTs
31.10.2017 - 11:02
4
Статус: Offline


цветок

Регистрация: 8.07.13
Сообщений: 2766
так никто же не сидит вконтактике и телевизоры все 5 лет назад выкинули в окно.
 
[^]
barney
31.10.2017 - 11:03
15
Статус: Offline


комментатор гифкофил

Регистрация: 28.05.15
Сообщений: 1544
бля открыл Пост и у меня всё зависло нахуй

 
[^]
AleXXX82
31.10.2017 - 11:03
5
Статус: Offline


Статус заблокирован

Регистрация: 2.02.16
Сообщений: 1039
Цитата
Как быстро и просто скачать плейлист с Вконткте


Ну в принципе понятно все стало alik.gif

Это сообщение отредактировал AleXXX82 - 31.10.2017 - 11:04

Как быстро и просто скачать плейлист с Вконтакте
 
[^]
IlyaFF
31.10.2017 - 11:03
5
Статус: Offline


Юморист

Регистрация: 31.01.14
Сообщений: 441
Так обычно Сотону вызывают.
 
[^]
Bu3uTeP
31.10.2017 - 11:04
3
Статус: Offline


Весельчак

Регистрация: 12.02.13
Сообщений: 162
Я не много прихуел от такого расклада, можно я не буду быстро скачивать плейлист.

Отправлено с мобильного клиента YAPik+
 
[^]
anubbis
31.10.2017 - 11:05
1
Статус: Offline


Юморист

Регистрация: 3.03.12
Сообщений: 444
Я сломал два пальца и все три руки.
 
[^]
Tpuдевятый
31.10.2017 - 11:05
4
Статус: Offline


Ярила

Регистрация: 29.06.14
Сообщений: 1123
Тот случай, когда комментарии интереснее самой новости
 
[^]
Himer
31.10.2017 - 11:06
4
Статус: Offline


Юморист

Регистрация: 17.09.13
Сообщений: 400
Круто! А кресло компьютерное мне можешь починить, чтоб не скрипело?
 
[^]
ahsanm
31.10.2017 - 11:07
7
Статус: Offline


Весельчак

Регистрация: 9.01.15
Сообщений: 147
ТС "Вот так легко и просто можно скачать всю нужную Вам музыку. " это значит, что пользователю достаточно нажать одну кнопку. Вот это будет легко и просто, а в этой статье нихера не просто. Я бы больше сказал, что из этой статьи вообще не следует вариант скачивания музыки.

Это сообщение отредактировал ahsanm - 31.10.2017 - 11:08
 
[^]
Minzdraw
31.10.2017 - 11:09
0
Статус: Offline


ЗамкадышЪ

Регистрация: 7.10.11
Сообщений: 397
Очень СЛОЖНААААаа) проще через расширение по 1 песенке выкачать)...

Это сообщение отредактировал Minzdraw - 31.10.2017 - 11:09
 
[^]
Hanglider
31.10.2017 - 11:09
7
Статус: Offline


Ярила

Регистрация: 3.01.15
Сообщений: 2491
bravo.gif Утер слезу. Мне понравилось. Честно!
Но потом вспомнил, что у меня есть DownLoadHelper на случай что надо какой-то поток мультимедиа дернуть с сайта.

Но, блин.. Ты красиво сделал. Чувствуется профи.

Это сообщение отредактировал Hanglider - 31.10.2017 - 11:10
 
[^]
moodween
31.10.2017 - 11:12
1
Статус: Offline


Бля Буддист

Регистрация: 4.07.14
Сообщений: 1399
Прости, дружище! :)

如何他妈的整个世界他妈的,而不是错误!
 
[^]
VampirBFW
31.10.2017 - 11:14
1
Статус: Offline


Поварствующий радиоуправляемый сисадмин

Регистрация: 20.02.10
Сообщений: 9895
Цитата (moodween @ 31.10.2017 - 11:12)
Прости, дружище! :)

如何他妈的整个世界他妈的,而不是错误!

Простите, но мы тут музыку качаем, а не занимаемся сексом с миром без ошибок.
 
[^]
moodween
31.10.2017 - 11:22
1
Статус: Offline


Бля Буддист

Регистрация: 4.07.14
Сообщений: 1399
Цитата (VampirBFW @ 31.10.2017 - 11:14)
Цитата (moodween @ 31.10.2017 - 11:12)
Прости, дружище! :)

如何他妈的整个世界他妈的,而不是错误!

Простите, но мы тут музыку качаем, а не занимаемся сексом с миром без ошибок.

Немного не так.

Ты выебал весь окружающий мир и не ошибся :)
А ведь реально, зачем нужен Гитхаб, гуглькод и прочие фрикхабы....

Когда есть ЯП!

Это сообщение отредактировал moodween - 31.10.2017 - 11:24
 
[^]
Аквариумист
31.10.2017 - 11:28
1
Статус: Offline


Весельчак

Регистрация: 27.01.15
Сообщений: 186
Рыбки уснули в пруду... !!! И не проснулись!!!!
 
[^]
Инсульт
31.10.2017 - 12:14
0
Статус: Offline


Балагур

Регистрация: 18.03.14
Сообщений: 850
Так обычно потом платить биткоинами за расшифровку просят...
 
[^]
ZMEELOV
31.10.2017 - 12:33
2
Статус: Offline


Приколист

Регистрация: 2.05.16
Сообщений: 301
Спасибо ТС
Охуительно просто и доступно обьяснил
Скачал все плейлисты..наслаждаюсь музыкой теперь cheer.gif brake.gif cheer.gif
 
[^]
Wait
31.10.2017 - 12:42
1
Статус: Offline


Хохмач

Регистрация: 8.11.13
Сообщений: 646
хаброеб
 
[^]
Woodcutter
31.10.2017 - 16:11
0
Статус: Offline


Ярила

Регистрация: 6.07.17
Сообщений: 1604
Тс, хоть бы для дилетантов в программировании объяснил бы по человечески. Непонятно же ни хрена.
 
[^]
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии. Авторизуйтесь, пожалуйста, или зарегистрируйтесь, если не зарегистрированы.
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей) Просмотры темы: 5360
0 Пользователей:
[ ОТВЕТИТЬ ] [ НОВАЯ ТЕМА ]


 
 



Активные темы








Наверх