listlace 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source :rubygems
2
+ gemspec
3
+
4
+ gem "mplayer-ruby", git: "git://github.com/yjerem/mplayer-ruby.git"
data/Gemfile.lock ADDED
@@ -0,0 +1,56 @@
1
+ GIT
2
+ remote: git://github.com/yjerem/mplayer-ruby.git
3
+ revision: ffa7213d1c0340fa79aa794929affba65d4cff28
4
+ specs:
5
+ mplayer-ruby (0.1.0)
6
+ open4 (>= 1.0.1)
7
+
8
+ PATH
9
+ remote: .
10
+ specs:
11
+ listlace (0.0.1)
12
+ activerecord
13
+ activesupport
14
+ mplayer-ruby
15
+ plist
16
+ pry
17
+ sqlite3
18
+
19
+ GEM
20
+ remote: http://rubygems.org/
21
+ specs:
22
+ activemodel (3.2.8)
23
+ activesupport (= 3.2.8)
24
+ builder (~> 3.0.0)
25
+ activerecord (3.2.8)
26
+ activemodel (= 3.2.8)
27
+ activesupport (= 3.2.8)
28
+ arel (~> 3.0.2)
29
+ tzinfo (~> 0.3.29)
30
+ activesupport (3.2.8)
31
+ i18n (~> 0.6)
32
+ multi_json (~> 1.0)
33
+ arel (3.0.2)
34
+ builder (3.0.0)
35
+ coderay (1.0.7)
36
+ i18n (0.6.0)
37
+ method_source (0.8)
38
+ multi_json (1.3.6)
39
+ open4 (1.3.0)
40
+ plist (3.1.0)
41
+ pry (0.9.10)
42
+ coderay (~> 1.0.5)
43
+ method_source (~> 0.8)
44
+ slop (~> 3.3.1)
45
+ rake (0.9.2.2)
46
+ slop (3.3.2)
47
+ sqlite3 (1.3.6)
48
+ tzinfo (0.3.33)
49
+
50
+ PLATFORMS
51
+ ruby
52
+
53
+ DEPENDENCIES
54
+ listlace!
55
+ mplayer-ruby!
56
+ rake
data/LICENSE ADDED
@@ -0,0 +1,7 @@
1
+ Copyright (c) 2012 Jeremy Ruten
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4
+
5
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6
+
7
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README ADDED
@@ -0,0 +1,43 @@
1
+ < listlace >
2
+
3
+ listlace is a music player with a REPL.
4
+ It allows you to forge complex playlists
5
+ with ease... as long as you know your
6
+ way around Ruby.
7
+
8
+ No more staring a database in the face.
9
+ No more click, shift-click, ctrl-click,
10
+ ctrl-click, drag-and-drop, click,
11
+ double-click.
12
+
13
+ Conjuring audio with spells is much more
14
+ appropriate, don't you think?
15
+
16
+ I'm thinking it'll go a little something
17
+ like this. Observe:
18
+
19
+ $ listlace
20
+ Hello, you have 1466 songs.
21
+ ll> muse = album("Origin of Symmetry") + song("Blackout", artist: "Muse")
22
+ => Playlist (12 songs)
23
+ ll> maps = album("Turning The Mind") - song("Die Happy, Die Smiling")
24
+ => Playlist (11 songs)
25
+ ll> playlist = muse.shuffle + maps.shuffle
26
+ => Playlist (23 songs)
27
+ ll> playlist.play
28
+ Now Playing: Blackout - Muse (0:00 / 4:22)
29
+ ll> p
30
+ Paused: Blackout - Muse (0:07 / 4:22)
31
+ ll> seek 3..10
32
+ Paused: Blackout - Muse (3:10 / 4:22)
33
+ ll> p
34
+ Now Playing: Blackout - Muse (3:10 / 4:22)
35
+ ll> playlist.save "Maps & Muse"
36
+ ll> status
37
+ Playing playlist "Maps & Muse" (1 / 23)
38
+ Now Playing: Blackout - Muse (4:04 / 4:22)
39
+ ll> next
40
+ Now Playing: Space Dementia - Muse (0:00 / 6:21)
41
+
42
+ And so on.
43
+
data/bin/listlace ADDED
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "pry"
5
+ require "fileutils"
6
+ require "listlace"
7
+
8
+ unless File.exists? Listlace::DIR
9
+ FileUtils.mkdir_p Listlace::DIR
10
+ end
11
+
12
+ Listlace::Database.connect
13
+ Listlace::Database.generate_schema unless Listlace::Database.exists?
14
+
15
+ puts "Hello, you have #{Listlace::Track.count} songs."
16
+
17
+ Listlace.pry quiet: true, prompt: Listlace::PROMPT
@@ -0,0 +1,42 @@
1
+ require "plist"
2
+ require "active_support/core_ext/string"
3
+
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
19
+
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
24
+
25
+ track = Track.new(attributes)
26
+ track.save!
27
+ end
28
+
29
+ data["Playlists"].each do |playlist_data|
30
+ playlist = Playlist.new(name: playlist_data["Name"])
31
+ playlist.save!
32
+
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!
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,15 @@
1
+ module Listlace
2
+ def play
3
+ if $player.queue.empty?
4
+ puts "Nothing to play."
5
+ else
6
+ $player.start
7
+ track = $player.current_track
8
+ puts "Now Playing: #{track.artist} - #{track.name} (0:00 / #{track.formatted_total_time})"
9
+ end
10
+ end
11
+
12
+ def stop
13
+ $player.stop
14
+ end
15
+ end
File without changes
File without changes
@@ -0,0 +1,64 @@
1
+ module Listlace
2
+ module Database
3
+ extend self
4
+
5
+ ADAPTER = "sqlite3"
6
+ PATH = "#{Listlace::DIR}/library.sqlite3"
7
+
8
+ def connect
9
+ ActiveRecord::Base.establish_connection(adapter: ADAPTER, database: PATH)
10
+ end
11
+
12
+ def exists?
13
+ File.exists? PATH
14
+ end
15
+
16
+ def generate_schema
17
+ ActiveRecord::Schema.define do
18
+ create_table :tracks do |t|
19
+ t.integer :original_id
20
+ t.string :name
21
+ t.string :artist
22
+ t.string :composer
23
+ t.string :album
24
+ t.string :album_artist
25
+ t.string :genre
26
+ t.string :kind
27
+ t.integer :size
28
+ t.integer :total_time
29
+ t.integer :disc_number
30
+ t.integer :disc_count
31
+ t.integer :track_number
32
+ t.integer :track_count
33
+ t.integer :year
34
+ t.datetime :date_modified
35
+ t.datetime :date_added
36
+ t.integer :bit_rate
37
+ t.integer :sample_rate
38
+ t.text :comments
39
+ t.integer :play_count
40
+ t.integer :play_date
41
+ t.datetime :play_date_utc
42
+ t.integer :skip_count
43
+ t.datetime :skip_date
44
+ t.integer :rating
45
+ t.integer :album_rating
46
+ t.boolean :album_rating_computed
47
+ t.string :location
48
+ end
49
+
50
+ create_table :playlists do |t|
51
+ t.string :name
52
+ t.datetime :created_at
53
+ t.datetime :updated_at
54
+ end
55
+
56
+ create_table :playlist_items do |t|
57
+ t.references :playlist, null: false
58
+ t.references :track, null: false
59
+ t.integer :position
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,6 @@
1
+ module Listlace
2
+ class Playlist < ActiveRecord::Base
3
+ has_many :playlist_items
4
+ has_many :tracks, through: :playlist_items, order: "playlist_items.position ASC"
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ module Listlace
2
+ class PlaylistItem < ActiveRecord::Base
3
+ belongs_to :playlist
4
+ belongs_to :track
5
+ end
6
+ end
@@ -0,0 +1,25 @@
1
+ module Listlace
2
+ class Track < ActiveRecord::Base
3
+ has_many :playlist_items
4
+ has_many :playlists, through: :playlist_items
5
+
6
+ def formatted_total_time
7
+ total_seconds = total_time / 1000
8
+
9
+ seconds = total_seconds % 60
10
+ minutes = (total_seconds / 60) % 60
11
+ hours = total_seconds / 3600
12
+
13
+ if hours > 0
14
+ "%d:%02d:%02d" % [hours, minutes, seconds]
15
+ else
16
+ "%d:%02d" % [minutes, seconds]
17
+ end
18
+ end
19
+
20
+ def play
21
+ $player.queue = [self]
22
+ Listlace.play
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,60 @@
1
+ module Listlace
2
+ class Player
3
+ attr_accessor :mplayer, :queue, :current_track
4
+
5
+ def initialize
6
+ @mplayer = nil
7
+ @queue = []
8
+ @current_track = nil
9
+ @current_track_index = nil
10
+ end
11
+
12
+ def start
13
+ unless @queue.empty?
14
+ @current_track = @queue.first
15
+ @current_track_index = 0
16
+ _play @current_track
17
+ end
18
+ end
19
+
20
+ def next
21
+ @current_track_index += 1
22
+ @current_track = @queue[@current_track_index]
23
+ if @current_track
24
+ _play @current_track
25
+ else
26
+ stop
27
+ end
28
+ end
29
+
30
+ def stop
31
+ @mplayer.quit if _mplayer_alive?
32
+ @mplayer = nil
33
+ @current_track = nil
34
+ @current_track_index = nil
35
+ end
36
+
37
+ private
38
+
39
+ def _play(track)
40
+ @mplayer.quit if _mplayer_alive?
41
+ @mplayer = MPlayer::Slave.new track.location
42
+
43
+ Thread.new do
44
+ Process.wait(@mplayer.pid)
45
+ $player.next
46
+ end
47
+ end
48
+
49
+ def _mplayer_alive?
50
+ if @mplayer
51
+ begin
52
+ Process.getpgid(@mplayer.pid)
53
+ true
54
+ rescue Errno::ESRCH
55
+ false
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
data/lib/listlace.rb ADDED
@@ -0,0 +1,28 @@
1
+ module Listlace
2
+ extend self
3
+
4
+ DIR = ENV["LISTLACE_DIR"] || (ENV["HOME"] + "/.listlace")
5
+ PROMPT = [proc { ">> " }, proc { " | " }]
6
+ end
7
+
8
+ require "mplayer-ruby"
9
+ require "active_record"
10
+
11
+ require "listlace/database"
12
+ require "listlace/player"
13
+
14
+ require "listlace/models/track"
15
+ require "listlace/models/playlist"
16
+ require "listlace/models/playlist_item"
17
+
18
+ require "listlace/commands/library"
19
+ require "listlace/commands/playback"
20
+ require "listlace/commands/selectors"
21
+ require "listlace/commands/volume"
22
+
23
+ # gotta ged rid of this global sometime
24
+ $player = Listlace::Player.new
25
+
26
+ at_exit do
27
+ Listlace.stop
28
+ end
data/listlace.gemspec ADDED
@@ -0,0 +1,26 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = "listlace"
3
+ s.version = "0.0.1"
4
+ s.date = "2012-08-22"
5
+ s.summary = "A music player in a REPL."
6
+ s.description = "Listlace is a music player which is interacted with through a Ruby REPL."
7
+ s.author = "Jeremy Ruten"
8
+ s.email = "jeremy.ruten@gmail.com"
9
+ s.homepage = "http://github.com/yjerem/listlace"
10
+ s.license = "MIT"
11
+ s.required_ruby_version = ">= 1.9.2"
12
+ s.requirements << "mplayer"
13
+ s.executables << "listlace"
14
+
15
+ s.files = ["Gemfile", "Gemfile.lock", "LICENSE", "listlace.gemspec", "README"]
16
+ s.files += ["bin/listlace"]
17
+ s.files += Dir["lib/**/*.rb"]
18
+
19
+ %w(pry plist sqlite3 activerecord activesupport mplayer-ruby).each do |gem_name|
20
+ s.add_runtime_dependency gem_name
21
+ end
22
+
23
+ %w(rake).each do |gem_name|
24
+ s.add_development_dependency gem_name
25
+ end
26
+ end
metadata ADDED
@@ -0,0 +1,176 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: listlace
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Jeremy Ruten
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-08-22 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: pry
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: plist
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: sqlite3
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ - !ruby/object:Gem::Dependency
63
+ name: activerecord
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ type: :runtime
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ - !ruby/object:Gem::Dependency
79
+ name: activesupport
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ! '>='
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ type: :runtime
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ! '>='
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ - !ruby/object:Gem::Dependency
95
+ name: mplayer-ruby
96
+ requirement: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ! '>='
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ type: :runtime
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ! '>='
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ - !ruby/object:Gem::Dependency
111
+ name: rake
112
+ requirement: !ruby/object:Gem::Requirement
113
+ none: false
114
+ requirements:
115
+ - - ! '>='
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ none: false
122
+ requirements:
123
+ - - ! '>='
124
+ - !ruby/object:Gem::Version
125
+ version: '0'
126
+ description: Listlace is a music player which is interacted with through a Ruby REPL.
127
+ email: jeremy.ruten@gmail.com
128
+ executables:
129
+ - listlace
130
+ extensions: []
131
+ extra_rdoc_files: []
132
+ files:
133
+ - Gemfile
134
+ - Gemfile.lock
135
+ - LICENSE
136
+ - listlace.gemspec
137
+ - README
138
+ - bin/listlace
139
+ - lib/listlace/commands/library.rb
140
+ - lib/listlace/commands/playback.rb
141
+ - lib/listlace/commands/selectors.rb
142
+ - lib/listlace/commands/volume.rb
143
+ - lib/listlace/database.rb
144
+ - lib/listlace/models/playlist.rb
145
+ - lib/listlace/models/playlist_item.rb
146
+ - lib/listlace/models/track.rb
147
+ - lib/listlace/player.rb
148
+ - lib/listlace.rb
149
+ homepage: http://github.com/yjerem/listlace
150
+ licenses:
151
+ - MIT
152
+ post_install_message:
153
+ rdoc_options: []
154
+ require_paths:
155
+ - lib
156
+ required_ruby_version: !ruby/object:Gem::Requirement
157
+ none: false
158
+ requirements:
159
+ - - ! '>='
160
+ - !ruby/object:Gem::Version
161
+ version: 1.9.2
162
+ required_rubygems_version: !ruby/object:Gem::Requirement
163
+ none: false
164
+ requirements:
165
+ - - ! '>='
166
+ - !ruby/object:Gem::Version
167
+ version: '0'
168
+ requirements:
169
+ - mplayer
170
+ rubyforge_project:
171
+ rubygems_version: 1.8.24
172
+ signing_key:
173
+ specification_version: 3
174
+ summary: A music player in a REPL.
175
+ test_files: []
176
+ has_rdoc: