glimmer-cw-video 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 10a0ed280e12d03b5c9a8a69e696043e208a58b54282d74fa8310bc4602ccbf7
4
+ data.tar.gz: 631708906e59bfb0232fd09fd20d673520dce51611fc59e16c8301fe098237d0
5
+ SHA512:
6
+ metadata.gz: f8c79642df581ebef469df2b0993e5f32de0715345307652be76002a31f0ec238871a416797980db539843a5dab521649dea2f3d171dd795244944f9552b66ab
7
+ data.tar.gz: d584693154c69b17d1aaf9cd85a501a7dbc5062c787734c8832dc8ff1b6835db5451185faa0bb421d43d301cf361a86db29f5244eeed8e42c74bb23c6b9b9ff8
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2020 Andy Maleh
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,125 @@
1
+ # Video 0.1.0 - Glimmer Custom Widget
2
+
3
+ ![Video Widget](images/glimmer-video-widget.png)
4
+
5
+ Glimmer custom widget for video used via `video` keyword.
6
+
7
+ ## Pre-requisites
8
+
9
+ - [Glimmer](https://github.com/AndyObtiva/glimmer) application
10
+ - JRuby version required by Glimmer
11
+ - Java version required by Glimmer
12
+
13
+ ## Setup
14
+
15
+ Add the following to a Glimmer application `Gemfile`:
16
+
17
+ ```ruby
18
+ gem 'glimmer-cw-video', '0.1.0'
19
+ ```
20
+
21
+ Run:
22
+
23
+ ```
24
+ jruby -S bundle
25
+ ```
26
+
27
+ (or just `bundle` if using RVM)
28
+
29
+ ## Options
30
+
31
+ Passed in an options hash as arguments to `video` widget:
32
+ - `autoplay` (true [default] or false): plays video automatically as soon as loaded
33
+ - `controls` (true [default] or false): displays controls
34
+ - `looped` (true or false [default]): plays video in looped mode
35
+ - `background` (Glimmer color [default: white]): sets background color just like with any other widget
36
+ - `fit_to_width` (true [default] or false): fits video width to widget allotted width regardless of video's original size. Maintains video aspect ratio.
37
+ - `fit_to_height` (true [default] or false): fits video height to widget allotted height regardless of video's original size. Maintains video aspect ratio.
38
+ - `offset_x` (integer [default: 0]): offset from left border. Could be a negative number if you want to show only an area of the video. Useful when fit_to_width is false to pick an area of the video to display.
39
+ - `offset_y` (integer [default: 0]): offset from top border. Could be a negative number if you want to show only an area of the video. Useful when fit_to_height is false to pick an area of the video to display.
40
+
41
+ ## Methods
42
+
43
+ - `#play`: plays video
44
+ - `#pause`: pauses video
45
+ - `#reload`: reloads video restarting from beginning
46
+ - `#position`: position in seconds (and fractions)
47
+ - `#position=`: seeks a new position in video
48
+ - `#duration`: length of video, maximum video position possible
49
+ - `#loaded?`: returns true when video has been initially loaded or reloaded
50
+ - `#playing?`: returns true when video is actively playing
51
+ - `#paused?`: returns true when video is not playing
52
+ - `#ended?`: returns true when video has reached the end (position == duration)
53
+
54
+ ## Observer Events:
55
+
56
+ - `on_loaded`: invoked when video `#loaded?` becomes true
57
+ - `on_ended`: invoked when video `#ended?` becomes true
58
+ - `on_playing`: invoked when video `#playing?` becomes true
59
+ - `on_paused`: invoked when video `#paused?` becomes true
60
+
61
+ ## Examples:
62
+
63
+ Example ([samples/hello_video.rb](samples/video/hello_video.rb)):
64
+
65
+ ```ruby
66
+ # ...
67
+ shell {
68
+ video(file: video_file)
69
+ }.open
70
+ ```
71
+
72
+ Example ([samples/hello_looped_video_with_black_background.rb](samples/video/hello_looped_video_with_black_background.rb)):
73
+
74
+ ```ruby
75
+ # ...
76
+ shell {
77
+ minimum_size 1024, 640
78
+ video(file: video_file, looped: true, background: :black)
79
+ }.open
80
+ ```
81
+
82
+ Example ([samples/hello_video_observers.rb](samples/video/hello_video_observers.rb)):
83
+
84
+ ```ruby
85
+ # ...
86
+ def display_video_status(video, status)
87
+ message_box = MessageBox.new(video.swt_widget.getShell)
88
+ message_box.setText(status)
89
+ message = "Video Position: #{video.position} seconds\n"
90
+ message += "Video Duration: #{video.duration} seconds"
91
+ message_box.setMessage(message)
92
+ message_box.open
93
+ end
94
+
95
+ @shell = shell {
96
+ minimum_size 800, 500
97
+ @video = video(file: video_file, background: :black) {
98
+ on_playing {
99
+ display_video_status(@video, 'Playing')
100
+ }
101
+ on_paused {
102
+ display_video_status(@video, 'Paused')
103
+ }
104
+ on_ended {
105
+ display_video_status(@video, 'Ended')
106
+ }
107
+ }
108
+ }
109
+ @shell.open
110
+ ```
111
+
112
+ ## Contributing to glimmer-cw-video
113
+
114
+ - Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet.
115
+ - Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it.
116
+ - Fork the project.
117
+ - Start a feature/bugfix branch.
118
+ - Commit and push until you are happy with your contribution.
119
+ - Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
120
+ - Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
121
+
122
+ ## Copyright
123
+
124
+ Copyright (c) 2020 Andy Maleh. See LICENSE.txt for
125
+ further details.
@@ -0,0 +1,5 @@
1
+ $LOAD_PATH.unshift(File.expand_path('..', __FILE__))
2
+
3
+ require 'bundler/setup'
4
+ Bundler.require(:default)
5
+ require 'views/glimmer/video'
@@ -0,0 +1,287 @@
1
+ require 'glimmer/ui/custom_widget'
2
+
3
+ module Glimmer
4
+ class Video
5
+ include Glimmer::UI::CustomWidget
6
+ include_package 'org.eclipse.swt.browser'
7
+
8
+ options :file, :url
9
+ option :autoplay, true
10
+ option :controls, true
11
+ option :looped, false
12
+ option :background, :white
13
+ option :fit_to_width, true
14
+ option :fit_to_height, true
15
+ option :offset_x, 0
16
+ option :offset_y, 0
17
+
18
+ alias autoplay? autoplay
19
+ alias controls? controls
20
+ alias looped? looped
21
+ alias fit_to_width? fit_to_width
22
+ alias fit_to_height? fit_to_height
23
+
24
+ body {
25
+ browser(:no_scroll) {
26
+ text html {
27
+ head {
28
+ style(id: "style") {
29
+ css {
30
+ body {
31
+ margin 0
32
+ padding 0
33
+ overflow :hidden
34
+ }
35
+ }
36
+ }
37
+ style(id: "style-body-background") {
38
+ css {
39
+ body {
40
+ pv 'background', browser_body_background
41
+ }
42
+ }
43
+ }
44
+ style(id: "style-body-offset-x") {
45
+ css {
46
+ body {
47
+ margin_left "#{browser_body_offset_x}px"
48
+ }
49
+ }
50
+ }
51
+ style(id: "style-body-offset-y") {
52
+ css {
53
+ body {
54
+ margin_top "#{browser_body_offset_y}px"
55
+ }
56
+ }
57
+ }
58
+ }
59
+ body {
60
+ video(browser_video_loop, browser_video_controls, browser_video_autoplay, id: 'video', src: source, width: browser_video_width, height: browser_video_height)
61
+ }
62
+ }
63
+ on_completed {
64
+ @completed = true
65
+ }
66
+ }
67
+ }
68
+
69
+ def source
70
+ file_source = file
71
+ if file_source
72
+ if file_source.start_with?('uri:classloader')
73
+ file_path = file_source.split(/\/\//).last
74
+ file_name = File.basename(file_source)
75
+ # supporting windows ENV['temp'] or mac/unix /tmp
76
+ tmp_dir = ENV['temp'] ? File.expand_path(ENV['temp']) : '/tmp'
77
+ tmp_dir += '/glimmer/lib/glimmer/ui/video'
78
+ FileUtils.mkdir_p(tmp_dir)
79
+ tmp_file = File.join(tmp_dir, file_name)
80
+ file_content = File.binread(file_source) rescue File.binread(file_path)
81
+ File.binwrite(tmp_file, file_content)
82
+ "file://#{tmp_file}"
83
+ else
84
+ "file://#{file_source}"
85
+ end
86
+ else
87
+ url
88
+ end
89
+ end
90
+
91
+ def file=(a_file)
92
+ options[:file] = a_file
93
+ set_video_source
94
+ end
95
+
96
+ def url=(a_url)
97
+ options[:url] = a_url
98
+ set_video_source
99
+ end
100
+
101
+ def play
102
+ video_action('play')
103
+ end
104
+
105
+ def pause
106
+ video_action('pause')
107
+ end
108
+
109
+ def reload
110
+ video_action('load')
111
+ end
112
+
113
+ def paused?
114
+ video_attribute('paused')
115
+ end
116
+
117
+ def playing?
118
+ !paused?
119
+ end
120
+
121
+ def ended?
122
+ video_attribute('ended')
123
+ end
124
+
125
+ # Video fully loaded and ready for playback
126
+ def loaded?
127
+ !!@completed
128
+ end
129
+
130
+ def position
131
+ video_attribute('currentTime')
132
+ end
133
+
134
+ def position=(new_position)
135
+ video_attribute_set('currentTime', new_position)
136
+ end
137
+
138
+ def duration
139
+ video_attribute('duration')
140
+ end
141
+
142
+ def can_handle_observation_request?(observation_request)
143
+ result = false
144
+ if observation_request.start_with?('on_')
145
+ attribute = observation_request.sub(/^on_/, '')
146
+ result = OBSERVED_ATTRIBUTE_TO_PROPERTY_MAPPING.keys.include?(attribute)
147
+ end
148
+ result || super
149
+ end
150
+
151
+ def handle_observation_request(observation_request, &block)
152
+ if observation_request.start_with?('on_')
153
+ attribute = observation_request.sub(/^on_/, '')
154
+ if attribute == 'loaded' && !@completed
155
+ super('on_completed', &block)
156
+ elsif OBSERVED_ATTRIBUTE_TO_PROPERTY_MAPPING.keys.include?(attribute)
157
+ add_video_observer(block, OBSERVED_ATTRIBUTE_TO_PROPERTY_MAPPING[attribute])
158
+ else
159
+ super
160
+ end
161
+ end
162
+ end
163
+
164
+ private
165
+
166
+ class VideoObserverBrowserFunction < BrowserFunction
167
+ def initialize(video, observer_proc, attribute)
168
+ @observer_proc = observer_proc
169
+ @attribute = attribute
170
+ name = self.class.generate_name(@attribute)
171
+ super(video.swt_widget, name)
172
+ end
173
+
174
+ def function(arguments)
175
+ @observer_proc.call
176
+ rescue => e
177
+ Glimmer::Config.logger&.error "#{e.message}\n#{e.backtrace.join("\n")}"
178
+ ensure
179
+ nil
180
+ end
181
+
182
+ private
183
+
184
+ class << self
185
+ def generate_name(attribute)
186
+ "video#{attribute}#{generate_attribute_id(attribute)}"
187
+ end
188
+
189
+ def generate_attribute_id(attribute)
190
+ attribute_max_ids[attribute] = attribute_max_id(attribute) + 1
191
+ end
192
+
193
+ def attribute_max_id(attribute)
194
+ attribute_max_ids[attribute] ||= 0
195
+ end
196
+
197
+ def attribute_max_ids
198
+ @attribute_max_ids ||= {}
199
+ end
200
+ end
201
+ end
202
+
203
+ OBSERVED_ATTRIBUTE_TO_PROPERTY_MAPPING = {
204
+ 'playing' => 'play',
205
+ 'paused' => 'pause',
206
+ 'ended' => 'ended',
207
+ 'loaded' => 'canplay',
208
+ }
209
+
210
+ def set_video_source
211
+ run_on_completed do
212
+ video_attribute_set('src', source)
213
+ end
214
+ end
215
+
216
+ def video_action(action)
217
+ run_on_completed do
218
+ swt_widget.execute("document.getElementById('video').#{action}()")
219
+ end
220
+ end
221
+
222
+ def video_attribute(attribute)
223
+ swt_widget.evaluate("return document.getElementById('video').#{attribute}") if @completed
224
+ end
225
+
226
+ def video_attribute_set(attribute, value)
227
+ value = "'#{value}'" if value.is_a?(String) || value.is_a?(Symbol)
228
+ run_on_completed do
229
+ swt_widget.execute("document.getElementById('video').#{attribute} = #{value}")
230
+ end
231
+ end
232
+
233
+ def add_video_observer(observer_proc, attribute)
234
+ run_on_completed do
235
+ video_observer_browser_function = VideoObserverBrowserFunction.new(self, observer_proc, attribute)
236
+ swt_widget.execute("document.getElementById('video').addEventListener('#{attribute}', function() {#{video_observer_browser_function.getName}()})")
237
+ end
238
+ end
239
+
240
+ def run_on_completed(&block)
241
+ if @completed
242
+ block.call
243
+ else
244
+ on_completed(&block)
245
+ end
246
+ end
247
+
248
+ def browser_video_autoplay
249
+ 'autoplay' if autoplay?
250
+ end
251
+
252
+ def browser_video_controls
253
+ 'controls' if controls?
254
+ end
255
+
256
+ def browser_video_loop
257
+ 'loop' if looped?
258
+ end
259
+
260
+ def browser_video_width
261
+ "100%" if fit_to_width
262
+ end
263
+
264
+ def browser_video_height
265
+ "100%" if fit_to_height
266
+ end
267
+
268
+ def browser_body_background
269
+ color = background
270
+ if color.is_a?(Symbol) || color.is_a?(String)
271
+ color = color(color)
272
+ end
273
+ if color.respond_to?(:swt_color)
274
+ color = color.swt_color
275
+ end
276
+ "rgba(#{color.getRed}, #{color.getGreen}, #{color.getBlue}, #{color.getAlpha})"
277
+ end
278
+
279
+ def browser_body_offset_x
280
+ offset_x
281
+ end
282
+
283
+ def browser_body_offset_y
284
+ offset_y
285
+ end
286
+ end
287
+ end
metadata ADDED
@@ -0,0 +1,105 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: glimmer-cw-video
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Andy Maleh
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2020-05-03 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - "~>"
17
+ - !ruby/object:Gem::Version
18
+ version: 0.7.0
19
+ name: glimmer
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 0.7.0
27
+ - !ruby/object:Gem::Dependency
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - "~>"
31
+ - !ruby/object:Gem::Version
32
+ version: 3.5.0
33
+ name: rspec
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 3.5.0
41
+ - !ruby/object:Gem::Dependency
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - '='
45
+ - !ruby/object:Gem::Version
46
+ version: 2.3.9
47
+ name: jeweler
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '='
53
+ - !ruby/object:Gem::Version
54
+ version: 2.3.9
55
+ - !ruby/object:Gem::Dependency
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ name: simplecov
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ description: Glimmer video widget with basic functionality like play, pause, loop,
70
+ and reload. Support mp4, webm, and ogg. Works with both local files and web URLs.
71
+ email: andy.am@gmail.com
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files:
75
+ - LICENSE.txt
76
+ - README.md
77
+ files:
78
+ - LICENSE.txt
79
+ - README.md
80
+ - lib/glimmer-cw-video.rb
81
+ - lib/views/glimmer/video.rb
82
+ homepage: http://github.com/AndyObtiva/glimmer-cw-video
83
+ licenses:
84
+ - MIT
85
+ metadata: {}
86
+ post_install_message:
87
+ rdoc_options: []
88
+ require_paths:
89
+ - lib
90
+ required_ruby_version: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - ">="
93
+ - !ruby/object:Gem::Version
94
+ version: '0'
95
+ required_rubygems_version: !ruby/object:Gem::Requirement
96
+ requirements:
97
+ - - ">="
98
+ - !ruby/object:Gem::Version
99
+ version: '0'
100
+ requirements: []
101
+ rubygems_version: 3.0.6
102
+ signing_key:
103
+ specification_version: 4
104
+ summary: Glimmer Custom Widget - Video
105
+ test_files: []