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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ae9ecda809fe61433d61d38c263715eebc2d99f3
4
- data.tar.gz: 46c6ef80d8507cb05d6a32f0f274e7eaf629cfbb
3
+ metadata.gz: e9195752c1e3f892ffc1d20509a533f195088591
4
+ data.tar.gz: 7b921a75027b04fcc866460727cc887ce68f8b4f
5
5
  SHA512:
6
- metadata.gz: e6f404e88f192deca0dd42e1acef2d4808bb70675b5a2a370cb293e9056e905fe1346f8ca56fc42b0780bb279ae47b5a9eb5df73fbe73cafd838ad95b0169cf2
7
- data.tar.gz: 41e9cda0d0b842f7a7e4e25917a7ae5cbc3c4bfd7623465a99e5dda5a7675342eb9e6640ac01abfdacc394e20849cc3cd67af996ef1b0d99d9d0b5f61d38143c
6
+ metadata.gz: 550e57fc4986d746c42ee7e45bc34ed022633a50c4007ed66d4438c68271fa93934294fa0b69961276b17b558aa50b803c1730d8d6f97ad0cb1c5572b1d50957
7
+ data.tar.gz: d680adf103db6d10dbcfbc6d99f7ca5ed6d30ce444935db395fd60eba9cee49709b1a954d46011c0a5ce8be660f1b6383e382d49d2cb46f57a4789b36357995b
data/.gitignore CHANGED
@@ -20,3 +20,4 @@ tmp
20
20
  Guardfile
21
21
  trials
22
22
  .ruby-*
23
+ .\#*
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
- - ruby-head
13
+ - 2.1.0
14
+ - ruby-head
data/Gemfile CHANGED
@@ -16,5 +16,4 @@ group :test do
16
16
  gem 'coveralls', :require => false
17
17
  end
18
18
 
19
- # Specify your gem's dependencies in vlc.gemspec
20
19
  gemspec
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
- @connection = Connection.new(host, port)
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
- private
75
+ private
74
76
  def bind_server(server, options = {})
75
77
  @connection.host = server.host
76
78
  @connection.port = server.port
@@ -16,7 +16,9 @@ module VLC
16
16
  connection.connected?
17
17
  end
18
18
 
19
- def disconnected?; not connected?; end
19
+ def disconnected?
20
+ not(connected?)
21
+ end
20
22
  end
21
23
  end
22
24
  end
@@ -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
- level.nil? ? Integer(connection.write("volume", false)) : connection.write("volume #{Integer(level)}")
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
- process_raw_playlist(list)
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 process_raw_playlist(list)
42
- list.map do |i|
43
- match = i.match(/^\|[\s]*(\d{1,2})\s-\s(.+)\((\d\d:\d\d:\d\d)\)(\s\[played\s(\d+)\stime[s]?\])?/)
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 => match[1].to_i,
48
- :title => match[2].strip,
49
- :length => match[3],
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
- attr_accessor :host, :port
9
+ DEFAULT_READ_TIMEOUT = 2 #secs
9
10
 
10
- def initialize(host, port)
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
- 2.times { read } #Clean the reading channel
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 @socket.nil?
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
- #TODO: Timeouts
66
- raw_data = @socket.gets.chomp
67
- if (data = process_data(raw_data))
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 process_data(data)
75
- data.match(/^[>*\s*]*(.*)$/)
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
@@ -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 ti a disconnected connection
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
@@ -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 @pid.nil?
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?; not running?; end
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
- @pid = Process.spawn(headless? ? 'cvlc' : 'vlc',
52
- '--extraintf', 'rc', '--rc-host', "#{@host}:#{@port}",
53
- :pgroup => detached,
54
- :in => '/dev/null',
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 not running?
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
@@ -1,3 +1,3 @@
1
1
  module VLC
2
- VERSION = "0.0.3"
2
+ VERSION = '0.0.4'
3
3
  end
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('./LICENSE', 'r')
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) { vlc.disconnect }
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,6 +1,6 @@
1
1
  describe VLC::Client::MediaControls do
2
- let(:vlc) { VLC::Client.new(:self_managed => false) }
3
2
  after(:each) { vlc.disconnect }
3
+ let(:vlc) { VLC::Client.new(:self_managed => false) }
4
4
 
5
5
  context 'plays media' do
6
6
  it 'from filesystem' do
@@ -1,7 +1,7 @@
1
1
  describe VLC::Client::PlaylistControls do
2
- let(:vlc) { VLC::Client.new(:self_managed => false) }
2
+ after(:each) { vlc.disconnect }
3
3
  let!(:server) { mock_tcp_server }
4
- after(:each) { vlc.disconnect }
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')
@@ -1,6 +1,6 @@
1
1
  describe VLC::Client::VideoControls do
2
- let(:vlc) { VLC::Client.new(:self_managed => false) }
3
2
  after(:each) { vlc.disconnect }
3
+ let(:vlc) { VLC::Client.new(:self_managed => false) }
4
4
 
5
5
  context 'manipulate the screen size' do
6
6
  it 'toggles fullscreen' do
@@ -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(:process_data).once.and_return(nil)
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
@@ -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.3
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-01-11 00:00:00.000000000 Z
11
+ date: 2014-03-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: retryable