rmplayer 1.0

Sign up to get free protection for your applications and to get access to all the features.
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
+