titlekit 1.0.0 → 1.1.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 +4 -4
- data/README.md +8 -0
- data/bin/template_job.rb +43 -0
- data/bin/titlekit +62 -0
- data/lib/titlekit/job.rb +27 -8
- data/lib/titlekit/parsers/ass.rb +19 -2
- data/lib/titlekit/parsers/srt.rb +18 -2
- data/lib/titlekit/parsers/ssa.rb +19 -24
- data/lib/titlekit/specification.rb +9 -1
- data/lib/titlekit/utilities.rb +3 -0
- data/lib/titlekit/version.rb +2 -1
- data/lib/titlekit/want.rb +3 -3
- data/spec/simultaneous_subtitles/triple_plus/ass/expected.ass +54 -53
- data/spec/simultaneous_subtitles/triple_plus/ass/out.ass +54 -53
- data/spec/simultaneous_subtitles/triple_plus/srt/expected.srt +34 -30
- data/spec/simultaneous_subtitles/triple_plus/srt/out.srt +34 -30
- data/spec/simultaneous_subtitles/triple_plus/ssa/expected.ssa +54 -53
- data/spec/simultaneous_subtitles/triple_plus/ssa/out.ssa +54 -53
- metadata +7 -3
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA1:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 650af440419b3a43cd9b6d57a2f83c7ccc61277e
         | 
| 4 | 
            +
              data.tar.gz: c1a6eee753972bc12345d5f3fa7beeebfab6ed9d
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: b85b8b7783b76a0e9a295790049194dbe47ff7c765d5376c9d27142bac96fe1c4697cf130d0df4a56339538c55f78f12c73febfbff5737bde45ea8469852b7e0
         | 
| 7 | 
            +
              data.tar.gz: 983e8444dbfced2363ad125ea9d8e720609ffae3804b3657d4799ad660e7871882b856de641c3bb8503821dbd829de810f169c3219b133208cb060d3a75867cb
         | 
    
        data/README.md
    CHANGED
    
    | @@ -43,6 +43,14 @@ unknown encoding) | |
| 43 43 | 
             
              end
         | 
