+ crutch, or download PLS playlists

    Hi Habrovtsy.
    I think not only I have a great playlist on More recently, I was puzzled by how to download music to listen to it offline. Soon I found a convenient service . And everything would be fine, but he can’t just pump out all the music at once. He offers us options:
    1. Give us a bunch of url so that we put the whole thing into the download manager, such as DownloadManager
    2. Save the playlist in m3u / pls that play url

    In the first case, we will have the file names 3ee56ab0933e.mp3. The ID3 tag will be in place ( UPD is not for all songs there is a correct ID3Tag), but you must admit, it’s inconvenient to open each song to see what it is
    In the second case, we have purely urls in the playlists, but the title of the song is right away.

    Since I didn’t want to watch files of the form 3ee56ab0933e.mp3, and also didn’t want to name all this manually, I sketched a tool on my knee that can read pls playlists and download music with 10 connections.

    Binary + source
    The compiled executable + source code (in Delphi) lies here

    How to use
    1. Scroll our VKontakte playlist to the bottom so that can get the full pls
    2. Choose to download the playlist:

    3. In the window that appears, copy the pls playlist to the clipboard:

    4. Paste this playlist into my utility in the box with the text Insert PLS text here:

    5. Click the Download button, and see how the music starts to download
    6. In the working directory of the program, if necessary, the VKMusic folder will be created. The folder name can be changed: the

    path can be absolute.

    If there is a daw in Allow skip files, then the program will check before downloading if there is a file with the same name on the disk, it will not download it.

    A very brief digression into the source code
    I am writing primarily for those who want to change the code for themselves.
    The program uses Virtual Treeview and Indy.
    untPLSparser.pas - parser of PLS ​​files. The module interface has one single function:
    function Parse(const text: string): TPLSItems;
    At the input - PLS playlist, returns an array of structures describing audio recordings (title + url + often track duration) This

    whole thing is converted to another TMusicList array described in untDownloadList.pas.
    TMusicList consists of TMusicItem and is needed in order to store information about the download status, as well as errors encountered.

    Next, the download process begins. 10 pre-created TDLThread threads whose implementation is in untDownloadThread.pas start downloading songs.
    Download is launched through TfrmMain.RunFreeDownload in untMain.pas.
    First, we get the index of the record that needs to be downloaded using the TfrmMain.GetFreeItem method. Then we check if we have a daw to skip files, then see if there is such a file, and if so, skip.

    In the process of downloading to callbacks
    DLProgress, DLError, DLComplete, DLTerminate
    events arrive where we actually update the information in TMusicItem, start a new download or report an error.

    Download streams work as follows.
    After creation, the thread waits for the download task in a loop:
          while (Url = '') do
            if Terminated then Exit;
            FInWork := False;
    as soon as there is Url to download - it starts downloading. Since Indy is a library on blocking sockets, there must be a mechanism to stop the download. I use the special EStopTask exception in the TidHTTP.OnWorkBegin, TidHTTP.OnWork, TidHTTP.OnWorkEnd callbacks, which allows me to actually abort the download at any time.

    If something went wrong, but we can process it correctly, and continue working, we process, we beat the incomplete file. If an exception occurs in the thread that we cannot handle (for example, AV), then according to the standard mechanism, the thread will be nailed and the exception object will be in FatalException. Therefore, in untMain.pas, I process OnTerminate, check the thread's exception object, and if it is, I throw an exception already in the main thread.


    That's all, thanks for reading. I am glad if my "crutch" suddenly turned out to be convenient for you.

    Also popular now: