webvtt-editor 0.0.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.
- checksums.yaml +7 -0
- data/README.md +39 -0
- data/lib/vtt/cue.rb +85 -0
- data/lib/vtt/smalt.rb +127 -0
- data/lib/vtt/timestamp.rb +76 -0
- data/lib/vtt/vtt.rb +22 -0
- data/lib/webvtt-editor.rb +17 -0
- metadata +48 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: a84565214ad4ba7a5590c566ea9263ae0f2f4654
|
4
|
+
data.tar.gz: 1c33fa1abcb621a6b90c03611ab3120fd7560c9d
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 81b27a20feaafecbb80aa8f2d0c5322ebfc988a7475f35d5d7dff63ac1c3fb4db74e58809e434b927a713808ad1c925cdf7e9bf9529663d7a0495a80509ea5e8
|
7
|
+
data.tar.gz: 32c86e880bfc64a021b25df62350abfdb0d565e14ab09bfebed1b89960ae7af5af769957ce50993762001090d62b9186567bb3007e3223301cdfcd2f535cc4fe
|
data/README.md
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
# webvtt-editor
|
2
|
+
Target
|
3
|
+
=========================
|
4
|
+
>作为rails第三方插件实现在线编辑webvtt字幕文件
|
5
|
+
|
6
|
+
Usage
|
7
|
+
---------------------------------------------
|
8
|
+
* 将文件夹放在rails的app目录下
|
9
|
+
* 引入插件
|
10
|
+
```
|
11
|
+
gem "webvtt-editor"
|
12
|
+
```
|
13
|
+
|
14
|
+
* 加载文件
|
15
|
+
|
16
|
+
```
|
17
|
+
webvtt = WebVTT.read("filepath")
|
18
|
+
```
|
19
|
+
|
20
|
+
* 插入字幕
|
21
|
+
|
22
|
+
```
|
23
|
+
webvtt.insert(start_time,end_time,subtitles)
|
24
|
+
```
|
25
|
+
|
26
|
+
* 删除字幕
|
27
|
+
```
|
28
|
+
webvtt.delete(start_time,end_time)
|
29
|
+
```
|
30
|
+
|
31
|
+
* 字幕信息
|
32
|
+
|
33
|
+
```
|
34
|
+
webvtt.cues do |cue|
|
35
|
+
cue.start
|
36
|
+
cue.end
|
37
|
+
cue.text
|
38
|
+
end
|
39
|
+
```
|
data/lib/vtt/cue.rb
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
"""
|
2
|
+
@author: smalt(jjs1233@163.com)
|
3
|
+
|
4
|
+
cue.rb
|
5
|
+
~~~~~~~~~~~~~~~~
|
6
|
+
"""
|
7
|
+
module WebVTT
|
8
|
+
class Cue
|
9
|
+
attr_accessor :identifier, :start, :end, :style, :text
|
10
|
+
|
11
|
+
def initialize(cue = nil)
|
12
|
+
@content = cue
|
13
|
+
@style = {}
|
14
|
+
end
|
15
|
+
|
16
|
+
#读取内容
|
17
|
+
def self.parse(cue)
|
18
|
+
cue = Cue.new(cue)
|
19
|
+
cue.parse
|
20
|
+
return cue
|
21
|
+
end
|
22
|
+
|
23
|
+
#把文字内容写入
|
24
|
+
def to_webvtt
|
25
|
+
res = ""
|
26
|
+
if @identifier
|
27
|
+
res << "#{@identifier}\n"
|
28
|
+
end
|
29
|
+
res << "#{@content}".strip
|
30
|
+
res
|
31
|
+
end
|
32
|
+
|
33
|
+
#时间戳转换成秒
|
34
|
+
def self.timestamp_in_sec(timestamp)
|
35
|
+
mres = timestamp.match(/([0-9]{2}):([0-9]{2}):([0-9]{2}\.[0-9]{3})/)
|
36
|
+
sec = mres[3].to_f # 秒
|
37
|
+
sec += mres[2].to_f * 60 #分
|
38
|
+
sec += mres[1].to_f * 60 * 60 #小时
|
39
|
+
return sec
|
40
|
+
end
|
41
|
+
|
42
|
+
#开始时间转换成fixnum类型
|
43
|
+
def start_in_sec
|
44
|
+
@start.to_f
|
45
|
+
end
|
46
|
+
|
47
|
+
#结束时间转换成fixnum类型
|
48
|
+
def end_in_sec
|
49
|
+
@end.to_f
|
50
|
+
end
|
51
|
+
|
52
|
+
#持续时间
|
53
|
+
def length
|
54
|
+
@end.to_f - @start.to_f
|
55
|
+
end
|
56
|
+
|
57
|
+
#时间添加
|
58
|
+
def offset_by( offset_secs )
|
59
|
+
@start += offset_secs
|
60
|
+
@end += offset_secs
|
61
|
+
end
|
62
|
+
|
63
|
+
#切割文字内容 把文字内容二次加工
|
64
|
+
def parse
|
65
|
+
lines = @content.split("\n").map(&:strip)
|
66
|
+
return if lines[0] =~ /NOTE/
|
67
|
+
|
68
|
+
if !lines[0].include?("-->")
|
69
|
+
@identifier = lines[0]
|
70
|
+
lines.shift
|
71
|
+
end
|
72
|
+
|
73
|
+
if lines.empty?
|
74
|
+
return
|
75
|
+
end
|
76
|
+
|
77
|
+
if lines[0].match(/(([0-9]{2}:)?[0-9]{2}:[0-9]{2}\.[0-9]{3}) -+> (([0-9]{2}:)?[0-9]{2}:[0-9]{2}\.[0-9]{3})(.*)/)
|
78
|
+
@start = Timestamp.new $1
|
79
|
+
@end = Timestamp.new $3
|
80
|
+
@style = Hash[$5.strip.split(" ").map{|s| s.split(":").map(&:strip) }]
|
81
|
+
end
|
82
|
+
@text = lines[1..-1].join("\n")
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
data/lib/vtt/smalt.rb
ADDED
@@ -0,0 +1,127 @@
|
|
1
|
+
"""
|
2
|
+
@author: smalt(jjs1233@163.com)
|
3
|
+
|
4
|
+
smalt.rb
|
5
|
+
~~~~~~~~~~~~~~~~
|
6
|
+
"""
|
7
|
+
module WebVTT
|
8
|
+
class Smalt
|
9
|
+
attr_reader :header, :path, :filename,:cues,:new,:old
|
10
|
+
attr_accessor :cue_parsed
|
11
|
+
def initialize(f)
|
12
|
+
@file = File.new(f,'a+')
|
13
|
+
@path = f
|
14
|
+
@filename = File.basename(@path)
|
15
|
+
parse
|
16
|
+
end
|
17
|
+
|
18
|
+
#初始化 读取文件信息 把文件内容写入cue 文件地址写入path 文件名写入filename
|
19
|
+
def parse
|
20
|
+
content = File.read(@path)
|
21
|
+
if content.nil? ||content.empty?
|
22
|
+
@output = "WEBVTT"
|
23
|
+
file_puts
|
24
|
+
end
|
25
|
+
@content = File.read(@path).gsub("\r\n", "\n")
|
26
|
+
@content.gsub!("\uFEFF", '')
|
27
|
+
cues = @content.split("\n\n")
|
28
|
+
@header = cues.shift
|
29
|
+
header_lines = @header.split("\n").map(&:strip)
|
30
|
+
@header.gsub!("\n","")
|
31
|
+
if (header_lines[0] =~ /^WEBVTT/).nil?
|
32
|
+
raise MalformedFile, "Not a valid WebVTT file"
|
33
|
+
end
|
34
|
+
|
35
|
+
@cues = []
|
36
|
+
cues.each do |cue|
|
37
|
+
cue_parsed = Cue.parse(cue.strip)
|
38
|
+
if !cue_parsed.text.nil?
|
39
|
+
@cues << cue_parsed
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
#删除字幕
|
45
|
+
def delete(*args)
|
46
|
+
if @cues.reject! do |cue|
|
47
|
+
cue.start.to_f == args[0] && cue.end.to_f == args[1]
|
48
|
+
end
|
49
|
+
else
|
50
|
+
raise ArgumentError.new("This time does not exist or The arguments you give wrong")
|
51
|
+
end
|
52
|
+
save
|
53
|
+
end
|
54
|
+
|
55
|
+
#插入字幕
|
56
|
+
def insert(*args)
|
57
|
+
@start = args[0]
|
58
|
+
@end = args[1]
|
59
|
+
if time_check.empty?
|
60
|
+
@new = Cue.parse([time_fix,args[-1]].join("\n").strip)
|
61
|
+
i = -1
|
62
|
+
begin
|
63
|
+
i += 1
|
64
|
+
end while !@cues[i].nil?&&@new.start.to_f > @cues[i].start.to_f
|
65
|
+
modify(i)
|
66
|
+
save
|
67
|
+
else
|
68
|
+
raise ArgumentError.new("The arguments you give wrong or This period of time in the file already exists")
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
#文件输出 写入内容后输出文件
|
73
|
+
def save(output=nil)
|
74
|
+
output ||= @path.gsub(".srt", ".vtt")
|
75
|
+
File.open(output, "w") do |f|
|
76
|
+
f.write(to_webvtt)
|
77
|
+
end
|
78
|
+
return output
|
79
|
+
end
|
80
|
+
|
81
|
+
#整合把cue内容转换成文件需要的内容
|
82
|
+
def to_webvtt
|
83
|
+
[@header, @cues.map(&:to_webvtt)].flatten.join("\n\n") << "\n"
|
84
|
+
end
|
85
|
+
|
86
|
+
#结束时间
|
87
|
+
def total_length
|
88
|
+
@cues.last.end_in_sec
|
89
|
+
end
|
90
|
+
|
91
|
+
#字幕持续时间
|
92
|
+
def actual_total_length
|
93
|
+
@cues.last.end_in_sec - @cues.first.start_in_sec
|
94
|
+
end
|
95
|
+
|
96
|
+
#把时间经行加工 混合
|
97
|
+
def time_fix
|
98
|
+
@time = [@start,@end].map do |time|
|
99
|
+
Timestamp.new(time).to_hms
|
100
|
+
end
|
101
|
+
@time.join(" --> ")
|
102
|
+
end
|
103
|
+
|
104
|
+
#判断时间格式是否正确
|
105
|
+
def time_check
|
106
|
+
if @end.to_f > @start.to_f
|
107
|
+
@cues.reject do|cue|
|
108
|
+
(cue.end.to_f >@start.to_f && cue.start.to_f > @end.to_f ) ||(cue.end.to_f < @start.to_f && cue.start.to_f < @end.to_f )
|
109
|
+
end
|
110
|
+
else
|
111
|
+
raise ArgumentError.new("The arguments you give wrong or End time must be greater than the Start")
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
#文件内容保存
|
116
|
+
def file_puts
|
117
|
+
@file.puts(@output)
|
118
|
+
@file.close
|
119
|
+
end
|
120
|
+
|
121
|
+
#把新字幕写入cue
|
122
|
+
def modify(a,b = 0)
|
123
|
+
@cues[a,b] = @new
|
124
|
+
end
|
125
|
+
|
126
|
+
end
|
127
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
"""
|
2
|
+
@author: smalt(jjs1233@163.com)
|
3
|
+
|
4
|
+
timestamp.rb
|
5
|
+
~~~~~~~~~~~~~~~~
|
6
|
+
"""
|
7
|
+
module WebVTT
|
8
|
+
class Timestamp
|
9
|
+
#时间戳转换成秒
|
10
|
+
def self.parse_seconds( timestamp )
|
11
|
+
if mres = timestamp.match(/\A([0-9]{2}):([0-9]{2}):([0-9]{2}\.[0-9]{3})\z/)
|
12
|
+
sec = mres[3].to_f
|
13
|
+
sec += mres[2].to_f * 60
|
14
|
+
sec += mres[1].to_f * 60 * 60
|
15
|
+
elsif mres = timestamp.match(/\A([0-9]{2}):([0-9]{2}\.[0-9]{3})\z/)
|
16
|
+
sec = mres[2].to_f
|
17
|
+
sec += mres[1].to_f * 60
|
18
|
+
else
|
19
|
+
raise ArgumentError.new("Invalid WebVTT timestamp format: #{timestamp.inspect}")
|
20
|
+
end
|
21
|
+
return sec
|
22
|
+
end
|
23
|
+
|
24
|
+
def initialize( time )
|
25
|
+
if time.to_s =~ /^\d+([.]\d*)?$/
|
26
|
+
@timestamp = time
|
27
|
+
elsif time.is_a? String
|
28
|
+
@timestamp = Timestamp.parse_seconds( time )
|
29
|
+
else
|
30
|
+
raise ArgumentError.new("time not Fixnum nor a string")
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
#输出类型转换城string
|
35
|
+
def to_s
|
36
|
+
@timestamp.to_s
|
37
|
+
end
|
38
|
+
|
39
|
+
#小时分秒转换
|
40
|
+
def to_hms
|
41
|
+
hms_start
|
42
|
+
@hms = @round.reduce( [ @timestamp ] ) { |m,o|m.unshift(m.shift.divmod(o)).flatten }
|
43
|
+
@hms << (@timestamp.divmod(1).last * 1000).round
|
44
|
+
hms_result
|
45
|
+
end
|
46
|
+
|
47
|
+
#小时判断
|
48
|
+
def hms_start
|
49
|
+
if @timestamp > 3600
|
50
|
+
@round = Array.new 2,60
|
51
|
+
else
|
52
|
+
@round = Array.new 1,60
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
#小时结果输出
|
57
|
+
def hms_result
|
58
|
+
if @timestamp > 3600
|
59
|
+
sprintf("%02d:%02d:%02d.%03d", *@hms)
|
60
|
+
else
|
61
|
+
sprintf("%02d:%02d.%03d", *@hms)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
#秒类型转换fixnum
|
66
|
+
def to_f
|
67
|
+
@timestamp.to_f
|
68
|
+
end
|
69
|
+
|
70
|
+
#秒向前滚动
|
71
|
+
def +(other)
|
72
|
+
Timestamp.new self.to_f + other.to_f
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
end
|
data/lib/vtt/vtt.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
"""
|
2
|
+
@author: smalt(jjs1233@163.com)
|
3
|
+
|
4
|
+
vtt.rb
|
5
|
+
~~~~~~~~~~~~~~~~
|
6
|
+
"""
|
7
|
+
module WebVTT
|
8
|
+
#读取文件
|
9
|
+
def self.read(f)
|
10
|
+
if is_vtt? f
|
11
|
+
Smalt.new(f)
|
12
|
+
else
|
13
|
+
raise MalformedFile, "Not a valid VTT file"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
#判断文件是否是vtt文件
|
18
|
+
def self.is_vtt?(path)
|
19
|
+
return path[/\.[^\.]+$/] == ".vtt"
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
"""
|
2
|
+
@author: smalt(jjs1233@163.com)
|
3
|
+
|
4
|
+
webvtt.rb
|
5
|
+
~~~~~~~~~~~~~~~~
|
6
|
+
"""
|
7
|
+
# encoding: UTF-8
|
8
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
9
|
+
if defined?(Encoding)
|
10
|
+
Encoding.default_internal = Encoding.default_external = "UTF-8"
|
11
|
+
end
|
12
|
+
|
13
|
+
|
14
|
+
require "vtt/vtt"
|
15
|
+
require "vtt/cue"
|
16
|
+
require "vtt/timestamp"
|
17
|
+
require "vtt/smalt"
|
metadata
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: webvtt-editor
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Smalt
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2017-04-20 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: A webvtt file edit gem
|
14
|
+
email: jjs1233@163.com
|
15
|
+
executables: []
|
16
|
+
extensions: []
|
17
|
+
extra_rdoc_files: []
|
18
|
+
files:
|
19
|
+
- README.md
|
20
|
+
- lib/vtt/cue.rb
|
21
|
+
- lib/vtt/smalt.rb
|
22
|
+
- lib/vtt/timestamp.rb
|
23
|
+
- lib/vtt/vtt.rb
|
24
|
+
- lib/webvtt-editor.rb
|
25
|
+
homepage: https://github.com/jjs1233/webvtt-editor
|
26
|
+
licenses: []
|
27
|
+
metadata: {}
|
28
|
+
post_install_message:
|
29
|
+
rdoc_options: []
|
30
|
+
require_paths:
|
31
|
+
- lib
|
32
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
33
|
+
requirements:
|
34
|
+
- - ">="
|
35
|
+
- !ruby/object:Gem::Version
|
36
|
+
version: '0'
|
37
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - ">="
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: '0'
|
42
|
+
requirements: []
|
43
|
+
rubyforge_project:
|
44
|
+
rubygems_version: 2.6.10
|
45
|
+
signing_key:
|
46
|
+
specification_version: 4
|
47
|
+
summary: webvtt-editor
|
48
|
+
test_files: []
|