rmplayer 1.0

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 ADDED
@@ -0,0 +1,10 @@
1
+ = RMPlayer =
2
+
3
+ Remote MPlayer. VLC HTTP interface implementation for MPlayer.
4
+
5
+ Tested using VLC Remote Android app.
6
+
7
+ = Usage =
8
+
9
+ rmplayer [mplayer options] file_name
10
+
@@ -0,0 +1,66 @@
1
+ require 'rake'
2
+ require 'rake/gempackagetask'
3
+ require 'rake/testtask'
4
+ require 'rake/clean'
5
+
6
+ PKG_NAME = 'rmplayer'
7
+ PKG_VERSION = "1.0"
8
+
9
+ PKG_FILES = FileList[
10
+ '[A-Z]*',
11
+ 'bin/**/*',
12
+ 'lib/**/*',
13
+ ]
14
+
15
+ CLEAN.include('build')
16
+
17
+ task :default => :package
18
+
19
+ spec = Gem::Specification.new do |s|
20
+ s.name = PKG_NAME
21
+ s.version = PKG_VERSION
22
+ s.summary = "Remote control interface for MPlayer"
23
+ s.description = <<-EOF
24
+ #{PKG_NAME} implements HTTP protocol used by Vlc to control MPlayer.
25
+ More to the point, I just wanted to use VLC remote android app to control MPlayer.
26
+ EOF
27
+
28
+ s.files = PKG_FILES.to_a
29
+
30
+ s.bindir = "bin"
31
+ s.executables = ["rmplayer"]
32
+ s.default_executable = "rmplayer"
33
+
34
+ s.require_path = 'lib'
35
+
36
+ s.add_dependency 'builder'
37
+
38
+ s.has_rdoc = false
39
+
40
+ s.author = "Peter Severin"
41
+ s.email = "peter_p_s@users.sourceforge.net"
42
+ end
43
+
44
+ Rake::GemPackageTask.new(spec) do |p|
45
+ p.need_tar = true
46
+ p.gem_spec = spec
47
+ end
48
+
49
+ desc "Run all the tests"
50
+ Rake::TestTask.new do |t|
51
+ t.test_files = FileList['test/test_*.rb', 'test/*_test.rb']
52
+ t.verbose = true
53
+ end
54
+
55
+
56
+ desc "Install the gem package"
57
+ task :install => :package do |t|
58
+ gem_file = Dir.glob("pkg/#{PKG_NAME}-*.gem").last
59
+ `gem install -l #{gem_file}`
60
+ end
61
+
62
+ desc "Uninstall the gem package"
63
+ task :uninstall do |t|
64
+ `echo 'y' | gem uninstall #{PKG_NAME}`
65
+ end
66
+
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rmplayer'
4
+
5
+ if ARGV.empty?
6
+ puts "Remote MPlayer. VLC Http interface for MPlayer."
7
+ puts "Usage: #$0 [mplayer options] file_name"
8
+ exit 1
9
+ end
10
+
11
+ RMPlayer::App.new.run(ARGV)
12
+
@@ -0,0 +1 @@
1
+ require 'rmplayer/app'
@@ -0,0 +1,145 @@
1
+ require 'webrick'
2
+ require 'builder'
3
+ require 'rmplayer/mplayer'
4
+
5
+ module RMPlayer
6
+ DEBUG = false
7
+
8
+ class NullLogger
9
+ def method_missing(*args)
10
+ end
11
+ end
12
+
13
+ class App
14
+ def run(args)
15
+ @mplayer = MPlayer.new(args)
16
+
17
+ s = ::WEBrick::HTTPServer.new(:Port => 8080,
18
+ :MaxClients => 5,
19
+ :DoNotReverseLookup => true,
20
+ :ShutdownSocketWithoutClose => true,
21
+ :Logger => DEBUG ? nil : NullLogger.new)
22
+
23
+ s.mount_proc('/requests/status.xml') do |req, resp|
24
+ begin
25
+ command = req.query['command'] || 'status'
26
+
27
+ puts "Executing #{command}" if DEBUG
28
+
29
+ case command
30
+ when 'in_play'
31
+ file = req.query['input']
32
+ if @mplayer
33
+ @mplayer.load_file file
34
+ else
35
+ @mplayer = MPlayer.new file
36
+ end
37
+ when 'fullscreen'
38
+ @mplayer.toggle_fullscreen
39
+ when 'seek'
40
+ val = req.query['val'].to_i
41
+ @mplayer.seek(val)
42
+ when 'volume'
43
+ val = req.query['val'].to_i
44
+ @mplayer.volume = ((val * 100.0) / 1024).to_i
45
+ when 'pl_next'
46
+ when 'pl_previous'
47
+ when 'pl_pause', 'pl_play'
48
+ @mplayer.pause
49
+ when 'pl_stop'
50
+ quit_mplayer
51
+ end
52
+
53
+ resp.status = 200
54
+ resp['Content-Type'] = 'text/xml'
55
+ resp.body = status
56
+ rescue Errno::EPIPE => ex
57
+ quit_mplayer
58
+ resp.status = 500
59
+ end
60
+ end
61
+
62
+ s.mount_proc('/requests/browse.xml') do |req, resp|
63
+ dir = req.query['dir']
64
+
65
+ resp.status = 200
66
+ resp['Content-Type'] = 'text/xml'
67
+ resp.body = browse(dir)
68
+ end
69
+
70
+ trap("INT") do
71
+ quit_mplayer
72
+ s.shutdown
73
+ end
74
+
75
+ Socket.do_not_reverse_lookup = true
76
+
77
+ s.start
78
+ end
79
+
80
+ def quit_mplayer
81
+ if @mplayer
82
+ begin
83
+ @mplayer.quit
84
+ @mplayer = nil
85
+ rescue Exception => ignore
86
+ ensure
87
+ @mplayer = nil
88
+ end
89
+ end
90
+ end
91
+
92
+ def status
93
+ xml = Builder::XmlMarkup.new
94
+ xml.root do
95
+ xml.volume @mplayer ? ((@mplayer.volume.to_i * 1024.0) / 100).to_i : 256
96
+ xml.length @mplayer ? @mplayer.time_length.to_i : 0
97
+ xml.time @mplayer ? @mplayer.time_pos.to_i : 0
98
+ xml.state @mplayer ? (@mplayer.paused? ? 'paused' : 'playing') : 'stop'
99
+ xml.position @mplayer ? @mplayer.percent_pos.to_i : 0
100
+ xml.fullscreen
101
+ xml.loop 0
102
+ xml.repeat 0
103
+ xml.information do
104
+ xml.tag! :'meta-information' do
105
+ xml.title @mplayer ? @mplayer.file_name : ''
106
+ end
107
+ end
108
+ end
109
+
110
+ puts xml.target! if DEBUG
111
+ xml.target!
112
+ end
113
+
114
+ def browse(dir)
115
+ base = File.expand_path(dir)
116
+ files = Dir.new(base).entries.sort
117
+
118
+ xml = Builder::XmlMarkup.new
119
+ xml.root do
120
+ files.each do |name|
121
+ f = "#{base}/#{name}"
122
+
123
+ next unless show_file?(f, name)
124
+
125
+ xml.element :type => (File.directory?(f) ? 'directory' : 'file'),
126
+ :size => File.size(f),
127
+ :date => File.mtime(f),
128
+ :path => f,
129
+ :name => File.basename(f),
130
+ :extension => File.extname(f)
131
+ end
132
+ end
133
+
134
+ puts xml.target! if DEBUG
135
+ xml.target!
136
+ end
137
+
138
+ def show_file?(file, name)
139
+ return true if name == '..'
140
+ return false if name[0, 1] == '.'
141
+ return true if File.directory?(file)
142
+ return %w(.avi .mpg .mpeg .mk4 .mov .ogg .mp3).include?(File.extname(name))
143
+ end
144
+ end
145
+ end
@@ -0,0 +1,118 @@
1
+ require 'thread'
2
+
3
+ module RMPlayer
4
+
5
+ class MPlayer
6
+ def initialize(args)
7
+ @mutex = Mutex.new
8
+
9
+ pstdin, pstdout, pstderr = IO.pipe, IO.pipe, IO.pipe
10
+
11
+ command = %w(/usr/bin/mplayer -slave -quiet) + args
12
+ fork do
13
+ STDIN.reopen pstdin.first
14
+ pstdin.last.close
15
+
16
+ STDERR.reopen pstderr.last
17
+ pstderr.first.close
18
+
19
+ STDOUT.reopen pstdout.last
20
+ pstdout.first.close
21
+
22
+ STDERR.sync = true
23
+ STDOUT.sync = true
24
+
25
+ exec(*command)
26
+ end
27
+
28
+ pstdin.first.close
29
+ pstderr.last.close
30
+ pstdout.last.close
31
+
32
+ @stdin, @stdout, @stderr = pstdin.last, pstdout.first, pstderr.first
33
+
34
+ STDERR.sync = true
35
+ STDOUT.sync = true
36
+
37
+ sleep 2
38
+ end
39
+
40
+ def paused?
41
+ get_property('pause') == 'yes'
42
+ end
43
+
44
+ def get_property(property)
45
+ cmd = "pausing_keep_force get_property #{property}"
46
+ match = "ANS_#{property.to_s}"
47
+ rex = /#{match}=(.+)/
48
+ response = send(cmd, rex)
49
+ response[rex, 1]
50
+ end
51
+
52
+ def get(property)
53
+ cmd = "pausing_keep_force get_#{property}"
54
+ match = case property
55
+ when "time_pos" then 'ANS_TIME_POSITION'
56
+ when "percent_pos" then 'ANS_PERCENT_POSITION'
57
+ when "time_length" then 'ANS_LENGTH'
58
+ when "file_name" then 'ANS_FILENAME'
59
+ else "ANS_#{property.to_s.upcase}"
60
+ end
61
+ rex = /#{match}=(.+)/
62
+ response = send(cmd, rex)
63
+ response[rex, 1]
64
+ end
65
+
66
+ %w(time_pos time_length file_name percent_pos vo_fullscreen).each do |field|
67
+ define_method(field.to_sym) { get(field) }
68
+ end
69
+
70
+ def pause
71
+ send('pause')
72
+ end
73
+
74
+ def quit
75
+ send('quit')
76
+ end
77
+
78
+ def seek(value)
79
+ send("seek #{value} 2")
80
+ end
81
+
82
+ def volume=(value)
83
+ send("volume #{value} 1")
84
+ end
85
+
86
+ def volume
87
+ get_property('volume')
88
+ end
89
+
90
+ def load_file(file)
91
+ send("loadfile #{file}")
92
+ end
93
+
94
+ def toggle_fullscreen
95
+ send('vo_fullscreen')
96
+ end
97
+
98
+ def send(cmd, match = nil)
99
+ @mutex.synchronize do
100
+ puts "Sending #{cmd}. Looking for #{match}" if DEBUG
101
+ @stdin.puts(cmd)
102
+
103
+ return nil if match.nil?
104
+
105
+ response = @stdout.gets
106
+ puts "Resp: #{response}. Looking for #{match}" if DEBUG
107
+ until response =~ match
108
+ response = @stdout.gets
109
+ puts "Resp: #{response}. Looking for #{match} in loop" if DEBUG
110
+ end
111
+ puts "Matched response: #{response}" if DEBUG
112
+ response
113
+ end
114
+ end
115
+ end
116
+
117
+ end
118
+
metadata ADDED
@@ -0,0 +1,70 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rmplayer
3
+ version: !ruby/object:Gem::Version
4
+ version: "1.0"
5
+ platform: ruby
6
+ authors:
7
+ - Peter Severin
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2010-10-27 00:00:00 +03:00
13
+ default_executable: rmplayer
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: builder
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "0"
24
+ version:
25
+ description: "\trmplayer implements HTTP protocol used by Vlc to control MPlayer.\n\
26
+ \tMore to the point, I just wanted to use VLC remote android app to control MPlayer.\n"
27
+ email: peter_p_s@users.sourceforge.net
28
+ executables:
29
+ - rmplayer
30
+ extensions: []
31
+
32
+ extra_rdoc_files: []
33
+
34
+ files:
35
+ - README
36
+ - Rakefile
37
+ - bin/rmplayer
38
+ - lib/rmplayer/app.rb
39
+ - lib/rmplayer/mplayer.rb
40
+ - lib/rmplayer.rb
41
+ has_rdoc: true
42
+ homepage:
43
+ licenses: []
44
+
45
+ post_install_message:
46
+ rdoc_options: []
47
+
48
+ require_paths:
49
+ - lib
50
+ required_ruby_version: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: "0"
55
+ version:
56
+ required_rubygems_version: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: "0"
61
+ version:
62
+ requirements: []
63
+
64
+ rubyforge_project:
65
+ rubygems_version: 1.3.5
66
+ signing_key:
67
+ specification_version: 3
68
+ summary: Remote control interface for MPlayer
69
+ test_files: []
70
+