vtt2ass 0.3.1 → 0.3.4
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 +4 -4
- data/README.md +68 -10
- data/lib/vtt2ass/{Application.rb → application.rb} +17 -7
- data/lib/vtt2ass/{ASSFile.rb → ass_file.rb} +10 -10
- data/lib/vtt2ass/{ASSLine.rb → ass_line.rb} +12 -12
- data/lib/vtt2ass/{ASSStyle.rb → ass_style.rb} +6 -3
- data/lib/vtt2ass/{ASSStyleParams.rb → ass_style_params.rb} +6 -6
- data/lib/vtt2ass/{CSSFile.rb → css_file.rb} +1 -1
- data/lib/vtt2ass/{CSSRule.rb → css_rule.rb} +0 -0
- data/lib/vtt2ass/{Validator.rb → validator.rb} +0 -0
- data/lib/vtt2ass/version.rb +1 -1
- data/lib/vtt2ass/{VTTFile.rb → vtt_file.rb} +2 -2
- data/lib/vtt2ass/{VTTLine.rb → vtt_line.rb} +0 -0
- data/lib/vtt2ass.rb +2 -1
- metadata +12 -12
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3a864637934d7b15e7f459c532cd5f521e21e3445e0408cea0a0a7b3c966f550
|
4
|
+
data.tar.gz: 5a58b036d877c8529accd0ccc21fe5568d0bdbd686d994ba119ebc894c906e3b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e46d22748e6e8b64ec2d0486ce42cce993bcdb00b88be35db80c234bbcdf0ddad0b869e35f2b880a30a451b0a81ce99f48dfb5d671cfa40ad284b4eece17f1d3
|
7
|
+
data.tar.gz: 3bbe4b767f309e820d4c44bf8c351090cbe0810219069970c4ac131e50453eeb7b593e9f4793987a69dc9596ab8d6f35815d2d9bbc6785afe755551bcec7c49d
|
data/README.md
CHANGED
@@ -2,35 +2,54 @@
|
|
2
2
|
|
3
3
|
[](https://badge.fury.io/rb/vtt2ass)
|
4
4
|
|
5
|
-
|
5
|
+
## Description
|
6
|
+
|
7
|
+
This is a simple CLI (Command Line Interface) application to convert VTT files to ASS subtitles.
|
8
|
+
|
9
|
+
This application is originally based on the `vttconvert` module of [anidl/hidive-downloader-nx](https://github.com/anidl/hidive-downloader-nx) repository. The [maxwbot/maxwhidive](https://github.com/maxwbot/maxwhidive) repository was also used as inspiration for handling the positionning of subs.
|
10
|
+
|
11
|
+
Those two tools were missing features and didn't work well on a lot of more complex subtitles files. For that reason, I wrote a new tool that can handle everything.
|
12
|
+
|
13
|
+
### Features
|
14
|
+
|
15
|
+
- Convert simple VTT files
|
16
|
+
- Convert complex VTT files with positioning
|
17
|
+
- Convert Hidive VTT files with CSS styling
|
18
|
+
- Convert subtitles in batches by specifying the input directory
|
19
|
+
- Handles subtitles made for lower resolution video
|
20
|
+
- Can add offset to subtitle lines
|
21
|
+
- Can output result to the CLI
|
22
|
+
- Can output to the specifed directory
|
23
|
+
- Can change the base font size
|
24
|
+
- Can specify a custom font family for non-styled lines
|
25
|
+
- Can add a title to the converted files
|
6
26
|
|
7
27
|
## Requirements
|
28
|
+
|
8
29
|
- ruby 2.7.2 or newer
|
9
30
|
|
10
|
-
|
31
|
+
Development is currently done on ruby 3.0+, but the Gitlab runner for builds works with ruby version 2.7.2. Older versions of ruby may be compatible, but they won't be tested.
|
11
32
|
|
12
33
|
## Installation
|
13
34
|
|
14
35
|
To install:
|
15
36
|
```bash
|
16
|
-
gem install vtt2ass
|
17
|
-
```
|
18
|
-
|
19
|
-
# Build
|
20
|
-
|
21
|
-
```bash
|
22
|
-
gem build vtt2ass.gemspec
|
37
|
+
$ gem install vtt2ass
|
23
38
|
```
|
24
39
|
|
25
40
|
## Usage
|
26
41
|
|
42
|
+
- Empty arguments lists the available commands
|
27
43
|
```bash
|
28
44
|
$ vtt2ass
|
29
45
|
Commands:
|
30
46
|
vtt2ass convert INPUT # Run the VTT to ASS conversion for the specified file(s)
|
31
47
|
vtt2ass help [COMMAND] # Describe available commands or one specific command
|
32
48
|
vtt2ass version # Show version
|
49
|
+
```
|
33
50
|
|
51
|
+
- Help command shows available options of the specified command
|
52
|
+
```bash
|
34
53
|
$ vtt2ass help convert
|
35
54
|
Usage:
|
36
55
|
vtt2ass convert INPUT
|
@@ -43,12 +62,51 @@ Options:
|
|
43
62
|
-f, [--font-family=FONT_FAMILY] # Specify a font family for the subtitles
|
44
63
|
# Default: Open Sans Semibold
|
45
64
|
-c, [--css=CSS] # Specify a CSS file path for Hidive subs
|
65
|
+
-l, [--line-offset=N] # Specify a line offset for the main dialog (e.g. 50 lowers the text line by 50px of the total height)
|
66
|
+
# Default: 0
|
46
67
|
-q, [--quiet], [--no-quiet] # Don't output to the console
|
47
68
|
|
48
69
|
Run the VTT to ASS conversion for the specified file(s)
|
49
70
|
```
|
50
71
|
|
51
|
-
|
72
|
+
- Convert command
|
73
|
+
```bash
|
74
|
+
$ vtt2ass convert ./path/to/input/ -o ./path/to/output/ -l 50 -q
|
75
|
+
```
|
76
|
+
|
77
|
+
- Version command shows the application version
|
78
|
+
```bash
|
79
|
+
$ vtt2ass version
|
80
|
+
0.3.3
|
81
|
+
```
|
82
|
+
|
83
|
+
## Contributing
|
84
|
+
|
85
|
+
Contributions are welcome. Create an *Issue* on Gitlab and link it with a *Pull Request* of the changes made. The changes needs to pass the ruby tests.
|
86
|
+
|
87
|
+
```
|
88
|
+
$ rake test
|
89
|
+
```
|
90
|
+
|
91
|
+
## Build
|
92
|
+
|
93
|
+
To build a gem file for local installation:
|
94
|
+
```bash
|
95
|
+
$ git clone https://gitlab.com/dkb-weeblets/vtt2ass.git
|
96
|
+
$ cd vtt2ass/
|
97
|
+
$ gem build vtt2ass.gemspec
|
98
|
+
```
|
99
|
+
|
100
|
+
To install the gem file:
|
101
|
+
```bash
|
102
|
+
$ gem install ./vtt2ass-0.3.3.gem
|
103
|
+
```
|
104
|
+
|
105
|
+
## License
|
106
|
+
|
107
|
+
Licensed under the **MIT** Licence. For more information read the `LICENSE.txt` file.
|
108
|
+
|
109
|
+
## Donate
|
52
110
|
|
53
111
|
If you want to support me, consider buying me a coffee.
|
54
112
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# Relative imports
|
2
|
-
require_relative '
|
3
|
-
require_relative '
|
2
|
+
require_relative 'vtt_file'
|
3
|
+
require_relative 'ass_file'
|
4
4
|
|
5
5
|
##
|
6
6
|
# Main application class that manages all the operations.
|
@@ -21,8 +21,9 @@ class Application
|
|
21
21
|
end
|
22
22
|
@quiet = options[:quiet]
|
23
23
|
if options[:css] then
|
24
|
-
@css = options[:css].gsub('\\', '/')
|
24
|
+
@css = options[:css].gsub('\\', '/').delete_suffix('/')
|
25
25
|
end
|
26
|
+
@line_offset = options[:line_offset]
|
26
27
|
end
|
27
28
|
|
28
29
|
##
|
@@ -44,7 +45,7 @@ class Application
|
|
44
45
|
def convert(input_path)
|
45
46
|
ass_file = vtt_to_ass(input_path)
|
46
47
|
if (not @output.nil?) then
|
47
|
-
ass_file.
|
48
|
+
ass_file.write_to_file(@output + '/' + File.basename(input_path).gsub('.vtt', '.ass'))
|
48
49
|
end
|
49
50
|
puts ass_file.to_s unless @quiet
|
50
51
|
end
|
@@ -53,14 +54,23 @@ class Application
|
|
53
54
|
# This method creates a new VTTFile object from the file path provided and convert its content
|
54
55
|
# inside a new ASSFile object.
|
55
56
|
def vtt_to_ass(file_path)
|
57
|
+
base_file_name = File.basename(file_path).gsub('.vtt', '')
|
58
|
+
css_file = nil
|
59
|
+
if defined?(@css) and File.directory?(@css) then
|
60
|
+
css_file = "#{@css}/#{base_file_name}.css"
|
61
|
+
elsif File.file?("#{file_path.gsub('.vtt', '')}.css") then
|
62
|
+
css_file = "#{file_path.gsub('.vtt', '')}.css"
|
63
|
+
else
|
64
|
+
css_file = @css
|
65
|
+
end
|
56
66
|
vtt_file = VTTFile.new(file_path, @width, @height)
|
57
67
|
ass_file = ASSFile.new(
|
58
|
-
(defined?(@title) ? @title :
|
68
|
+
(defined?(@title) ? @title : base_file_name),
|
59
69
|
@width,
|
60
70
|
@height,
|
61
|
-
|
71
|
+
css_file
|
62
72
|
)
|
63
|
-
ass_file.
|
73
|
+
ass_file.convert_vtt_to_ass(vtt_file, @font_family, @font_size, @line_offset)
|
64
74
|
return ass_file
|
65
75
|
end
|
66
76
|
|
@@ -1,8 +1,8 @@
|
|
1
1
|
# Relative imports
|
2
|
-
require_relative '
|
3
|
-
require_relative '
|
4
|
-
require_relative '
|
5
|
-
require_relative '
|
2
|
+
require_relative 'ass_line'
|
3
|
+
require_relative 'ass_style'
|
4
|
+
require_relative 'css_file'
|
5
|
+
require_relative 'css_rule'
|
6
6
|
|
7
7
|
##
|
8
8
|
# This class defines an ASS subtitle file.
|
@@ -45,12 +45,12 @@ class ASSFile
|
|
45
45
|
# This method receives a VTTFile object and font arguments creates new ASSLine with the params of
|
46
46
|
# each VTTLine. All those ASSLine are stored in an array. It also creates an array of ASSStyle that
|
47
47
|
# will be used in the ASS style list.
|
48
|
-
def
|
48
|
+
def convert_vtt_to_ass(vtt_file, font_family, font_size, line_offset = 0)
|
49
49
|
fs = font_size
|
50
|
-
font_color = '&H00FFFFFF'
|
51
|
-
is_italic = false
|
52
|
-
is_bold = false
|
53
50
|
vtt_file.lines.each do |line|
|
51
|
+
font_color = '&H00FFFFFF'
|
52
|
+
is_italic = false
|
53
|
+
is_bold = false
|
54
54
|
@ass_lines.push(ASSLine.new(line.style, line.time_start, line.time_end, line.text))
|
55
55
|
style_exists = false
|
56
56
|
@ass_styles.each do |style|
|
@@ -88,14 +88,14 @@ class ASSFile
|
|
88
88
|
end
|
89
89
|
end
|
90
90
|
end
|
91
|
-
@ass_styles.push(ASSStyle.new(line.style, line.params, font_family, font_size, font_color, is_bold, is_italic, @width, @height))
|
91
|
+
@ass_styles.push(ASSStyle.new(line.style, line.params, font_family, font_size, font_color, is_bold, is_italic, line_offset, @width, @height))
|
92
92
|
end
|
93
93
|
end
|
94
94
|
end
|
95
95
|
|
96
96
|
##
|
97
97
|
# This method writes the content of the ASSFile object into a file path that is provided.
|
98
|
-
def
|
98
|
+
def write_to_file(file_path)
|
99
99
|
File.open(file_path, 'w') do |line|
|
100
100
|
line.print "\ufeff"
|
101
101
|
line.puts self.to_s
|
@@ -14,9 +14,9 @@ class ASSLine
|
|
14
14
|
# * Requires +text+, a VTT formatted string as input.
|
15
15
|
def initialize(style, time_start, time_end, text)
|
16
16
|
@style = style
|
17
|
-
@time_start =
|
18
|
-
@time_end =
|
19
|
-
@text =
|
17
|
+
@time_start = convert_time(time_start)
|
18
|
+
@time_end = convert_time(time_end)
|
19
|
+
@text = convert_to_ass_text(text)
|
20
20
|
end
|
21
21
|
|
22
22
|
##
|
@@ -29,7 +29,7 @@ class ASSLine
|
|
29
29
|
# This method replaces characters and tags to ASS compatible characters and tags.
|
30
30
|
#
|
31
31
|
# * Requires +text+, a string of VTT formated text as input.
|
32
|
-
def
|
32
|
+
def convert_to_ass_text(text)
|
33
33
|
decoder = HTMLEntities.new()
|
34
34
|
text = text
|
35
35
|
.gsub(/\r/, '')
|
@@ -52,16 +52,16 @@ class ASSLine
|
|
52
52
|
# This method validates the time format and sends the matching time to be converted
|
53
53
|
#
|
54
54
|
# * Requires +str+, a VTT formatted time string.
|
55
|
-
def
|
55
|
+
def convert_time(time)
|
56
56
|
mTime = time.match(/([\d:]*)\.?(\d*)/)
|
57
|
-
return
|
57
|
+
return to_subs_time(mTime[0])
|
58
58
|
end
|
59
59
|
|
60
60
|
##
|
61
61
|
# This method converts time from VTT format to the ASS format.
|
62
62
|
#
|
63
63
|
# * Requires +str+, a VTT formatted time string.
|
64
|
-
def
|
64
|
+
def to_subs_time(str)
|
65
65
|
n = []
|
66
66
|
x = str.split(/[:.]/).map { |x| x.to_i }
|
67
67
|
|
@@ -72,12 +72,12 @@ class ASSLine
|
|
72
72
|
sx = x[0]*60*60 + x[1]*60 + x[2] + x[3].to_f
|
73
73
|
sx = ("%.2f" % sx).split('.')
|
74
74
|
|
75
|
-
n.unshift(
|
75
|
+
n.unshift(pad_time_num('.', sx[1], msLen))
|
76
76
|
sx = sx[0].to_f
|
77
77
|
|
78
|
-
n.unshift(
|
79
|
-
n.unshift(
|
80
|
-
n.unshift(
|
78
|
+
n.unshift(pad_time_num(':', (sx % 60).to_i, 2))
|
79
|
+
n.unshift(pad_time_num(':', (sx / 60).floor % 60, 2))
|
80
|
+
n.unshift(pad_time_num('', (sx / 3600).floor % 60, hLen))
|
81
81
|
|
82
82
|
return n.join('')
|
83
83
|
end
|
@@ -88,7 +88,7 @@ class ASSLine
|
|
88
88
|
# * Requires +sep+, a string separator.
|
89
89
|
# * Requires +input+, an integer.
|
90
90
|
# * Requires +pad+, an integer for the number of digits to be padded.
|
91
|
-
def
|
91
|
+
def pad_time_num(sep, input, pad)
|
92
92
|
return sep + (input.to_s).rjust(pad, '0')
|
93
93
|
end
|
94
94
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# Relative imports
|
2
|
-
require_relative '
|
3
|
-
require_relative '
|
2
|
+
require_relative 'ass_style_params'
|
3
|
+
require_relative 'validator'
|
4
4
|
require 'redgreenblue'
|
5
5
|
|
6
6
|
##
|
@@ -15,7 +15,7 @@ class ASSStyle
|
|
15
15
|
# * Requires +params+, a string of VTT styling as input.
|
16
16
|
# * Requires a video +width+ as input.
|
17
17
|
# * Requires a video +height+ as input.
|
18
|
-
def initialize(style_name, params, font_family, font_size, font_color, is_bold, is_italic, width, height)
|
18
|
+
def initialize(style_name, params, font_family, font_size, font_color, is_bold, is_italic, line_offset, width, height)
|
19
19
|
@width = width
|
20
20
|
@height = height
|
21
21
|
@font_family = font_family
|
@@ -26,6 +26,9 @@ class ASSStyle
|
|
26
26
|
if style_name.eql? 'MainTop' then
|
27
27
|
@s_params.vertical_margin = 50
|
28
28
|
end
|
29
|
+
if style_name.include? 'Subtitle' then
|
30
|
+
@s_params.vertical_margin -= line_offset
|
31
|
+
end
|
29
32
|
@is_italic = is_italic
|
30
33
|
@is_bold = is_bold
|
31
34
|
end
|
@@ -19,15 +19,15 @@ class ASSStyleParams
|
|
19
19
|
@align = p[1].chomp
|
20
20
|
end
|
21
21
|
end
|
22
|
-
|
23
|
-
|
24
|
-
|
22
|
+
create_alignment()
|
23
|
+
create_horizontal_margin(width)
|
24
|
+
create_vertical_margin(height)
|
25
25
|
end
|
26
26
|
|
27
27
|
##
|
28
28
|
# This method decides the alignement value in a 9 position grid based of the
|
29
29
|
# values in cue settings "align" and "line".
|
30
|
-
def
|
30
|
+
def create_alignment()
|
31
31
|
if (defined?(@line) and not defined?(@position)) then
|
32
32
|
if (defined?(@align)) then
|
33
33
|
case @align
|
@@ -60,7 +60,7 @@ class ASSStyleParams
|
|
60
60
|
##
|
61
61
|
# This method calculates the horizontal margin in px between the alignement position and
|
62
62
|
# and the content displayed by using the "position" cue setting.
|
63
|
-
def
|
63
|
+
def create_horizontal_margin(width)
|
64
64
|
steps = (width / 100).to_i
|
65
65
|
if defined?(@position) then
|
66
66
|
@horizontal_margin = @position * steps
|
@@ -72,7 +72,7 @@ class ASSStyleParams
|
|
72
72
|
##
|
73
73
|
# This method calculates the vertical margin in px between the alignement position and
|
74
74
|
# and the content displayed by using the "line" cue setting.
|
75
|
-
def
|
75
|
+
def create_vertical_margin(height)
|
76
76
|
steps = (height / 100).to_i
|
77
77
|
if defined?(@line) then
|
78
78
|
if (@alignment == 1) then
|
File without changes
|
File without changes
|
data/lib/vtt2ass/version.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
# Relative imports
|
2
|
-
require_relative '
|
2
|
+
require_relative 'vtt_line'
|
3
3
|
|
4
4
|
##
|
5
5
|
# This class defines a VTT subtile file.
|
@@ -42,7 +42,7 @@ class VTTFile
|
|
42
42
|
|
43
43
|
##
|
44
44
|
# This method writes the content of the VTTFile object into a file path that is provided.
|
45
|
-
def
|
45
|
+
def write_to_file(file_path)
|
46
46
|
File.open(file_path, 'w') do |line|
|
47
47
|
line.print "\ufeff"
|
48
48
|
line.puts self.to_s
|
File without changes
|
data/lib/vtt2ass.rb
CHANGED
@@ -3,7 +3,7 @@ require 'thor'
|
|
3
3
|
|
4
4
|
# Relative imports
|
5
5
|
require_relative 'vtt2ass/version'
|
6
|
-
require_relative 'vtt2ass/
|
6
|
+
require_relative 'vtt2ass/application'
|
7
7
|
|
8
8
|
class MainCommand < Thor
|
9
9
|
def self.exit_on_failure?
|
@@ -16,6 +16,7 @@ class MainCommand < Thor
|
|
16
16
|
method_option :font_size, :aliases => '-s', :desc => 'Specify a font size for the subtitles', :default => 52, :type => :numeric
|
17
17
|
method_option :font_family, :aliases => '-f', :desc => 'Specify a font family for the subtitles', :default => 'Open Sans Semibold', :type => :string
|
18
18
|
method_option :css, :aliases => '-c', :desc => 'Specify a CSS file path for Hidive subs', :type => :string
|
19
|
+
method_option :line_offset, :aliases => '-l', :desc => 'Specify a line offset for the main dialog (e.g. 50 lowers the text line by 50px of the total height)', :default => 0, :type => :numeric
|
19
20
|
method_option :quiet, :aliases => '-q', :desc => 'Don\'t output to the console', :type => :boolean
|
20
21
|
def convert(input)
|
21
22
|
app = Application.new(input, options)
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: vtt2ass
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Louis-Philippe Fortin
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-05-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: htmlentities
|
@@ -153,17 +153,17 @@ files:
|
|
153
153
|
- doc/top-level-namespace.html
|
154
154
|
- exe/vtt2ass
|
155
155
|
- lib/vtt2ass.rb
|
156
|
-
- lib/vtt2ass/
|
157
|
-
- lib/vtt2ass/
|
158
|
-
- lib/vtt2ass/
|
159
|
-
- lib/vtt2ass/
|
160
|
-
- lib/vtt2ass/
|
161
|
-
- lib/vtt2ass/
|
162
|
-
- lib/vtt2ass/
|
163
|
-
- lib/vtt2ass/
|
164
|
-
- lib/vtt2ass/VTTLine.rb
|
165
|
-
- lib/vtt2ass/Validator.rb
|
156
|
+
- lib/vtt2ass/application.rb
|
157
|
+
- lib/vtt2ass/ass_file.rb
|
158
|
+
- lib/vtt2ass/ass_line.rb
|
159
|
+
- lib/vtt2ass/ass_style.rb
|
160
|
+
- lib/vtt2ass/ass_style_params.rb
|
161
|
+
- lib/vtt2ass/css_file.rb
|
162
|
+
- lib/vtt2ass/css_rule.rb
|
163
|
+
- lib/vtt2ass/validator.rb
|
166
164
|
- lib/vtt2ass/version.rb
|
165
|
+
- lib/vtt2ass/vtt_file.rb
|
166
|
+
- lib/vtt2ass/vtt_line.rb
|
167
167
|
- vtt2ass.gemspec
|
168
168
|
homepage: https://gitlab.com/dkb-weeblets/vtt2ass
|
169
169
|
licenses:
|