listlace 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- listlace (0.0.2)
4
+ listlace (0.0.3)
5
5
  activerecord
6
6
  activesupport
7
7
  open4
data/README CHANGED
@@ -39,7 +39,7 @@ The only way to populate the database right
39
39
  now is to import your iTunes library.
40
40
  That goes a little something like this:
41
41
 
42
- >> import_from_itunes "/Users/jeremy/Music/iTunes/iTunes Music Library.xml"
42
+ >> import :itunes, "/Users/jeremy/Music/iTunes/iTunes Music Library.xml"
43
43
 
44
44
  Now you can play your music.
45
45
 
@@ -75,3 +75,12 @@ itself will start playing the queue.
75
75
  * queue
76
76
  - q: append some tracks to the queue, or get the queue
77
77
  - clear: clear the queue
78
+ - shuffle: shuffle the songs in the queue
79
+ - sort: sort the songs in the queue however you want
80
+ * library
81
+ - import: import another program's music library
82
+ - wipe_library: remove all tracks and playlists from the library
83
+
84
+ -- selectors
85
+
86
+ ...
data/bin/listlace CHANGED
@@ -2,7 +2,6 @@
2
2
 
3
3
  require "bundler/setup"
4
4
  require "pry"
5
- require "fileutils"
6
5
  require "listlace"
7
6
 
8
7
  unless File.exists? Listlace::DIR
@@ -2,41 +2,84 @@ require "plist"
2
2
  require "active_support/core_ext/string"
3
3
 
4
4
  module Listlace
5
- def import_from_itunes(path_to_xml)
6
- data = Plist::parse_xml(path_to_xml)
7
-
8
- whitelist = Track.new.attributes.keys
9
- data["Tracks"].each do |track_id, row|
10
- # row already contains a hash of attributes almost ready to be passed to
11
- # ActiveRecord. We just need to modify the keys, e.g. change "Play Count"
12
- # to "play_count".
13
- attributes = row.inject({}) do |acc, (key, value)|
14
- attribute = key.gsub(" ", "").underscore
15
- attribute = "original_id" if attribute == "track_id"
16
- acc[attribute] = value if whitelist.include? attribute
17
- acc
18
- end
5
+ # Imports the music library from another program. Currently only iTunes is
6
+ # supported.
7
+ def import(from, path)
8
+ if not File.exists?(path)
9
+ puts "File '%s' doesn't exist." % [path]
10
+ elsif from == :itunes
11
+ puts "Parsing XML..."
12
+ data = Plist::parse_xml(path)
19
13
 
20
- # change iTunes' URL-style locations into simple paths
21
- if attributes["location"] && attributes["location"] =~ /^file:\/\//
22
- attributes["location"] = CGI::unescape(attributes["location"].sub(/^file:\/\/localhost/, ""))
23
- end
14
+ puts "Importing #{data['Tracks'].length} tracks..."
15
+ num_tracks = 0
16
+ whitelist = Track.new.attributes.keys
17
+ data["Tracks"].each do |track_id, row|
18
+ # row already contains a hash of attributes almost ready to be passed to
19
+ # ActiveRecord. We just need to modify the keys, e.g. change "Play Count"
20
+ # to "play_count".
21
+ attributes = row.inject({}) do |acc, (key, value)|
22
+ attribute = key.gsub(" ", "").underscore
23
+ attribute = "original_id" if attribute == "track_id"
24
+ acc[attribute] = value if whitelist.include? attribute
25
+ acc
26
+ end
24
27
 
25
- track = Track.new(attributes)
26
- track.save!
27
- end
28
+ # change iTunes' URL-style locations into simple paths
29
+ if attributes["location"] && attributes["location"] =~ /^file:\/\//
30
+ attributes["location"].sub! /^file:\/\/localhost/, ""
31
+
32
+ # CGI::unescape changes plus signs to spaces. This is a work around to
33
+ # keep the plus signs.
34
+ attributes["location"].gsub! "+", "%2B"
35
+
36
+ attributes["location"] = CGI::unescape(attributes["location"])
37
+ end
28
38
 
29
- data["Playlists"].each do |playlist_data|
30
- playlist = Playlist.new(name: playlist_data["Name"])
31
- playlist.save!
39
+ track = Track.new(attributes)
32
40
 
