vlc-client 0.0.3 → 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.travis.yml +2 -6
- data/Gemfile +0 -1
- data/lib/vlc-client.rb +5 -3
- data/lib/vlc-client/client/connection_management.rb +3 -1
- data/lib/vlc-client/client/media_controls.rb +2 -1
- data/lib/vlc-client/client/playlist_controls.rb +18 -8
- data/lib/vlc-client/connection.rb +28 -11
- data/lib/vlc-client/errors.rb +4 -1
- data/lib/vlc-client/server.rb +54 -36
- data/lib/vlc-client/version.rb +1 -1
- data/spec/helper.rb +3 -3
- data/spec/vlc-client/client/connection_management_spec.rb +2 -2
- data/spec/vlc-client/client/media_controls_spec.rb +1 -1
- data/spec/vlc-client/client/playlist_controls_spec.rb +2 -2
- data/spec/vlc-client/client/video_controls_spec.rb +1 -1
- data/spec/vlc-client/connection_spec.rb +37 -2
- data/spec/vlc_client_spec.rb +7 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e9195752c1e3f892ffc1d20509a533f195088591
|
4
|
+
data.tar.gz: 7b921a75027b04fcc866460727cc887ce68f8b4f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 550e57fc4986d746c42ee7e45bc34ed022633a50c4007ed66d4438c68271fa93934294fa0b69961276b17b558aa50b803c1730d8d6f97ad0cb1c5572b1d50957
|
7
|
+
data.tar.gz: d680adf103db6d10dbcfbc6d99f7ca5ed6d30ce444935db395fd60eba9cee49709b1a954d46011c0a5ce8be660f1b6383e382d49d2cb46f57a4789b36357995b
|
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
@@ -1,8 +1,3 @@
|
|
1
|
-
before_install:
|
2
|
-
#This is a temporary workaround a rubygems bug! Remove later
|
3
|
-
#see: https://github.com/bundler/bundler/issues/2784 & https://github.com/rubygems/rubygems/pull/763
|
4
|
-
- gem update --system 2.1.11
|
5
|
-
- gem --version
|
6
1
|
language: ruby
|
7
2
|
script: bundle exec rake --verbose --trace
|
8
3
|
bundler_args: --without development
|
@@ -15,4 +10,5 @@ rvm:
|
|
15
10
|
- 1.9.2
|
16
11
|
- 1.9.3
|
17
12
|
- 2.0.0
|
18
|
-
-
|
13
|
+
- 2.1.0
|
14
|
+
- ruby-head
|
data/Gemfile
CHANGED
data/lib/vlc-client.rb
CHANGED
@@ -46,6 +46,7 @@ module VLC
|
|
46
46
|
# @option options [Boolean] :auto_start When false, the server lifecycle is not managed automatically and controll is passed to the developer
|
47
47
|
# @option options [Integer] :conn_retries Number of connection retries (each separated by a second) to make on auto-connect. Defaults to 5.
|
48
48
|
# @option options [Boolean] :daemonize When true and only when on server auto-start mode, the server will be detached and run as a daemon process. Defaults to false.
|
49
|
+
# @option options [Integer] :read_timeout Read timout value
|
49
50
|
#
|
50
51
|
# @example
|
51
52
|
# vlc = VLC::Client.new(VLC::Server.new)
|
@@ -63,14 +64,15 @@ module VLC
|
|
63
64
|
#
|
64
65
|
def initialize(*args)
|
65
66
|
args = NullObject.Null?(args)
|
66
|
-
options = args.extract_options!
|
67
67
|
|
68
|
+
options = args.extract_options!
|
68
69
|
process_args(args)
|
69
|
-
|
70
|
+
|
71
|
+
@connection = Connection.new(host, port, options[:read_timeout])
|
70
72
|
bind_server(server, options) unless server.nil?
|
71
73
|
end
|
72
74
|
|
73
|
-
|
75
|
+
private
|
74
76
|
def bind_server(server, options = {})
|
75
77
|
@connection.host = server.host
|
76
78
|
@connection.port = server.port
|
@@ -90,7 +90,8 @@ module VLC
|
|
90
90
|
# @param [Integer] level the volume level to set
|
91
91
|
#
|
92
92
|
def volume(level = nil)
|
93
|
-
|
93
|
+
return Integer(connection.write("volume", false)) if level.nil?
|
94
|
+
connection.write("volume #{Integer(level)}")
|
94
95
|
rescue ArgumentError
|
95
96
|
level.nil? ? 0 : nil
|
96
97
|
end
|
@@ -4,6 +4,14 @@ module VLC
|
|
4
4
|
# @private
|
5
5
|
PLAYLIST_TERMINATOR = "+----[ End of playlist ]"
|
6
6
|
|
7
|
+
# @private
|
8
|
+
LIST_ITEM_REGEXP = %r{
|
9
|
+
^\|[\s]*(\d{1,2})\s-\s(.+)
|
10
|
+
\((\d\d:\d\d:\d\d)\)
|
11
|
+
(\s\[played\s(\d+)
|
12
|
+
\stime[s]?\])?
|
13
|
+
}x
|
14
|
+
|
7
15
|
# Adds media to the playlist
|
8
16
|
#
|
9
17
|
# @param media [String, File, URI] the media to be played
|
@@ -20,7 +28,8 @@ module VLC
|
|
20
28
|
begin
|
21
29
|
list << connection.read
|
22
30
|
end while list.last != PLAYLIST_TERMINATOR
|
23
|
-
|
31
|
+
|
32
|
+
parse_playlist(list)
|
24
33
|
end
|
25
34
|
|
26
35
|
# Plays the next element on the playlist
|
@@ -37,19 +46,20 @@ module VLC
|
|
37
46
|
def clear
|
38
47
|
connection.write("clear")
|
39
48
|
end
|
49
|
+
|
40
50
|
private
|
41
|
-
def
|
42
|
-
list.map do |
|
43
|
-
match =
|
51
|
+
def parse_playlist(list)
|
52
|
+
list.map do |item|
|
53
|
+
match = item.match(LIST_ITEM_REGEXP)
|
44
54
|
|
45
55
|
next if match.nil?
|
46
56
|
|
47
|
-
{:number
|
48
|
-
:title
|
49
|
-
:length
|
57
|
+
{:number => match[1].to_i,
|
58
|
+
:title => match[2].strip,
|
59
|
+
:length => match[3],
|
50
60
|
:times_played => match[5].to_i}
|
51
61
|
end.compact
|
52
62
|
end
|
53
63
|
end
|
54
64
|
end
|
55
|
-
end
|
65
|
+
end
|
@@ -1,21 +1,26 @@
|
|
1
1
|
require 'socket'
|
2
|
+
require 'timeout'
|
2
3
|
|
3
4
|
module VLC
|
4
5
|
#
|
5
6
|
# Manages the connection to a VLC server
|
6
7
|
#
|
7
8
|
class Connection
|
8
|
-
|
9
|
+
DEFAULT_READ_TIMEOUT = 2 #secs
|
9
10
|
|
10
|
-
|
11
|
+
attr_accessor :host, :port, :read_timeout
|
12
|
+
|
13
|
+
def initialize(host, port, read_timeout=nil)
|
11
14
|
@host, @port = host, port
|
12
15
|
@socket = NullObject.new
|
16
|
+
@read_timeout = read_timeout || DEFAULT_READ_TIMEOUT
|
13
17
|
end
|
14
18
|
|
15
19
|
# Connects to VLC RC interface on Client#host and Client#port
|
16
20
|
def connect
|
17
21
|
@socket = TCPSocket.new(@host, @port)
|
18
|
-
|
22
|
+
#Channel cleanup: some vlc versions echo two lines of text on connect.
|
23
|
+
2.times { read(0.1) rescue nil }
|
19
24
|
true
|
20
25
|
rescue Errno::ECONNREFUSED => e
|
21
26
|
raise VLC::ConnectionRefused, "Could not connect to #{@host}:#{@port}: #{e}"
|
@@ -26,7 +31,7 @@ module VLC
|
|
26
31
|
# @return [Boolean] true is connected, false otherwise
|
27
32
|
#
|
28
33
|
def connected?
|
29
|
-
not
|
34
|
+
not(@socket.nil?)
|
30
35
|
end
|
31
36
|
|
32
37
|
# Disconnects from VLC RC interface
|
@@ -59,20 +64,32 @@ module VLC
|
|
59
64
|
|
60
65
|
# Reads data from the TCP server
|
61
66
|
#
|
67
|
+
# @param timeout read timeout value for a read operation.
|
68
|
+
# If omited the configured value or DEFAULT_READ_TIMEOUT will be used.
|
69
|
+
#
|
70
|
+
#
|
62
71
|
# @return [String] the data
|
63
72
|
#
|
64
|
-
def read
|
65
|
-
|
66
|
-
raw_data =
|
67
|
-
|
73
|
+
def read(timeout=nil)
|
74
|
+
timeout = read_timeout if timeout.nil?
|
75
|
+
raw_data = nil
|
76
|
+
|
77
|
+
Timeout.timeout(timeout) do
|
78
|
+
raw_data = @socket.gets.chomp
|
79
|
+
end
|
80
|
+
|
81
|
+
if (data = parse_raw_data(raw_data))
|
68
82
|
data[1]
|
69
83
|
else
|
70
|
-
raise ProtocolError, "could not interpret the playload: #{raw_data}"
|
84
|
+
raise VLC::ProtocolError, "could not interpret the playload: #{raw_data}"
|
71
85
|
end
|
86
|
+
rescue Timeout::Error
|
87
|
+
raise VLC::ReadTimeoutError, "read timeout"
|
72
88
|
end
|
73
89
|
|
74
|
-
def
|
75
|
-
data.
|
90
|
+
def parse_raw_data(data)
|
91
|
+
return nil if data.nil?
|
92
|
+
data.match(%r{^[>*\s*]*(.*)$})
|
76
93
|
end
|
77
94
|
end
|
78
95
|
end
|
data/lib/vlc-client/errors.rb
CHANGED
@@ -11,6 +11,9 @@ module VLC
|
|
11
11
|
# Raised on a write to a broken connection
|
12
12
|
class BrokenConnectionError < Error; end
|
13
13
|
|
14
|
-
# Raised on a write
|
14
|
+
# Raised on a write to a disconnected connection
|
15
15
|
class NotConnectedError < Error; end
|
16
|
+
|
17
|
+
# Raised on a read timeout
|
18
|
+
class ReadTimeoutError < Error; end
|
16
19
|
end
|
data/lib/vlc-client/server.rb
CHANGED
@@ -23,7 +23,7 @@ module VLC
|
|
23
23
|
# @return [Boolean] true is VLC is running, false otherwise
|
24
24
|
#
|
25
25
|
def running?
|
26
|
-
not
|
26
|
+
not(@pid.nil?)
|
27
27
|
end
|
28
28
|
|
29
29
|
alias :started? :running?
|
@@ -32,7 +32,9 @@ module VLC
|
|
32
32
|
#
|
33
33
|
# @return [Boolean] true is VLC is stopped, false otherwise
|
34
34
|
#
|
35
|
-
def stopped
|
35
|
+
def stopped?
|
36
|
+
not(running?)
|
37
|
+
end
|
36
38
|
|
37
39
|
# Starts a VLC instance in a subprocess
|
38
40
|
#
|
@@ -47,38 +49,11 @@ module VLC
|
|
47
49
|
return @pid if running?
|
48
50
|
detached ? @deamon = true : setup_traps
|
49
51
|
|
50
|
-
if RUBY_VERSION >= '1.9'
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
:out => '/dev/null',
|
56
|
-
:err => '/dev/null')
|
57
|
-
|
58
|
-
return @pid
|
59
|
-
end
|
60
|
-
|
61
|
-
# for Ruby 1.8 and below
|
62
|
-
rd, wr = IO.pipe
|
63
|
-
if Process.fork #parent
|
64
|
-
wr.close
|
65
|
-
@pid = rd.read.to_i
|
66
|
-
rd.close
|
67
|
-
return @pid
|
68
|
-
else #child
|
69
|
-
rd.close
|
70
|
-
|
71
|
-
detach if detached #daemonization
|
72
|
-
|
73
|
-
wr.write(Process.pid)
|
74
|
-
wr.close
|
75
|
-
|
76
|
-
STDIN.reopen "/dev/null"
|
77
|
-
STDOUT.reopen "/dev/null", "a"
|
78
|
-
STDERR.reopen "/dev/null", "a"
|
79
|
-
|
80
|
-
Kernel.exec "#{headless? ? 'cvlc' : 'vlc'} --extraintf rc --rc-host #{@host}:#{@port}"
|
81
|
-
end
|
52
|
+
@pid = if RUBY_VERSION >= '1.9'
|
53
|
+
process_spawn(detached)
|
54
|
+
else
|
55
|
+
process_spawn_ruby_1_8(detached)
|
56
|
+
end
|
82
57
|
end
|
83
58
|
|
84
59
|
# Start a VLC instance as a system deamon
|
@@ -106,7 +81,7 @@ module VLC
|
|
106
81
|
# as no effect (e.g. VLC not running)
|
107
82
|
#
|
108
83
|
def stop
|
109
|
-
return nil if
|
84
|
+
return nil if stopped?
|
110
85
|
|
111
86
|
Process.kill('INT', pid = @pid)
|
112
87
|
@pid = NullObject.new
|
@@ -115,6 +90,48 @@ module VLC
|
|
115
90
|
end
|
116
91
|
|
117
92
|
private
|
93
|
+
def process_spawn(detached)
|
94
|
+
if ENV['OS'] == 'Windows_NT'
|
95
|
+
# We don't have pgroup, and should write to NUL in case the env doesn't simulate /dev/null
|
96
|
+
Process.spawn(headless? ? 'cvlc' : 'vlc',
|
97
|
+
'--extraintf', 'rc', '--rc-host', "#{@host}:#{@port}",
|
98
|
+
:in => 'NUL',
|
99
|
+
:out => 'NUL',
|
100
|
+
:err => 'NUL')
|
101
|
+
else
|
102
|
+
Process.spawn(headless? ? 'cvlc' : 'vlc',
|
103
|
+
'--extraintf', 'rc', '--rc-host', "#{@host}:#{@port}",
|
104
|
+
:pgroup => detached,
|
105
|
+
:in => '/dev/null',
|
106
|
+
:out => '/dev/null',
|
107
|
+
:err => '/dev/null')
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
# For ruby 1.8
|
112
|
+
def process_spawn_ruby_1_8(detached)
|
113
|
+
rd, wr = IO.pipe
|
114
|
+
if Process.fork #parent
|
115
|
+
wr.close
|
116
|
+
pid = rd.read.to_i
|
117
|
+
rd.close
|
118
|
+
return pid
|
119
|
+
else #child
|
120
|
+
rd.close
|
121
|
+
|
122
|
+
detach if detached #daemonization
|
123
|
+
|
124
|
+
wr.write(Process.pid)
|
125
|
+
wr.close
|
126
|
+
|
127
|
+
STDIN.reopen "/dev/null"
|
128
|
+
STDOUT.reopen "/dev/null", "a"
|
129
|
+
STDERR.reopen "/dev/null", "a"
|
130
|
+
|
131
|
+
Kernel.exec "#{headless? ? 'cvlc' : 'vlc'} --extraintf rc --rc-host #{@host}:#{@port}"
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
118
135
|
def setup_traps
|
119
136
|
trap("EXIT") do
|
120
137
|
stop
|
@@ -126,10 +143,11 @@ module VLC
|
|
126
143
|
exit
|
127
144
|
end
|
128
145
|
|
146
|
+
|
129
147
|
trap("CLD") do
|
130
148
|
@pid = NullObject.new
|
131
149
|
@deamon = false
|
132
|
-
end
|
150
|
+
end if Signal.list['CLD'] # Windows does not support this signal. Or daemons.
|
133
151
|
end
|
134
152
|
|
135
153
|
def detach
|
data/lib/vlc-client/version.rb
CHANGED
data/spec/helper.rb
CHANGED
@@ -48,11 +48,11 @@ module Mocks
|
|
48
48
|
end
|
49
49
|
|
50
50
|
def mock_file(filename)
|
51
|
-
File.stub(:open).and_return
|
52
|
-
f = File.new('./
|
51
|
+
File.stub(:open).and_return do
|
52
|
+
f = File.new('./README.md', 'r')
|
53
53
|
f.should_receive(:path).once.and_return(filename)
|
54
54
|
f
|
55
|
-
|
55
|
+
end
|
56
56
|
end
|
57
57
|
end
|
58
58
|
|
@@ -1,7 +1,7 @@
|
|
1
1
|
describe VLC::Client::ConnectionManagement do
|
2
|
-
let(:vlc) { VLC::Client.new(:self_managed => false) }
|
3
2
|
before(:each) { mock_tcp_server }
|
4
|
-
after(:each)
|
3
|
+
after(:each) { vlc.disconnect }
|
4
|
+
let(:vlc) { VLC::Client.new(:self_managed => false) }
|
5
5
|
|
6
6
|
context 'when disconnected' do
|
7
7
|
specify { vlc.should be_disconnected }
|
@@ -1,7 +1,7 @@
|
|
1
1
|
describe VLC::Client::PlaylistControls do
|
2
|
-
|
2
|
+
after(:each) { vlc.disconnect }
|
3
3
|
let!(:server) { mock_tcp_server }
|
4
|
-
|
4
|
+
let(:vlc) { VLC::Client.new(:self_managed => false) }
|
5
5
|
|
6
6
|
it 'enqueues media' do
|
7
7
|
server.should_receive(:puts).once.with('enqueue media.mp3')
|
@@ -42,14 +42,49 @@ describe VLC::Connection do
|
|
42
42
|
end
|
43
43
|
end
|
44
44
|
|
45
|
+
context 'supports read timeouts' do
|
46
|
+
it 'per call' do
|
47
|
+
tcp = mock_tcp_server
|
48
|
+
connection.connect
|
49
|
+
|
50
|
+
Timeout.should_receive(:timeout).with(5)
|
51
|
+
connection.should_receive(:parse_raw_data).and_return([])
|
52
|
+
connection.read(5)
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'configured' do
|
56
|
+
tcp = mock_tcp_server
|
57
|
+
connection = VLC::Connection.new('localhost', 9595, 3)
|
58
|
+
connection.connect
|
59
|
+
|
60
|
+
Timeout.should_receive(:timeout).with(3)
|
61
|
+
connection.should_receive(:parse_raw_data).and_return([])
|
62
|
+
connection.read
|
63
|
+
connection.close
|
64
|
+
end
|
65
|
+
|
66
|
+
it "defaults to #{VLC::Connection::DEFAULT_READ_TIMEOUT}" do
|
67
|
+
connection = VLC::Connection.new('localhost', 9595, nil)
|
68
|
+
connection.read_timeout.should eq(VLC::Connection::DEFAULT_READ_TIMEOUT)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
45
72
|
context 'raises error on' do
|
73
|
+
it 'read timeout' do
|
74
|
+
tcp = mock_tcp_server
|
75
|
+
connection.connect
|
76
|
+
|
77
|
+
Timeout.should_receive(:timeout).and_raise(Timeout::Error)
|
78
|
+
expect { connection.read(0) }.to raise_error(VLC::ReadTimeoutError)
|
79
|
+
end
|
80
|
+
|
46
81
|
it 'unreadable content' do
|
47
82
|
tcp = mock_tcp_server
|
48
83
|
tcp.should_receive(:puts).once.with('some data')
|
49
84
|
tcp.should_receive(:gets).once.and_return('some response data')
|
50
85
|
|
51
86
|
connection.connect
|
52
|
-
connection.should_receive(:
|
87
|
+
connection.should_receive(:parse_raw_data).once.and_return(nil)
|
53
88
|
|
54
89
|
expect { connection.write('some data', false) }.to raise_error(VLC::ProtocolError)
|
55
90
|
end
|
@@ -67,4 +102,4 @@ describe VLC::Connection do
|
|
67
102
|
expect { connection.write('something') }.to raise_error(VLC::NotConnectedError)
|
68
103
|
end
|
69
104
|
end
|
70
|
-
end
|
105
|
+
end
|
data/spec/vlc_client_spec.rb
CHANGED
@@ -27,6 +27,13 @@ describe VLC::Client do
|
|
27
27
|
vlc.server.should_not be_started
|
28
28
|
vlc.should_not be_connected
|
29
29
|
end
|
30
|
+
|
31
|
+
it 'accepts timeout configuration' do
|
32
|
+
mock_system_calls(:kill => false)
|
33
|
+
|
34
|
+
vlc = VLC::Client.new(VLC::Server.new('10.0.0.1', 9999), :read_timeout => 3)
|
35
|
+
vlc.connection.read_timeout.should eq(3)
|
36
|
+
end
|
30
37
|
end
|
31
38
|
|
32
39
|
it 'may manage an embedded VLC server' do
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: vlc-client
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Miguel Guinada
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-03-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: retryable
|