resizing-rails 0.1.0.pre
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +28 -0
- data/Rakefile +41 -0
- data/app/assets/config/resizing_rails_manifest.js +2 -0
- data/app/assets/javascripts/resizing/rails/application.js +15 -0
- data/app/assets/javascripts/resizing/rails/clipboard.js +15 -0
- data/app/assets/javascripts/resizing/rails/progressbar.js +33 -0
- data/app/assets/javascripts/resizing/rails/toast.js +35 -0
- data/app/assets/javascripts/resizing/rails/video.js +69 -0
- data/app/assets/javascripts/resizing/rails/video_fetcher.js +15 -0
- data/app/assets/javascripts/resizing/rails/video_uploader.js +77 -0
- data/app/assets/stylesheets/resizing/rails/application.scss +15 -0
- data/app/assets/stylesheets/resizing/rails/videos.scss +4 -0
- data/app/controllers/resizing/rails/application_controller.rb +7 -0
- data/app/controllers/resizing/rails/videos_controller.rb +26 -0
- data/app/helpers/resizing/rails/application_helper.rb +6 -0
- data/app/helpers/resizing/rails/videos_helper.rb +4 -0
- data/app/helpers/resizing/rails/webpack_bundle_helper.rb +21 -0
- data/app/javascript/packs/resizing.js +1 -0
- data/app/javascript/src/video.js +42 -0
- data/app/jobs/resizing/rails/application_job.rb +6 -0
- data/app/mailers/resizing/rails/application_mailer.rb +8 -0
- data/app/models/resizing/rails/application_record.rb +7 -0
- data/app/models/resizing/rails/video.rb +37 -0
- data/app/views/kaminari/_first_page.html.slim +2 -0
- data/app/views/kaminari/_gap.html.slim +2 -0
- data/app/views/kaminari/_last_page.html.slim +2 -0
- data/app/views/kaminari/_next_page.html.slim +2 -0
- data/app/views/kaminari/_page.html.slim +6 -0
- data/app/views/kaminari/_paginator.html.slim +12 -0
- data/app/views/kaminari/_prev_page.html.slim +2 -0
- data/app/views/layouts/resizing/rails/application.html.slim +20 -0
- data/app/views/resizing/rails/common/_clipboard.html.slim +1 -0
- data/app/views/resizing/rails/common/_toast.html.slim +10 -0
- data/app/views/resizing/rails/videos/_upload_form.html.slim +35 -0
- data/app/views/resizing/rails/videos/index.html.slim +53 -0
- data/app/views/resizing/rails/videos/show.html.slim +75 -0
- data/config/routes.rb +7 -0
- data/db/migrate/20210122043613_create_resizing_rails_videos.rb +9 -0
- data/lib/resizing/rails.rb +7 -0
- data/lib/resizing/rails/engine.rb +25 -0
- data/lib/resizing/rails/version.rb +5 -0
- data/lib/tasks/resizing/rails_tasks.rake +4 -0
- metadata +204 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 8e0b8f97f32819b39ebb857fea3e47d87a24dde886efeafa5b27311a91f2fc83
|
4
|
+
data.tar.gz: 2bc13646968446e0903d4f7e29af1c7aa7a4b441a161ddbed11f10a83f721004
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 7a05f15665f5d6dea1451c95e0c78090bda0bffdfc89fbc80b3ec2e60a9bd8e3c13f25aed7e7b8906a01acc26e5eb3297259da219d93d4428d80a9fd3d8c3392
|
7
|
+
data.tar.gz: ca25a67ff560dad4aa4b48b6f5ab36abfbc97045b7719e86075307185ef1d8f5e98d461924a73eaba02f52c67eabed364861170baeaac6ffe057acd5b7e90e32
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2021 Junichiro Kasuya
|
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.
|
data/README.md
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# Resizing::Rails
|
2
|
+
Short description and motivation.
|
3
|
+
|
4
|
+
## Usage
|
5
|
+
How to use my plugin.
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
Add this line to your application's Gemfile:
|
9
|
+
|
10
|
+
```ruby
|
11
|
+
gem 'resizing-rails'
|
12
|
+
```
|
13
|
+
|
14
|
+
And then execute:
|
15
|
+
```bash
|
16
|
+
$ bundle
|
17
|
+
```
|
18
|
+
|
19
|
+
Or install it yourself as:
|
20
|
+
```bash
|
21
|
+
$ gem install resizing-rails
|
22
|
+
```
|
23
|
+
|
24
|
+
## Contributing
|
25
|
+
Contribution directions go here.
|
26
|
+
|
27
|
+
## License
|
28
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
begin
|
2
|
+
require 'bundler/setup'
|
3
|
+
rescue LoadError
|
4
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
5
|
+
end
|
6
|
+
|
7
|
+
require 'rdoc/task'
|
8
|
+
require 'github_changelog_generator/task'
|
9
|
+
|
10
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
11
|
+
rdoc.rdoc_dir = 'rdoc'
|
12
|
+
rdoc.title = 'Resizing::Rails'
|
13
|
+
rdoc.options << '--line-numbers'
|
14
|
+
rdoc.rdoc_files.include('README.md')
|
15
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
16
|
+
end
|
17
|
+
|
18
|
+
APP_RAKEFILE = File.expand_path("test/dummy/Rakefile", __dir__)
|
19
|
+
load 'rails/tasks/engine.rake'
|
20
|
+
|
21
|
+
load 'rails/tasks/statistics.rake'
|
22
|
+
|
23
|
+
require 'bundler/gem_tasks'
|
24
|
+
|
25
|
+
require 'rake/testtask'
|
26
|
+
|
27
|
+
Rake::TestTask.new(:test) do |t|
|
28
|
+
t.libs << 'test'
|
29
|
+
t.pattern = 'test/**/*_test.rb'
|
30
|
+
t.verbose = false
|
31
|
+
end
|
32
|
+
|
33
|
+
task default: :test
|
34
|
+
|
35
|
+
|
36
|
+
GitHubChangelogGenerator::RakeTask.new :changelog do |config|
|
37
|
+
config.user = 'jksy'
|
38
|
+
config.project = 'resizing-rails'
|
39
|
+
# config.since_tag = '0.0.1'
|
40
|
+
config.future_release = 'add-changelog'
|
41
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
// This is a manifest file that'll be compiled into application.js, which will include all the files
|
2
|
+
// listed below.
|
3
|
+
//
|
4
|
+
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
|
5
|
+
// or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path.
|
6
|
+
//
|
7
|
+
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
|
8
|
+
// compiled file. JavaScript code in this file should be added after the last require_* statement.
|
9
|
+
//
|
10
|
+
// Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
|
11
|
+
// about supported directives.
|
12
|
+
//
|
13
|
+
//= require rails-ujs
|
14
|
+
//= require bootstrap
|
15
|
+
//= require_tree .
|
@@ -0,0 +1,15 @@
|
|
1
|
+
window.addEventListener('click', (e) => {
|
2
|
+
src = e.srcElement
|
3
|
+
if(src.hasAttribute('data-copy-url')) {
|
4
|
+
url = src.getAttribute('data-copy-url')
|
5
|
+
if(url !== null) {
|
6
|
+
elem = document.getElementById('clipboard')
|
7
|
+
elem.value = url
|
8
|
+
elem.select()
|
9
|
+
document.execCommand("copy")
|
10
|
+
toast = new Resizing.Rails.Toast()
|
11
|
+
index = url.lastIndexOf('/')
|
12
|
+
toast.show("コピーしました", '...' + url.substr(index, url.length))
|
13
|
+
}
|
14
|
+
}
|
15
|
+
})
|
@@ -0,0 +1,33 @@
|
|
1
|
+
window.Resizing ||= {}
|
2
|
+
window.Resizing.Rails ||= {}
|
3
|
+
|
4
|
+
// Usage
|
5
|
+
// min = 0
|
6
|
+
// max = 100
|
7
|
+
// bar = new Resizing.Rails.ProgressBar(document.querySelector('...'), min, max)
|
8
|
+
// bar.setCurrent(20)
|
9
|
+
//
|
10
|
+
|
11
|
+
class ProgressBar {
|
12
|
+
constructor(element, min, max) {
|
13
|
+
this.element = element
|
14
|
+
this.current = this.min = min
|
15
|
+
this.max = max
|
16
|
+
}
|
17
|
+
|
18
|
+
setCurrent(value) {
|
19
|
+
this.current = value
|
20
|
+
this.applyStyle()
|
21
|
+
}
|
22
|
+
|
23
|
+
applyStyle() {
|
24
|
+
let percentage = Math.floor(this.current / (this.max - this.min) * 100)
|
25
|
+
this.element.style = `width: ${percentage}%;`
|
26
|
+
this.element.setAttribute('aria-valuenow', this.current)
|
27
|
+
this.element.setAttribute('aria-valuemin', this.min)
|
28
|
+
this.element.setAttribute('aria-valuemax', this.max)
|
29
|
+
this.element.textContent = `${percentage}%`
|
30
|
+
}
|
31
|
+
}
|
32
|
+
|
33
|
+
window.Resizing.Rails.ProgressBar = ProgressBar
|
@@ -0,0 +1,35 @@
|
|
1
|
+
window.Resizing ||= {}
|
2
|
+
window.Resizing.Rails ||= {}
|
3
|
+
|
4
|
+
// Usage
|
5
|
+
// toast = new Resizing.Rails.Toast()
|
6
|
+
// toast.show('title', 'body-text')
|
7
|
+
//
|
8
|
+
class Toast {
|
9
|
+
constructor() {
|
10
|
+
this.container = document.getElementById('toast-container')
|
11
|
+
this.template = document.getElementById('toast-template').content
|
12
|
+
}
|
13
|
+
|
14
|
+
show(title, text) {
|
15
|
+
let $node = document.importNode(this.template, true)
|
16
|
+
let $toast = $node.querySelector('.toast')
|
17
|
+
let id = $toast.id = `toast-${this.generateUniqueId()}`
|
18
|
+
$node.querySelector('.toast-title').textContent = title
|
19
|
+
$node.querySelector('.toast-body').textContent = text
|
20
|
+
this.container.appendChild($node)
|
21
|
+
|
22
|
+
let $elem = document.getElementById(id)
|
23
|
+
let t = new bootstrap.Toast($elem)
|
24
|
+
t.show()
|
25
|
+
$elem.addEventListener('hidden.bs.toast',() => {
|
26
|
+
$elem.remove()
|
27
|
+
})
|
28
|
+
}
|
29
|
+
|
30
|
+
generateUniqueId() {
|
31
|
+
return (new Date).getTime().toString(16)
|
32
|
+
}
|
33
|
+
}
|
34
|
+
|
35
|
+
window.Resizing.Rails.Toast = Toast
|
@@ -0,0 +1,69 @@
|
|
1
|
+
// Place all the behaviors and hooks related to the matching controller here.
|
2
|
+
// All this logic will automatically be available in application.js.
|
3
|
+
|
4
|
+
window.Resizing ||= {}
|
5
|
+
window.Resizing.Rails ||= {}
|
6
|
+
|
7
|
+
class Video {
|
8
|
+
constructor(self_url, parentElement) {
|
9
|
+
this.self_url = self_url
|
10
|
+
this.parentElement = parentElement
|
11
|
+
this.listener = null
|
12
|
+
let video = this.buildVideoTag()
|
13
|
+
this.video = videojs(video.id, {fluid: true})
|
14
|
+
this.record = null
|
15
|
+
}
|
16
|
+
|
17
|
+
fetch() {
|
18
|
+
let fetcher = new Resizing.Rails.VideoFetcher(this.self_url)
|
19
|
+
fetcher.fetch().then(record => {
|
20
|
+
this.record = record
|
21
|
+
this.call('video_fetched', record)
|
22
|
+
if(record.thumbnail_url) {
|
23
|
+
this.renderVideo(record)
|
24
|
+
}
|
25
|
+
if(record.state != 'ready') {
|
26
|
+
setTimeout(this.fetch.bind(this), 5_000)
|
27
|
+
}
|
28
|
+
})
|
29
|
+
}
|
30
|
+
|
31
|
+
renderVideo(record) {
|
32
|
+
this.video.poster(record.thumbnail_url)
|
33
|
+
if(record.m3u8_url) {
|
34
|
+
this.video.src({type: 'application/x-mpegURL', src: record.m3u8_url})
|
35
|
+
}
|
36
|
+
if(record.avc_url) {
|
37
|
+
this.video.src({type: 'video/mp4', src: record.avc_url})
|
38
|
+
}
|
39
|
+
}
|
40
|
+
|
41
|
+
buildVideoTag() {
|
42
|
+
let video = document.createElement('video')
|
43
|
+
video.setAttribute('class', 'video-js')
|
44
|
+
video.setAttribute('muted', 'true')
|
45
|
+
video.setAttribute('controls', '')
|
46
|
+
video.setAttribute('preload', 'metadata')
|
47
|
+
video.setAttribute('data-setup', '{}')
|
48
|
+
video.setAttribute('poster', '')
|
49
|
+
video.id = `video-${this.generateUniqueId()}`
|
50
|
+
this.parentElement.appendChild(video)
|
51
|
+
return video
|
52
|
+
}
|
53
|
+
|
54
|
+
generateUniqueId() {
|
55
|
+
return (new Date).getTime().toString(16)
|
56
|
+
}
|
57
|
+
|
58
|
+
addEventListener(listener) {
|
59
|
+
this.listener = listener
|
60
|
+
}
|
61
|
+
|
62
|
+
call(...args) {
|
63
|
+
if(this.listener !== null) {
|
64
|
+
this.listener(...args)
|
65
|
+
}
|
66
|
+
}
|
67
|
+
}
|
68
|
+
|
69
|
+
window.Resizing.Rails.Video = Video
|
@@ -0,0 +1,15 @@
|
|
1
|
+
window.Resizing ||= {}
|
2
|
+
window.Resizing.Rails ||= {}
|
3
|
+
|
4
|
+
class VideoFetcher {
|
5
|
+
constructor(self_url) {
|
6
|
+
this.self_url = self_url
|
7
|
+
}
|
8
|
+
|
9
|
+
fetch() {
|
10
|
+
return fetch(this.self_url, {method: 'GET', credentials: 'same-origin', headers: {'Content-Type': 'application/json'}})
|
11
|
+
.then(response => response.json())
|
12
|
+
}
|
13
|
+
}
|
14
|
+
|
15
|
+
window.Resizing.Rails.VideoFetcher = VideoFetcher
|
@@ -0,0 +1,77 @@
|
|
1
|
+
// Place all the behaviors and hooks related to the matching controller here.
|
2
|
+
// All this logic will automatically be available in application.js.
|
3
|
+
|
4
|
+
window.Resizing ||= {}
|
5
|
+
window.Resizing.Rails ||= {}
|
6
|
+
|
7
|
+
class VideoUploader {
|
8
|
+
constructor(file_field, prepare_url) {
|
9
|
+
this.file_field = file_field
|
10
|
+
this.prepare_url = prepare_url
|
11
|
+
this.callback = null
|
12
|
+
}
|
13
|
+
|
14
|
+
upload() {
|
15
|
+
let file = this.file_field.files[0]
|
16
|
+
if(file === undefined) {
|
17
|
+
this.call('no_file_found')
|
18
|
+
return
|
19
|
+
}
|
20
|
+
this.prepare(file.name)
|
21
|
+
.catch(error => {
|
22
|
+
this.call('upload_failed')
|
23
|
+
})
|
24
|
+
}
|
25
|
+
|
26
|
+
prepare(filename) {
|
27
|
+
let body = JSON.stringify({filename: filename})
|
28
|
+
return fetch(this.prepare_url, {method: 'POST', credentials: 'same-origin', headers: {'Content-Type': 'application/json'}, body: body})
|
29
|
+
.then(response => {
|
30
|
+
if(!response.ok) {
|
31
|
+
return Promise.reject(response)
|
32
|
+
}
|
33
|
+
return response.json()
|
34
|
+
}).then(record => {
|
35
|
+
return this.uploadFile(record)
|
36
|
+
})
|
37
|
+
}
|
38
|
+
|
39
|
+
uploadFile(record) {
|
40
|
+
let file = this.file_field.files[0]
|
41
|
+
let data = record.data
|
42
|
+
return fetch(data.s3_presigned_url, {method: 'PUT', credentials: 'same-origin', headers: {'Content-Type': file.type}, body: file})
|
43
|
+
.then(response => {
|
44
|
+
if(!response.ok) {
|
45
|
+
return Promise.reject(response)
|
46
|
+
}
|
47
|
+
// ignore response body
|
48
|
+
}).then(data => {
|
49
|
+
return this.uploadDone(record)
|
50
|
+
})
|
51
|
+
}
|
52
|
+
|
53
|
+
uploadDone(record) {
|
54
|
+
let data = record.data
|
55
|
+
return fetch(data.upload_completed_url, {method: 'PUT', credentials: 'same-origin', headers:{'Content-Type': 'application/json'}})
|
56
|
+
.then(response => {
|
57
|
+
if(!response.ok) {
|
58
|
+
return Promise.reject(response)
|
59
|
+
}
|
60
|
+
return response.json()
|
61
|
+
}).then(data => {
|
62
|
+
window.location.pathname = record.self_path
|
63
|
+
})
|
64
|
+
}
|
65
|
+
|
66
|
+
addEventListener(callback) {
|
67
|
+
this.callback = callback
|
68
|
+
}
|
69
|
+
|
70
|
+
call(state) {
|
71
|
+
if(this.callback !== undefined) {
|
72
|
+
this.callback(state)
|
73
|
+
}
|
74
|
+
}
|
75
|
+
}
|
76
|
+
|
77
|
+
window.Resizing.Rails.VideoUploader = VideoUploader
|
@@ -0,0 +1,15 @@
|
|
1
|
+
/*
|
2
|
+
* This is a manifest file that'll be compiled into application.css, which will include all the files
|
3
|
+
* listed below.
|
4
|
+
*
|
5
|
+
* Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
|
6
|
+
* or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
|
7
|
+
*
|
8
|
+
* You're free to add application-wide styles to this file and they'll appear at the bottom of the
|
9
|
+
* compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
|
10
|
+
* files in this directory. Styles in this file should be added after the last require_* statement.
|
11
|
+
* It is generally better to create a new file per style scope.
|
12
|
+
*
|
13
|
+
*/
|
14
|
+
@import 'bootstrap';
|
15
|
+
@import 'videos';
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require_dependency "resizing/rails/application_controller"
|
2
|
+
|
3
|
+
module Resizing::Rails
|
4
|
+
class VideosController < ApplicationController
|
5
|
+
skip_before_action :verify_authenticity_token, only: [:prepare]
|
6
|
+
|
7
|
+
def index
|
8
|
+
@videos = Resizing::Rails::Video.order('created_at desc').page(params[:page]).per(20)
|
9
|
+
render text: 'index'
|
10
|
+
end
|
11
|
+
|
12
|
+
def prepare
|
13
|
+
response = client.prepare
|
14
|
+
video = Resizing::Rails::Video.create!(data: response)
|
15
|
+
render json: video
|
16
|
+
end
|
17
|
+
|
18
|
+
def client
|
19
|
+
@client ||= Resizing::Video::Client.new
|
20
|
+
end
|
21
|
+
|
22
|
+
def show
|
23
|
+
@video = Resizing::Rails::Video.find(params[:id])
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# ref. https://qiita.com/Tak-Iwamoto/items/efce14f67eb572d8742e
|
2
|
+
module Resizing::Rails::WebpackBundleHelper
|
3
|
+
class BundleNotFound < StandardError; end
|
4
|
+
|
5
|
+
def asset_bundle_path(file)
|
6
|
+
valid_file?(file)
|
7
|
+
return "/assets" + manifest.fetch(file)
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def manifest
|
13
|
+
return @manifest ||= JSON.parse(File.read("app/javascript/dist/manifest.json"))
|
14
|
+
end
|
15
|
+
|
16
|
+
def valid_file?(entry)
|
17
|
+
return true if manifest.key?(entry)
|
18
|
+
raise BundleNotFound, "Could not find bundle with name #{entry}"
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
import { Video } from '../src/video'
|
@@ -0,0 +1,42 @@
|
|
1
|
+
class Video {
|
2
|
+
constructor(element) {
|
3
|
+
this.element = element
|
4
|
+
this.element
|
5
|
+
}
|
6
|
+
|
7
|
+
upload() {
|
8
|
+
file = this.element.files[0]
|
9
|
+
prepare(file.name)
|
10
|
+
}
|
11
|
+
|
12
|
+
prepare(filename) {
|
13
|
+
body = JSON.stringify({filename: filename})
|
14
|
+
fetch(prepare_url, {method: 'POST', credentials: 'same-origin', headers: {'Content-Type': 'application/json'}, body: body})
|
15
|
+
.then(response => response.json())
|
16
|
+
.then(data => console.log(data))
|
17
|
+
}
|
18
|
+
|
19
|
+
file_upload(record) {
|
20
|
+
file = this.element.files[0]
|
21
|
+
fetch(record.s3_presigned_url, {method: 'PUT', credentials: 'same-origin', headers: {'Content-Type': file.type}, body: file})
|
22
|
+
.then(response => console.log(response))
|
23
|
+
.then(data => done_upload(record))
|
24
|
+
}
|
25
|
+
|
26
|
+
done_upload(record) {
|
27
|
+
fetch(record.upload_completed_url, {method: 'PUT', credentials: 'same-origin', headers:{'Content-Type': 'application/json'}})
|
28
|
+
.then(response => response.json())
|
29
|
+
.then(data => monitor_state(data))
|
30
|
+
}
|
31
|
+
|
32
|
+
monitor_state(record) {
|
33
|
+
alert('uploaded')
|
34
|
+
}
|
35
|
+
|
36
|
+
// monitor_state(record) {
|
37
|
+
// _record = record
|
38
|
+
// intervalID = setInternal(() => fetch(_record.self_url, method: 'GET', credentials: 'same-origin', headers:{'Content-Type': 'application/json'})
|
39
|
+
// }
|
40
|
+
}
|
41
|
+
|
42
|
+
export { Video }
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Resizing::Rails
|
2
|
+
class Video < ApplicationRecord
|
3
|
+
serialize :data, JSON
|
4
|
+
|
5
|
+
%w(
|
6
|
+
id
|
7
|
+
project_id
|
8
|
+
state
|
9
|
+
source_uri
|
10
|
+
deleted_at
|
11
|
+
s3_presigned_url
|
12
|
+
converted_uri
|
13
|
+
created_at
|
14
|
+
updated_at
|
15
|
+
upload_completed_url
|
16
|
+
self_url
|
17
|
+
m3u8_url
|
18
|
+
hevc_url
|
19
|
+
avc_url
|
20
|
+
thumbnail_url
|
21
|
+
job_state
|
22
|
+
).each do |name|
|
23
|
+
define_method "data_#{name}" do
|
24
|
+
self.data[name]
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def self_path
|
29
|
+
Resizing::Rails.railtie_routes_url_helpers.video_path(self)
|
30
|
+
end
|
31
|
+
|
32
|
+
def as_json *args
|
33
|
+
hash = super(*args)
|
34
|
+
hash.merge(self_path: self_path)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
= paginator.render do
|
2
|
+
nav
|
3
|
+
ul.pagination.justify-content-center
|
4
|
+
== first_page_tag unless current_page.first?
|
5
|
+
== prev_page_tag unless current_page.first?
|
6
|
+
- each_page do |page|
|
7
|
+
- if page.left_outer? || page.right_outer? || page.inside_window?
|
8
|
+
== page_tag page
|
9
|
+
- elsif !page.was_truncated?
|
10
|
+
== gap_tag
|
11
|
+
== next_page_tag unless current_page.last?
|
12
|
+
== last_page_tag unless current_page.last?
|
@@ -0,0 +1,20 @@
|
|
1
|
+
doctype html
|
2
|
+
html
|
3
|
+
head
|
4
|
+
meta charset='utf-8'
|
5
|
+
title Resizing rails
|
6
|
+
= csrf_meta_tags
|
7
|
+
= csp_meta_tag
|
8
|
+
|
9
|
+
link href="//vjs.zencdn.net/7.8.2/video-js.min.css" rel="stylesheet"
|
10
|
+
script src="//vjs.zencdn.net/7.8.2/video.min.js"
|
11
|
+
|
12
|
+
= stylesheet_link_tag "resizing/rails/application", media: "all"
|
13
|
+
= javascript_include_tag "resizing/rails/application"
|
14
|
+
|
15
|
+
body
|
16
|
+
.container
|
17
|
+
= yield
|
18
|
+
|
19
|
+
= render 'resizing/rails/common/toast'
|
20
|
+
= render 'resizing/rails/common/clipboard'
|
@@ -0,0 +1 @@
|
|
1
|
+
input#clipboard type='hidden' value=''
|
@@ -0,0 +1,10 @@
|
|
1
|
+
#toast-container.toast-container.position-fixed.top-0.end-0.p-3 style=("z-index: 5")
|
2
|
+
template#toast-template
|
3
|
+
.toast aria-atomic="true" aria-live="assertive" id="" role="alert"
|
4
|
+
.toast-header
|
5
|
+
/! img src="..." class="rounded me-2" alt="..."
|
6
|
+
strong.me-auto.toast-title Bootstrap
|
7
|
+
small.text-muted 2 seconds ago
|
8
|
+
button.btn-close aria-label="Close" data-bs-dismiss="toast" type="button"
|
9
|
+
.toast-body
|
10
|
+
| Heads up, toasts will stack automatically
|
@@ -0,0 +1,35 @@
|
|
1
|
+
form
|
2
|
+
.mb-3.row
|
3
|
+
label.form-label.col-sm-3.col-form-label for='video' File(MP4/MOV/AVI/WMV/ASF/WebM)
|
4
|
+
.col-sm-10
|
5
|
+
input.form-control#video type='file'
|
6
|
+
button.btn.btn-primary.mb-3#submit type='submit' upload
|
7
|
+
|
8
|
+
javascript:
|
9
|
+
document.addEventListener('DOMContentLoaded', (event)=> {
|
10
|
+
video = new Resizing.Rails.VideoUploader(
|
11
|
+
document.getElementById('video'),
|
12
|
+
#{raw Resizing::Rails.railtie_routes_url_helpers.prepare_videos_url(only_path: true).to_json}
|
13
|
+
);
|
14
|
+
|
15
|
+
document.getElementById('submit').addEventListener(
|
16
|
+
'click',
|
17
|
+
(e) => {
|
18
|
+
e.preventDefault()
|
19
|
+
e.target.setAttribute('disabled', 'true')
|
20
|
+
video.upload()
|
21
|
+
}
|
22
|
+
)
|
23
|
+
|
24
|
+
video.addEventListener(e => {
|
25
|
+
switch(e) {
|
26
|
+
case 'no_file_found':
|
27
|
+
(new Resizing.Rails.Toast()).show('Error', 'ファイルを指定してください')
|
28
|
+
break;
|
29
|
+
case 'upload_failed':
|
30
|
+
(new Resizing.Rails.Toast()).show('Error', 'アップロードに失敗しました')
|
31
|
+
break;
|
32
|
+
}
|
33
|
+
document.getElementById('submit').removeAttribute('disabled')
|
34
|
+
})
|
35
|
+
})
|
@@ -0,0 +1,53 @@
|
|
1
|
+
h1 動画アップロード
|
2
|
+
|
3
|
+
= render 'resizing/rails/videos/upload_form'
|
4
|
+
|
5
|
+
= paginate(@videos)
|
6
|
+
|
7
|
+
.row.row-cols-1.row-cols-md-4.g-3
|
8
|
+
- @videos.each do |video|
|
9
|
+
.col
|
10
|
+
.card.h-100 data-video-url=video.data_self_url
|
11
|
+
img.js-video-thumbnail.card-img-top
|
12
|
+
.card-body
|
13
|
+
h5.card-title = "#{video.id}:#{video.data_id}"
|
14
|
+
ul.list-group.list-group-flush
|
15
|
+
li.list-group-item
|
16
|
+
| State:
|
17
|
+
span.video-state = video.data_state
|
18
|
+
li.list-group-item
|
19
|
+
| AVC
|
20
|
+
a.card-link.avc-url.data-copy-url href='#'
|
21
|
+
| Copy URL
|
22
|
+
li.list-group-item
|
23
|
+
| HEVC
|
24
|
+
a.card-link.hevc-url.data-copy-url href='#'
|
25
|
+
| Copy URL
|
26
|
+
.card-footer
|
27
|
+
small.text-muted = 'asfadf'
|
28
|
+
.card-body
|
29
|
+
= link_to 'Show video details', video, class: 'btn btn-primary'
|
30
|
+
|
31
|
+
= paginate(@videos)
|
32
|
+
|
33
|
+
javascript:
|
34
|
+
document.addEventListener('DOMContentLoaded', ()=> {
|
35
|
+
let setDataCopyURLOrRemoveElement = (elem, value) => {
|
36
|
+
if(value) {
|
37
|
+
elem.setAttribute('data-copy-url', value)
|
38
|
+
} else {
|
39
|
+
elem.remove()
|
40
|
+
}
|
41
|
+
}
|
42
|
+
elements = document.querySelectorAll('[data-video-url]')
|
43
|
+
elements.forEach(elem => {
|
44
|
+
url = elem.getAttribute('data-video-url')
|
45
|
+
fetcher = new Resizing.Rails.VideoFetcher(url)
|
46
|
+
fetcher.fetch().then(data => {
|
47
|
+
elem.querySelector('.js-video-thumbnail').setAttribute('src', data.thumbnail_url)
|
48
|
+
elem.querySelector('.video-state').textContent = data.state
|
49
|
+
setDataCopyURLOrRemoveElement(elem.querySelector('.avc-url'), data.avc_url)
|
50
|
+
setDataCopyURLOrRemoveElement(elem.querySelector('.hevc-url'), data.hevc_url)
|
51
|
+
})
|
52
|
+
})
|
53
|
+
})
|
@@ -0,0 +1,75 @@
|
|
1
|
+
|
2
|
+
.card
|
3
|
+
.card-img-top
|
4
|
+
#video
|
5
|
+
.card-body
|
6
|
+
.card-title = "Video##{@video.id}"
|
7
|
+
ul.list-group.list-group-flush
|
8
|
+
li.list-group-item
|
9
|
+
| 進捗
|
10
|
+
.progress
|
11
|
+
.progress-bar.progress-bar-striped.progress-bar-animated role='progressbar' style="width: 0%;" aria-valuenow="25" aria-valuemin="0" aria-valuemax="100" 25%
|
12
|
+
li.list-group-item
|
13
|
+
| AVC
|
14
|
+
a.card-link.avc-url.data-copy-url href='#'
|
15
|
+
| Copy URL
|
16
|
+
li.list-group-item
|
17
|
+
| HEVC
|
18
|
+
a.card-link.hevc-url.data-copy-url href='#'
|
19
|
+
| Copy URL
|
20
|
+
li.list-group-item
|
21
|
+
label.form-label for='copy-tag' コピー用のタグ(このサイト内だけで有効です)
|
22
|
+
textarea#copy-tag class='form-control' rows='10'
|
23
|
+
| <div id='video-#{@video.id}'></div>
|
24
|
+
<script>
|
25
|
+
document.addEventListner('DOMContentLoaded', function () {
|
26
|
+
video = new Resizing.Rails.Video("#{@video.data_self_url}", document.querySelector('video-#{@video.id}'))
|
27
|
+
video.fetch()
|
28
|
+
})
|
29
|
+
</script>
|
30
|
+
|
31
|
+
p
|
32
|
+
| ※Resizing.Rails.Video classの読み込みが必要です。
|
33
|
+
b 例:
|
34
|
+
pre
|
35
|
+
code
|
36
|
+
| javascript_include_tag "resizing/rails/video"
|
37
|
+
|
38
|
+
javascript:
|
39
|
+
document.addEventListener('DOMContentLoaded', function() {
|
40
|
+
progress = new Resizing.Rails.ProgressBar(document.querySelector('.progress-bar'), 0, 100)
|
41
|
+
|
42
|
+
let setDataCopyURLOrRemoveElement = (elem, value) => {
|
43
|
+
if(!elem) {
|
44
|
+
return
|
45
|
+
}
|
46
|
+
|
47
|
+
if(value) {
|
48
|
+
elem.setAttribute('data-copy-url', value)
|
49
|
+
elem.textContent = 'Copy URL'
|
50
|
+
} else {
|
51
|
+
elem.textContent = ''
|
52
|
+
}
|
53
|
+
}
|
54
|
+
|
55
|
+
video_root = document.querySelector('#video')
|
56
|
+
video = new Resizing.Rails.Video("#{@video.data_self_url}", video_root)
|
57
|
+
video.fetch()
|
58
|
+
video.addEventListener((state, data) => {
|
59
|
+
console.log('eventListener')
|
60
|
+
console.log(data)
|
61
|
+
switch(state) {
|
62
|
+
case 'video_fetched':
|
63
|
+
if(data.job_state?.job_percent_complete !== undefined) {
|
64
|
+
progress.setCurrent(data.job_state?.job_percent_complete)
|
65
|
+
}
|
66
|
+
setDataCopyURLOrRemoveElement(document.querySelector('.avc-url'), data.avc_url)
|
67
|
+
setDataCopyURLOrRemoveElement(document.querySelector('.hevc-url'), data.hevc_url)
|
68
|
+
break
|
69
|
+
default:
|
70
|
+
break
|
71
|
+
}
|
72
|
+
})
|
73
|
+
|
74
|
+
})
|
75
|
+
|
data/config/routes.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
Gem.loaded_specs['resizing-rails'].dependencies.each do |d|
|
2
|
+
require d.name
|
3
|
+
rescue LoadError
|
4
|
+
require d.name.gsub('-', '/')
|
5
|
+
end
|
6
|
+
|
7
|
+
module Resizing
|
8
|
+
module Rails
|
9
|
+
class Engine < ::Rails::Engine
|
10
|
+
isolate_namespace Resizing::Rails
|
11
|
+
|
12
|
+
# initializer 'ResizingRails precompile hook', group: :all do |app|
|
13
|
+
# puts app.config.assets.precompile
|
14
|
+
# app.config.assets.precompile += %w(
|
15
|
+
# resizing/rails/videos.js
|
16
|
+
# )
|
17
|
+
# end
|
18
|
+
|
19
|
+
# rake_tasks do
|
20
|
+
# Dir[File.join(File.dirname(__FILE__), '../tasks/*.rake')].each { |f| load f }
|
21
|
+
# end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
metadata
ADDED
@@ -0,0 +1,204 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: resizing-rails
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0.pre
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Junichiro Kasuya
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2021-02-21 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rails
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 5.2.4
|
20
|
+
- - ">="
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 5.2.4.4
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - "~>"
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 5.2.4
|
30
|
+
- - ">="
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 5.2.4.4
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: resizing
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - "~>"
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: 0.8.0
|
40
|
+
type: :runtime
|
41
|
+
prerelease: false
|
42
|
+
version_requirements: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - "~>"
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: 0.8.0
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: slim-rails
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - ">="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :runtime
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - ">="
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '0'
|
61
|
+
- !ruby/object:Gem::Dependency
|
62
|
+
name: kaminari
|
63
|
+
requirement: !ruby/object:Gem::Requirement
|
64
|
+
requirements:
|
65
|
+
- - ">="
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: '0'
|
68
|
+
type: :runtime
|
69
|
+
prerelease: false
|
70
|
+
version_requirements: !ruby/object:Gem::Requirement
|
71
|
+
requirements:
|
72
|
+
- - ">="
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: '0'
|
75
|
+
- !ruby/object:Gem::Dependency
|
76
|
+
name: bootstrap
|
77
|
+
requirement: !ruby/object:Gem::Requirement
|
78
|
+
requirements:
|
79
|
+
- - "~>"
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: 5.0.0.beta1
|
82
|
+
type: :runtime
|
83
|
+
prerelease: false
|
84
|
+
version_requirements: !ruby/object:Gem::Requirement
|
85
|
+
requirements:
|
86
|
+
- - "~>"
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: 5.0.0.beta1
|
89
|
+
- !ruby/object:Gem::Dependency
|
90
|
+
name: sassc
|
91
|
+
requirement: !ruby/object:Gem::Requirement
|
92
|
+
requirements:
|
93
|
+
- - ">="
|
94
|
+
- !ruby/object:Gem::Version
|
95
|
+
version: '0'
|
96
|
+
type: :runtime
|
97
|
+
prerelease: false
|
98
|
+
version_requirements: !ruby/object:Gem::Requirement
|
99
|
+
requirements:
|
100
|
+
- - ">="
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
version: '0'
|
103
|
+
- !ruby/object:Gem::Dependency
|
104
|
+
name: sqlite3
|
105
|
+
requirement: !ruby/object:Gem::Requirement
|
106
|
+
requirements:
|
107
|
+
- - ">="
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
110
|
+
type: :development
|
111
|
+
prerelease: false
|
112
|
+
version_requirements: !ruby/object:Gem::Requirement
|
113
|
+
requirements:
|
114
|
+
- - ">="
|
115
|
+
- !ruby/object:Gem::Version
|
116
|
+
version: '0'
|
117
|
+
- !ruby/object:Gem::Dependency
|
118
|
+
name: github_changelog_generator
|
119
|
+
requirement: !ruby/object:Gem::Requirement
|
120
|
+
requirements:
|
121
|
+
- - ">="
|
122
|
+
- !ruby/object:Gem::Version
|
123
|
+
version: '0'
|
124
|
+
type: :development
|
125
|
+
prerelease: false
|
126
|
+
version_requirements: !ruby/object:Gem::Requirement
|
127
|
+
requirements:
|
128
|
+
- - ">="
|
129
|
+
- !ruby/object:Gem::Version
|
130
|
+
version: '0'
|
131
|
+
description: Resizing mountable module for Rails application.
|
132
|
+
email:
|
133
|
+
- junichiro.kasuya@gmail.com
|
134
|
+
executables: []
|
135
|
+
extensions: []
|
136
|
+
extra_rdoc_files: []
|
137
|
+
files:
|
138
|
+
- MIT-LICENSE
|
139
|
+
- README.md
|
140
|
+
- Rakefile
|
141
|
+
- app/assets/config/resizing_rails_manifest.js
|
142
|
+
- app/assets/javascripts/resizing/rails/application.js
|
143
|
+
- app/assets/javascripts/resizing/rails/clipboard.js
|
144
|
+
- app/assets/javascripts/resizing/rails/progressbar.js
|
145
|
+
- app/assets/javascripts/resizing/rails/toast.js
|
146
|
+
- app/assets/javascripts/resizing/rails/video.js
|
147
|
+
- app/assets/javascripts/resizing/rails/video_fetcher.js
|
148
|
+
- app/assets/javascripts/resizing/rails/video_uploader.js
|
149
|
+
- app/assets/stylesheets/resizing/rails/application.scss
|
150
|
+
- app/assets/stylesheets/resizing/rails/videos.scss
|
151
|
+
- app/controllers/resizing/rails/application_controller.rb
|
152
|
+
- app/controllers/resizing/rails/videos_controller.rb
|
153
|
+
- app/helpers/resizing/rails/application_helper.rb
|
154
|
+
- app/helpers/resizing/rails/videos_helper.rb
|
155
|
+
- app/helpers/resizing/rails/webpack_bundle_helper.rb
|
156
|
+
- app/javascript/packs/resizing.js
|
157
|
+
- app/javascript/src/video.js
|
158
|
+
- app/jobs/resizing/rails/application_job.rb
|
159
|
+
- app/mailers/resizing/rails/application_mailer.rb
|
160
|
+
- app/models/resizing/rails/application_record.rb
|
161
|
+
- app/models/resizing/rails/video.rb
|
162
|
+
- app/views/kaminari/_first_page.html.slim
|
163
|
+
- app/views/kaminari/_gap.html.slim
|
164
|
+
- app/views/kaminari/_last_page.html.slim
|
165
|
+
- app/views/kaminari/_next_page.html.slim
|
166
|
+
- app/views/kaminari/_page.html.slim
|
167
|
+
- app/views/kaminari/_paginator.html.slim
|
168
|
+
- app/views/kaminari/_prev_page.html.slim
|
169
|
+
- app/views/layouts/resizing/rails/application.html.slim
|
170
|
+
- app/views/resizing/rails/common/_clipboard.html.slim
|
171
|
+
- app/views/resizing/rails/common/_toast.html.slim
|
172
|
+
- app/views/resizing/rails/videos/_upload_form.html.slim
|
173
|
+
- app/views/resizing/rails/videos/index.html.slim
|
174
|
+
- app/views/resizing/rails/videos/show.html.slim
|
175
|
+
- config/routes.rb
|
176
|
+
- db/migrate/20210122043613_create_resizing_rails_videos.rb
|
177
|
+
- lib/resizing/rails.rb
|
178
|
+
- lib/resizing/rails/engine.rb
|
179
|
+
- lib/resizing/rails/version.rb
|
180
|
+
- lib/tasks/resizing/rails_tasks.rake
|
181
|
+
homepage: https://github.com/jksy/resizing-rails/
|
182
|
+
licenses:
|
183
|
+
- MIT
|
184
|
+
metadata: {}
|
185
|
+
post_install_message:
|
186
|
+
rdoc_options: []
|
187
|
+
require_paths:
|
188
|
+
- lib
|
189
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
190
|
+
requirements:
|
191
|
+
- - ">="
|
192
|
+
- !ruby/object:Gem::Version
|
193
|
+
version: '0'
|
194
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
195
|
+
requirements:
|
196
|
+
- - ">"
|
197
|
+
- !ruby/object:Gem::Version
|
198
|
+
version: 1.3.1
|
199
|
+
requirements: []
|
200
|
+
rubygems_version: 3.0.3
|
201
|
+
signing_key:
|
202
|
+
specification_version: 4
|
203
|
+
summary: Resizing mountable module for Rails application.
|
204
|
+
test_files: []
|