33
- playlist_data["Playlist Items"].map(&:values).flatten.each.with_index do |track_id, i|
34
- playlist_item = PlaylistItem.new(position: i)
35
- playlist_item.playlist = playlist
36
- if playlist_item.track = Track.where(original_id: track_id).first
37
- playlist_item.save!
41
+ if track.kind =~ /audio/
42
+ if track.save
43
+ num_tracks += 1
44
+ end
45
+ else
46
+ puts "[skipping non-audio file]"
38
47
  end
39
48
  end
49
+ puts "Imported #{num_tracks} tracks successfully."
50
+
51
+ puts "Importing #{data['Playlists'].length} playlists..."
52
+ num_playlists = 0
53
+ data["Playlists"].each do |playlist_data|
54
+ playlist = Playlist.new(name: playlist_data["Name"])
55
+
56
+ if ["Library", "Music", "Movies", "TV Shows", "iTunes DJ"].include? playlist.name
57
+ puts "[skipping \"#{playlist.name}\" playlist]"
58
+ else
59
+ if playlist.save
60
+ playlist_data["Playlist Items"].map(&:values).flatten.each.with_index do |track_id, i|
61
+ playlist_item = PlaylistItem.new(position: i)
62
+ playlist_item.playlist = playlist
63
+ if playlist_item.track = Track.where(original_id: track_id).first
64
+ playlist_item.save!
65
+ end
66
+ end
67
+ num_playlists += 1
68
+ end
69
+ end
70
+ end
71
+ puts "Imported #{num_playlists} playlists successfully."
72
+ end
73
+ end
74
+
75
+ # Wipes the database. With no arguments, it just asks "Are you sure?" without
76
+ # doing anything. To actually wipe the database, pass :yes_im_sure.
77
+ def wipe_library(are_you_sure = :nope)
78
+ if are_you_sure == :yes_im_sure
79
+ Database.wipe
80
+ puts "Library wiped."
81
+ else
82
+ puts "Are you sure? If you are, then type: wipe_library :yes_im_sure"
40
83
  end
41
84
  end
42
85
  end
@@ -48,8 +48,8 @@ module Listlace
48
48
  end
49
49
 
50
50
  # Go back one song in the queue.
51
- def back
52
- if $player.back
51
+ def back(n = 1)
52
+ if $player.back(n)
53
53
  status
54
54
  else
55
55
  puts "End of queue."
@@ -57,8 +57,8 @@ module Listlace
57
57
  end
58
58
 
59
59
  # Go directly to the next song in the queue.
60
- def skip
61
- if $player.skip
60
+ def skip(n = 1)
61
+ if $player.skip(n)
62
62
  status
63
63
  else
64
64
  puts "End of queue."
@@ -114,9 +114,9 @@ module Listlace
114
114
  num_tracks = q.length
115
115
  repeat_one = $player.repeat_mode == :one ? REPEAT_SYMBOL : ""
116
116
  repeat_all = $player.repeat_mode == :all ? REPEAT_SYMBOL : ""
117
- puts "Playlist: queue (%d%s / %d%s)" % [track_number, repeat_one, num_tracks, repeat_all]
117
+ puts "Playlist: %s (%d%s / %d%s)" % [q.name, track_number, repeat_one, num_tracks, repeat_all]
118
118
  else
119
- puts "Playlist: queue (%d songs)" % [q.length]
119
+ puts "Playlist: %s" % [q]
120
120
  end
121
121
  when :playing
122
122
  if $player.started?
@@ -1,21 +1,10 @@
1
1
  module Listlace
2
- # The queue command. Simply appends tracks to the queue. Tracks can be
3
- # specified by a single Track, a Playlist, an ActiveRecord::Relation, or an
4
- # Array containing any of the above. With or without arguments, it returns the
5
- # queue as an Array of Tracks, so this can be used as an accessor method.
6
- def q(*tracks)
7
- tracks.each do |playlist_or_track|
8
- case playlist_or_track
9
- when Track
10
- $player.queue playlist_or_track
11
- when Playlist
12
- q *playlist_or_track.tracks
13
- when Array
14
- q *playlist_or_track
15
- when ActiveRecord::Relation
16
- q *playlist_or_track.all
17
- end
18
- end
2
+ # The queue command. Simply appends tracks to the queue. It creates a playlist
3
+ # with the arguments you give it, so anything you can pass to the playlist()
4
+ # method you can pass to this. It returns the queue, so you can use this
5
+ # method as an accessor by not passing any arguments.
6
+ def q(*args)
7
+ $player.queue playlist(*args)
19
8
  $player.queue
