thuss-shift_subtitle 0.2.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.
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
data/.gitignore ADDED
@@ -0,0 +1,5 @@
1
+ *.sw?
2
+ .DS_Store
3
+ coverage
4
+ rdoc
5
+ pkg
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Todd Huss
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.rdoc ADDED
@@ -0,0 +1,37 @@
1
+ = shift_subtitle
2
+
3
+ My submission for Ruby Challenge #1: Shift Subtitle
4
+
5
+ http://rubylearning.com/blog/2009/09/24/rpcfn-shift-subtitle-1
6
+
7
+ == Features
8
+ * 100% RSpec[http://rspec.info/] test coverage of both lib/* and bin/*
9
+ * Bundled as a github gem (thanks to Jeweler[http://github.com/technicalpickles/jeweler])
10
+ * No external gem dependencies to use the gem
11
+ * Command line related code in shift_subtitle_cli.rb and SubRib/SRT processing code in shift_subtitle.rb
12
+ * shift_subtitle.rb uses IO streams (such as File and StringIO) to support processing large files
13
+ * Time shifting handles boundary cases
14
+ * Lower boundary shifting 00:00:00,001 down by a second shifts to 00:00:00,000
15
+ * Shifting above the 24 hour boundary works fine (25, 26, 27 hours) and doesn't rollover back to 00 hours
16
+
17
+ == Requirements
18
+
19
+ You must have Github in your gem sources
20
+
21
+ gem sources -a http://gems.github.com
22
+
23
+ == Install
24
+
25
+ sudo gem install thuss-shift_subtitle
26
+
27
+ == Usage
28
+ shift_subtitle --operation add --time 2,500 input output
29
+
30
+ == Todo
31
+
32
+ * Add a --version flag
33
+ * Perhaps throw a warning if a subtraction shift results in the floor of 00:00:00,000
34
+
35
+ == Copyright
36
+
37
+ Copyright (c) 2009 Todd Huss. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,49 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "thuss-shift_subtitle"
8
+ gem.summary = %Q{Ruby Challenge #1: Shift Subtitle}
9
+ gem.description = %Q{Submission for the Ruby Challenge to create a command line tool to shift SubRib formatted movie subtitles}
10
+ gem.email = "thuss@gabrito.com"
11
+ gem.homepage = "http://github.com/thuss/shift_subtitle"
12
+ gem.authors = ["Todd Huss"]
13
+ gem.add_development_dependency "rspec"
14
+ end
15
+ Jeweler::GemcutterTasks.new
16
+ rescue LoadError
17
+ puts "Jeweler is not available. Install it with: sudo gem install jeweler"
18
+ end
19
+
20
+ require 'spec/rake/spectask'
21
+ Spec::Rake::SpecTask.new(:spec) do |spec|
22
+ spec.libs << 'lib' << 'spec'
23
+ spec.spec_files = FileList['spec/**/*_spec.rb']
24
+ end
25
+
26
+ Spec::Rake::SpecTask.new(:rcov) do |spec|
27
+ spec.libs << 'lib' << 'spec'
28
+ spec.pattern = 'spec/**/*_spec.rb'
29
+ spec.rcov = true
30
+ spec.rcov_opts = ['--exclude', 'lib/spec,bin/spec,spec/*,rcov*']
31
+ end
32
+
33
+ task :spec => :check_dependencies
34
+
35
+ task :default => :spec
36
+
37
+ require 'rake/rdoctask'
38
+ Rake::RDocTask.new do |rdoc|
39
+ if File.exist?('VERSION')
40
+ version = File.read('VERSION')
41
+ else
42
+ version = ""
43
+ end
44
+
45
+ rdoc.rdoc_dir = 'rdoc'
46
+ rdoc.title = "shift_subtitle #{version}"
47
+ rdoc.rdoc_files.include('README*')
48
+ rdoc.rdoc_files.include('lib/**/*.rb')
49
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.2.0
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # Created on 2009-9-26.
4
+ # Copyright (c) 2009. All rights reserved.
5
+
6
+ $LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__) + "/../lib"))
7
+ require "shift_subtitle_cli"
8
+
9
+ ShiftSubtitleCli.new.execute(ARGV)
@@ -0,0 +1,33 @@
1
+ require 'time'
2
+
3
+ class ShiftSubtitle
4
+
5
+ # Takes an SRT IO stream (such as File) and shifts it by shift_seconds (e.g. -2.5)
6
+ def shift_srt(input_srt, output_srt, shift_seconds)
7
+ input_srt.each_line do | line |
8
+ srt_time_regex = /^(\d\d:\d\d:\d\d,\d\d\d)( --> )(\d\d:\d\d:\d\d,\d\d\d)/
9
+ if (line =~ srt_time_regex)
10
+ start_time = shift_timestamp($1, shift_seconds)
11
+ end_time = shift_timestamp($3, shift_seconds)
12
+ line.gsub!(srt_time_regex, start_time + $2 + end_time)
13
+ end
14
+ output_srt.write line
15
+ end
16
+ end
17
+
18
+ # Takes an SRT timestamp ('01:01:23,500') and shifts it by shift seconds (-2.5)
19
+ def shift_timestamp(srt_time_string, shift_seconds)
20
+ if (srt_time_string =~ /(\d\d):(\d\d):(\d\d),(\d\d\d)/)
21
+ time = Time.parse('2000-01-01 ' + srt_time_string + 'UTC') + shift_seconds
22
+ hours = time.hour
23
+ case
24
+ when time.day == 31 then hours = 0; time = Time.at(0).utc # Never go below 00:00:00,000
25
+ when time.day > 1 then hours += (time.day - 1) * 24 # Support times > 23 hours
26
+ end
27
+ "#{'%02d'%hours}:#{'%02d'%time.min}:#{'%02d'%time.sec},#{'%03d'%(time.usec/1000)}"
28
+ else
29
+ raise ArgumentError, "unexpected SRT timestamp format " + srt_time_string
30
+ end
31
+ end
32
+
33
+ end
@@ -0,0 +1,59 @@
1
+ require 'optparse'
2
+ require 'shift_subtitle'
3
+
4
+ class ShiftSubtitleCli < ShiftSubtitle
5
+ def execute(arguments)
6
+ begin
7
+ options = parse_options arguments
8
+ input_file = File.new options[:input_file], 'r'
9
+ output_file = File.new options[:output_file], 'w'
10
+ shift_srt input_file, output_file, time_to_shift(options)
11
+ ensure
12
+ input_file.close unless input_file.nil?
13
+ output_file.close unless output_file.nil?
14
+ end
15
+ end
16
+
17
+ def parse_options(arguments)
18
+ options = {}
19
+ mandatory_options = [ :operation, :seconds, :milliseconds, :input_file, :output_file ]
20
+ parser = OptionParser.new do |opts|
21
+ opts.banner = <<-BANNER.gsub(/^ /,'')
22
+ Shift Subtitle Ruby Challenge
23
+
24
+ Usage: #{File.basename($0)} --operation [add|sub] --time [seconds,milliseconds] input_file output_file
25
+
26
+ Options are:
27
+ BANNER
28
+ opts.separator ""
29
+
30
+ opts.on("-o", "--operation add|sub", [:add, :sub], "Add or Subtract time") do |operation|
31
+ options[:operation] = operation
32
+ end
33
+
34
+ opts.on("-t", "--time seconds,milliseconds", "Seconds AND milliseconds to add or subtract") do |time|
35
+ if (time =~ /\d+,\d+/)
36
+ options[:seconds], options[:milliseconds] = time.split(/,/).map!{ |t| t.to_i }
37
+ else
38
+ raise OptionParser::InvalidArgument, "should be seconds,milliseconds"
39
+ end
40
+ end
41
+
42
+ opts.on("-h", "--help", "Show this help message.") { puts opts; exit 0 }
43
+
44
+ opts.parse!(arguments)
45
+ options[:input_file], options[:output_file] = arguments.pop(2)
46
+
47
+ if mandatory_options.find { |option| options[option].nil? }
48
+ $stderr.puts opts; exit 1
49
+ end
50
+ end
51
+ options
52
+ end
53
+
54
+ # Converts the time and operation into a float (:sub 2,500 returns -2.5)
55
+ def time_to_shift(options)
56
+ shift_time = options[:seconds].to_i + options[:milliseconds].to_f/1000
57
+ shift_time *= (options[:operation] == :sub)?-1:1
58
+ end
59
+ end
@@ -0,0 +1,59 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run `rake gemspec`
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{shift_subtitle}
8
+ s.version = "0.2.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Todd Huss"]
12
+ s.date = %q{2009-10-03}
13
+ s.default_executable = %q{shift_subtitle}
14
+ s.description = %q{Submission for the Ruby Challenge to create a command line tool to shift SubRib formatted movie subtitles}
15
+ s.email = %q{thuss@gabrito.com}
16
+ s.executables = ["shift_subtitle"]
17
+ s.extra_rdoc_files = [
18
+ "LICENSE",
19
+ "README.rdoc"
20
+ ]
21
+ s.files = [
22
+ ".document",
23
+ ".gitignore",
24
+ "LICENSE",
25
+ "README.rdoc",
26
+ "Rakefile",
27
+ "VERSION",
28
+ "bin/shift_subtitle",
29
+ "lib/shift_subtitle.rb",
30
+ "lib/shift_subtitle_cli.rb",
31
+ "shift_subtitle.gemspec",
32
+ "spec/shift_subtitle_cli_spec.rb",
33
+ "spec/shift_subtitle_spec.rb",
34
+ "spec/spec_helper.rb"
35
+ ]
36
+ s.homepage = %q{http://github.com/thuss/shift_subtitle}
37
+ s.rdoc_options = ["--charset=UTF-8"]
38
+ s.require_paths = ["lib"]
39
+ s.rubygems_version = %q{1.3.5}
40
+ s.summary = %q{Ruby Challenge #1: Shift Subtitle}
41
+ s.test_files = [
42
+ "spec/shift_subtitle_cli_spec.rb",
43
+ "spec/shift_subtitle_spec.rb",
44
+ "spec/spec_helper.rb"
45
+ ]
46
+
47
+ if s.respond_to? :specification_version then
48
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
49
+ s.specification_version = 3
50
+
51
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
52
+ s.add_development_dependency(%q<rspec>, [">= 0"])
53
+ else
54
+ s.add_dependency(%q<rspec>, [">= 0"])
55
+ end
56
+ else
57
+ s.add_dependency(%q<rspec>, [">= 0"])
58
+ end
59
+ end
@@ -0,0 +1,89 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+ require 'shift_subtitle_cli'
3
+
4
+ describe ShiftSubtitleCli do
5
+
6
+ before(:each) do
7
+ @cli = ShiftSubtitleCli.new
8
+ end
9
+
10
+ describe "running bin/shift_subtitle" do
11
+ before :each do
12
+ Object.send(:remove_const, :ARGV)
13
+ input = StringIO.new("1\n00:00:24,600 --> 00:00:27,800\nthis is a test...")
14
+ @output = StringIO.new
15
+ File.stub!(:new).and_return(input, @output)
16
+ end
17
+
18
+ it "should shift the time when an SRT file is provided" do
19
+ ARGV = ['--operation', 'sub', '--time', '2,500', 'infile', 'outfile']
20
+ eval File.read(File.join(File.dirname(__FILE__), '..', 'bin', 'shift_subtitle'))
21
+ @output.string.should eql("1\n00:00:22,100 --> 00:00:25,300\nthis is a test...")
22
+ end
23
+ end
24
+
25
+ it "should print help to stderr when no options are provided" do
26
+ output = capture_stderr do
27
+ lambda { @cli.parse_options([]) }.should raise_error(SystemExit)
28
+ end
29
+ output.should match(/Usage:/)
30
+ end
31
+
32
+ it "should set the input_file and output_file in the options hash" do
33
+ options = @cli.parse_options(['--operation', 'add', '--time', '2,500', 'infile', 'outfile'])
34
+ options[:input_file].should eql('infile')
35
+ options[:output_file].should eql('outfile')
36
+ end
37
+
38
+ it "should not allow a missing argument" do
39
+ args = ['--operation', 'add', '--time', '2,500', 'infile']
40
+ output = capture_stderr do
41
+ lambda { @cli.parse_options(args) }.should raise_error(SystemExit)
42
+ end
43
+ end
44
+
45
+ it "should convert the operation, seconds, and milliseconds into a float of seconds to shift" do
46
+ options = @cli.parse_options(['--operation', 'sub', '--time', '2,500', 'infile', 'outfile'])
47
+ @cli.time_to_shift(options).should eql(-2.5)
48
+ end
49
+
50
+ it "should convert unusually large millisecond values correctly" do
51
+ options = @cli.parse_options(['--operation', 'add', '--time', '2,5000', 'infile', 'outfile'])
52
+ @cli.time_to_shift(options).should eql(7.0)
53
+ end
54
+
55
+ describe "when the --operation argument is specified" do
56
+ it "should not allow an invalid operation" do
57
+ args = ['--operation', 'foo', '--time', '2,500', 'infile', 'outfile']
58
+ lambda { @cli.parse_options(args) }.should raise_error(OptionParser::InvalidArgument)
59
+ end
60
+
61
+ it "should allow the add operation and set the options hash" do
62
+ options = @cli.parse_options(['--operation', 'add', '--time', '2,500', 'infile', 'outfile'])
63
+ options[:operation].should eql(:add)
64
+ end
65
+ end
66
+
67
+ describe "when the --time argument is provided" do
68
+ it "should not allow an invalid time" do
69
+ args = ['--operation', 'add', '--time', 'XYZ', 'infile', 'outfile']
70
+ output = capture_stderr do
71
+ lambda { @cli.parse_options(args) }.should raise_error(OptionParser::InvalidArgument)
72
+ end
73
+ end
74
+
75
+ it "should parse a valid time and set the options hash" do
76
+ options = @cli.parse_options(['--operation', 'add', '--time', '2,500', 'infile', 'outfile'])
77
+ options[:seconds].should eql(2)
78
+ options[:milliseconds].should eql(500)
79
+ end
80
+ end
81
+
82
+ def capture_stderr
83
+ $stderr = StringIO.new
84
+ yield
85
+ $stderr.string
86
+ ensure
87
+ $stderr = STDERR
88
+ end
89
+ end
@@ -0,0 +1,66 @@
1
+ require File.dirname(__FILE__) + '/spec_helper.rb'
2
+
3
+ describe ShiftSubtitle do
4
+ before(:each) do
5
+ @shift_subtitle = ShiftSubtitle.new
6
+ end
7
+
8
+ describe "when shifting time" do
9
+ it "should raise an exception on invalid input" do
10
+ lambda { @shift_subtitle.shift_timestamp('X1:31:51,210', 0) }.should raise_error(ArgumentError)
11
+ end
12
+
13
+ it "should leave time unchanged when shifting by zero" do
14
+ @shift_subtitle.shift_timestamp('01:31:51,210', 0).should eql('01:31:51,210')
15
+ end
16
+
17
+ it "should add time" do
18
+ @shift_subtitle.shift_timestamp('01:31:51,210', 1.5).should eql('01:31:52,710')
19
+ end
20
+
21
+ it "should add time beyond the 24 hour boundary" do
22
+ @shift_subtitle.shift_timestamp('23:59:59,500', 1.5).should eql('24:00:01,000')
23
+ end
24
+
25
+ it "should subtract time" do
26
+ @shift_subtitle.shift_timestamp('01:31:51,210', -1.5).should eql('01:31:49,710')
27
+ end
28
+
29
+ it "should not subtract below zero" do
30
+ @shift_subtitle.shift_timestamp('00:00:01,000', -1.5).should eql('00:00:00,000')
31
+ end
32
+ end
33
+
34
+ describe "when processing srt input" do
35
+ before(:each) do
36
+ @input_srt = StringIO.new(<<-SRT.gsub(/^ /,'')
37
+ 1
38
+ 00:00:20,000 --> 00:00:24,400
39
+ In connection with a dramatic increase
40
+ in crime in certain neighbourhoods,
41
+
42
+ 2
43
+ 00:00:24,600 --> 00:00:27,800
44
+ the government is implementing a new policy...
45
+ SRT
46
+ )
47
+ @output_srt = StringIO.new
48
+ end
49
+
50
+ it "should output the shifted srt" do
51
+ @shift_subtitle.shift_srt(@input_srt, @output_srt, 1.5)
52
+ @output_srt.string.should eql(<<-SRTOUT.gsub(/^ /,'')
53
+ 1
54
+ 00:00:21,500 --> 00:00:25,900
55
+ In connection with a dramatic increase
56
+ in crime in certain neighbourhoods,
57
+
58
+ 2
59
+ 00:00:26,100 --> 00:00:29,300
60
+ the government is implementing a new policy...
61
+ SRTOUT
62
+ )
63
+ end
64
+ end
65
+
66
+ end
@@ -0,0 +1,9 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
+ require 'shift_subtitle'
4
+ require 'spec'
5
+ require 'spec/autorun'
6
+
7
+ Spec::Runner.configure do |config|
8
+
9
+ end
metadata ADDED
@@ -0,0 +1,79 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: thuss-shift_subtitle
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.0
5
+ platform: ruby
6
+ authors:
7
+ - Todd Huss
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-10-03 00:00:00 -07:00
13
+ default_executable: shift_subtitle
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: rspec
17
+ type: :development
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "0"
24
+ version:
25
+ description: Submission for the Ruby Challenge to create a command line tool to shift SubRib formatted movie subtitles
26
+ email: thuss@gabrito.com
27
+ executables:
28
+ - shift_subtitle
29
+ extensions: []
30
+
31
+ extra_rdoc_files:
32
+ - LICENSE
33
+ - README.rdoc
34
+ files:
35
+ - .document
36
+ - .gitignore
37
+ - LICENSE
38
+ - README.rdoc
39
+ - Rakefile
40
+ - VERSION
41
+ - bin/shift_subtitle
42
+ - lib/shift_subtitle.rb
43
+ - lib/shift_subtitle_cli.rb
44
+ - shift_subtitle.gemspec
45
+ - spec/shift_subtitle_cli_spec.rb
46
+ - spec/shift_subtitle_spec.rb
47
+ - spec/spec_helper.rb
48
+ has_rdoc: true
49
+ homepage: http://github.com/thuss/shift_subtitle
50
+ licenses: []
51
+
52
+ post_install_message:
53
+ rdoc_options:
54
+ - --charset=UTF-8
55
+ require_paths:
56
+ - lib
57
+ required_ruby_version: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: "0"
62
+ version:
63
+ required_rubygems_version: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: "0"
68
+ version:
69
+ requirements: []
70
+
71
+ rubyforge_project:
72
+ rubygems_version: 1.3.5
73
+ signing_key:
74
+ specification_version: 3
75
+ summary: "Ruby Challenge #1: Shift Subtitle"
76
+ test_files:
77
+ - spec/shift_subtitle_cli_spec.rb
78
+ - spec/shift_subtitle_spec.rb
79
+ - spec/spec_helper.rb