#!/usr/bin/env python

###################################################################
#
# RandSong:
#   Reads a text file containing a list of tracks and randomly
#   chooses songs. The songs are copied to a destination directory.
#   Intended to be used with portable mp3/ogg players to get a
#   random sampling of music from a larger collection.
#
# Author: Mike Pilone <mpilone@slac.com>
#         http://www.slac.com/mpilone/projects/
#
# License: BSD
#          http://www.opensource.org/licenses/bsd-license.html
#
# Copyright: 2002 Mike Pilone
#
# Modified: 02/15/02 
#
# Changelog:
#   v0.1:
#       o Initial release
#
###################################################################



import string, sys, random
import os, shutil, stat, re

APP_VERSION = "0.1"

def loadPlaylist(playlist):
    "Loads the playlist from file into a list of strings"
    
    try:
        playlistFile = open(playlist, "r")
    except:
        print "Error opening file", playlist, ". Aborting..."
        sys.exit(0)

    lines = playlistFile.readlines()
    playlistFile.close()
    
    return lines
    
def copyFiles(songs, size, dest):
    "Copies files from the song list to the destination dir"
    
    # Generate a random number
    random.shuffle(songs)
    
    # While the total size is less than the max and we haven't gotten to the
    # end of the list, copy the file to the destination
    numCopy = 0
    totalSize = 0
    for song in songs:
        song = song[:-1]   # Trim return char
        filename = os.path.basename(song)
        
        # Check the file is valid. Sometimes playlists get out of date.
        if not os.path.isfile(song):
            print "WARNING:", filename, "doesn't seem to exist. Skipping..."
            continue
            
        st = os.lstat(song)
        
        if (st[stat.ST_SIZE] + totalSize <= (size*1024*1024)):
            print "\t\to", filename
            shutil.copy(song, dest)
            numCopy += 1
            totalSize += st[stat.ST_SIZE]

    return numCopy
            
def filterSongs(songs, songFilter):
    "Filters the list based on the regexp"
    
    prog = re.compile(songFilter)
    
    index = 0
    while index < len(songs):
        song = songs[index]
        
        if not prog.match(song):
            del songs[index]
        else:
            index += 1
    
    return songs
         
def printUsage(appName):
    print "RandSong v" + APP_VERSION
    print "Usage:", appName, "[-sf] <playlist> <destination>\n"
    print """  <playlist>\tThe playlist to load from
  <destination>\tThe destination directory to copy to
  -s <size>\tThe maximum total megabytes to copy [default: 30]
  -f <filter>\tA regular expression used to filter tracks [default: '.*']"""
    

def main():
    
    dest = ""
    playlist = ""
    songFilter = ".*"
    size = 30
    
    # Check the args
    index = 1
    while index < len(sys.argv):
        arg = sys.argv[index]
        index += 1
        
        if arg == "-s":
            size = int(sys.argv[index])
            index += 1
        if arg == "-f":
            songFilter = sys.argv[index]
            index += 1
        elif index == len(sys.argv):
            dest = arg
        else:
            playlist = arg

    if len(playlist) == 0 or len(dest) == 0:
        printUsage(sys.argv[0])
        sys.exit(0)

    # Make sure dest is valid
    if not os.path.isdir(dest):
        print "Error: Destination not a valid directory. Aborting..."
        sys.exit(0)
        
    print "RandSong v" + APP_VERSION + " initialized"
    
    print "\to Loading playlist from file."
    
    # We have the playlist, now load it
    songs = loadPlaylist(playlist)
    
    print "\to Playlist contained", len(songs), "unfiltered tracks."
    print "\to Filtering tracks using '" + songFilter + "'"
    songs = filterSongs(songs, songFilter)
    
    print "\to Copying", size, "megabytes from " + str(len(songs)),
    print "tracks..."
    
    numCopy = copyFiles(songs, size, dest)
    
    print "\to Finished.", numCopy, "tracks copied to", dest
    
if __name__ == "__main__": main()