20
9
  end
21
10
 
@@ -25,11 +14,38 @@ module Listlace
25
14
  puts "Queue cleared."
26
15
  end
27
16
 
17
+ # Shuffles the queue, keeping the current track at the top.
28
18
  def shuffle
29
-
19
+ $player.shuffle
20
+ puts "Shuffled."
30
21
  end
31
22
 
32
- def sort(by = :artist_asc_album_asc_track_number_asc)
33
-
23
+ # Sorts the queue by a list of fields and directions in the form of a symbol,
24
+ # or uses the proc given to it, which should take two Tracks and return -1, 0,
25
+ # or 1.
26
+ def sort(by = :artist_asc_album_asc_track_number_asc, &proc)
27
+ if proc
28
+ $player.sort(&proc)
29
+ else
30
+ $player.sort do |a, b|
31
+ result = 0
32
+ by.to_s.scan(/([a-z_]+?)_(asc|desc)(?:_|$)/).each do |column, direction|
33
+ a_value = a.send(column)
34
+ b_value = b.send(column)
35
+ a_value = a_value.downcase if a_value.respond_to? :downcase
36
+ b_value = b_value.downcase if b_value.respond_to? :downcase
37
+ dir = (direction == "desc") ? -1 : 1
38
+ if a_value != b_value
39
+ if a_value.nil? || b_value.nil?
40
+ result = dir
41
+ else
42
+ result = (a_value <=> b_value) * dir
43
+ end
44
+ break
45
+ end
46
+ end
47
+ result
48
+ end
49
+ end
34
50
  end
35
51
  end
