vlc-client 0.0.3 → 0.0.4
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.
- 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
|