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 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