@@ -0,0 +1,186 @@
1
+ module Listlace
2
+ STRING_SELECTORS = %w(name artist composer album album_artist genre comments location)
3
+ INTEGER_SELECTORS = %w(disc_number disc_count track_number track_count year bit_rate sample_rate play_count skip_count rating)
4
+
5
+ STRING_SELECTORS.each do |column|
6
+ define_method(column) do |*args|
7
+ options = args.last.is_a?(Hash) ? args.pop : {}
8
+
9
+ playlists = args.map { |query| string_selector(column, query, options) }
10
+ playlist *playlists
11
+ end
12
+ end
13
+
14
+ INTEGER_SELECTORS.each do |column|
15
+ define_method(column) do |*args|
16
+ playlists = args.map { |arg| integer_selector(column, arg) }
17
+ playlist *playlists
18
+ end
19
+ end
20
+
21
+ # rename the "name" selector to "song"
22
+ alias_method :song, :name
23
+ remove_method :name
24
+
25
+ # The length selector is an integer selector for the length of a track. A
26
+ # plain integer given to it represents the number of seconds. It can also take
27
+ # a String in the format "1:23", to represent 83 seconds, for example. These
28
+ # can be part of a Range, as usual: "1:23".."2:05", for example.
29
+ def length(*args)
30
+ normalize = lambda do |value|
31
+ case value
32
+ when String
33
+ Track.parse_time(value)
34
+ when Integer
35
+ value * 1000
36
+ when Range
37
+ (normalize.(value.begin))..(normalize.(value.end))
38
+ end
39
+ end
40
+
41
+ playlists = args.map do |arg|
42
+ if arg.is_a? Hash
43
+ key = arg.keys.first
44
+ arg[key] = normalize.(arg[key])
45
+ else
46
+ arg = normalize.(arg)
47
+ end
48
+
49
+ # If they want tracks of length "0:05", for example, we need to look for
50
+ # tracks that are from 5000 to 5999 milliseconds long.
51
+ if arg.is_a? Integer
52
+ arg = (arg)..(arg + 999)
53
+ end
54
+
55
+ integer_selector(:total_time, arg)
56
+ end
57
+
58
+ playlist *playlists
59
+ end
60
+
61
+ # Makes a playlist out of tracks that match the string query on the given
62
+ # column. It's SQL underneath, so you can use % and _ as wildcards in the
63
+ # query. By default, % wildcards are inserted on the left and right of your
64
+ # query. Use the :match option to change this:
65
+ #
66
+ # :match => :middle "%query%" (default)
67
+ # :match => :left "query%"
68
+ # :match => :right "%query"
69
+ # :match => :exact "query"
70
+ #
71
+ # This method shouldn't have to be used directly. Many convenient methods are
72
+ # generated for you, one for each string field you may want to select on.
73
+ # These are: artist, composer, album, album_artist, genre, comments, location.
74
+ # For example:
75
+ #
76
+ # artist :muse, match: :exact #=> playlist (108 tracks)
77
+ # composer :rachmanino #=> playlist (33 tracks)
78
+ #
79
+ # To match the name of a track, use song:
80
+ #
81
+ # song "frontier psychiatrist" #=> playlist (1 track)
82
+ #
83
+ def string_selector(column, query, options = {})
84
+ options[:match] ||= :middle
85
+
86
+ query = {
87
+ exact: "#{query}",
88
+ left: "#{query}%",
89
+ right: "%#{query}",
90
+ middle: "%#{query}%"
91
+ }[options[:match]]
92
+
93
+ tracks = Track.arel_table
94
+ PlaylistArray.new(Track.where(tracks[column].matches(query)).all)
95
+ end
96
+
97
+ # Makes a playlist out of tracks that satisfy certain conditions on the given
98
+ # integer column. You can pass an exact value to check for equality, a range,
99
+ # or a hash that specifies greater-than and less-than options like this:
100
+ #
101
+ # integer_selector :year, greater_than: 2000 #=> playlist (3555 tracks)
102
+ #
103
+ # The possible operators, with their shortcuts, are:
104
+ #
105
+ # :greater_than / :gt
106
+ # :less_than / :lt
107
+ # :greater_than_or_equal / :gte
108
+ # :less_than_or_equal / :lte
109
+ # :not_equal / :ne
110
+ #
111
+ # Note: You can only use one of these operators at a time. If you want a
112
+ # range, use a Range.
113
+ #
114
+ # This method shouldn't have to be used directly. Many convenient methods are
115
+ # generated for you, one for each integer field you may want to select on.
116
+ # These are: disc_number, disc_count, track_number, track_count, year,
117
+ # bit_rate, sample_rate, play_count, skip_count, rating, length. Length is
118
+ # special, it can take any of the time formats that the seek command can. For
119
+ # example:
120
+ #
121
+ # year 2010..2012 #=> playlist (1060 tracks)
122
+ # length gt: "4:00" #=> playlist (2543 tracks)
123
+ #
124
+ def integer_selector(column, value_or_options)
125
+ if value_or_options.is_a? Hash
126
+ operator = {
127
+ greater_than: ">",
128
+ gt: ">",
129
+ less_than: "<",
130
+ lt: "<",
131
+ greater_than_or_equal: ">=",
132
+ gte: ">=",
133
+ less_than_or_equal: "<=",
134
+ lte: "<=",
135
+ not_equal: "<>",
136
+ ne: "<>"
137
+ }[value_or_options.keys.first]
138
+ tracks = Track.where("tracks.#{column} #{operator} ?", value_or_options.values.first)
139
+ PlaylistArray.new(tracks.all)
140
+ else
141
+ tracks = Track.arel_table
142
+ PlaylistArray.new(Track.where(column => value_or_options).all)
143
+ end
144
+ end
145
+
146
+ # Creates or looks up a playlist. You can pass any number of multiple types of
147
+ # objects to make a playlist:
148
+ #
149
+ # Track: Makes a playlist with one track
150
+ # ActiveRecord::Relation: Makes a playlist out of the resulting Track or Playlist records
151
+ # Symbol or String: Tries to retrieve a saved playlist with the given name.
152
+ # If it can't find one, it creates a new one.
153
+ #
154
+ # You can also pass in the results of a selector. In this way you can create a
155
+ # playlist out of many smaller pieces.
156
+ #
157
+ # If given no arguments, it returns a blank playlist.
158
+ #
159
+ def playlist(*args)
160
+ args.map do |object|
161
+ case object
162
+ when Track
163
+ PlaylistArray.new([object])
164
+ when Playlist
165
+ PlaylistArray.new([object.tracks.all], object.name)
166
+ when PlaylistArray
167
+ object
168
+ when Array
169
+ playlist *object
170
+ when ActiveRecord::Relation
171
+ if object.table.name == "tracks"
172
+ PlaylistArray.new([object.all])
173
+ elsif object.table.name == "playlists"
174
+ playlist *object.all
175
+ end
176
+ when Symbol, String
177
+ playlists = Playlist.arel_table
178
+ if playlist = Playlist.where(playlists[:name].matches(object.to_s)).first
179
+ PlaylistArray.new(playlist)
180
+ else
181
+ PlaylistArray.new([], object)
182
+ end
183
+ end
184
+ end.inject(:+)
185
+ end
186
+ end
@@ -13,6 +13,16 @@ module Listlace
13
13
  File.exists? PATH