| 44 44 | 
             
            ```
         | 
| 45 45 |  | 
| 46 | 
            +
            ### Template
         | 
| 47 | 
            +
             | 
| 48 | 
            +
            To get you started quickly with an edit script for subtitles, you can use a console command provided by Titlekit:
         | 
| 49 | 
            +
             | 
| 50 | 
            +
                 $ titlekit template [optional_title]
         | 
| 51 | 
            +
             | 
| 52 | 
            +
            This will generate either `template_job.rb` or `[optional_title].rb` if you have provided an optional title (Inside the directory you are in). The template script contains a basically complete Titlekit script, you just need to fill in your filenames, encodings, references, etc. as needed. There are also some comments included so you know where to start off!
         | 
| 53 | 
            +
             | 
| 46 54 | 
             
            ### All features by example
         | 
| 47 55 |  | 
| 48 56 | 
             
            In all following examples I will omit `(1)` and `(4)` from the basic example, because they stay the same.  
         | 
    
        data/bin/template_job.rb
    ADDED
    
    | @@ -0,0 +1,43 @@ | |
| 1 | 
            +
            require 'titlekit'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            job = Titlekit::Job.new
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            job.have do
         | 
| 6 | 
            +
             | 
| 7 | 
            +
              # Specify the file you already have; Also works with .ssa and .ass
         | 
| 8 | 
            +
              file('original.srt')
         | 
| 9 | 
            +
             | 
| 10 | 
            +
              # Change this to your encoding, uncomment if you don't know
         | 
| 11 | 
            +
              encoding('utf-8')
         | 
| 12 | 
            +
             | 
| 13 | 
            +
              # Uncomment and edit to set a reference in the existing subtitles
         | 
| 14 | 
            +
              # reference(:first, srt_timecode: '00:00:00,000')
         | 
| 15 | 
            +
             | 
| 16 | 
            +
              # Uncomment and edit to set another reference in the existing subtitles
         | 
| 17 | 
            +
              # reference(:second, srt_timecode: '00:00:00,000')
         | 
| 18 | 
            +
             | 
| 19 | 
            +
            end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
            job.want do
         | 
| 22 | 
            +
             | 
| 23 | 
            +
              # Specify the file to be created; Also works with .ssa and .ass
         | 
| 24 | 
            +
              file('target.srt')
         | 
| 25 | 
            +
             | 
| 26 | 
            +
              # Change this to your desired target encoding
         | 
| 27 | 
            +
              encoding('utf-8')
         | 
| 28 | 
            +
             | 
| 29 | 
            +
              # Uncomment and edit to set a new target timecode for the first reference
         | 
| 30 | 
            +
              # reference(:first, srt_timecode: '00:00:00,000')
         | 
| 31 | 
            +
             | 
| 32 | 
            +
              # Uncomment and edit to also set the second target timecode
         | 
| 33 | 
            +
              # reference(:second, srt_timecode: '00:00:00,000')
         | 
| 34 | 
            +
             | 
| 35 | 
            +
            end
         | 
| 36 | 
            +
             | 
| 37 | 
            +
            if job.run
         | 
| 38 | 
            +
              puts 'Job completed without errors!'
         | 
| 39 | 
            +
            else
         | 
| 40 | 
            +
              puts 'There were errors:'
         | 
| 41 | 
            +
              puts job.report.join("\n")
         | 
| 42 | 
            +
            end
         | 
| 43 | 
            +
             | 
    
        data/bin/titlekit
    ADDED
    
    | @@ -0,0 +1,62 @@ | |
| 1 | 
            +
            #!/usr/bin/env ruby
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            if ARGV.length > 0 && ARGV[0] == 'template'
         | 
| 4 | 
            +
             | 
| 5 | 
            +
              filename = ARGV.length > 1 ? ARGV[1] + '.rb' : 'template_job.rb'
         | 
| 6 | 
            +
              
         | 
| 7 | 
            +
              content = <<HERETEMPLATE
         | 
| 8 | 
            +
            require 'titlekit'
         | 
| 9 | 
            +
             | 
| 10 | 
            +
            job = Titlekit::Job.new
         | 
| 11 | 
            +
             | 
| 12 | 
            +
            job.have do
         | 
| 13 | 
            +
             | 
| 14 | 
            +
              # Specify the file you already have; Also works with .ssa and .ass
         | 
| 15 | 
            +
              file('original.srt')
         | 
| 16 | 
            +
             | 
| 17 | 
            +
              # Change this to your encoding, uncomment if you don't know
         | 
| 18 | 
            +
              encoding('utf-8')
         | 
| 19 | 
            +
             | 
| 20 | 
            +
              # Uncomment and edit to set a reference in the existing subtitles
         | 
| 21 | 
            +
              # reference(:first, srt_timecode: '00:00:00,000')
         | 
| 22 | 
            +
             | 
| 23 | 
            +
              # Uncomment and edit to set another reference in the existing subtitles
         | 
| 24 | 
            +
              # reference(:second, srt_timecode: '00:00:00,000')
         | 
| 25 | 
            +
             | 
| 26 | 
            +
            end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
            job.want do
         | 
| 29 | 
            +
             | 
| 30 | 
            +
              # Specify the file to be created; Also works with .ssa and .ass
         | 
| 31 | 
            +
              file('target.srt')
         | 
| 32 | 
            +
             | 
| 33 | 
            +
              # Change this to your desired target encoding
         | 
| 34 | 
            +
              encoding('utf-8')
         | 
| 35 | 
            +
             | 
| 36 | 
            +
              # Uncomment and edit to set a new target timecode for the first reference
         | 
| 37 | 
            +
              # reference(:first, srt_timecode: '00:00:00,000')
         | 
| 38 | 
            +
             | 
| 39 | 
            +
              # Uncomment and edit to also set the second target timecode
         | 
| 40 | 
            +
              # reference(:second, srt_timecode: '00:00:00,000')
         | 
| 41 | 
            +
             | 
| 42 | 
            +
            end
         | 
| 43 | 
            +
             | 
| 44 | 
            +
            if job.run
         | 
| 45 | 
            +
              puts 'Job completed without errors!'
         | 
| 46 | 
            +
            else
         | 
| 47 | 
            +
              puts 'There were errors:'
         | 
| 48 | 
            +
              puts job.report.join("\\n")
         | 
| 49 | 
            +
            end
         | 
| 50 | 
            +
             | 
| 51 | 
            +
            HERETEMPLATE
         | 
| 52 | 
            +
             | 
| 53 | 
            +
              IO.write(filename, content)
         | 
| 54 | 
            +
             | 
| 55 | 
            +
              puts "Created generic job script '#{filename}' in current directory;"
         | 
| 56 | 
            +
              puts "Edit and then run with 'ruby #{filename}'"
         | 
| 57 | 
            +
             | 
| 58 | 
            +
            else
         | 
| 59 | 
            +
              puts 'Your either provided an unknown option, or none at all;'
         | 
| 60 | 
            +
              puts 'Currently only \'template [optional_title]\' is available;'
         | 
| 61 | 
            +
              puts 'E.g. \'titlekit template myscript\''
         | 
| 62 | 
            +
            end
         | 
    
        data/lib/titlekit/job.rb
    CHANGED
    
    | @@ -4,14 +4,14 @@ module Titlekit | |
| 4 4 |  | 
| 5 5 | 
             
              class Job
         | 
| 6 6 |  | 
| 7 | 
            -
                # Returns everything  | 
| 7 | 
            +
                # Returns everything you {Have}
         | 
| 8 8 | 
             
                #
         | 
| 9 | 
            -
                # @return [Array<Have>]  | 
| 9 | 
            +
                # @return [Array<Have>] Everything you {Have}
         | 
| 10 10 | 
             
                attr_reader :haves
         | 
| 11 11 |  | 
| 12 | 
            -
                # Returns everything  | 
| 12 | 
            +
                # Returns everything you {Want}
         | 
| 13 13 | 
             
                #
         | 
| 14 | 
            -
                # @return [Array<Want>]  | 
| 14 | 
            +
                # @return [Array<Want>] Everything you {Want}
         | 
| 15 15 | 
             
                attr_reader :wants
         | 
| 16 16 |  | 
| 17 17 | 
             
                # Returns the job report, which documents the direct cause of failures
         | 
| @@ -23,7 +23,7 @@ module Titlekit | |
| 23 23 |  | 
| 24 24 | 
             
                # Starts a new job.
         | 
| 25 25 | 
             
                #
         | 
| 26 | 
            -
                # A job requires at least one  | 
| 26 | 
            +
                # A job requires at least one file you {Have} and one file you {Want}
         | 
| 27 27 | 
             
                # in order to be runable. Use {Job#have} and {Job#want} to add
         | 
| 28 28 | 
             
                # and obtain specification interfaces for the job.
         | 
| 29 29 | 
             
                #
         | 
| @@ -42,7 +42,7 @@ module Titlekit | |
| 42 42 | 
             
                  end  
         | 
| 43 43 | 
             
                end
         | 
| 44 44 |  | 
| 45 | 
            -
                #  | 
| 45 | 
            +
                # Runs the job.
         | 
| 46 46 | 
             
                #
         | 
| 47 47 | 
             
                # @return [Boolean] true if the job succeeds, false if it fails.
         | 
| 48 48 | 
             
                #   {Job#report} provides information in case of failure.
         | 
| @@ -214,6 +214,8 @@ module Titlekit | |
| 214 214 | 
             
                      SSA.import(data)
         | 
| 215 215 | 
             
                    when '.srt'
         | 
| 216 216 | 
             
                      SRT.import(data)
         | 
| 217 | 
            +
                    when '.yt'
         | 
| 218 | 
            +
                      YT.import(data)        
         | 
| 217 219 | 
             
                    else
         | 
| 218 220 | 
             
                      raise 'Not supported'
         | 
| 219 221 | 
             
                    end
         | 
| @@ -258,7 +260,9 @@ module Titlekit | |
| 258 260 | 
             
                  end
         | 
| 259 261 | 
             
                end
         | 
| 260 262 |  | 
| 261 | 
            -
                #  | 
| 263 | 
            +
                # Cleans out subtitles that fell out of the usable time range
         | 
| 264 | 
            +
                #
         | 
| 265 | 
            +
                # @params have [Have] What we {Have}   
         | 
| 262 266 | 
             
                def cull(have)
         | 
| 263 267 | 
             
                  have.subtitles.reject! { |subtitle| subtitle[:end] < 0 }
         | 
| 264 268 | 
             
                  have.subtitles.each do |subtitle|
         | 
| @@ -266,8 +270,10 @@ module Titlekit | |
| 266 270 | 
             
                  end
         | 
| 267 271 | 
             
                end
         | 
| 268 272 |  | 
| 269 | 
            -
                #  | 
| 273 | 
            +
                # Assigns track identification fields for distinguishing
         | 
| 270 274 | 
             
                # between continuous/simultaneous subtitles
         | 
| 275 | 
            +
                #
         | 
| 276 | 
            +
                # @params have [Have] What we {Have} 
         | 
| 271 277 | 
             
                def group(have)
         | 
| 272 278 | 
             
                  if have.track
         | 
| 273 279 | 
             
                    # Assign a custom track identifier if one was supplied
         | 
| @@ -348,6 +354,9 @@ module Titlekit | |
| 348 354 | 
             
                    when '.srt'
         | 
| 349 355 | 
             
                      SRT.master(want.subtitles)
         | 
| 350 356 | 
             
                      SRT.export(want.subtitles)
         | 
| 357 | 
            +
                    when '.yt'
         | 
| 358 | 
            +
                      YT.master(want.subtitles)
         | 
| 359 | 
            +
                      YT.export(want.subtitles)         
         | 
| 351 360 | 
             
                    else
         | 
| 352 361 | 
             
                      raise 'Not supported'
         | 
| 353 362 | 
             
                    end
         | 
| @@ -391,6 +400,12 @@ module Titlekit | |
| 391 400 | 
             
                  end
         | 
| 392 401 | 
             
                end
         | 
| 393 402 |  | 
| 403 | 
            +
                # Rescales timecodes based on two differing framerates and then applies a
         | 
| 404 | 
            +
                # simple timeshift to the subtitles we {Have}.
         | 
| 405 | 
            +
                #
         | 
| 406 | 
            +
                # @param have [Have] the subtitles we {Have}
         | 
| 407 | 
            +
                # @param want [Want] the subtitles we {Want}
         | 
| 408 | 
            +
                # @param reference [Symbol, String] the key of the reference
         | 
| 394 409 | 
             
                def retime_by_framerate_plus_reference(have, want, reference)
         | 
| 395 410 | 
             
                  ratio = want.fps.to_f / have.fps.to_f
         | 
| 396 411 | 
             
                  have.references[reference][:timecode] *= ratio
         | 
| @@ -435,6 +450,10 @@ module Titlekit | |
| 435 450 | 
             
                  end
         | 
| 436 451 | 
             
                end
         | 
| 437 452 |  | 
| 453 | 
            +
                # Rescales timecodes based on two differing framerates.
         | 
| 454 | 
            +
                #
         | 
| 455 | 
            +
                # @param have [Have] the subtitles we {Have}
         | 
| 456 | 
            +
                # @param want [Want] the subtitles we {Want}
         | 
| 438 457 | 
             
                def retime_by_framerate(have, want)
         | 
| 439 458 | 
             
                  ratio = want.fps.to_f / have.fps.to_f
         | 
| 440 459 | 
             
                  have.subtitles.each do |subtitle|
         | 
    
        data/lib/titlekit/parsers/ass.rb
    CHANGED
    
    | @@ -3,24 +3,28 @@ require 'treetop' | |
| 3 3 | 
             
            module Titlekit
         | 
| 4 4 | 
             
              module ASS
         | 
| 5 5 |  | 
| 6 | 
            +
                # Internal intermediate class used for parsing with treetop
         | 
| 6 7 | 
             
                class Subtitles < Treetop::Runtime::SyntaxNode
         | 
| 7 8 | 
             
                  def build
         | 
| 8 9 | 
             
                    event_section.events.build
         | 
| 9 10 | 
             
                  end
         | 
| 10 11 | 
             
                end
         | 
| 11 12 |  | 
| 13 | 
            +
                # Internal intermediate class used for parsing with treetop
         | 
| 12 14 | 
             
                class ScriptInfo < Treetop::Runtime::SyntaxNode
         | 
| 13 15 | 
             
                  def build
         | 
| 14 16 | 
             
                    # elements.map { |subtitle| subtitle.build }
         | 
| 15 17 | 
             
                  end
         | 
| 16 18 | 
             
                end
         | 
| 17 19 |  | 
| 20 | 
            +
                # Internal intermediate class used for parsing with treetop
         | 
| 18 21 | 
             
                class V4PStyles < Treetop::Runtime::SyntaxNode
         | 
| 19 22 | 
             
                  def build
         | 
| 20 23 | 
             
                    # elements.map { |subtitle| subtitle.build }
         | 
| 21 24 | 
             
                  end
         | 
| 22 25 | 
             
                end
         | 
| 23 26 |  | 
| 27 | 
            +
                # Internal intermediate class used for parsing with treetop
         | 
| 24 28 | 
             
                class Events < Treetop::Runtime::SyntaxNode
         | 
| 25 29 | 
             
                  def build
         | 
| 26 30 | 
             
                    elements.map do |line|
         | 
| @@ -38,9 +42,10 @@ module Titlekit | |
| 38 42 | 
             
                  end
         | 
| 39 43 | 
             
                end
         | 
| 40 44 |  | 
| 41 | 
            -
                # Parses the supplied string and  | 
| 42 | 
            -
                #
         | 
| 45 | 
            +
                # Parses the supplied string and builds the resulting subtitles array.
         | 
| 43 46 | 
             
                #
         | 
| 47 | 
            +
                # @param string [String] proper UTF-8 ASS file content
         | 
| 48 | 
            +
                # @return [Array<Hash>] the imported subtitles
         | 
| 44 49 | 
             
                def self.import(string)
         | 
| 45 50 | 
             
                  Treetop.load(File.join(__dir__, 'ass'))
         | 
| 46 51 | 
             
                  parser = ASSParser.new
         | 
| @@ -119,6 +124,10 @@ module Titlekit | |
| 119 124 | 
             
                  end
         | 
| 120 125 | 
             
                end
         | 
| 121 126 |  | 
| 127 | 
            +
                # Exports the supplied subtitles to ASS format
         | 
| 128 | 
            +
                #
         | 
| 129 | 
            +
                # @param subtitles [Array<Hash>] The subtitle to export
         | 
| 130 | 
            +
                # @return [String] Proper UTF-8 ASS as a string
         | 
| 122 131 | 
             
                def self.export(subtitles)
         | 
| 123 132 | 
             
                  result = ''
         | 
| 124 133 |  | 
| @@ -159,6 +168,10 @@ module Titlekit | |
| 159 168 |  | 
| 160 169 | 
             
                protected
         | 
| 161 170 |  | 
| 171 | 
            +
                # Builds an ASS-formatted timecode from a float representing seconds
         | 
| 172 | 
            +
                #
         | 
| 173 | 
            +
                # @param seconds [Float] an amount of seconds
         | 
| 174 | 
            +
                # @return [String] An ASS-formatted timecode ('h:mm:ss.ms')
         | 
| 162 175 | 
             
                def self.build_timecode(seconds)
         | 
| 163 176 | 
             
                  sprintf("%01d:%02d:%02d.%s",
         | 
| 164 177 | 
             
                          seconds / 3600,
         | 
| @@ -167,6 +180,10 @@ module Titlekit | |
| 167 180 | 
             
                          sprintf("%.2f", seconds)[-2, 3])
         | 
| 168 181 | 
             
                end
         | 
| 169 182 |  | 
| 183 | 
            +
                # Parses an ASS-formatted timecode into a float representing seconds
         | 
| 184 | 
            +
                #
         | 
| 185 | 
            +
                # @param timecode [String] An ASS-formatted timecode ('h:mm:ss.ms')
         | 
| 186 | 
            +
                # @param [Float] an amount of seconds
         | 
| 170 187 | 
             
                def self.parse_timecode(timecode)
         | 
| 171 188 | 
             
                  mres = timecode.match(/(?<h>\d):(?<m>\d{2}):(?<s>\d{2})[:|\.](?<ms>\d+)/)
         | 
| 172 189 | 
             
                  return "#{mres["h"].to_i * 3600 + mres["m"].to_i * 60 + mres["s"].to_i}.#{mres["ms"]}".to_f
         | 
    
        data/lib/titlekit/parsers/srt.rb
    CHANGED
    
    | @@ -3,12 +3,14 @@ require 'treetop' | |
| 3 3 | 
             
            module Titlekit
         | 
| 4 4 | 
             
              module SRT
         | 
| 5 5 |  | 
| 6 | 
            +
                # Internal intermediate class used for parsing with treetop
         | 
| 6 7 | 
             
                class Subtitles < Treetop::Runtime::SyntaxNode
         | 
| 7 8 | 
             
                  def build
         | 
| 8 9 | 
             
                    elements.map { |subtitle| subtitle.build }
         | 
| 9 10 | 
             
                  end
         | 
| 10 11 | 
             
                end
         | 
| 11 12 |  | 
| 13 | 
            +
                # Internal intermediate class used for parsing with treetop
         | 
| 12 14 | 
             
                class Subtitle < Treetop::Runtime::SyntaxNode
         | 
| 13 15 | 
             
                  def build
         | 
| 14 16 | 
             
                    {
         | 
| @@ -20,6 +22,7 @@ module Titlekit | |
| 20 22 | 
             
                  end
         | 
| 21 23 | 
             
                end
         | 
| 22 24 |  | 
| 25 | 
            +
                # Internal intermediate class used for parsing with treetop
         | 
| 23 26 | 
             
                class Timecode < Treetop::Runtime::SyntaxNode
         | 
| 24 27 | 
             
                  def build
         | 
| 25 28 | 
             
                    value = 0
         | 
| @@ -31,9 +34,10 @@ module Titlekit | |
| 31 34 | 
             
                  end
         | 
| 32 35 | 
             
                end
         | 
| 33 36 |  | 
| 34 | 
            -
                # Parses the supplied string and  | 
| 35 | 
            -
                #
         | 
| 37 | 
            +
                # Parses the supplied string and builds the resulting subtitles array.
         | 
| 36 38 | 
             
                #
         | 
| 39 | 
            +
                # @param string [String] proper UTF-8 SRT file content
         | 
| 40 | 
            +
                # @return [Array<Hash>] the imported subtitles
         | 
| 37 41 | 
             
                def self.import(string)
         | 
| 38 42 | 
             
                  Treetop.load(File.join(__dir__, 'srt'))
         | 
| 39 43 | 
             
                  parser = SRTParser.new
         | 
| @@ -104,6 +108,10 @@ module Titlekit | |
| 104 108 | 
             
                  end
         | 
| 105 109 | 
             
                end
         | 
| 106 110 |  | 
| 111 | 
            +
                # Exports the supplied subtitles to SRT format
         | 
| 112 | 
            +
                #
         | 
| 113 | 
            +
                # @param subtitles [Array<Hash>] The subtitle to export
         | 
| 114 | 
            +
                # @return [String] Proper UTF-8 SRT as a string
         | 
| 107 115 | 
             
                def self.export(subtitles)
         | 
| 108 116 | 
             
                  result = ''
         | 
| 109 117 |  | 
| @@ -123,6 +131,10 @@ module Titlekit | |
| 123 131 |  | 
| 124 132 | 
             
                protected
         | 
| 125 133 |  | 
| 134 | 
            +
                # Builds an SRT-formatted timecode from a float representing seconds
         | 
| 135 | 
            +
                #
         | 
| 136 | 
            +
                # @param seconds [Float] an amount of seconds
         | 
| 137 | 
            +
                # @return [String] An SRT-formatted timecode ('hh:mm:ss,ms')
         | 
| 126 138 | 
             
                def self.build_timecode(seconds)
         | 
| 127 139 | 
             
                  sprintf("%02d:%02d:%02d,%s",
         | 
| 128 140 | 
             
                          seconds / 3600,
         | 
| @@ -131,6 +143,10 @@ module Titlekit | |
| 131 143 | 
             
                          sprintf("%.3f", seconds)[-3, 3])
         | 
| 132 144 | 
             
                end
         | 
| 133 145 |  | 
| 146 | 
            +
                # Parses an SRT-formatted timecode into a float representing seconds
         | 
| 147 | 
            +
                #
         | 
| 148 | 
            +
                # @param timecode [String] An SRT-formatted timecode ('hh:mm:ss,ms')
         | 
| 149 | 
            +
                # @param [Float] an amount of seconds
         | 
| 134 150 | 
             
                def self.parse_timecode(timecode)
         | 
| 135 151 | 
             
                  mres = timecode.match(/(?<h>\d+):(?<m>\d+):(?<s>\d+),(?<ms>\d+)/)
         | 
| 136 152 | 
             
                  "#{mres["h"].to_i * 3600 + mres["m"].to_i * 60 + mres["s"].to_i}.#{mres["ms"]}".to_f
         | 
    
        data/lib/titlekit/parsers/ssa.rb
    CHANGED
    
    | @@ -3,24 +3,28 @@ require 'treetop' | |
| 3 3 | 
             
            module Titlekit
         | 
| 4 4 | 
             
              module SSA
         | 
| 5 5 |  | 
| 6 | 
            +
                # Internal intermediate class used for parsing with treetop
         | 
| 6 7 | 
             
                class Subtitles < Treetop::Runtime::SyntaxNode
         | 
| 7 8 | 
             
                  def build
         | 
| 8 9 | 
             
                    event_section.events.build
         | 
| 9 10 | 
             
                  end
         | 
| 10 11 | 
             
                end
         | 
| 11 12 |  | 
| 13 | 
            +
                # Internal intermediate class used for parsing with treetop
         | 
| 12 14 | 
             
                class ScriptInfo < Treetop::Runtime::SyntaxNode
         | 
| 13 15 | 
             
                  def build
         | 
| 14 16 | 
             
                    # elements.map { |subtitle| subtitle.build }
         | 
| 15 17 | 
             
                  end
         | 
| 16 18 | 
             
                end
         | 
| 17 19 |  | 
| 20 | 
            +
                # Internal intermediate class used for parsing with treetop
         | 
| 18 21 | 
             
                class V4PStyles < Treetop::Runtime::SyntaxNode
         | 
| 19 22 | 
             
                  def build
         | 
| 20 23 | 
             
                    # elements.map { |subtitle| subtitle.build }
         | 
| 21 24 | 
             
                  end
         | 
| 22 25 | 
             
                end
         | 
| 23 26 |  | 
| 27 | 
            +
                # Internal intermediate class used for parsing with treetop
         | 
| 24 28 | 
             
                class Events < Treetop::Runtime::SyntaxNode
         | 
| 25 29 | 
             
                  def build
         | 
| 26 30 | 
             
                    elements.map do |line|
         | 
| @@ -38,31 +42,10 @@ module Titlekit | |
| 38 42 | 
             
                  end
         | 
| 39 43 | 
             
                end    
         | 
| 40 44 |  | 
| 41 | 
            -
                #  | 
| 42 | 
            -
                #   def build
         | 
| 43 | 
            -
                #     {
         | 
| 44 | 
            -
                #       id: id.text_value.to_i,
         | 
| 45 | 
            -
                #       start: from.build,
         | 
| 46 | 
            -
                #       end: to.build,
         | 
| 47 | 
            -
                #       lines: lines.text_value.rstrip
         | 
| 48 | 
            -
                #     }
         | 
| 49 | 
            -
                #   end
         | 
| 50 | 
            -
                # end
         | 
| 51 | 
            -
             | 
| 52 | 
            -
                # class Timecode < Treetop::Runtime::SyntaxNode
         | 
| 53 | 
            -
                #   def build
         | 
| 54 | 
            -
                #     value = 0
         | 
| 55 | 
            -
                #     value += hours.text_value.to_i * 3600
         | 
| 56 | 
            -
                #     value += minutes.text_value.to_i * 60
         | 
| 57 | 
            -
                #     value += seconds.text_value.to_i
         | 
| 58 | 
            -
                #     value += "0.#{fractions.text_value}".to_f
         | 
| 59 | 
            -
                #     value
         | 
| 60 | 
            -
                #   end
         | 
| 61 | 
            -
                # end
         | 
| 62 | 
            -
             | 
| 63 | 
            -
                # Parses the supplied string and returns the results.
         | 
| 64 | 
            -
                #
         | 
| 45 | 
            +
                # Parses the supplied string and builds the resulting subtitles array.
         | 
| 65 46 | 
             
                #
         | 
| 47 | 
            +
                # @param string [String] proper UTF-8 SSA file content
         | 
| 48 | 
            +
                # @return [Array<Hash>] the imported subtitles
         | 
| 66 49 | 
             
                def self.import(string)
         | 
| 67 50 | 
             
                  Treetop.load(File.join(__dir__, 'ssa'))
         | 
| 68 51 | 
             
                  parser = SSAParser.new
         | 
| @@ -141,6 +124,10 @@ module Titlekit | |
| 141 124 | 
             
                  end
         | 
| 142 125 | 
             
                end
         | 
| 143 126 |  | 
| 127 | 
            +
                # Exports the supplied subtitles to SSA format
         | 
| 128 | 
            +
                #
         | 
| 129 | 
            +
                # @param subtitles [Array<Hash>] The subtitle to export
         | 
| 130 | 
            +
                # @return [String] Proper UTF-8 SSA as a string
         | 
| 144 131 | 
             
                def self.export(subtitles)
         | 
| 145 132 | 
             
                  result = ''
         | 
| 146 133 |  | 
| @@ -185,6 +172,10 @@ module Titlekit | |
| 185 172 |  | 
| 186 173 | 
             
                protected
         | 
| 187 174 |  | 
| 175 | 
            +
                # Builds an SSA-formatted timecode from a float representing seconds
         | 
| 176 | 
            +
                #
         | 
| 177 | 
            +
                # @param seconds [Float] an amount of seconds
         | 
| 178 | 
            +
                # @return [String] An SSA-formatted timecode ('h:mm:ss.ms')
         | 
| 188 179 | 
             
                def self.build_timecode(seconds)
         | 
| 189 180 | 
             
                  sprintf("%01d:%02d:%02d.%s",
         | 
| 190 181 | 
             
                          seconds / 3600,
         | 
| @@ -193,6 +184,10 @@ module Titlekit | |
| 193 184 | 
             
                          sprintf("%.2f", seconds)[-2, 3])
         | 
| 194 185 | 
             
                end 
         | 
| 195 186 |  | 
| 187 | 
            +
                # Parses an SSA-formatted timecode into a float representing seconds
         | 
| 188 | 
            +
                #
         | 
| 189 | 
            +
                # @param timecode [String] An SSA-formatted timecode ('h:mm:ss.ms')
         | 
| 190 | 
            +
                # @param [Float] an amount of seconds
         | 
| 196 191 | 
             
                def self.parse_timecode(timecode)
         | 
| 197 192 | 
             
                  mres = timecode.match(/(?<h>\d):(?<m>\d{2}):(?<s>\d{2})[:|\.](?<ms>\d+)/)
         | 
| 198 193 | 
             
                  return "#{mres["h"].to_i * 3600 + mres["m"].to_i * 60 + mres["s"].to_i}.#{mres["ms"]}".to_f
         | 
| @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            module Titlekit
         | 
| 2 2 | 
             
              class Specification
         | 
| 3 3 |  | 
| 4 | 
            -
                # Only for internal usage by the job | 
| 4 | 
            +
                # Only for internal usage by the job
         | 
| 5 5 | 
             
                attr_accessor :subtitles
         | 
| 6 6 |  | 
| 7 7 | 
             
                def initialize
         | 
| @@ -15,6 +15,8 @@ module Titlekit | |
| 15 15 | 
             
                  return self
         | 
| 16 16 | 
             
                end
         | 
| 17 17 |  | 
| 18 | 
            +
                # Specifies the encoding you have or want.
         | 
| 19 | 
            +
                #
         | 
| 18 20 | 
             
                # @param [String] A string specifying the encoding, e.g. 'utf-8' or 'ISO-8859-1'
         | 
| 19 21 | 
             
                # @return If you omit the argument, it returns the already specified encoding
         | 
| 20 22 | 
             
                def encoding(*args)
         | 
| @@ -26,6 +28,8 @@ module Titlekit | |
| 26 28 | 
             
                  end
         | 
| 27 29 | 
             
                end
         | 
| 28 30 |  | 
| 31 | 
            +
                # Specifies the file (path) you have or want.
         | 
| 32 | 
            +
                #
         | 
| 29 33 | 
             
                # @param [String] A string specifying the path to the file
         | 
| 30 34 | 
             
                # @return If you omit the argument, it returns the already specified path 
         | 
| 31 35 | 
             
                def file(*args)
         | 
| @@ -37,6 +41,8 @@ module Titlekit | |
| 37 41 | 
             
                  end
         | 
| 38 42 | 
             
                end
         | 
| 39 43 |  | 
| 44 | 
            +
                # Specifies the track the subtitles should be assigned to.
         | 
| 45 | 
            +
                #
         | 
| 40 46 | 
             
                # @param [String] A string specifying the track identifier
         | 
| 41 47 | 
             
                # @return If you omit the argument, it returns the already specified track 
         | 
| 42 48 | 
             
                def track(*args)
         | 
| @@ -48,6 +54,8 @@ module Titlekit | |
| 48 54 | 
             
                  end
         | 
| 49 55 | 
             
                end      
         | 
| 50 56 |  | 
| 57 | 
            +
                # Specifies the framerate you have or want.
         | 
| 58 | 
            +
                #
         | 
| 51 59 | 
             
                # @param [Float] A float specifying the frames per second, e.g. 23.976
         | 
| 52 60 | 
             
                # @return If you omit the argument, it returns the already specified fps
         | 
| 53 61 | 
             
                def fps(*args)
         | 
    
        data/lib/titlekit/utilities.rb
    CHANGED
    
    | @@ -1,3 +1,6 @@ | |
| 1 1 | 
             
            module Titlekit
         | 
| 2 | 
            +
              # The default palette is used to distinguish simultaneous subtitles
         | 
| 3 | 
            +
              # by their color (if distinguishing them by different position is either
         | 
| 4 | 
            +
              # not possible due to the format or not sensible in the specific case)
         | 
| 2 5 | 
             
              DEFAULT_PALETTE = %w{EDF393 F5E665 FFC472 FFA891 89BABE}
         | 
| 3 6 | 
             
            end
         | 
    
        data/lib/titlekit/version.rb
    CHANGED
    
    
    
        data/lib/titlekit/want.rb
    CHANGED
    
    | @@ -3,12 +3,12 @@ module Titlekit | |
| 3 3 |  | 
| 4 4 | 
             
                def initialize
         | 
| 5 5 | 
             
                  super
         | 
| 6 | 
            -
                  @glue_treshold = 0. | 
| 6 | 
            +
                  @glue_treshold = 0.3
         | 
| 7 7 | 
             
                end
         | 
| 8 8 |  | 
| 9 | 
            -
                # For dual subtitles the starts and ends of simultaneously occuring
         | 
| 9 | 
            +
                # For dual+ subtitles the starts and ends of simultaneously occuring
         | 
| 10 10 | 
             
                # subtitles can be micro-adjusted together if their distance is smaller
         | 
| 11 | 
            -
                # than the glue_treshold. Normally defaults to 0. | 
| 11 | 
            +
                # than the glue_treshold. Normally defaults to 0.3
         | 
| 12 12 | 
             
                #
         | 
| 13 13 | 
             
                # @param [Float] Specifies the new glue_treshold
         | 
| 14 14 | 
             
                # @return If you omit the argument, it returns the set glue_treshold
         |