songbirdsh 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Mark Ryall
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,42 @@
1
+ = Songbird
2
+
3
+ This is a command line shell for queuing music tracks.
4
+
5
+ It relies on you having a songbird database that has all of your tracks imported.
6
+
7
+ This is eventually supposed to be platform independent but at this stage will probably only work on mac os x.
8
+
9
+ = Usage
10
+
11
+ Here you sit expectantly in front of a computer at the command line.
12
+
13
+ == Install
14
+
15
+ gem install songbirdsh
16
+
17
+ == Launch
18
+
19
+ songbirdsh
20
+
21
+ == Commands
22
+
23
+ If readline was correctly installed, you should find that tab completion works for all of the commands.
24
+
25
+ * ? <command> - show commands/help for command
26
+ * help <command> - show commands/help for command
27
+ * + <id> - enqueue track with id
28
+ * next - skip currently playing track
29
+ * start - start music player
30
+ * stop - stop music player
31
+ * reload - reload track information (required for search)
32
+ * search <text> - search in memory list of tracks (see reload)
33
+ * exit - exit
34
+ * quit - exit
35
+
36
+ = Future plans for world domination
37
+
38
+ * Add documentation for all commands
39
+ * Improve search
40
+ * Add music progress indicator
41
+ * Add some color
42
+ * Get working on linux and windows
data/bin/songbirdsh ADDED
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+ $: << File.dirname(__FILE__)+'/../lib'
3
+ require 'songbirdsh/cli'
4
+ Songbirdsh::Cli.new.push
data/gemspec ADDED
@@ -0,0 +1,22 @@
1
+ Gem::Specification.new do |spec|
2
+ spec.name = 'songbirdsh'
3
+ spec.version = '0.0.1'
4
+ spec.summary = 'command line jukebox music player'
5
+ spec.description = <<-EOF
6
+ A command line jukebox music player that uses your songbird music player database
7
+ EOF
8
+ spec.authors << 'Mark Ryall'
9
+ spec.email = 'mark@ryall.name'
10
+ spec.homepage = 'http://github.com/markryall/songbirdsh'
11
+ spec.files = Dir['lib/**/*'] + Dir['bin/*'] + ['README.rdoc', 'MIT-LICENSE', 'gemspec']
12
+ spec.executables << 'songbirdsh'
13
+
14
+ spec.add_dependency 'splat', '~>0.1'
15
+ spec.add_dependency 'shell_shock', '~>0.0.5'
16
+ spec.add_dependency 'sequel', '~> 3'
17
+ spec.add_dependency 'splat', '~> 0.1'
18
+ spec.add_dependency 'sqlite3', '~> 1'
19
+
20
+ spec.add_development_dependency 'rake', '~>0.8.7'
21
+ spec.add_development_dependency 'gemesis', '~>0.0.4'
22
+ end
@@ -0,0 +1,32 @@
1
+ require 'shell_shock/context'
2
+
3
+ require 'songbirdsh'
4
+ require 'songbirdsh/player'
5
+ require 'songbirdsh/library'
6
+ require 'songbirdsh/command/enqueue'
7
+ require 'songbirdsh/command/show_properties'
8
+ require 'songbirdsh/command/start'
9
+ require 'songbirdsh/command/reload'
10
+ require 'songbirdsh/command/stop'
11
+ require 'songbirdsh/command/restart'
12
+ require 'songbirdsh/command/search'
13
+
14
+ class Songbirdsh::Cli
15
+ include ShellShock::Context
16
+
17
+ def initialize
18
+ library = Songbirdsh::Library.new
19
+ player = Songbirdsh::Player.new library
20
+ at_exit { player.stop }
21
+ @prompt_text = "sbsh > "
22
+ @commands = {
23
+ 'show' => Songbirdsh::Command::ShowProperties.new(library),
24
+ '+' => Songbirdsh::Command::Enqueue.new(library),
25
+ 'start' => Songbirdsh::Command::Start.new(player),
26
+ 'stop' => Songbirdsh::Command::Stop.new(player),
27
+ 'next' => Songbirdsh::Command::Restart.new(player),
28
+ 'reload' => Songbirdsh::Command::Reload.new(library),
29
+ 'search' => Songbirdsh::Command::Search.new(library)
30
+ }
31
+ end
32
+ end
@@ -0,0 +1,16 @@
1
+ require 'yaml'
2
+
3
+ class Songbirdsh::Command::Enqueue
4
+ def initialize library
5
+ @library = library
6
+ end
7
+
8
+ def execute text
9
+ ids = text.split(/\W/)
10
+ @library.with_db do |db|
11
+ ids.each do |id|
12
+ File.open("#{Time.now.to_i}-#{(rand*1000).to_i}.song", 'w') {|f| f.print db[:media_items][:media_item_id=>id].to_yaml }
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,9 @@
1
+ class Songbirdsh::Command::Reload
2
+ def initialize library
3
+ @library = library
4
+ end
5
+
6
+ def execute ignored=nil
7
+ @library.reload
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ class Songbirdsh::Command::Restart
2
+ def initialize player
3
+ @player = player
4
+ end
5
+
6
+ def execute ignored=nil
7
+ @player.restart
8
+ end
9
+ end
@@ -0,0 +1,11 @@
1
+ class Songbirdsh::Command::Search
2
+ def initialize library
3
+ @library = library
4
+ end
5
+
6
+ def execute text
7
+ @library.tracks.each do |track|
8
+ puts track[:display] if track[:search_string].include? text
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ require 'pp'
2
+
3
+ class Songbirdsh::Command::ShowProperties
4
+ def initialize library
5
+ @library = library
6
+ end
7
+
8
+ def execute id
9
+ @library.with_track(id) {|track| pp track }
10
+ end
11
+ end
@@ -0,0 +1,9 @@
1
+ class Songbirdsh::Command::Start
2
+ def initialize player
3
+ @player = player
4
+ end
5
+
6
+ def execute ignored=nil
7
+ @player.start
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ class Songbirdsh::Command::Stop
2
+ def initialize player
3
+ @player = player
4
+ end
5
+
6
+ def execute ignored=nil
7
+ @player.stop
8
+ end
9
+ end
@@ -0,0 +1,66 @@
1
+ class Songbirdsh::Library
2
+ attr_reader :tracks
3
+
4
+ def initialize
5
+ home = File.expand_path '~'
6
+ debug "Home Directory is \"#{home}\""
7
+ songbird_home = "#{home}/Library/Application Support/Songbird2"
8
+ debug "Songbird home is \"#{songbird_home}\""
9
+ profiles = "#{songbird_home}/Profiles"
10
+ profile = `ls \"#{profiles}\"`.chomp
11
+ debug "found profile \"#{profile}\""
12
+ @db_path = "#{profiles}/#{profile}/db/main@library.songbirdnest.com.db"
13
+ debug "using db \"#{@db_path}\""
14
+ end
15
+
16
+ def with_db
17
+ db = Sequel.sqlite @db_path
18
+ begin
19
+ val = yield db
20
+ ensure
21
+ db.disconnect
22
+ end
23
+ val
24
+ end
25
+
26
+ def with_track id
27
+ with_db do |db|
28
+ db[:resource_properties].filter(:media_item_id=>id).each do |row|
29
+ yield to_track(row) if row[:property_id] == 3
30
+ end
31
+ end
32
+ end
33
+
34
+ def reload
35
+ s = Time.now.to_i
36
+ @tracks = []
37
+ with_db do |db|
38
+ db[:resource_properties].each do |row|
39
+ @tracks << to_track(row) if row[:property_id] == 3
40
+ end
41
+ end
42
+ puts "reloaded db with #{@tracks.size} tracks in #{Time.now.to_i-s} seconds"
43
+ end
44
+ private
45
+ def debug message
46
+ if ENV['DEBUG']
47
+ puts message
48
+ gets
49
+ end
50
+ end
51
+
52
+ def to_track row
53
+ rest = row[:obj_secondary_sortable].split("\037")
54
+ track = {
55
+ :id => row[:media_item_id],
56
+ :artist => row[:obj_sortable],
57
+ :album => rest.shift,
58
+ :disc => rest.shift.to_i,
59
+ :number => rest.shift.to_i,
60
+ :track => rest.shift
61
+ }
62
+ track[:search_string] = track[:artist]+track[:album]+track[:track]
63
+ track[:display] = "#{track[:id]}: #{track[:artist]} #{track[:album]} #{track[:number]} #{track[:track]}"
64
+ track
65
+ end
66
+ end
@@ -0,0 +1,52 @@
1
+ require 'songbirdsh/queue'
2
+ require 'cgi'
3
+ require 'yaml'
4
+ require 'fileutils'
5
+ require 'splat'
6
+
7
+ class Songbirdsh::Player
8
+ include Songbirdsh::Queue
9
+
10
+ def initialize library
11
+ @library=library
12
+ end
13
+
14
+ def start
15
+ if @pid
16
+ puts "Already started (pid #{@pid})"
17
+ return
18
+ end
19
+ @pid = fork do
20
+ player_pid = nil
21
+ Signal.trap('TERM') do
22
+ Process.kill 'TERM', player_pid if player_pid
23
+ exit
24
+ end
25
+ total_tracks = @library.with_db {|db| db[:media_items].count }
26
+ loop do
27
+ id = dequeue || (rand * total_tracks).to_i
28
+ row = @library.with_db {|db| db[:media_items][:media_item_id=>id] }
29
+ if row
30
+ path = CGI.unescape(row[:content_url].slice(7..-1)) if row[:content_url] =~ /^file/
31
+ if path
32
+ puts "playing #{id}: \"#{path}\""
33
+ player_pid = path.to_player
34
+ Process.wait player_pid
35
+ end
36
+ end
37
+ end
38
+ end
39
+ puts "Started (pid #{@pid})"
40
+ end
41
+
42
+ def stop
43
+ return unless @pid
44
+ Process.kill 'TERM', @pid
45
+ @pid = nil
46
+ end
47
+
48
+ def restart
49
+ stop
50
+ start
51
+ end
52
+ end
@@ -0,0 +1,16 @@
1
+ module Songbirdsh::Queue
2
+ def enqueue id
3
+ with_db do |db|
4
+ File.open("#{Time.now.to_i}-#{(rand*1000).to_i}.song", 'w') {|f| f.print db[:media_items][:media_item_id=>id].to_yaml }
5
+ end
6
+ end
7
+
8
+ def dequeue
9
+ file = Dir.glob('*.song').sort.first
10
+ return nil unless file
11
+ hash = YAML.load(File.read(file))
12
+ id = hash[:media_item_id] if hash
13
+ FileUtils.rm file
14
+ id
15
+ end
16
+ end
data/lib/songbirdsh.rb ADDED
@@ -0,0 +1,7 @@
1
+ require 'rubygems'
2
+ require 'sequel'
3
+
4
+ module Songbirdsh
5
+ module Command
6
+ end
7
+ end
metadata ADDED
@@ -0,0 +1,179 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: songbirdsh
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 0
8
+ - 1
9
+ version: 0.0.1
10
+ platform: ruby
11
+ authors:
12
+ - Mark Ryall
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2011-01-30 00:00:00 +10:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: splat
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ~>
27
+ - !ruby/object:Gem::Version
28
+ segments:
29
+ - 0
30
+ - 1
31
+ version: "0.1"
32
+ type: :runtime
33
+ version_requirements: *id001
34
+ - !ruby/object:Gem::Dependency
35
+ name: shell_shock
36
+ prerelease: false
37
+ requirement: &id002 !ruby/object:Gem::Requirement
38
+ none: false
39
+ requirements:
40
+ - - ~>
41
+ - !ruby/object:Gem::Version
42
+ segments:
43
+ - 0
44
+ - 0
45
+ - 5
46
+ version: 0.0.5
47
+ type: :runtime
48
+ version_requirements: *id002
49
+ - !ruby/object:Gem::Dependency
50
+ name: sequel
51
+ prerelease: false
52
+ requirement: &id003 !ruby/object:Gem::Requirement
53
+ none: false
54
+ requirements:
55
+ - - ~>
56
+ - !ruby/object:Gem::Version
57
+ segments:
58
+ - 3
59
+ version: "3"
60
+ type: :runtime
61
+ version_requirements: *id003
62
+ - !ruby/object:Gem::Dependency
63
+ name: splat
64
+ prerelease: false
65
+ requirement: &id004 !ruby/object:Gem::Requirement
66
+ none: false
67
+ requirements:
68
+ - - ~>
69
+ - !ruby/object:Gem::Version
70
+ segments:
71
+ - 0
72
+ - 1
73
+ version: "0.1"
74
+ type: :runtime
75
+ version_requirements: *id004
76
+ - !ruby/object:Gem::Dependency
77
+ name: sqlite3
78
+ prerelease: false
79
+ requirement: &id005 !ruby/object:Gem::Requirement
80
+ none: false
81
+ requirements:
82
+ - - ~>
83
+ - !ruby/object:Gem::Version
84
+ segments:
85
+ - 1
86
+ version: "1"
87
+ type: :runtime
88
+ version_requirements: *id005
89
+ - !ruby/object:Gem::Dependency
90
+ name: rake
91
+ prerelease: false
92
+ requirement: &id006 !ruby/object:Gem::Requirement
93
+ none: false
94
+ requirements:
95
+ - - ~>
96
+ - !ruby/object:Gem::Version
97
+ segments:
98
+ - 0
99
+ - 8
100
+ - 7
101
+ version: 0.8.7
102
+ type: :development
103
+ version_requirements: *id006
104
+ - !ruby/object:Gem::Dependency
105
+ name: gemesis
106
+ prerelease: false
107
+ requirement: &id007 !ruby/object:Gem::Requirement
108
+ none: false
109
+ requirements:
110
+ - - ~>
111
+ - !ruby/object:Gem::Version
112
+ segments:
113
+ - 0
114
+ - 0
115
+ - 4
116
+ version: 0.0.4
117
+ type: :development
118
+ version_requirements: *id007
119
+ description: |
120
+ A command line jukebox music player that uses your songbird music player database
121
+
122
+ email: mark@ryall.name
123
+ executables:
124
+ - songbirdsh
125
+ extensions: []
126
+
127
+ extra_rdoc_files: []
128
+
129
+ files:
130
+ - lib/songbirdsh/cli.rb
131
+ - lib/songbirdsh/command/enqueue.rb
132
+ - lib/songbirdsh/command/reload.rb
133
+ - lib/songbirdsh/command/restart.rb
134
+ - lib/songbirdsh/command/search.rb
135
+ - lib/songbirdsh/command/show_properties.rb
136
+ - lib/songbirdsh/command/start.rb
137
+ - lib/songbirdsh/command/stop.rb
138
+ - lib/songbirdsh/library.rb
139
+ - lib/songbirdsh/player.rb
140
+ - lib/songbirdsh/queue.rb
141
+ - lib/songbirdsh.rb
142
+ - bin/songbirdsh
143
+ - README.rdoc
144
+ - MIT-LICENSE
145
+ - gemspec
146
+ has_rdoc: true
147
+ homepage: http://github.com/markryall/songbirdsh
148
+ licenses: []
149
+
150
+ post_install_message:
151
+ rdoc_options: []
152
+
153
+ require_paths:
154
+ - lib
155
+ required_ruby_version: !ruby/object:Gem::Requirement
156
+ none: false
157
+ requirements:
158
+ - - ">="
159
+ - !ruby/object:Gem::Version
160
+ segments:
161
+ - 0
162
+ version: "0"
163
+ required_rubygems_version: !ruby/object:Gem::Requirement
164
+ none: false
165
+ requirements:
166
+ - - ">="
167
+ - !ruby/object:Gem::Version
168
+ segments:
169
+ - 0
170
+ version: "0"
171
+ requirements: []
172
+
173
+ rubyforge_project:
174
+ rubygems_version: 1.3.7
175
+ signing_key:
176
+ specification_version: 3
177
+ summary: command line jukebox music player
178
+ test_files: []
179
+