14
14
  end
15
15
 
16
+ def delete
17
+ FileUtils.rm PATH
18
+ end
19
+
20
+ def wipe
21
+ delete
22
+ connect
23
+ generate_schema
24
+ end
25
+
16
26
  def generate_schema
17
27
  ActiveRecord::Schema.define do
18
28
  create_table :tracks do |t|
@@ -7,11 +7,6 @@ module Listlace
7
7
  Track.format_time(total_time)
8
8
  end
9
9
 
10
- def play
11
- $player.queue = [self]
12
- Listlace.play
13
- end
14
-
15
10
  def self.format_time(milliseconds)
16
11
  total_seconds = milliseconds / 1000
17
12
 
@@ -25,5 +20,13 @@ module Listlace
25
20
  "%d:%02d" % [minutes, seconds]
26
21
  end
27
22
  end
23
+
24
+ def self.parse_time(string)
25
+ parts = string.split(":").map(&:to_i)
26
+ parts = [0] + parts if parts.length == 2
27
+ hours, minutes, seconds = parts
28
+ seconds = hours * 3600 + minutes * 60 + seconds
29
+ seconds * 1000
30
+ end
28
31
  end
29
32
  end
@@ -7,7 +7,7 @@ module Listlace
7
7
 
8
8
  def initialize
9
9
  @mplayer = nil
10
- @queue = []
10
+ @queue = PlaylistArray.new([], :queue)
11
11
  @current_track = nil
12
12
  @current_track_index = nil
13
13
  @paused = false
@@ -15,14 +15,14 @@ module Listlace
15
15
  @repeat_mode = false
16
16
  end
17
17
 
18
- def queue(track = nil)
19
- @queue << track if track.is_a? Track
18
+ def queue(playlist = nil)
19
+ @queue << playlist if playlist
20
20
  @queue.dup
21
21
  end
22
22
 
23
23
  def clear
24
24
  stop
25
- @queue = []
25
+ @queue.clear
26
26
  end
27
27
 
28
28
  def empty?
@@ -88,12 +88,12 @@ module Listlace
88
88
  change_track(0)
89
89
  end
90
90
 
91
- def back
92
- change_track(-1)
91
+ def back(n = 1)
92
+ change_track(-n)
93
93
  end
94
94
 
95
- def skip
96
- change_track(1)
95
+ def skip(n = 1)
96
+ change_track(n)
97
97
  end
98
98
 
99
99
  def seek(where)
@@ -103,10 +103,7 @@ module Listlace
103
103
  when Range
104
104
  @mplayer.command("seek %d 2" % [where.begin * 60 + where.end], expect_answer: true)
105
105
  when String
106
- parts = where.split(":").map(&:to_i)
107
- parts = [0] + parts if parts.length == 2
108
- hours, minutes, seconds = parts
109
- @mplayer.command("seek %d 2" % [hours * 3600 + minutes * 60 + seconds], expect_answer: true)
106
+ @mplayer.command("seek %d 2" % [Track.parse_time(where) / 1000], expect_answer: true)
110
107
  when Hash
111
108
  if where[:abs]
112
109
  if where[:abs].is_a? Integer
@@ -131,6 +128,23 @@ module Listlace
131
128
  @mplayer.command("speed_set %f" % [speed], expect_answer: true)
132
129
  end
133
130
 
131
+ def shuffle
132
+ if started?
133
+ @queue.shuffle_except! @current_track
134
+ @current_track_index = 0
135
+ else
136
+ @queue.shuffle!
137
+ end
138
+ end
139
+
140
+ def sort(&by)
141
+ @queue.sort! &by
142
+
143
+ if started?
144
+ @current_track_index = @queue.index(@current_track)
145
+ end
146
+ end
147
+
134
148
  def current_time
