#!ruby # --- Playlist class --- # # Author: Magnus Engström # Email: magnus@gisab.se # File: playlist # # Description # ----------- # The Playlist class handles everything a playlist should be able to manage. # Shuffle it, unshuffle it, wrap it if desired, add new songs, find songs and # so on. Cool huh? :) # ---------------------- class Playlist # create_from_file() creates a playlist from a file and returns either a Playlist instance or -1 in case of error # This function should be used instead of the ::new, because this one # returns -1 on file read errors, which the ::new doesn't. def Playlist::create_from_file(filename) # Check that the file is readable if(FileTest::readable_real?(filename)) new(filename) # Return the Playlist class instance else -1 # Return -1 on error end end # initialize reads the playlist from a file and returns the Playlist instance def initialize(filename) @filename = filename # Store the filename for later use @playlist = Array::new() # This hash contains the whole playlist @index = 0 # Playlist's current position @wrap = false # Don't repeat the list as default # Parse these fields, separated with double pipes (||) (songname, artist, album, year, comment, tracknum, genre_id, genre) File::foreach(filename) { |line| # Iterate through every line in the file foo = line.split(/\|\|/) @playlist << { "filename" => foo[0], "songname" => foo[1], "artist" => foo[2], "album" => foo[3], "year" => foo[4], "comment" => foo[5], "tracknum" => foo[6], "genre_id" => foo[7], "genre" => foo[8] } # Add a hash to the @playlist array with all values found in the playlist file } end def insert(song, placement = 0) # Check song information return -1 if(song.type != Hash) song = { "filename" => song["filename"], "songname" => song["songname"], "artist" => song["artist"], "album" => song["album"], "year" => song["year"], "comment" => song["comment"], "tracknum" => song["tracknum"], "genre_id" => song["genre_id"], "genre" => song["genre"] } # Check minimum and maximum values placement = 0 if(placement < 0) placement = @playlist.length() if(placement > @playlist.length() ) # Retrieve the two parts of the split playlist first = @playlist[0...placement] second = @playlist[placement...@playlist.length()] # Put it together again @playlist = Array::new() @playlist = first @playlist << song @playlist.concat(second) end def remove(placement = 0) # Check boundaries placement = 0 if(placement < 0) placement = @playlist.length()-1 if( placement >= @playlist.length() ) # Delete the item @playlist.delete_at(placement) end def find(search_string, case_insensitive = false, fields = ["songname", "filename"]) case_insensitive = nil if(case_insensitive == false) results = Array::new() regex = Regexp::new(search_string, case_insensitive) # The regex that will be matched # Iterate through the playlist to find one or more matching songs @playlist.length().times { |index| # Iterate through the user supplied list of fields to be searched fields.each { |field| # Make sure this is a hash, so we don't go and crash, or make someone's dog sick :) if(@playlist[index].type == Hash) results << index if( regex.match(@playlist[index][field]) && !(results.include?(index)) ) # If it matches, and if it doesn't already is in the results. We don't want duplicates :) end } } results # Return the results end def shuffle() # Iterate through the playlist ( 0...@playlist.length() ).each { |i| j = rand @playlist.length() # Grab a random value between 0 and @playlist.length() # Maintain index if(@index == j) @index = i elsif(@index == i) @index = j end @playlist[i], @playlist[j] = @playlist[j], @playlist[i] } end def re_read() # Maintain index current_filename = @playlist[@index]["filename"] # Create a new playlist array @playlist = Array::new() @index = 0 foo_index = 0 # Just to keep the count while adding all songs to the @playlist # Parse these fields, separated with double pipes (||) (songname, artist, album, year, comment, tracknum, genre_id, genre) # Iterate through every line in the file File::foreach(@filename) { |line| foo = line.split(/\|\|/) # Separate the fields with double pipes (||) @playlist << { "filename" => foo[0], "songname" => foo[1], "artist" => foo[2], "album" => foo[3], "year" => foo[4], "comment" => foo[5], "tracknum" => foo[6], "genre_id" => foo[7], "genre" => foo[8] } # Add a hash to the @playlist array with all values found in the playlist file # Maintain index @index = foo_index if(foo[0] == current_filename) foo_index += 1 } end def next() # Increase the counter and return -1 if the playlist went to far, and wrap isn't true @index += 1 if( @index >= @playlist.length() ) if(@wrap) @index = 0 else @index -= 1 -1 # Return an error end else @index end end def prev() # Decrease the counter and return -1 if the playlist went to far, and wrap isn't true @index -= 1 if( @index < 0 ) if(@wrap) @index = @playlist.length() -1 else @index += 1 -1 # Return an error end else @index end end def song_info(index = @index) @playlist[index] end def goto(index = 0) if( index >= 0 && index < @playlist.length() ) @index = index else return -1 end end def length() @playlist.length() end def each() @playlist.each { |song| yield(song) } end attr_reader :wrap, :index, :filename attr_writer :wrap end