Python script to randomise an m3u playlist

While I'm blogging scripts for playlist manipulation here is one I use in a nightly cron job to shuffle our playlists so that various devices playing from them have some daily variety. All disclaimers apply, it's rough and ready but WorksForMe (TM).

I have an entry in my crontab like this

0 4 * * * /home/colin/bin/playlist-shuffle.py -q -i /var/media/mp3/A_Colin.m3u -o /var/media/mp3/A_Colin_Shuffle.m3u

which takes a static playlist and produces a nightly shuffled version.

#!/usr/bin/env python
#
# Simple script to randomise an m3u playlist
# Colin Turner <ct@piglets.com>
# 2013
# GPL v2
#

import random
import re

# We want to be able to process some command line options.
from optparse import OptionParser

def process_lines(options, all_lines):
  'process the list of all playlist lines into three chunks'
  # Eventually we want to support several formats
  m3u = True
  extm3u = False
  if options.verbose:
    print "Read %u lines..." % len(all_lines)
  header = list()
  middle = list()
  footer = list()
  
  # Check first line for #EXTM3U
  if re.match("^#EXTM3U", all_lines[0]):     if options.verbose:       print "EXTM3U format file..."     extm3u = True     header.append(all_lines[0])     del all_lines[0]      loop = 0   while loop < len(all_lines):     # Each 'item' may be multiline     item = list()     if re.match("^#EXTINF.*", all_lines[loop]):
      item.append(all_lines[loop])
      loop = loop + 1
    # A proper regexp for filenames would be good
    if loop < len(all_lines):
      item.append(all_lines[loop])
      loop = loop + 1
    if options.verbose: print item
    middle.append(item)
            
  return (header, middle, footer)

def load_playlist(options):
  'loads the playlist into an array of arrays'
  if options.verbose:
    print "Reading playlist %s ..." % options.in_filename
  with open(options.in_filename, 'r') as file:
    all_lines = file.readlines()
  (header, middle, footer) = process_lines(options, all_lines)
  return (header, middle, footer)

def write_playlist(options, header, middle, footer):
  'writes the shuffled playlist'
  if options.verbose:
    print "Writing playlist %s ..." % options.out_filename
  with open(options.out_filename, 'w') as file:
    for line in header:
      file.write(line)
    for item in middle:
      for line in item:
        file.write(line)
    for line in footer:
      file.write(line)


def shuffle(options):
  'perform the shuffle on the playlist'
  # read the existing data into three arrays in a tuple
  (header, middle, footer) = load_playlist(options)
  # and shuffle the lines array
  if options.verbose:
    print "Shuffling..."
  random.shuffle(middle)
  # now spit them back out
  write_playlist(options, header, middle, footer)

def print_banner():
  print "playlist-shuffle"

def main():
  'the main function that kicks everything else off'
  
  usage = "usage: %prog [options] arg"
  parser = OptionParser(usage)
  parser.add_option("-i", "--input-file", dest="in_filename",
                    help="read playlist from FILENAME")
  parser.add_option("-o", "--output-file", dest="out_filename",
                    help="write new playlist to FILENAME")
  parser.add_option("-v", "--verbose",
                    action="store_true", dest="verbose")
  parser.add_option("-q", "--quiet", default=False,
                    action="store_true", dest="quiet")
                    
  (options, args) = parser.parse_args()
#  if len(args) == 0:
#      parser.error("use -h for more help")
  
  if not options.quiet:
    print_banner()
  
  shuffle(options)
  
  if not options.quiet:
      print "Playlist shuffle complete..."
  
 
if  __name__ == '__main__':
  main()

Follow me!

7 thoughts on “Python script to randomise an m3u playlist

  1. Justin says:

    This script looks like it does exactly what I'd like. I'm getting some errors when trying to run it, though.

    osmc@osmc:~$ ~/shuffler.py -q -i /home/osmc/.kodi/userdata/playlists/video/test.m3u -o /home/osmc/.kodi/userdata/playlists/video/test_Shuffle.m3u
    File "/home/osmc/shuffler.py", line 17
    'process the list of all playlist lines into three chunks'
    ^
    IndentationError: expected an indented block

    I don't know how to write scripts, so if you could give me a hand that'd be great!

    Justin

    1. Colin says:

      Justin,

      I tried to reply a moment ago and it seemed to get lost, so apologies if you get two replies!

      The fault is entirely mine, the way I had pasted the code into the blog and the syntax highlighter I was using didn't show the indentation in the code, which is critical in Python. In fact I just noticed this last Friday when showing some students.

      I have swapped over to a different highlighter and you should see the indentation, it even provides a button (hover over the area) to copy all the code to your clipboard.

      Let me know if you get success now or have any other problems.

      Thanks for the comment and the heads up.

      CT.

      1. Justin says:

        Thanks! Seems to be working great now.

        1. Colin says:

          Excellent :-).

          1. Justin says:

            I've added a guide to installing your script on the forums of the linux mediacenter distro that I use (OSMC). Thanks again for the code. =)

            https://discourse.osmc.tv/t/howto-run-nightly-script-to-randomize-playlists/8715

  2. Justin says:

    My python version:

    osmc@osmc:~$ python
    Python 2.7.9 (default, Mar 1 2015, 13:48:22)
    [GCC 4.9.2] on linux2

  3. Pingback: Python Script To Copy a Playlist and Linked Files | Proving the Obviously Untrue

Leave a Reply to Colin Cancel reply

Your email address will not be published. Required fields are marked *