ruby-ampache 0.0.10 → 0.1.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/README.rdoc +8 -13
- data/VERSION +1 -1
- data/bin/ruby-ampache +96 -66
- data/lib/lib-ampache.rb +73 -60
- data/lib/lib-classes.rb +176 -147
- metadata +4 -5
data/README.rdoc
CHANGED
@@ -6,15 +6,11 @@ Ruby-ampache is a really simple command line player for the ampache music server
|
|
6
6
|
|
7
7
|
You need to have mplayer installed to use ruby-ampache. Mplayer is used for playing music streams.
|
8
8
|
|
9
|
-
|
10
|
-
|
9
|
+
I've recently changed the way mplayer is invoked as mplayer slave mode is great,
|
10
|
+
but not good to manage playlists..
|
11
|
+
I'm still testing it right now but it should work far better.
|
11
12
|
|
12
|
-
the
|
13
|
-
set TIMEOUT variable in your .ruby-ampache config file
|
14
|
-
tuning it depending on your ampache server delay
|
15
|
-
|
16
|
-
Yes, this should be handled different
|
17
|
-
I'm free to any kind of suggestion on how to refactor this simple piece of software :)
|
13
|
+
A few options have been added to the menu and most of all it is full of colors now!
|
18
14
|
|
19
15
|
Gem can be installed as usual
|
20
16
|
|
@@ -27,11 +23,8 @@ example file:
|
|
27
23
|
AMPACHE_HOST="http://path_to_your_ampache_host"
|
28
24
|
AMPACHE_USER="username"
|
29
25
|
AMPACHE_USER_PSW="userpsw"
|
30
|
-
|
31
26
|
#optional (default is /usr/bin/mplayer)
|
32
27
|
MPLAYER_PATH="/usr/bin/mplayer"
|
33
|
-
# try to increase this value if you experience issues like "err on reading data"
|
34
|
-
TIMEOUT=20 #20 is a good value for a remote host
|
35
28
|
|
36
29
|
Simply execute ruby-ampache that should be found in you $PATH after installation
|
37
30
|
|
@@ -42,6 +35,10 @@ Also sometimes if mplayer get stucked playing a song the app does the same.
|
|
42
35
|
|
43
36
|
If you found more issues please let me know and I'll try to fix them as soon as possible
|
44
37
|
|
38
|
+
* fix encoding issues with file metadata retrieved from mplayer
|
39
|
+
|
40
|
+
|
41
|
+
|
45
42
|
== Notes
|
46
43
|
Special thanks goes to the developer of mplayer-ruby gem.
|
47
44
|
I've borrowed a couple of methods from his useful library
|
@@ -50,8 +47,6 @@ I've borrowed a couple of methods from his useful library
|
|
50
47
|
|
51
48
|
* Fork the project.
|
52
49
|
* Make your feature addition or bug fix.
|
53
|
-
* Add tests for it. This is important so I don't break it in a
|
54
|
-
future version unintentionally.
|
55
50
|
* Commit, do not mess with rakefile, version, or history.
|
56
51
|
(if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
|
57
52
|
* Send me a pull request. Bonus points for topic branches.
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.1.1
|
data/bin/ruby-ampache
CHANGED
@@ -2,12 +2,12 @@
|
|
2
2
|
# encoding: UTF-8
|
3
3
|
|
4
4
|
def secure_require(name)
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
5
|
+
begin
|
6
|
+
require name
|
7
|
+
rescue LoadError
|
8
|
+
$stderr.print "#{File.basename(__FILE__)} requires #{name} gem to work\n Pleas install it with: gem install #{name}\n"
|
9
|
+
exit
|
10
|
+
end
|
11
11
|
end
|
12
12
|
|
13
13
|
require 'rubygems'
|
@@ -16,77 +16,105 @@ secure_require 'highline/import'
|
|
16
16
|
secure_require 'parseconfig'
|
17
17
|
secure_require 'nokogiri'
|
18
18
|
secure_require 'iconv'
|
19
|
-
require File.join(File.dirname(__FILE__),'..','lib','lib-ampache')
|
20
|
-
require File.join(File.dirname(__FILE__),'..','lib','lib-classes')
|
19
|
+
require File.join(File.dirname(__FILE__), '..', 'lib', 'lib-ampache')
|
20
|
+
require File.join(File.dirname(__FILE__), '..', 'lib', 'lib-classes')
|
21
21
|
|
22
22
|
# XXX monkey patch for utf8 on ruby 1.9
|
23
23
|
if /^1\.9/ === RUBY_VERSION then
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
end
|
40
|
-
wrapped << line
|
41
|
-
end
|
42
|
-
return wrapped.join
|
24
|
+
class HighLine
|
25
|
+
def wrap (text)
|
26
|
+
text = text.force_encoding("UTF-8")
|
27
|
+
wrapped = []
|
28
|
+
text.each_line do |line|
|
29
|
+
while line =~ /([^\n]{#{@wrap_at + 1},})/
|
30
|
+
search = $1.dup
|
31
|
+
replace = $1.dup
|
32
|
+
if index = replace.rindex(" ", @wrap_at)
|
33
|
+
replace[index, 1] = "\n"
|
34
|
+
replace.sub!(/\n[ \t]+/, "\n")
|
35
|
+
line.sub!(search, replace)
|
36
|
+
else
|
37
|
+
line[$~.begin(1) + @wrap_at, 0] = "\n"
|
38
|
+
end
|
43
39
|
end
|
40
|
+
wrapped << line
|
41
|
+
end
|
42
|
+
return wrapped.join
|
44
43
|
end
|
44
|
+
end
|
45
45
|
end
|
46
46
|
|
47
47
|
# Ampache ruby parameters
|
48
48
|
begin
|
49
|
-
ar_config = ParseConfig.new(File.expand_path('~/.ruby-ampache'))
|
49
|
+
ar_config = ParseConfig.new(File.expand_path('~/.ruby-ampache'))
|
50
50
|
rescue
|
51
|
-
|
51
|
+
raise "\nPlease create a .ruby-ampache file on your home\n See http://github.com/ghedamat/ruby-ampache for infos\n"
|
52
52
|
end
|
53
53
|
|
54
54
|
# ruby-ampache highline version
|
55
55
|
$terminal.wrap_at = 80
|
56
56
|
$terminal.page_at = 22
|
57
57
|
|
58
|
+
def print_songs(album)
|
59
|
+
choose do |menu|
|
60
|
+
menu.prompt = "PICK A SONG (4..N), ADD WHOLE ALBUM (3), GO BACK(2) or BACK TO MENU(1)"
|
61
|
+
menu.choice(HighLine.new.color "BACK TO MENU", :red)
|
62
|
+
menu.choice(HighLine.new.color "BACK", :magenta) { print_albums(album.artist.albums) }
|
63
|
+
menu.choice(HighLine.new.color "ADD WHOLE ALBUM", :green) { album.add_to_playlist(@pl); print_albums(album.artist.albums) }
|
64
|
+
album.songs.each do |s|
|
65
|
+
menu.choice(s.title) { s.add_to_playlist(@pl); print_songs(album) }
|
66
|
+
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
58
71
|
def print_albums(albums)
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
72
|
+
choose do |menu|
|
73
|
+
menu.prompt = "CHOOSE AN ALBUM (4..N), ADD WHOLE ARTIST(3), BACK TO LIST(2) or BACK TO MENU (1) "
|
74
|
+
menu.choice(HighLine.new.color "BACK TO MENU", :red)
|
75
|
+
menu.choice(HighLine.new.color "BACK", :magenta) { print_artists(@ar.artists) }
|
76
|
+
menu.choice(HighLine.new.color "ADD WHOLE ARTIST", :green) { albums.first.artist.add_to_playlist(@pl); print_artists(@ar.artists) }
|
77
|
+
|
78
|
+
albums.each do |a|
|
79
|
+
menu.choice(a.name) { print_songs(a) }
|
80
|
+
end
|
81
|
+
end
|
66
82
|
end
|
67
83
|
|
68
84
|
def print_artists(artists)
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
end
|
85
|
+
if artists.empty?
|
86
|
+
reset_token
|
87
|
+
say("No results, retrying")
|
88
|
+
artists = @ar.artists
|
89
|
+
end
|
90
|
+
choose do |menu|
|
91
|
+
menu.prompt = "CHOOSE AN ARTIST (2..N) or BACK TO MENU (1)"
|
92
|
+
menu.choice(HighLine.new.color "BACK TO MENU", :red)
|
93
|
+
artists.each do |a|
|
94
|
+
menu.choice(a.name) { print_albums(a.albums) }
|
80
95
|
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def print_playlist
|
100
|
+
if @pl.list.empty?
|
101
|
+
say(HighLine.new.color "No more songs!\n",:red)
|
102
|
+
return
|
103
|
+
end
|
104
|
+
say(HighLine.new.color "Next Songs:", :yellow)
|
105
|
+
@pl.list.each_with_index do |p,i|
|
106
|
+
say(HighLine.new.color(i.to_s + " : ", :green) + p.title)
|
107
|
+
end
|
108
|
+
puts ""
|
81
109
|
end
|
82
110
|
|
83
111
|
# try to reset token if it's not valid
|
84
112
|
def reset_token
|
85
|
-
|
113
|
+
@ar.token = @ar.getAuthToken(@ar.user, @ar.psw)
|
86
114
|
end
|
87
115
|
|
88
116
|
def credits
|
89
|
-
|
117
|
+
s = <<STR
|
90
118
|
Ruby-Ampache: Ultra-simple, low-featured command line Ampache player (uses mplayer for playing)
|
91
119
|
Author: Mattia Gheda aka ghedamat
|
92
120
|
Homepage: http://github.com/ghedamat/ruby-ampache
|
@@ -94,32 +122,34 @@ Author-mail: thamayor@gmail.com
|
|
94
122
|
|
95
123
|
Usage: pick your choice from the menu.
|
96
124
|
You can start playing songs from your ampache server right now!
|
97
|
-
Simply choose an artist
|
125
|
+
Simply choose an artist,an album or a single song
|
98
126
|
You can queue up as many albums you like
|
99
|
-
Songs are queued up into mplayer playlist
|
100
|
-
|
101
127
|
STR
|
102
|
-
|
128
|
+
return s
|
103
129
|
end
|
104
130
|
|
105
131
|
# MAIN
|
106
|
-
@ar =AmpacheRuby.new(ar_config.get_value('AMPACHE_HOST'),ar_config.get_value('AMPACHE_USER'), ar_config.get_value('AMPACHE_USER_PSW'))
|
132
|
+
@ar =AmpacheRuby.new(ar_config.get_value('AMPACHE_HOST'), ar_config.get_value('AMPACHE_USER'), ar_config.get_value('AMPACHE_USER_PSW'))
|
107
133
|
$options = {}
|
108
134
|
$options[:path] = ar_config.get_value('MPLAYER_PATH')
|
109
135
|
$options[:timeout] = ar_config.get_value('TIMEOUT').to_i
|
110
136
|
@pl = AmpachePlaylist.new
|
111
137
|
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
138
|
+
say(HighLine.new.color "Welcome To ruby Ampache\n", :green)
|
139
|
+
while true
|
140
|
+
choose do |menu|
|
141
|
+
menu.prompt = HighLine.new.color("pick your choice!\n", :yellow)
|
142
|
+
menu.choice(HighLine.new.color("add artist/album/song to the playlist", :green)) { print_artists(@ar.artists); say(HighLine.new.color(@pl.now_playing, :red)) }
|
143
|
+
menu.choice(HighLine.new.color("search artist", :green)) { print_artists(@ar.artists(ask(HighLine.new.color("Artist name?", :red)))); say(HighLine.new.color(@pl.now_playing, :red)) }
|
144
|
+
|
145
|
+
menu.choice(HighLine.new.color("now playing", :magenta)) { say(HighLine.new.color(@pl.now_playing, :red)) }
|
146
|
+
menu.choice(HighLine.new.color("view next songs", :magenta)) {print_playlist}
|
147
|
+
menu.choice(HighLine.new.color("skip current song", :magenta)) { @pl.next; sleep 1;say(HighLine.new.color(@pl.now_playing, :red)) }
|
148
|
+
menu.choice(HighLine.new.color "stop playing and clear playlist", :magenta) { @pl.stop }
|
149
|
+
|
150
|
+
menu.choice(HighLine.new.color "pause playing",:magenta) { @pl.pause; say(HighLine.new.color("pause toggle!", :red)) }
|
151
|
+
menu.choice(HighLine.new.color "help and about", :yellow) { say(HighLine.new.color credits, :red) }
|
152
|
+
menu.choice("quit") { @pl.stop; exit }
|
153
|
+
end
|
124
154
|
end
|
125
155
|
|
data/lib/lib-ampache.rb
CHANGED
@@ -3,7 +3,7 @@ require 'net/http'
|
|
3
3
|
require 'open-uri'
|
4
4
|
require 'digest/sha2'
|
5
5
|
|
6
|
-
require File.join(File.dirname(__FILE__),'lib-ampache')
|
6
|
+
require File.join(File.dirname(__FILE__), 'lib-ampache')
|
7
7
|
|
8
8
|
=begin
|
9
9
|
Class is initialized with Hostname, user and password
|
@@ -13,78 +13,91 @@ To get the artist list from database you can
|
|
13
13
|
call the method artists(nil) and you'll get an array
|
14
14
|
of AmpacheArtists.
|
15
15
|
|
16
|
-
To get albums from an artist you can
|
16
|
+
To get albums from an artist you can use
|
17
17
|
artist_instance.albums or ampache_ruby.instance.albums(artist_instance)
|
18
18
|
=end
|
19
|
+
|
19
20
|
class AmpacheRuby
|
20
|
-
|
21
|
-
|
22
|
-
def initialize(host,user,psw)
|
23
|
-
uri = URI.parse(host)
|
24
|
-
@host = uri.host
|
25
|
-
@path = uri.path
|
26
|
-
@user = user
|
27
|
-
@psw = psw
|
28
|
-
@token = nil
|
29
|
-
@token = getAuthToken(user,psw)
|
30
|
-
end
|
31
21
|
|
32
|
-
attr_accessor :host, :path, :user, :psw, :token, :playlist
|
33
|
-
|
34
|
-
# tryies to obtain an auth token
|
35
|
-
def getAuthToken(user,psw)
|
36
|
-
action= "handshake"
|
37
|
-
# auth string
|
38
|
-
key = Digest::SHA2.new << psw
|
39
|
-
time = Time.now.to_i.to_s
|
40
|
-
psk = Digest::SHA2.new << (time + key.to_s)
|
41
22
|
|
42
|
-
|
43
|
-
|
23
|
+
def initialize(host, user, psw)
|
24
|
+
uri = URI.parse(host)
|
25
|
+
@host = uri.host
|
26
|
+
@path = uri.path
|
27
|
+
@user = user
|
28
|
+
@psw = psw
|
29
|
+
@token = nil
|
30
|
+
@token = getAuthToken(user, psw)
|
31
|
+
end
|
32
|
+
|
33
|
+
attr_accessor :host, :path, :user, :psw, :token, :playlist
|
34
|
+
|
35
|
+
# tryies to obtain an auth token
|
36
|
+
def getAuthToken(user, psw)
|
37
|
+
begin
|
38
|
+
action= "handshake"
|
39
|
+
# auth string
|
40
|
+
key = Digest::SHA2.new << psw
|
41
|
+
time = Time.now.to_i.to_s
|
42
|
+
psk = Digest::SHA2.new << (time + key.to_s)
|
44
43
|
|
45
|
-
|
44
|
+
args = {'auth' => psk, 'timestamp'=> time, 'version' => '350001', 'user' => user}
|
45
|
+
doc = callApiMethod(action, args);
|
46
|
+
|
47
|
+
return doc.at("auth").content
|
48
|
+
rescue Exception => e
|
49
|
+
warn ""
|
50
|
+
warn "token not valid or expired, check your username and password"
|
51
|
+
warn ""
|
46
52
|
end
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
53
|
+
end
|
54
|
+
|
55
|
+
# generic api method call
|
56
|
+
def callApiMethod(method, args={})
|
57
|
+
begin
|
58
|
+
args['auth'] ||= token if token
|
59
|
+
url = path + "/server/xml.server.php?action=#{method}&#{args.keys.collect { |k| "#{k}=#{args[k]}" }.join('&')}"
|
60
|
+
response = Net::HTTP.get_response(host, url)
|
61
|
+
return Nokogiri::XML(response.body)
|
62
|
+
rescue Errno::ECONNREFUSED => e
|
63
|
+
warn "Ampache closed with the following error"
|
64
|
+
warn e.message
|
65
|
+
exit
|
54
66
|
end
|
67
|
+
end
|
55
68
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
end
|
66
|
-
return artists
|
69
|
+
# retrive artists lists from database,
|
70
|
+
# name is an optional filter
|
71
|
+
def artists(name = nil)
|
72
|
+
args = {}
|
73
|
+
args = {'filter' => name.to_s} if name # artist search
|
74
|
+
artists = []
|
75
|
+
doc = callApiMethod("artists", args)
|
76
|
+
doc.xpath("//artist").each do |a|
|
77
|
+
artists << AmpacheArtist.new(self, a['id'], a.at("name").content)
|
67
78
|
end
|
79
|
+
return artists
|
80
|
+
end
|
68
81
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
end
|
76
|
-
return albums
|
82
|
+
def albums(artist)
|
83
|
+
albums = []
|
84
|
+
args = {'filter' => artist.uid.to_s}
|
85
|
+
doc = callApiMethod("artist_albums", args)
|
86
|
+
doc.xpath("//album").each do |a|
|
87
|
+
albums << AmpacheAlbum.new(self, a['id'], a.at("name").content, artist)
|
77
88
|
end
|
89
|
+
return albums
|
90
|
+
end
|
78
91
|
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
end
|
86
|
-
return songs
|
92
|
+
def songs(album)
|
93
|
+
songs = []
|
94
|
+
args = {'filter' => album.uid.to_s}
|
95
|
+
doc = callApiMethod("album_songs", args)
|
96
|
+
doc.xpath("//song").each do |s|
|
97
|
+
songs << AmpacheSong.new(self, s['id'], s.at("title").content, album.artist, album, s.at("url").content)
|
87
98
|
end
|
88
|
-
|
99
|
+
return songs
|
100
|
+
end
|
101
|
+
|
89
102
|
end
|
90
103
|
|
data/lib/lib-classes.rb
CHANGED
@@ -1,185 +1,214 @@
|
|
1
1
|
require 'open4'
|
2
2
|
require 'timeout'
|
3
3
|
class AmpacheArtist
|
4
|
-
|
5
|
-
# include play module
|
6
|
-
def initialize(ar,uid,name)
|
7
|
-
@ar = ar
|
8
|
-
@uid = uid
|
9
|
-
@name = name
|
10
|
-
end
|
11
4
|
|
12
|
-
|
5
|
+
# include play module
|
6
|
+
def initialize(ar, uid, name)
|
7
|
+
@ar = ar
|
8
|
+
@uid = uid
|
9
|
+
@name = name
|
10
|
+
end
|
13
11
|
|
14
|
-
|
15
|
-
|
16
|
-
|
12
|
+
attr_reader :uid, :name
|
13
|
+
|
14
|
+
def albums
|
15
|
+
@albums ||= @ar.albums(self)
|
16
|
+
end
|
17
|
+
|
18
|
+
def add_to_playlist(pl)
|
19
|
+
albums.each do |s|
|
20
|
+
s.add_to_playlist(pl)
|
21
|
+
sleep 1
|
22
|
+
end
|
23
|
+
end
|
17
24
|
end
|
18
25
|
|
19
26
|
|
20
27
|
class AmpacheAlbum
|
21
|
-
|
22
|
-
def initialize(ar,uid,name,artist)
|
23
|
-
@ar = ar
|
24
|
-
@uid = uid
|
25
|
-
@name = name
|
26
|
-
@artist = artist
|
27
|
-
end
|
28
28
|
|
29
|
-
|
29
|
+
def initialize(ar, uid, name, artist)
|
30
|
+
@ar = ar
|
31
|
+
@uid = uid
|
32
|
+
@name = name
|
33
|
+
@artist = artist
|
34
|
+
end
|
30
35
|
|
31
|
-
|
32
|
-
@songs ||= @ar.songs(self)
|
33
|
-
end
|
36
|
+
attr_reader :uid, :name, :artist
|
34
37
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
38
|
+
def songs
|
39
|
+
@songs ||= @ar.songs(self)
|
40
|
+
end
|
41
|
+
|
42
|
+
def add_to_playlist(pl)
|
43
|
+
songs.each do |s|
|
44
|
+
s.add_to_playlist(pl)
|
39
45
|
end
|
46
|
+
end
|
40
47
|
|
41
48
|
end
|
42
49
|
|
43
50
|
class AmpacheSong
|
44
51
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
52
|
+
def initialize(ar, uid, title, artist, album, url)
|
53
|
+
@ar = ar
|
54
|
+
@uid = uid
|
55
|
+
@title = title
|
56
|
+
@artist = artist
|
57
|
+
@album = album
|
58
|
+
@url = url
|
59
|
+
end
|
53
60
|
|
54
|
-
|
61
|
+
attr_reader :uid, :title, :artist, :album, :url
|
55
62
|
|
56
|
-
|
57
|
-
|
58
|
-
|
63
|
+
def add_to_playlist(pl)
|
64
|
+
pl.add(self)
|
65
|
+
end
|
59
66
|
|
60
67
|
end
|
61
68
|
|
62
|
-
class AmpachePlaylist
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
69
|
+
class AmpachePlaylist
|
70
|
+
|
71
|
+
def initialize
|
72
|
+
@started = false
|
73
|
+
@list = []
|
74
|
+
end
|
75
|
+
|
76
|
+
attr_reader :list
|
77
|
+
|
78
|
+
def started?
|
79
|
+
@started == true
|
80
|
+
end
|
81
|
+
|
82
|
+
def started!
|
83
|
+
@started = true
|
84
|
+
end
|
85
|
+
|
86
|
+
|
87
|
+
def mplayer_start(song)
|
88
|
+
#puts song.inspect
|
89
|
+
$options[:path] ||= '/usr/bin/mplayer'
|
90
|
+
$options[:timeout] ||= 15
|
91
|
+
mplayer_options = "-slave -quiet"
|
92
|
+
mplayer = "#{$options[:path]} #{mplayer_options} \"#{song.url}\""
|
93
|
+
@pid, @stdin, @stdout, @stderr = Open4.popen4(mplayer)
|
94
|
+
#puts mplayer
|
95
|
+
started!
|
96
|
+
Thread.new do
|
97
|
+
ignored, status = Process::waitpid2 @pid
|
98
|
+
next_song = @list.slice!(0)
|
99
|
+
if next_song && started?
|
100
|
+
mplayer_start(next_song)
|
101
|
+
else
|
102
|
+
puts "PLAYLIST OVER"
|
103
|
+
@started = false
|
104
|
+
@pid = nil
|
105
|
+
end
|
91
106
|
end
|
107
|
+
end
|
92
108
|
|
93
|
-
|
94
|
-
|
109
|
+
def console
|
110
|
+
while ((cmd = gets.chomp) != 'exit' )
|
111
|
+
@stdin.puts cmd
|
95
112
|
end
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
113
|
+
end
|
114
|
+
|
115
|
+
def add(song)
|
116
|
+
say(HighLine.new.color("adding song ",:green) + "#{song.title}")
|
117
|
+
if !@pid && !started?
|
118
|
+
mplayer_start(song)
|
119
|
+
else
|
120
|
+
@list << song
|
104
121
|
end
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
122
|
+
end
|
123
|
+
|
124
|
+
def stop
|
125
|
+
begin
|
126
|
+
@started = false
|
127
|
+
@list = []
|
128
|
+
@stdin.puts "quit" if @pid
|
129
|
+
rescue Errno::EPIPE
|
130
|
+
puts "playlist is over"
|
112
131
|
end
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
132
|
+
@pid = nil
|
133
|
+
end
|
134
|
+
|
135
|
+
def pause
|
136
|
+
begin
|
137
|
+
@stdin.puts "pause" if @pid && started?
|
138
|
+
rescue Errno::EPIPE
|
139
|
+
puts "playlist is over"
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
def next
|
144
|
+
begin
|
145
|
+
# quit current mplayer instance.. thread will fire up next song!
|
146
|
+
@stdin.puts "quit" if @pid && started?
|
147
|
+
rescue Errno::EPIPE => e
|
148
|
+
puts "playlist is over on next"
|
149
|
+
@pid = nil
|
121
150
|
end
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
rescue Timeout::Error
|
139
|
-
@tim += 1
|
140
|
-
if (@tim > 3 )
|
141
|
-
@tim = 0
|
142
|
-
return "err"
|
143
|
-
else
|
144
|
-
return nowPlaying
|
145
|
-
end
|
146
|
-
end
|
147
|
-
rescue Errno::EPIPE => e
|
148
|
-
@pid = nil
|
149
|
-
return "playlist is over here" #, or you got an ERROR from mplayer: #{e.to_s}"
|
151
|
+
end
|
152
|
+
|
153
|
+
def now_playing
|
154
|
+
return "Not playing man!" unless started? && !@pid.nil?
|
155
|
+
begin
|
156
|
+
s = get("meta_title")
|
157
|
+
return "data not available OR playlist is over" if s.nil?
|
158
|
+
s+= get("meta_artist") rescue s
|
159
|
+
s+= get("meta_album") rescue s
|
160
|
+
s.chomp!
|
161
|
+
return s
|
162
|
+
|
163
|
+
rescue Errno::EPIPE => e
|
164
|
+
@pid = nil
|
165
|
+
@started = false
|
166
|
+
return "playlist is over here" #, or you got an ERROR from mplayer: #{e.to_s}"
|
150
167
|
|
151
|
-
end
|
152
168
|
end
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
169
|
+
end
|
170
|
+
|
171
|
+
# I borrowed these two methods from the author of mplayer-ruby!
|
172
|
+
# so my thanks to Artuh Chiu and his great gem mplayer-ruby
|
173
|
+
def get(value)
|
174
|
+
field = value.to_s
|
175
|
+
match = case field
|
176
|
+
when "time_pos" then
|
177
|
+
"ANS_TIME_POSITION"
|
178
|
+
when "time_length" then
|
179
|
+
"ANS_LENGTH"
|
180
|
+
when "file_name" then
|
181
|
+
"ANS_FILENAME"
|
182
|
+
else
|
183
|
+
"ANS_#{field.upcase}"
|
166
184
|
end
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
response
|
185
|
+
res = command("get_#{value}", /#{match}/)
|
186
|
+
res.gsub("#{match}=", "").gsub("'", "") unless res.nil?
|
187
|
+
end
|
188
|
+
|
189
|
+
def command(cmd, match = //)
|
190
|
+
@stdin.puts(cmd)
|
191
|
+
response = ""
|
192
|
+
begin
|
193
|
+
t = Timeout::timeout(3) do
|
194
|
+
until response =~ match
|
195
|
+
response = @stdout.gets
|
196
|
+
#puts response
|
197
|
+
#XXX escaping bad utf8 chars
|
198
|
+
ic = Iconv.new('UTF-8//IGNORE', 'UTF-8')
|
199
|
+
if response
|
200
|
+
response =ic.iconv(response + ' ')[0..-2]
|
201
|
+
else
|
202
|
+
response == ''
|
203
|
+
end
|
179
204
|
end
|
180
205
|
end
|
181
|
-
response.gsub("\e[A\r\e[K","")
|
206
|
+
return response.gsub("\e[A\r\e[K", "")
|
207
|
+
rescue Timeout::Error
|
208
|
+
return
|
182
209
|
end
|
183
210
|
|
211
|
+
end
|
212
|
+
|
184
213
|
end
|
185
214
|
|
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: ruby-ampache
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 0.
|
5
|
+
version: 0.1.1
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- ghedmat
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2011-
|
13
|
+
date: 2011-09-26 00:00:00 +02:00
|
14
14
|
default_executable: ruby-ampache
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
@@ -104,6 +104,5 @@ rubygems_version: 1.5.0
|
|
104
104
|
signing_key:
|
105
105
|
specification_version: 3
|
106
106
|
summary: Ruby ampache command line client
|
107
|
-
test_files:
|
108
|
-
|
109
|
-
- test/test_ruby-ampache.rb
|
107
|
+
test_files: []
|
108
|
+
|