Скачиваем список песенок с Soundcloud
Морально-юридический вопрос
Я понимаю, что это хак. Мне даже немного стыдно, хотя я ничего не ломаю, эксплоиты не использую. Если сюда набежит кто-то из Soundcloud, то я заранее перед этим человеком извиняюсь =)
С чего началось
В последнее время я немного подсел на вот такие dubstep-подборки.
Но
- Не всегда удобно гонять с ютуба (особенно без интернета).
- Хочется песенки из всех этих подборок разом в перемешанном виде играть, составляя плейлисты на 3-4 часа.
Выход? Скачать эти песенки и положить на проигрыватель (у меня, кстати, вот такой).
Немного входных допущений
Ну, во-первых, названия всех нужных мне песенок уже написаны. С шазамом я тут не интегрируюсь. То есть входными данными у меня является файл со списком названий песен.
Во-вторых, все эти песни являются ремиксами ремиксов и потому с большой вероятностью доступны для бесплатного прослушивания на Soundcloud. Песни, которые отсутствуют на Soundcloud, я готов пропустить.
Чего я жду от программы
Есть список песен, который я руками скопипастил из описания на ютубе. В этом списке каждая строка — название песни (полное, с исполнителем). Этот файл я скармливаю своей программе, которая скачивает мне все эти песни в папку.
Скачиваем песни
Получаем ссылку на Soundcloud
Чтобы скачать песню на Soundcloud, надо её сначала найти. Так как в современном мире есть куча поисковиков, то заниматься написанием своего я не решился.
Сналача я посмотрел на Google. У него есть какой-то Custom Search, но я не особо понял, как его использовать, да и там надо и приложение регать и ещё и денежку вроде как платить, если запросов в день больше 100. Короче, не моя история.
Потом я рещил обратить внимание на одну нидерладнскую компанию. Там была та же история, что и с гуглом — надо регаться и потом с некоторой вероятностью денежку платить. Снова мимо.
Но, хвала опенсорцу и безумному сообществу, есть DuckDuckGo.
DuckDuckGo
Сначала я нашёл Instant Answer API. Отличная штука, подходит. Выдаёт красивые json’ы (не надо парсить DOM), ограничений нет, регаться не надо. Но, увы, использовать это API не получилось, потому что “из-за ряда юридических проблем Instant Answer API не может осуществлять глубокие запросы”. А мне именно они и нужны…
Но не беда. Оказалось, что DuckDuckGo умеет отдавать отрендреный html (а не кусок обфусцированного js, как у Гугла или Яндекса), поэтому не надо использовать никаких headless-браузеров — достаточно просто попарсить DOM.
Получить страницу можно по ссылке https://duckduckgo.com/html/?q=текст запроса.
Я сделал допущение, что первый результат — то, что нужно.
После того, как получили текст запроса, достаточно найти нужную ссылку в DOM. Для этого нужно выгрести элемент с классом result__a
и href
со ссылкой на Soundcloud. Можно, конечно, сделать это попарсив дом, но я обошёлся регуляркой. Например, такой: /class="result__a".+href=".+(https.+soundcloud\.com.+)"/
(здесь первый capture как раз даст нам нужную ссылку).
Готово! Осталось только скачать песенку с Soundcloud.
Качаем песенку с Soundcloud
Тут начинается самое интересное.
Есть два способа получить песенку с Soundcloud:
- Постучаться к ним в API. Снова история с ограничением, регистрацией приложения и прочим.
- Забрать её так, как её проигрывает браузер.
Я, как адепт Emacs (на момент написания этой статьи) считаю, что всё можно похачить. Не взломать, так как это не вопрос информационной безопасности, а просто воспользоваться тем, что доступно, своим, нужным для меня способом. Поэтому я решил воспользоваться вторым способом получения песни — похачить Soundcloud.
Так как плеер Soundcloud — поделка на js, а не тег <audio>
, просто дёрнуть из тела страницы и скачать не получится. Но ведь должен же как-то плеер идентифицировать песню? Вопрос в том, как получить этот идентификатор.
Получаем идентификатор песни
Для начала скачиваем текст страницы песни на Soundcloud (ссылка у нас уже есть).
Эмпирически я выяснил, что выдернуть идентификатор можно из ссылок “share” где-то наверху страницы. Регулярка получилась примерно такая: /api.soundcloud.com%2Ftracks%2F([0-9]+)/
. В результате мы получаем некоторый набор цифр, который нам и нужен (из первого capture).
Получаем идентификатор клиента
У Soundcloud есть клиенты. Эти клиенты имеют право проигрывать музыку. Либо это стронний клиент (регистрация на доступ в API и создаёт такого клиента), либо собственный (soundcloud’а), который используется в браузере. Мне нужен был последний.
Идентификатор этого клиента есть в файле /assets/app-a6bbad0-a3829ac-3.js
(хеш, конечно же, может быть любой).
- Для начала выгребем ссылку на это файл из тела страницы регуляркой
/(https?:\/\/[^\/]+\/assets\/app[^\.]+\.js)/
. - Потом качаем его.
- И затем в нём ищем идентификатор клиента вот такой регуляркой:
/client_id:"([0-9a-zA-Z]+)"/
.
Ищем ссылку на песенку по идентификатору
Тут всё ещё интереснее, потому как все ссылки я выгреб из инспектора браузера, а допущения в этом пункте настолько сильны, что способ может сломаться в любой момент.
Из инспектора я выгреб ссылку https://api.soundcloud.com/i1/tracks/291177064/streams?client_id=Z4iXVvmpbal2YXoYjBZVHxCJjcifbljN
. В этой ссылке 291177064
— идентификатор песни, а Z4iXVvmpbal2YXoYjBZVHxCJjcifbljN
— идентификатор браузерного клиента Soundcloud.
По ссылке (которую собираем для каждой песни) мы получаем json такого вида:
{
"http_mp3_128_url": "https://cf-media.sndcdn.com/Xlvvl47X5snD.128.mp3?Policy=eyJTdGF0ZW1lbnQiOlt7IlJlc291cmNlIjoiKjovL2NmLW1lZGlhLnNuZGNkbi5jb20vWGx2dmw0N1g1c25ELjEyOC5tcDMiLCJDb25kaXRpb24iOnsiRGF0ZUxlc3NUaGFuIjp7IkFXUzpFcG9jaFRpbWUiOjE1MTE0MjI4OTd9fX1dfQ__&Signature=ljJuP5xFAg-63FUBENz9kdDTAUPhQ5dZXKR7Oly92KRI01X50w55~Umnm8Y2OzPmupUKX8XFUwFtGRLx5cxNGY8apK44PKGqpojS9oPl~y9QvrD1~x2~1IEUxiX6ekl-vVT8O~x3NlfQZD-RuBuaa8w6tUsOayJKb2SyGsWlf3tWywj5MIKKvIQj7EPbDiwwKm7Pjykiu4EOCJc~7Zaoh-BYZSEmn7Sf~1lRXuMYThjTIkyLEPXS3XxIcz8R0KE5UqlWzX-gJF7qE7ONk5RGiojEM6kitH-Tjo7PYhGcP474H4dNGSfG9DgThshedG4U4o6OgeKgzbQcaR40cieZQA__&Key-Pair-Id=APKAJAGZ7VMH2PFPW6UQ",
"hls_mp3_128_url": "https://cf-hls-media.sndcdn.com/playlist/Xlvvl47X5snD.128.mp3/playlist.m3u8?Policy=eyJTdGF0ZW1lbnQiOlt7IlJlc291cmNlIjoiKjovL2NmLWhscy1tZWRpYS5zbmRjZG4uY29tL3BsYXlsaXN0L1hsdnZsNDdYNXNuRC4xMjgubXAzL3BsYXlsaXN0Lm0zdTgiLCJDb25kaXRpb24iOnsiRGF0ZUxlc3NUaGFuIjp7IkFXUzpFcG9jaFRpbWUiOjE1MTE0MjI4OTd9fX1dfQ__&Signature=OSNoc56u8svEduVUSpsJwCRV3FrshVxFLSafaHEN4PgLzu0klPTVTUQtvIi6fJUvY3vL1LbaW-4wH1VxIEqNSB5WEHK-~-2Xwy6a9RuDeWDerNQCyP6MjkA~KbgLGW0VRBHW2CR1PzfhNubG6Irm1vAzEbKiWY7fzy7EI3ngN16~HjAgJdwRbg~n7oM9eOjj94PJD5EChQcMTl2e1kjRcBB-XkcDCQKxXCIMXuIcYAVVxO1YU-V40w373UmALyfat-ggfLIErebHx4a85dfk~h4YVYntmXPkdLiNMJHydA2-IBrm967vDS8EbHm07OEDDvt2XOMRooMLPqGerwKIXg__&Key-Pair-Id=APKAJAGZ7VMH2PFPW6UQ",
"hls_opus_64_url": "https://cf-hls-opus-media.sndcdn.com/playlist/Xlvvl47X5snD.64.opus/playlist.m3u8?Policy=eyJTdGF0ZW1lbnQiOlt7IlJlc291cmNlIjoiKjovL2NmLWhscy1vcHVzLW1lZGlhLnNuZGNkbi5jb20vcGxheWxpc3QvWGx2dmw0N1g1c25ELjY0Lm9wdXMvcGxheWxpc3QubTN1OCIsIkNvbmRpdGlvbiI6eyJEYXRlTGVzc1RoYW4iOnsiQVdTOkVwb2NoVGltZSI6MTUxMTQyMjg5N319fV19&Signature=AjcgtA-xawQQKJB3jlUFcT~7~kPb-M2vmmGPSBeLQ6LPZF-slEcf0xpr6hhNRSZah32Q5fzyE2U~ntuIMvAQ7BfgEx8l~ZFK~p5487kJV5~UZb5E-AodmzETm6O9tihIm812X1R1tgutK0UpIII4ovYdT1~JwRqRfqxBW71ZwbM-88VKndln424PgeFWCHRJLlJQaCZ0bU8myOQ3jRyXgN2ADgn3TmwzBTmcoXQhvSTyc7EevS8tk-0GPdTuNsNIhs0pVoLj2I-MbA8~UdlimMdj-SYbz3ycorwOsMUFkJBIC5HhygT0BQt1z-sP~FY2wijcW7JPgiWjS5ceEJERMA__&Key-Pair-Id=APKAJAGZ7VMH2PFPW6UQ",
"preview_mp3_128_url": "https://cf-preview-media.sndcdn.com/preview/0/30/Xlvvl47X5snD.128.mp3?Policy=eyJTdGF0ZW1lbnQiOlt7IlJlc291cmNlIjoiKjovL2NmLXByZXZpZXctbWVkaWEuc25kY2RuLmNvbS9wcmV2aWV3LzAvMzAvWGx2dmw0N1g1c25ELjEyOC5tcDMiLCJDb25kaXRpb24iOnsiRGF0ZUxlc3NUaGFuIjp7IkFXUzpFcG9jaFRpbWUiOjE1MTE0MjI3MjZ9fX1dfQ__&Signature=MMKxbBT-pmgHRMV4x5aRdr21gxRnxyfGqcZ452JTTA8C6fy6c0s-VaVtYrr39EtJlEws5FyUiMPvUA9cgNBy-Ms0ogF5zpKinyCanusXUC~QvhMGDjjmTD2DdDk0ehZcv3cDJnBcObp1Rdm1qkiPVxhuDMCuwGAp10ea2~qF7q2N6AJAB0t8nljJe-uRkt~6IgCkUK-UywWlZmZQYAUyDnR8QLORzw5vGsCSXipYN2jSqQK~RIwuCCoX4qXFODdLSIzhIoyMJ-eeFlhF9fcdqNcYn93h5sinTxZOung4AZDENkdeEDtmEMXA5LobO1eR2os0QTgk6zVFGNn1eoDk8g__&Key-Pair-Id=APKAJAGZ7VMH2PFPW6UQ"
}
В этом json’е все ссылки ведут уже на наши целевые файлы. Осталось только выбрать нужный формат и скачать. Я пользую http_mp3_128_url
.
Готово! Можно качать песенку, сохранив с именем файла из списка, потому как в json’е имена файлов не очень хорошо читаются.
Ну и остальное
Описывать построчный разбор файла со списком песенок я не буду, ибо задача тривиальна. Как и скачивание файлов. Это можете и сами сделать =)
Результат?
Песенки скачаны, можно копировать на проигрыватель и слушать =)
Готово, вы восхитительны!
Как-нибудь выложу свой говнокод на elixir’е на Github Выложил свой говнокод на Github.