Привет хабровцы.
Я думаю не только у меня большой плейлист на vk.com. Совсем недавно я озадачился тем, как бы выкачать музыку, чтобы слушать её оффлайн. Вскоре я нашел удобный сервис SaveFrom.net. И все бы ничего, да только выкачивать сразу всю музыку он не умеет. Он предлагает нам варинаты:
1. Дать нам кучу url, чтобы мы вставили все это дело в менеджер загрузок, типа DownloadManager
2. Сохранить плейлист в m3u/pls, которые играют по урл
В первом случае у нас имена файлов будут вида 3ee56ab0933e.mp3. ID3 tag будет на месте (UPD оказывается не для всех композиций есть корректный ID3Tag), но согласитесь, это неудобно, открывать каждую композицию чтобы посмотреть что это
Во втором случае — у нас чисто url-ы в плейлистах, но зато title песни есть сразу.
Поскольку наблюдать файлы вида 3ee56ab0933e.mp3 мне не хотелось, а так же не хотелось вручную все это именовать — я набросал на коленке тулзу, которая умеет читать pls плейлисты, и скачивать музыку в 10 коннектов.
2. Выбираем скачать плейлист:
3. В появившемся окне копируем pls плейлист в буфер обмена:
4. Вставляем этот плейлист в мою утилиту в поле с текстом Insert PLS text here:
5. Жмем кнопочку Download, и видим как начинает скачиваться музыка
6. В рабочем каталоге программы если надо — будет создана папка VKMusic. Имя папки можно поменять:
путь может быть абсолютным.
Если стоит галка в Allow skip files, то программа перед скачиванием будет проверять, если есть на диске файл с таким же именем, то качать его она не будет.
Программа использует Virtual Treeview и Indy.
untPLSparser.pas — парсер PLS файлов. В интерфейсе модуля одна единственная функция:
Все это дело конвертируется в другой массив TMusicList описанный в untDownloadList.pas.
TMusicList состоит из TMusicItem и нужен для того, чтобы хранить информацию о статусе скачивания, а так же возникших ошибках.
Далее начинается процесс загрузки. 10 заранее созданных потоков TDLThread, реализация которых находится в untDownloadThread.pas начинают скачивать композиции.
Скачивание запускается через TfrmMain.RunFreeDownload в untMain.pas.
Сначала получаем индекс записи, которую надо скачать с помощью метода TfrmMain.GetFreeItem. Затем проверяем, если у нас стоит галка пропускать файлы, то смотрим есть ли такой файл, и если есть — пропускаем.
В процессе скачивания в коллбеки
Скачивающи потоки работают следующим образом.
После создания поток ждет задачи на скачивание в цикле:
Если что-то пошло не так, но мы можем корректно обработать это, и продолжить работу, мы обрабатываем, недокачанный файл прибиваем. Если в потоке возникло исключение, которое мы не можем обработать (например AV), то согласно стандартному механизму — поток будет прибит, а в FatalException будет лежать объект исключения. Поэтому в untMain.pas я обрабатываю OnTerminate, проверяю объект исключения потока, и если он есть — то бросаю исключение уже в главной нити.
Вот собственно и все, спасибо за чтение. Рад если мой «костыль» вдруг оказался для вас удобным.
Я думаю не только у меня большой плейлист на vk.com. Совсем недавно я озадачился тем, как бы выкачать музыку, чтобы слушать её оффлайн. Вскоре я нашел удобный сервис SaveFrom.net. И все бы ничего, да только выкачивать сразу всю музыку он не умеет. Он предлагает нам варинаты:
1. Дать нам кучу url, чтобы мы вставили все это дело в менеджер загрузок, типа DownloadManager
2. Сохранить плейлист в m3u/pls, которые играют по урл
В первом случае у нас имена файлов будут вида 3ee56ab0933e.mp3. ID3 tag будет на месте (UPD оказывается не для всех композиций есть корректный ID3Tag), но согласитесь, это неудобно, открывать каждую композицию чтобы посмотреть что это
Во втором случае — у нас чисто url-ы в плейлистах, но зато title песни есть сразу.
Поскольку наблюдать файлы вида 3ee56ab0933e.mp3 мне не хотелось, а так же не хотелось вручную все это именовать — я набросал на коленке тулзу, которая умеет читать pls плейлисты, и скачивать музыку в 10 коннектов.
Бинарник + исходник
Откомпилированный экзешник + исходный код (на Delphi) лежит тутКак пользоваться
1. Прокручиваем наш плейлист вконтакте до самого низа, чтобы SaveFrom.net мог получить полный pls2. Выбираем скачать плейлист:
3. В появившемся окне копируем pls плейлист в буфер обмена:
4. Вставляем этот плейлист в мою утилиту в поле с текстом Insert PLS text here:
5. Жмем кнопочку Download, и видим как начинает скачиваться музыка
6. В рабочем каталоге программы если надо — будет создана папка VKMusic. Имя папки можно поменять:
путь может быть абсолютным.
Если стоит галка в Allow skip files, то программа перед скачиванием будет проверять, если есть на диске файл с таким же именем, то качать его она не будет.
Очень краткий экскурс в исходный код
Пишу в первую очередь для тех, кто захочет изменить код под себя.Программа использует Virtual Treeview и Indy.
untPLSparser.pas — парсер PLS файлов. В интерфейсе модуля одна единственная функция:
function Parse(const text: string): TPLSItems;
На входе — PLS плейлист, возвращает массив структур описывающих аудиозаписи (заголовок + урл + зачастую длительность трека)Все это дело конвертируется в другой массив TMusicList описанный в untDownloadList.pas.
TMusicList состоит из TMusicItem и нужен для того, чтобы хранить информацию о статусе скачивания, а так же возникших ошибках.
Далее начинается процесс загрузки. 10 заранее созданных потоков TDLThread, реализация которых находится в untDownloadThread.pas начинают скачивать композиции.
Скачивание запускается через TfrmMain.RunFreeDownload в untMain.pas.
Сначала получаем индекс записи, которую надо скачать с помощью метода TfrmMain.GetFreeItem. Затем проверяем, если у нас стоит галка пропускать файлы, то смотрим есть ли такой файл, и если есть — пропускаем.
В процессе скачивания в коллбеки
DLProgress, DLError, DLComplete, DLTerminate
прилетают евенты где мы собственно обновляем информацию в TMusicItem, начинаем новую загрузку или сообщаем об ошибке.Скачивающи потоки работают следующим образом.
После создания поток ждет задачи на скачивание в цикле:
while (Url = '') do
begin
if Terminated then Exit;
FInWork := False;
Sleep(1);
end;
как только есть Url для скачивания — он начинает загрузку. Поскольку Indy — библиотека на блокирующих сокетах — то должен быть механизм, чтобы остановить загруку. Я использую специальное исключение EStopTask в коллбеках TidHTTP.OnWorkBegin, TidHTTP.OnWork, TidHTTP.OnWorkEnd, что позволяет мне фактически прервать загрузку в любой момент.Если что-то пошло не так, но мы можем корректно обработать это, и продолжить работу, мы обрабатываем, недокачанный файл прибиваем. Если в потоке возникло исключение, которое мы не можем обработать (например AV), то согласно стандартному механизму — поток будет прибит, а в FatalException будет лежать объект исключения. Поэтому в untMain.pas я обрабатываю OnTerminate, проверяю объект исключения потока, и если он есть — то бросаю исключение уже в главной нити.
В заключение
Вот собственно и все, спасибо за чтение. Рад если мой «костыль» вдруг оказался для вас удобным.