Python Dynamic Playlist Script for SHOUTcast Transcoder (for Linux)

If you want to provide music to a SHOUTcast server directly from the same server (instead of streaming it to the server from you PC) then SHOUTcast Transcoder is your weapon of choice.

However, out-of-the-box the SHOUTcast Transcoder supports only the playback of static playlists. If you, however, like me want to stream music from a FTP directory where the contents constantly change, you will find the rigid concept of static playlists quite unhandy. Although there are some webapps that support the server-side management of music content for the SHOUTcast transcoder (like Centova Cast), these are expensive and overkill for the above mentioned purpose.

Therefore, I wrote a script in Python that provides the mentioned functionality. Additionally, it can mix in a jingle now and then. Download the fully commented dynamicPlaylist.py script.

You can also join the discussion in the Winamp forum.

Posted in python, SHOUTcast Tagged with: linux, music, python, shoutcast, ubuntu
  • This Is exactly what I was looking for nice one 🙂

    I have a question though im not very well up on scripting will this script run itself every day or do I need to set some type of a cron job ?

    For instance will the script run itself each time i add a new track to my music folder or will i need to run it manually each time ?

    Thanks

    James

  • the shoutcast transcoder executes the script automatically (see line 13 of the script dynamicPlaylist.py). therefore, if your shoutcast setup (including the transcoder) runs, you will not need a cronjob or anything else. if you add new music to your folder and want to trigger a refresh of the playlist, you will need to “delete the file called ‘position’ in the baseDirectory” (see line 15 of dynamicPlaylist.py).

    if the script does not work for you or you have additional thoughts, drop me a line!

    cheers

  • J-B

    Hallo,

    so ganz verstehe ich das Script nicht. Es erstellt zwar eine Dynamische Playlist mit nur 5 Songs, obwohl weit ĂĽber 1000 mp3s drin sind.

    Des weiteren wird keine neue Playlist erzeugt wenn ich “baseDirectory+”position”” lösche. Selbst wenn die Playlist zu Ende ist, wird sie nicht von vorne abgespielt, es kommt die Fehlermeldung:

    Traceback (most recent call last):
    File “/home/musik/musik/playlist1/dynamicPlaylist.py”, line 122, in
    buildAndSaveRandomPlaylist()
    File “/home/musik/musik/playlist1/dynamicPlaylist.py”, line 85, in buildAndSaveRandomPlaylist
    jingle = jinglesDirectory + shuffledJingles[int(random()*len(shuffledJingles))]
    IndexError: list index out of range
    2013-05-29 11:42:18 E msg:[PLAYLISTMGR] runRemoteApp WEXITSTATUS() == 1 [/usr/bin/python /home/musik/musik/playlist1/dynamicPlaylist.py 3]

    Ne Idee was ich falsch mache?

  • hi,
    leider kann ich dir bei dem problem nicht helfen. aber offensichtlich scheint bei dir was bei der funktion “buildAndSaveRandomPlaylist()” nicht zu funktionieren, sonst wäre initial wohl die playlist länger als fĂĽnf lieder. du kannst allerdings versuchen durch loggen herauszubekommen, wo das problem ist. ich wĂĽrde mal shuffledMusicFiles in zeile 76 loggen per
    syslog.syslog(“shuffledMusicFiles: “+shuffledMusicFiles+” length: “+str(len(shuffledMusicFiles)))
    das musst du dir dann im systemlog anschauen (keine ahnung auf welchem os du bist). danach musst du dich dann entsprechend durchhangeln.

    mehr kann ich dir leider ferndiagnostisch auch nicht sagen…

  • od

    This is what the transcoder came back with and said playlist empty at the end…
    [code]
    2014-11-21 07:47:41 I msg:[MP3ENC] 1855295717/44100/2/64000 MP3 setup complete
    Traceback (most recent call last):
    File “/usr/local/shoutcast/playlists/oldgeneration.py”, line 119, in
    position = printNextSongs(position, numTracks)
    File “/usr/local/shoutcast/playlists/oldgeneration.py”, line 36, in printNextS ongs
    nextMp3FileExists = checkIfMusicFileExists(entries[position%len(entries)][:- 1])
    ZeroDivisionError: integer division or modulo by zero
    2014-11-21 07:47:41 E msg:[PLAYLISTMGR] runRemoteApp WEXITSTATUS() == 1 [/usr/bin/python /usr/local/shoutcast/playlists/oldgeneration.py 3]
    2014-11-21 07:47:41 I msg:[PLAYLISTMGR] Deactivating playlist=playlist id=-1
    2014-11-21 07:47:41 I msg:[UVOX2] 727555666 Sending Ultravox 2.1 authe ntication
    2014-11-21 07:47:41 I msg:[UVOX2] 727555666 Mime type
    2014-11-21 07:47:41 I msg:[UVOX2] 727555666 Broadcast setup
    2014-11-21 07:47:41 I msg:[UVOX2] 727555666 Negotiating buffer sizes
    2014-11-21 07:47:41 I msg:[UVOX2] 727555666 Negotiated buffer size is 160KB
    2014-11-21 07:47:41 I msg:[UVOX2] 727555666 Negotiating payload sizes
    2014-11-21 07:47:41 I msg:[UVOX2] 727555666 Negotiated payload size is 16377
    2014-11-21 07:47:41 I msg:[UVOX2] 727555666 Configuring ICY-NAME [Brik ouri Radio]
    2014-11-21 07:47:41 I msg:[UVOX2] 727555666 Configuring ICY-GENRE [Mis c]
    2014-11-21 07:47:41 I msg:[UVOX2] 727555666 Configuring ICY-URL [http: //www.brikouri.com]
    2014-11-21 07:47:41 I msg:[UVOX2] 727555666 Configuring ICY-PUB [0]
    2014-11-21 07:47:41 I msg:[UVOX2] 727555666 Flush metadata
    2014-11-21 07:47:41 I msg:[UVOX2] 727555666 Standby
    2014-11-21 07:47:41 I msg:[UVOX2] 727555666 Streaming
    2014-11-21 07:47:43 W msg:[DECODE] Playlist is empty
    2014-11-21 07:50:15 I msg:[MAIN] SIGWINCH; Next Song
    [/code] any fix ?

  • judging from what i see, i’d guess that ‘playlistFile’ is empty and i have forgotten to check that. before calling ‘nextMp3FileExists = checkIfMusicFileExists…’ you check whether len(entries) > 0.

    (if you think that playlistFile should not be empty, you can also have a look at the playlist file in the OS. but if it is empty, looking at this file will probably not help you any further…)

  • od

    I looked in that folder, the playlist file is created, but it is empty. I am not a python guy, where do I check for empty? What about the error messages? Does it work for you or are you getting the same errors? This would be a cool list. Thanks for the reply…