135
149
  answer = @mplayer.command "get_time_pos", expect_answer: true
136
150
  if answer =~ /^ANS_TIME_POSITION=([0-9.]+)$/
@@ -0,0 +1,82 @@
1
+ module Listlace
2
+ class PlaylistArray < Array
3
+ attr_accessor :name, :model
4
+
5
+ def initialize(tracks_or_playlist = [], name = :playlist)
6
+ if tracks_or_playlist.is_a? Playlist
7
+ replace tracks_or_playlist.tracks.to_a
8
+ @name = tracks_or_playlist.name
9
+ @model = tracks_or_playlist
10
+ else
11
+ replace tracks_or_playlist.to_a
12
+ @name = name.to_s
13
+ @model = nil
14
+ end
15
+ end
16
+
17
+ def save(name = nil)
18
+ if @model
19
+ @model.playlist_items.destroy_all
20
+ @model.name = @name = name if name
21
+ else
22
+ @name = name if name
23
+ @model = Playlist.new(name: @name)
24
+ end
25
+
26
+ if @model.save
27
+ each.with_index do |track, i|
28
+ item = PlaylistItem.new(position: i)
29
+ item.playlist = @model
30
+ item.track = track
31
+ item.save!
32
+ end
33
+ @model
34
+ else
35
+ false
36
+ end
37
+ end
38
+
39
+ def <<(other)
40
+ if other.is_a? Track
41
+ super
42
+ else
43
+ other.each do |track|
44
+ self << track
45
+ end
46
+ end
47
+ end
48
+
49
+ def +(other)
50
+ result = self.dup
51
+ result << Listlace.playlist(other)
52
+ result
53
+ end
54
+
55
+ def &(other)
56
+ replace super
57
+ end
58
+
59
+ def shuffle_except(track)
60
+ ary = dup
61
+ dup.shuffle_except! track
62
+ dup
63
+ end
64
+
65
+ def shuffle_except!(track)
66
+ replace([track] + (self - [track]).shuffle)
67
+ end
68
+
69
+ def to_s
70
+ "%s (%d track%s)" % [@name || "playlist", length, ("s" if length != 1)]
71
+ end
72
+
73
+ def inspect
74
+ to_s
75
+ end
76
+
77
+ # override pry
78
+ def pretty_inspect
79
+ inspect
80
+ end
81
+ end
82
+ end
data/lib/listlace.rb CHANGED
@@ -8,10 +8,12 @@ end
8
8
  require "open4"
9
9
  require "shellwords"
10
10
  require "active_record"
11
+ require "fileutils"
11
12
 
12
13
  require "listlace/database"
13
14
  require "listlace/player"
14
15
  require "listlace/mplayer"
16
+ require "listlace/playlist_array"
15
17
 
16
18
  require "listlace/models/track"
17
19
  require "listlace/models/playlist"
@@ -23,7 +25,6 @@ require "listlace/commands/selectors"
23
25
  require "listlace/commands/volume"
24
26
  require "listlace/commands/queue"
25
27
 
26
- # gotta ged rid of this global sometime
27
28
  $player = Listlace::Player.new
28
29
 
29
30
  at_exit do
data/listlace.gemspec CHANGED
@@ -1,7 +1,7 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = "listlace"
3
- s.version = "0.0.3"
4
- s.date = "2012-08-24"
3
+ s.version = "0.0.4"
4
+ s.date = "2012-08-25"
5
5
  s.summary = "A music player in a REPL."
6
6
  s.description = "Listlace is a music player which is interacted with through a Ruby REPL."
7
7
  s.author = "Jeremy Ruten"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: listlace
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.4
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-08-24 00:00:00.000000000 Z
12
+ date: 2012-08-25 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: pry
@@ -147,6 +147,7 @@ files:
147
147
  - lib/listlace/models/track.rb
148
148
  - lib/listlace/mplayer.rb
149
149
  - lib/listlace/player.rb
150
+ - lib/listlace/playlist_array.rb
150
151
  - lib/listlace.rb
151
152
  homepage: http://github.com/yjerem/listlace
152
153
  licenses: