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 +10 -0
- data/Rakefile +66 -0
- data/bin/rmplayer +12 -0
- data/lib/rmplayer.rb +1 -0
- data/lib/rmplayer/app.rb +145 -0
- data/lib/rmplayer/mplayer.rb +118 -0
- metadata +70 -0
data/README
ADDED
data/Rakefile
ADDED
@@ -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
|
+
|
data/bin/rmplayer
ADDED
data/lib/rmplayer.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'rmplayer/app'
|
data/lib/rmplayer/app.rb
ADDED
@@ -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
|
+
|