rakemkv 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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: cd54a538d15fb78a5905d935a82afd6015cb9c5d
4
+ data.tar.gz: dae6fb5b06d867b7174c9f5d8783cbad34d3f37d
5
+ SHA512:
6
+ metadata.gz: 9af5fa59cabaa281f2f7a8fdbd26f2468896333f9209b037156a01e1037e6fce90a7dceb5791112ca3d02a6a1adcad6f731f62bdbdbc5ef165d350416453a56d
7
+ data.tar.gz: f4295cb3583406b97e197c99e8efe29d3e245dbdc509b6de6537a1413102b54828c338b946288dbee3bf23b732df146be85d8ba9668083fd2b01be9f4606423a
data/.gitignore ADDED
@@ -0,0 +1,20 @@
1
+ *.gem
2
+ *.orig
3
+ *.rbc
4
+ .#*
5
+ .bundle
6
+ .config
7
+ .rspec
8
+ .yardoc
9
+ Gemfile.lock
10
+ InstalledFiles
11
+ _yardoc
12
+ coverage
13
+ doc/
14
+ lib/bundler/man
15
+ pkg
16
+ rdoc
17
+ spec/reports
18
+ test/tmp
19
+ test/version_tmp
20
+ tmp
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.0.0
4
+ - 1.9.3
5
+ - 1.9.2
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
data/Guardfile ADDED
@@ -0,0 +1,8 @@
1
+ # A sample Guardfile
2
+ # More info at https://github.com/guard/guard#readme
3
+
4
+ guard :rspec do
5
+ watch(%r{^spec/.+_spec\.rb$})
6
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
7
+ watch('spec/spec_helper.rb') { "spec" }
8
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013-2015 Eric Collins
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,51 @@
1
+ [![Build Status](https://travis-ci.org/tabfugnic/rakemkv.png)](https://travis-ci.org/tabfugnic/rakemkv)
2
+
3
+ # Rakemkv
4
+
5
+ A fully object oriented wrapper around MakeMKV to help facilitate more
6
+ programmable backups.
7
+
8
+ ## Requirements
9
+
10
+ - MakeMKV
11
+
12
+ ## Installation
13
+
14
+ Add this line to your application's Gemfile:
15
+
16
+ gem 'rakemkv'
17
+
18
+ And then execute:
19
+
20
+ $ bundle
21
+
22
+ Or install it yourself as:
23
+
24
+ $ gem install rakemkv
25
+
26
+ ## Usage
27
+
28
+ ```
29
+ disc = RakeMKV::Disc.new('location/to/disc')
30
+ disc.transcode!
31
+ ```
32
+
33
+ ## Configuration
34
+
35
+ You can configure RakeMKV by doing the following:
36
+
37
+ ```ruby
38
+ RakeMKV.configure do |config|
39
+ config.binary = 'new_makemkv_binary'
40
+ config.destination = 'new/destination/path'
41
+ config.minimum_title_length = 120 # Number in seconds
42
+ end
43
+ ```
44
+
45
+ ## Contributing
46
+
47
+ 1. Fork it
48
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
49
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
50
+ 4. Push to the branch (`git push origin my-new-feature`)
51
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,5 @@
1
+ require "bundler/gem_tasks"
2
+ require 'rspec/core/rake_task'
3
+
4
+ task default: :spec
5
+ RSpec::Core::RakeTask.new
@@ -0,0 +1,62 @@
1
+ # Code
2
+ class RakeMKV::Code
3
+ CODES = [
4
+ :unknown,
5
+ :type,
6
+ :name,
7
+ :language_code,
8
+ :language_name,
9
+ :codec_id,
10
+ :codec_short,
11
+ :codec_long,
12
+ :chapter_count,
13
+ :duration,
14
+ :disk_size,
15
+ :disk_size_bytes,
16
+ :stream_type_extension,
17
+ :bitrate,
18
+ :audio_channels_count,
19
+ :angle_info,
20
+ :source_file_name,
21
+ :audio_sample_rate,
22
+ :audio_sample_size,
23
+ :video_size,
24
+ :video_aspect_ratio,
25
+ :video_frame_rate,
26
+ :stream_flags,
27
+ :date_time,
28
+ :original_title_id,
29
+ :segments_count,
30
+ :segments_map,
31
+ :output_file_name,
32
+ :metadata_language_code,
33
+ :metadata_language_name,
34
+ :tree_info,
35
+ :panel_title,
36
+ :volume_name,
37
+ :order_weight,
38
+ :output_format,
39
+ :output_format_description,
40
+ :seamless_info,
41
+ :panel_text,
42
+ :mkv_flags,
43
+ :mkv_flags_text
44
+ ]
45
+
46
+ attr_reader :index
47
+
48
+ # Initialize code
49
+ def initialize(index)
50
+ @index = index.to_i
51
+ end
52
+
53
+ # Take code and convert it to the proper symbol
54
+ def to_sym
55
+ CODES[index]
56
+ end
57
+
58
+ # Short hand to initialize code and convert it to symbol
59
+ def self.[](index)
60
+ new(index).to_sym
61
+ end
62
+ end
@@ -0,0 +1,35 @@
1
+ # Command Object
2
+ class RakeMKV::Command
3
+ # Initialize with path
4
+ def initialize(path)
5
+ @path = path
6
+ end
7
+
8
+ # Check if mkv is installed
9
+ def self.installed?
10
+ output = Cocaine::CommandLine.new('which', RakeMKV.config.binary).run
11
+ !output.empty?
12
+ end
13
+
14
+ # Call info command on disc
15
+ def info
16
+ @info ||= execute("info #{@path}")
17
+ end
18
+
19
+ # Call mkv command on disc
20
+ def mkv(title_id, destination)
21
+ @mkv ||= execute("mkv #{@path} #{title_id} #{destination}")
22
+ end
23
+
24
+ private
25
+
26
+ def execute(command)
27
+ Cocaine::CommandLine.new(
28
+ "#{RakeMKV.config.binary} -r", full_command(command)
29
+ ).run
30
+ end
31
+
32
+ def full_command(command)
33
+ RakeMKV::CommandBuilder.new(command).build
34
+ end
35
+ end
@@ -0,0 +1,19 @@
1
+ class RakeMKV::CommandBuilder
2
+ def initialize(command)
3
+ @command = command
4
+ end
5
+
6
+ def build
7
+ [command, minimum_length].join(' ').strip
8
+ end
9
+
10
+ private
11
+
12
+ attr_reader :command
13
+
14
+ def minimum_length
15
+ if RakeMKV.config.minimum_title_length
16
+ "--minlength=#{RakeMKV.config.minimum_title_length}"
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,20 @@
1
+ class RakeMKV::Configuration
2
+ include Singleton
3
+
4
+ attr_accessor :minimum_title_length
5
+ attr_writer :binary, :destination
6
+
7
+ def binary
8
+ @binary || 'makemkvcon'
9
+ end
10
+
11
+ def destination
12
+ @destination || Dir.pwd
13
+ end
14
+
15
+ def reset!
16
+ self.binary = nil
17
+ self.destination = nil
18
+ self.minimum_title_length = nil
19
+ end
20
+ end
@@ -0,0 +1,64 @@
1
+ # Disc object
2
+ class RakeMKV::Disc
3
+ attr_reader :location
4
+
5
+ # Initialize disc
6
+ def initialize(location)
7
+ @location = location
8
+ end
9
+
10
+ # Get path from location
11
+ def path
12
+ if location =~ /^\/dev/
13
+ "dev:#{location}"
14
+ elsif location =~ /iso$/
15
+ "iso:#{location}"
16
+ elsif location.is_a?(Integer)
17
+ "disc:#{location}"
18
+ elsif location =~ /^disc/
19
+ location
20
+ else
21
+ raise RuntimeError
22
+ end
23
+ end
24
+
25
+ # parse file info from command
26
+ def info
27
+ @info ||= RakeMKV::Parser.new(command.info)
28
+ end
29
+
30
+ # Transcode information on disc
31
+ def transcode!(options = {})
32
+ destination = options[:destination] || RakeMKV.config.destination
33
+ title_id = options[:title_id] || titles.longest.id
34
+ command.mkv(title_id, destination)
35
+ end
36
+
37
+ # Get titles for disc
38
+ def titles
39
+ RakeMKV::Titles.new(build_titles)
40
+ end
41
+
42
+ # Meta disc information
43
+ def method_missing(method, *args)
44
+ info.cinfo[method.to_sym] || super
45
+ end
46
+
47
+ private
48
+
49
+ def command
50
+ RakeMKV::Command.new(path)
51
+ end
52
+
53
+ def build_titles
54
+ info.tinfo.each_with_index.map do |title, title_id|
55
+ RakeMKV::Title.new(title_id, title)
56
+ end
57
+ end
58
+
59
+ def check_directory!(destination)
60
+ unless File.directory? destination
61
+ raise StandardError
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,85 @@
1
+ # Parser
2
+ class RakeMKV::Parser
3
+ CINFO_REGEX = /CINFO:(\d+),\d+,"(.+)"/
4
+ DRIVES_REGEX = /DRV:\d+,\d+,\d+,(\d+),"(.*)","(.*)","(.*)"/
5
+ MSG_REGEX = /MSG:[^"]*"([^"]*)"/
6
+ SINFO_REGEX = /SINFO:(\d+),(\d+),(\d+),\d+,"(.*)"/
7
+ TINFO_REGEX = /TINFO:(\d+),(\d+),\d+,"(.*)"/
8
+
9
+ attr_reader :raw
10
+
11
+ # Initialize using info received from disc
12
+ def initialize(raw_info)
13
+ @raw = raw_info
14
+ end
15
+
16
+ # Grab information from cinfo
17
+ def cinfo
18
+ cinfo = {}
19
+ parse(CINFO_REGEX) do |code, info|
20
+ code = RakeMKV::Code[code]
21
+ cinfo[code] = info
22
+ end
23
+ cinfo
24
+ end
25
+
26
+ # Grab information from tinfo
27
+ def tinfo
28
+ tinfo = []
29
+ parse(TINFO_REGEX) do |title_id, code, info|
30
+ code = RakeMKV::Code[code]
31
+ tinfo[title_id.to_i] ||= Hash.new
32
+ tinfo[title_id.to_i][code] = info
33
+ end
34
+ tinfo
35
+ end
36
+
37
+ # Grab information from sinfo
38
+ def sinfo
39
+ sinfo = []
40
+ parse(SINFO_REGEX) do |title_id, section_id, code, info|
41
+ code = RakeMKV::Code[code]
42
+ title = title_id.to_i
43
+ section = section_id.to_i
44
+ sinfo[title] ||= Array.new
45
+ sinfo[title][section] ||= Hash.new
46
+ sinfo[title][section][code] = info
47
+ end
48
+ sinfo
49
+ end
50
+
51
+ # Grab information from messages
52
+ def messages
53
+ messages = []
54
+ parse(MSG_REGEX) do |info|
55
+ messages << info.first
56
+ end
57
+ messages
58
+ end
59
+
60
+ # Grab information from discs
61
+ def drives
62
+ drives = []
63
+ parse(DRIVES_REGEX) do |accessible, drive_name, disc_name, location|
64
+ drives << {
65
+ accessible: accessible(accessible),
66
+ drive_name: drive_name,
67
+ disc_name: disc_name,
68
+ location: location
69
+ }
70
+ end
71
+ drives
72
+ end
73
+
74
+ private
75
+
76
+ def accessible(accessible)
77
+ accessible != '0'
78
+ end
79
+
80
+ def parse(regex, &block)
81
+ raw.split('\n').each do |line|
82
+ line.scan(regex, &block)
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,40 @@
1
+ # Title
2
+ class RakeMKV::Title
3
+ attr_reader :id, :code, :chapter_count, :size
4
+
5
+ MINUTE = 60
6
+ HOUR = 3600
7
+
8
+ # Initialize with a required id
9
+ def initialize(id, options = {})
10
+ # These claim to start at 1, but the CLI treats them as starting from 0
11
+ @id = id
12
+ @duration = options[:duration]
13
+ @chapter_count = options[:chapter_count].to_i
14
+ @size = options[:disk_size_bytes].to_i
15
+ end
16
+
17
+ # Find short lengthed title
18
+ def short_length?
19
+ time > 900 && time < 2100
20
+ end
21
+
22
+ def time
23
+ time_from_integer || time_from_string
24
+ end
25
+
26
+ private
27
+
28
+ attr_reader :duration
29
+
30
+ def time_from_integer
31
+ if duration.is_a? Integer
32
+ duration
33
+ end
34
+ end
35
+
36
+ def time_from_string
37
+ times = duration.split(':')
38
+ (times[0].to_i * HOUR) + (times[1].to_i * MINUTE) + (times[2].to_i)
39
+ end
40
+ end
@@ -0,0 +1,22 @@
1
+ # Titles
2
+ class RakeMKV::Titles
3
+ include Enumerable
4
+
5
+ def initialize(titles)
6
+ @titles = titles
7
+ end
8
+
9
+ def each(&block)
10
+ @titles.each(&block)
11
+ end
12
+
13
+ # Find title by id
14
+ def at_id(id)
15
+ detect { |title| title.id == id }
16
+ end
17
+
18
+ # Get longest title
19
+ def longest
20
+ max { |a, b| a.time <=> b.time }
21
+ end
22
+ end
@@ -0,0 +1,3 @@
1
+ module RakeMKV
2
+ VERSION = '0.2.0'
3
+ end
data/lib/rakemkv.rb ADDED
@@ -0,0 +1,20 @@
1
+ module RakeMKV
2
+ def self.config
3
+ Configuration.instance
4
+ end
5
+
6
+ def self.configure
7
+ yield config
8
+ end
9
+ end
10
+
11
+ require "cocaine"
12
+ require "singleton"
13
+ require "rakemkv/code"
14
+ require "rakemkv/command"
15
+ require "rakemkv/command_builder"
16
+ require "rakemkv/configuration"
17
+ require "rakemkv/disc"
18
+ require "rakemkv/parser"
19
+ require "rakemkv/title"
20
+ require "rakemkv/titles"
data/rakemkv.gemspec ADDED
@@ -0,0 +1,25 @@
1
+ lib = File.expand_path('../lib', __FILE__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+ require 'rakemkv/version'
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "rakemkv"
7
+ spec.version = RakeMKV::VERSION
8
+ spec.authors = ["Eric Collins"]
9
+ spec.email = ["eric@tabfugni.cc"]
10
+ spec.description = %q{A fully object oriented wrapper around MakeMKV to help facilitate more programmable backups.}
11
+ spec.summary = %q{Object oriented wrapper around MakeMKV}
12
+ spec.homepage = "https://github.com/tabfugnic/rakemkv"
13
+ spec.license = "MIT"
14
+
15
+ spec.files = `git ls-files`.split($/)
16
+ spec.test_files = spec.files.grep(%r{spec/})
17
+ spec.require_paths = ["lib"]
18
+
19
+ spec.add_dependency "json", "~> 1.7"
20
+ spec.add_dependency "cocaine", "~> 0.5"
21
+
22
+ spec.add_development_dependency "bundler"
23
+ spec.add_development_dependency "rake"
24
+ spec.add_development_dependency "rspec", "~> 3.2"
25
+ end
Binary file
@@ -0,0 +1,17 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'transcoding disc' do
4
+ it 'copies disc to destination' do
5
+ movie = File.new('./spec/fixtures/movie.iso')
6
+ movie_path = File.expand_path(movie.path)
7
+
8
+ Dir.mktmpdir do |directory|
9
+ RakeMKV.config.minimum_title_length = 2
10
+ RakeMKV.config.destination = directory
11
+
12
+ RakeMKV::Disc.new(movie_path).transcode!
13
+
14
+ expect(Dir.entries(directory)).to include('title00.mkv')
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,21 @@
1
+ require 'spec_helper'
2
+
3
+ describe RakeMKV::Code do
4
+ describe '#new' do
5
+ it 'takes the index' do
6
+ expect(RakeMKV::Code.new(5)).to be_a RakeMKV::Code
7
+ expect(RakeMKV::Code.new(5).index).to eq 5
8
+ end
9
+ end
10
+ describe '#to_sym' do
11
+ it 'returns the code' do
12
+ expect(RakeMKV::Code.new(5).to_sym).to eq :codec_id
13
+ end
14
+ end
15
+
16
+ describe '.[]' do
17
+ it 'gets the code' do
18
+ expect(RakeMKV::Code[5]).to eq :codec_id
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,15 @@
1
+ require 'spec_helper'
2
+
3
+ describe RakeMKV::CommandBuilder do
4
+ describe '#build' do
5
+ it 'adds minimum length from configuration' do
6
+ RakeMKV.configure do |config|
7
+ config.minimum_title_length = 5
8
+ end
9
+
10
+ full_command = RakeMKV::CommandBuilder.new("command").build
11
+
12
+ expect(full_command).to eq "command --minlength=5"
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,33 @@
1
+ require 'spec_helper'
2
+
3
+ describe RakeMKV::Command do
4
+ describe '.installed?' do
5
+
6
+ it 'verifies makemkv is installed' do
7
+ allow(Cocaine::CommandLine).to receive(:new)
8
+ .with('which', 'makemkvcon')
9
+ .and_return(double('command', run: '/something/great'))
10
+ expect(RakeMKV::Command).to be_installed
11
+ end
12
+ end
13
+
14
+ describe '#info' do
15
+ it 'gets the info for the object' do
16
+ command = RakeMKV::Command.new('disc:0')
17
+ allow(Cocaine::CommandLine).to receive(:new)
18
+ .with('makemkvcon -r', 'info disc:0')
19
+ .and_return(double('cocaine', run: 'info'))
20
+ expect(command.info).to eq 'info'
21
+ end
22
+ end
23
+
24
+ describe '#mkv' do
25
+ it 'takes title and destination' do
26
+ command = RakeMKV::Command.new('disc:0')
27
+ allow(Cocaine::CommandLine).to receive(:new)
28
+ .with('makemkvcon -r', 'mkv disc:0 5 /path/to/heart')
29
+ .and_return(double('cocaine', run: 'mkv'))
30
+ expect(command.mkv(5,'/path/to/heart')).to eq 'mkv'
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,47 @@
1
+ require 'spec_helper'
2
+
3
+ describe RakeMKV::Configuration do
4
+ before do
5
+ config.reset!
6
+ end
7
+
8
+ describe '#binary' do
9
+ it 'returns default makemkvcon' do
10
+ expect(config.binary).to eq 'makemkvcon'
11
+ end
12
+
13
+ it 'set a new binary' do
14
+ config.binary = 'new_binary'
15
+ expect(config.binary).to eq 'new_binary'
16
+ end
17
+ end
18
+
19
+ describe '#destination' do
20
+ it 'defaults the to current directory' do
21
+ expect(config.destination).to eq Dir.pwd
22
+ end
23
+
24
+ it 'sets a new destination' do
25
+ config.binary = 'new_destination'
26
+ expect(config.binary).to eq 'new_destination'
27
+ end
28
+ end
29
+
30
+ describe '#reset!' do
31
+ it 'resets all the things' do
32
+ config.minimum_title_length = 3
33
+ config.binary = 'stuff'
34
+ config.destination = '/path/somewhere'
35
+
36
+ config.reset!
37
+
38
+ expect(config.minimum_title_length).to be_nil
39
+ expect(config.binary).to eq 'makemkvcon'
40
+ expect(config.destination).to eq Dir.pwd
41
+ end
42
+ end
43
+
44
+ def config
45
+ RakeMKV::Configuration.instance
46
+ end
47
+ end