Skip to content

Commit

Permalink
Complete commandline utility with start and config options
Browse files Browse the repository at this point in the history
Adds a progress bar over HandBrakeCLI output. Improvements
to the tagging process. and allow user to specify the title
of the movie prior to lookup. Adding Thor for CLI
functionality. Adding the ability to store configuration in
the user's home directory.
Matthew Nichols authored and mattnichols committed Nov 7, 2015

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
1 parent aa44372 commit 70db01f
Showing 31 changed files with 652 additions and 300 deletions.
17 changes: 16 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,20 @@
.DS_Store
.ruby-gemset
.ruby-version
/.bundle/
/.yardoc
/Gemfile.lock
/_yardoc/
/coverage/
/doc/
/pkg/
/spec/reports/
/tmp/
Gemfile.lock
posters
posters
test.rb
encode.log
temp/
log/


2 changes: 2 additions & 0 deletions .rspec
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
--format documentation
--color
4 changes: 4 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
language: ruby
rvm:
- 2.2.0
before_install: gem install bundler -v 1.10.6
13 changes: 13 additions & 0 deletions CODE_OF_CONDUCT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Contributor Code of Conduct

As contributors and maintainers of this project, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities.

We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, or religion.

Examples of unacceptable behavior by participants include the use of sexual language or imagery, derogatory comments or personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct.

Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. Project maintainers who do not follow the Code of Conduct may be removed from the project team.

Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers.

This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.0.0, available at [http://contributor-covenant.org/version/1/0/0/](http://contributor-covenant.org/version/1/0/0/)
16 changes: 1 addition & 15 deletions Gemfile
Original file line number Diff line number Diff line change
@@ -1,17 +1,3 @@
source 'https://rubygems.org'

# Movie DBs
gem 'themoviedb'
gem 'imdb'

# mp4 Meta Data Writing
gem 'atomic-parsley-ruby'

# Help with searches
gem 'levenshtein'

# Watch for a new DVD insertion
gem 'rb-fsevent'

# Console IO
gem 'highline'
gemspec
21 changes: 21 additions & 0 deletions LICENSE.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
The MIT License (MIT)

Copyright (c) 2015 matthew-nichols

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
19 changes: 0 additions & 19 deletions README.markdown

This file was deleted.

60 changes: 60 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# dvd_ripper

A command line tool that will make it easy to rip and tag your dvd collection. It ties together many great tools to get the job done. -- HandBrake, AtomicParsley, exiftool, imdb and tmdb.

It takes a bit on configuration, but once it is setup, ripping your DVD collection will be a breeze.

Enjoy!

## Installation

Install Handbrake: [downloads](https://handbrake.fr/downloads.php)
Install HandBrakeCLI: [downloads](https://handbrake.fr/downloads2.php)

$ brew install AtomicParsley

$ brew install exiftool

$ brew install tag

$ brew install libdvdcss

$ gem install dvd_ripper

## Usage

$ dvd_ripper

## Troubleshooting

### nokogiri fails to install
$ xcode-select --install

$ gem install nokogiri -- --use-system-libraries

$ bundle config build.nokogiri --use-system-libraries

### HandBrake Errors

* Make sure that you have the same version of HandBrake and HandBrakeCLI
* Make sure that you have installed libdvdcss


## Notes

http://manpages.ubuntu.com/manpages/hardy/man1/AtomicParsley.1.html
https://github.com/cparratto/atomic-parsley-ruby

http://www.sno.phy.queensu.ca/~phil/exiftool/
http://miniexiftool.rubyforge.org

https://github.com/jdberry/tag

https://github.com/ahmetabdi/themoviedb
https://github.com/ariejan/imdb


## To Do

* Add ability to set HandBrake encoding options
* Add better support for TV show ripping
6 changes: 6 additions & 0 deletions Rakefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
require "bundler/gem_tasks"
require "rspec/core/rake_task"

RSpec::Core::RakeTask.new(:spec)

task :default => :spec
14 changes: 14 additions & 0 deletions bin/console
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#!/usr/bin/env ruby

require "bundler/setup"
require "dvd_ripper"

# You can add fixtures and/or initialization code here to make experimenting
# with your gem easier. You can also use a different console, if you like.

# (If you use this, don't forget to add pry to your Gemfile!)
# require "pry"
# Pry.start

require "irb"
IRB.start
7 changes: 7 additions & 0 deletions bin/setup
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#!/bin/bash
set -euo pipefail
IFS=$'\n\t'

bundle install

# Do any other automated setup that you need to do here
18 changes: 0 additions & 18 deletions config.rb

This file was deleted.

45 changes: 0 additions & 45 deletions dvd.rb

This file was deleted.

33 changes: 33 additions & 0 deletions dvd_ripper.gemspec
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# coding: utf-8
lib = File.expand_path('../lib', __FILE__)
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
require 'dvd_ripper/version'

Gem::Specification.new do |spec|
spec.name = "dvd_ripper"
spec.version = DvdRipper::VERSION
spec.authors = ["matthew-nichols"]
spec.email = ["[email protected]"]

spec.summary = %q{Quickly rip and tag DVDs}
spec.description = %q{A command-line utility that makes it easy to rip and tag DVDs. Just install and run the utility. Then insert a DVD and follow prompts. Repeat.}
spec.homepage = "TODO: Put your gem's website or public repo URL here."
spec.license = "MIT"

spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
spec.bindir = "exe"
spec.executables = ["dvd_ripper"]
spec.require_paths = ["lib"]

spec.add_runtime_dependency 'thor'
spec.add_runtime_dependency 'nokogiri', '~> 1.6.0'
spec.add_runtime_dependency 'themoviedb', '~> 0.0.20'
spec.add_runtime_dependency 'imdb', '~> 0.8.1'
spec.add_runtime_dependency 'rb-fsevent', '~> 0.9.4'
spec.add_runtime_dependency 'levenshtein', '~> 0.2.2'
spec.add_runtime_dependency 'atomic-parsley-ruby' #, :git => 'https://github.com/cparratto/atomic-parsley-ruby.git'

spec.add_development_dependency "bundler", "~> 1.10"
spec.add_development_dependency "rake", "~> 10.0"
spec.add_development_dependency "rspec", '~> 3.2'
end
54 changes: 54 additions & 0 deletions exe/dvd_ripper
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
#!/usr/bin/env ruby

require 'dvd_ripper'
require "thor"

module DvdRipper
class Cli < ::Thor
desc "start", "start tool"
def start
check_config!
dvd_ripper = ::DvdRipper::Client.new
dvd_ripper.start
end
map %w[--version -v] => :__print_version

desc "--version, -v", "print the version"
def __print_version
puts "DvdRipper v#{::DvdRipper::VERSION}"
end

desc "config", "configure dvd_ripper"
def config
Config.instance.prompt!
end

desc "help", "display this help"
def help_banner
puts <<-BANNER
Dvd Ripper
This commandline utility cleanly and simply captures your dvd contents and
tags the movies.
Movie information is pulled from www.imdb.com and www.themoviedb.org
Dvd content captured using Handbrake (https://handbrake.fr/)
BANNER
help
end

no_commands do
def check_config!
unless Config.instance.exists?
config
end
end
end

# "www.themoviedb.org"

end
end

::DvdRipper::Cli.start
21 changes: 21 additions & 0 deletions lib/dvd_ripper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
require "dvd_ripper/version"

require 'thread'
require 'rb-fsevent'
require 'atomic-parsley-ruby'
require 'fileutils'
require 'io/console'
require 'imdb'
require 'themoviedb'
require 'levenshtein'

require_relative 'dvd_ripper/movie_stub.rb'
require_relative 'dvd_ripper/movie_extensions.rb'
require_relative 'dvd_ripper/search_factory.rb'
require_relative 'dvd_ripper/search_imdb.rb'
require_relative 'dvd_ripper/search_tmdb.rb'
require_relative 'dvd_ripper/search.rb'
require_relative 'dvd_ripper/dvd.rb'
require_relative 'dvd_ripper/movie.rb'
require_relative 'dvd_ripper/config.rb'
require_relative 'dvd_ripper/client.rb'
129 changes: 129 additions & 0 deletions lib/dvd_ripper/client.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
module DvdRipper
class Client
def initialize
@command = nil
@title = nil
@last_volume = ""
@dvd = Dvd.new
end

def process_dvd
puts
puts "--------------------------------------------------------------"
puts "-- Volume: #{@dvd.volume}"
puts "-- Title: #{@dvd.title}"
puts "--------------------------------------------------------------"
puts

searcher = Search.new
movie = searcher.closest(@title || @dvd.title)
if movie.nil?
puts "- Provide details for movie -"
puts "Enter Movie Title:"
movie = ::Movie.new
movie.title = $stdin.gets
puts "Enter Movie Year:"
movie.release_date = "#{$stdin.gets.chomp}-01-01"
end
title = "#{movie.title} (#{movie.year})"
output = File.join(::DvdRipper::Config.instance.working_dir, "#{title.gsub(": ", " - ").gsub(":", " - ")}.m4v")
puts
puts "--------------------------------------------------------------"
puts "-- Title: #{movie.title}"
puts "-- Year: #{movie.year}"
puts "--------------------------------------------------------------"
puts
puts "Continue? (y/n) |y|"
continue = $stdin.gets.strip
continue = 'y' if continue.blank?
if continue != 'y'
return
end

@dvd.rip(output)

movie.tag(output) unless movie.nil?

puts "\"#{output}\" complete"
@dvd.eject
FileUtils.mv(output, ::DvdRipper::Config.instance.dest_dir)
end

def force_user_input(input)
@command = input
@user_command.raise("wakeup")
end

def start
Tmdb::Api.key(::DvdRipper::Config.instance.tmdb_api_key)

@user_command = Thread.new do
while true
begin
if @command.nil?
puts "Choose command [(r)ip, (s)pecify title, (q)uit, (e)ject] or insert a DVD"
@command = $stdin.gets.chomp
end
sleep 1
rescue Exception => e
puts e.message
end
end
end

fsevent = FSEvent.new
fsevent.watch %W(/Volumes) do |directories|
if @command.nil? and @dvd.present? and (@last_volume != @dvd.volume)
force_user_input("r")
@last_volume = @dvd.volume
end
end

Signal.trap("INT") do
fsevent.stop
Kernel.exit(0)
end

message_thread = Thread.new do
while true
begin
while @command.nil?
sleep 1
end
if @command == "r"
process_dvd
end
if @command == "s"
puts "Enter title:"
@title = $stdin.gets
process_dvd
end
if @command == "q"
puts "Quitting..."
fsevent.stop
break
end
if @command == "e"
@dvd.eject
end
rescue Exception => e
puts e.message
puts e.class
puts e.backtrace
ensure
@command = nil
@title = nil
end
end
end

fsevent.run

message_thread.kill
message_thread.join

@user_command.kill
@user_command.join
end
end
end
84 changes: 84 additions & 0 deletions lib/dvd_ripper/config.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
require 'singleton'
require 'yaml'

module DvdRipper
class Config
include Singleton

attr_accessor :config

DEFAULTS = {
:working_dir => "~/tmp/movies",
:dest_dir => "~/movies",
:poster_dir => "~/tmp/movies/posters",
:distance_threshold => 0.2,
:tmdb_api_key => nil
}.freeze

def load
self.config = DEFAULTS.merge(read_config)
end

def read_config
yml = ""
yml = File.read(config_path) if exists?

return YAML.load(yml) unless yml.blank?

{}
end

def exists?
File.exist?(config_path)
end

def working_dir
config[:working_dir]
end

def dest_dir
config[:dest_dir]
end

def tmdb_api_key
config[:tmdb_api_key]
end

def poster_dir
config[:poster_dir]
end

def distance_threshold
config[:distance_threshold]
end

def config_path
File.expand_path("~/.dvd_ripper")
end

def save!
File.open(config_path, "w+") do |config_file|
config_file.write(config.to_yaml)
end
end

def prompt!
config.each do |k, v|
puts "#{k} (ENTER: #{v}):"
new_value = $stdin.gets
config[k] = new_value.strip unless (new_value.strip.blank?)
end

save!
end
end
end

::DvdRipper::Config.instance.load

# WORKING_DIR = "/Users/mnichols/Movies/Ripping"
# DEST_DIR = "/Users/mnichols/Movies/Ripped"
# POSTER_PATH = "./Posters"
# DISTANCE_THRESHOLD = 0.2

# @api_key = "867c178725a7e646a0f108ee78781a49"
119 changes: 119 additions & 0 deletions lib/dvd_ripper/dvd.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
class Dvd
attr_accessor :volumes

def initialize
@volumes = "/Volumes"
end

def volume
vol = nil
Dir.entries(@volumes).each do |video_dir|
if not [".", ".."].member?(video_dir)
full_path = File.join(@volumes, video_dir)
if Dir.exists?(File.join(full_path, "VIDEO_TS"))
vol = full_path
break
end
end
end
vol
end

def title
raise "Invalid DVD Root or DVD not mounted at #{@volumes}" if not present?
File.basename(volume).gsub("_", " ").capitalize
end

def present?
!volume.nil?
end

def rip(output)
File.delete(output) if File.exists?(output)

state = :scanning
percent = "0.0"
eta = "unknown"
dc = 0
spinner = ["-", "\\", "|", "/"]

encoding_reg = /Encoding: task \d+ of \d+, (?<percent>\d+\.\d+) %.*ETA (?<eta>\d{2}h\d{2}m\d{2}s)/i
status_update = Thread.new do
while true do
sleep(1)
dc = dc + 1

if state == :encoding
print "\r#{spinner[dc%4]} Encoding #{percent} % (time left #{eta})"
end

if state == :scanning
print("\r" + (" " * 50)) if ((dc % 20) == 0)
print "\r#{spinner[dc%4]} Scanning Titles.#{"." * (dc % 20)}"
end
end
end

command_output = []
last_line = nil
File.open("./encode.log", "w+") do |log|
IO.popen("HandBrakeCLI -Z \"AppleTV 3\" --main-feature -i \"#{volume}\" -o \"#{output}\" 2>&1", "w+") do |f|
begin
while buf = f.read(255)
lines = buf.split(/\r|\n/)
lines.compact!

if (lines.size > 1) and (not last_line.nil?)
command_output << last_line + lines.shift
end

if buf[-1] == "\r" or buf[-1] == "\n"
last_line = nil
else
last_line = lines.pop
end

command_output << lines
command_output.flatten!

while ln = command_output.shift
ln = ln.strip unless ln.nil?

# Change to encoding as soon as a matching line is found
if encoding_reg =~ ln
state = :encoding
end

if state == :encoding
if m = encoding_reg.match(ln)
percent = m[:percent]
eta = m[:eta]
end
end

log.write "#{state}:#{percent}:#{eta} - #{ln}\n"
end
command_output = []
end
rescue Exception => e
puts e.message
puts e.class
puts e.backtrace
end
end
end
exit_code = $?

if exit_code.exitstatus != 0
`killall HandBrakeCLI`
puts "Encoding Failed. See encode.log"
end
ensure
status_update.kill
status_update.join
end

def eject
system("drutil tray eject")
end
end
51 changes: 27 additions & 24 deletions movie.rb → lib/dvd_ripper/movie.rb
Original file line number Diff line number Diff line change
@@ -1,55 +1,58 @@
class Movie
extend Forwardable
def initialize(tmdb_info, imdb_info)
@tmdb_info = tmdb_info
@imdb_info = imdb_info

def initialize(tmdb_info=nil, imdb_info=nil)
@tmdb_info = tmdb_info.nil? ? ::MovieStub.new : tmdb_info
@imdb_info = imdb_info.nil? ? ::MovieStub.new : imdb_info
end

def_delegators :@tmdb_info, :title, :year, :poster_path
def_delegators :@imdb_info, :plot, :genres, :plot_summary

require 'open-uri'

def tag(output)
Dir.mkdir(POSTER_PATH) if not Dir.exists?(POSTER_PATH)
poster_file_path = File.expand_path(File.join(POSTER_PATH, poster_path))
poster = File.open(poster_file_path, "wb")
begin
open("http://image.tmdb.org/t/p/w500#{poster_path}", "rb") do |download|
poster.write(download.read)
end
ensure
poster.close()
poster_file_path = nil
unless poster_path.nil?
Dir.mkdir(::DvdRipper::Config.instance.poster_dir) if not Dir.exists?(::DvdRipper::Config.instance.poster_dir)
poster_file_path = File.expand_path(File.join(::DvdRipper::Config.instance.poster_dir, poster_path))
poster = File.open(poster_file_path, "wb")
begin
open("http://image.tmdb.org/t/p/w500#{poster_path}", "rb") do |download|
poster.write(download.read)
end
ensure
poster.close()
end
end

# Remove stik and other artwork, just in case
v = AtomicParsleyRuby::Media.new(output)
v.artwork "REMOVE_ALL"
v.stik "remove"
v.overwrite true
v.process

v = AtomicParsleyRuby::Media.new(output)
v.overwrite true
v.title title
v.comment plot unless plot.nil?
v.description plot unless plot.nil?
v.year year.to_s
v.year year.to_s
v.stik "0"
v.genre genres[0]
v.longdesc plot_summary unless plot_summary.nil?
v.artwork poster_file_path
v.artwork poster_file_path unless poster_file_path.nil?
v.process

# m = MiniExiftool.new output
# m["director"] = info.director

# Need to use mp4v2 lib extensions to write this stuff
# m["directors//name"] = "Bob"
# m["producers//name"] = "George"
# m["screenwriters//name"] = "Writers"
# m["studio//name"] = "Studio C"
# m["studio//name"] = "Studio C"
# m.save
end
end
end
File renamed without changes.
3 changes: 3 additions & 0 deletions lib/dvd_ripper/movie_stub.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
class MovieStub
attr_accessor :title, :year, :poster_path, :plot, :genres, :plot_summary
end
38 changes: 19 additions & 19 deletions search.rb → lib/dvd_ripper/search.rb
Original file line number Diff line number Diff line change
@@ -1,55 +1,55 @@
require './search_factory'
require 'levenshtein'

class Search
def closest(title)
searcher = SearchFactory.get("tmdb")

movies = leven_sort(title, searcher.search(title))
while movies.empty?
puts "Unable to locate title"
puts "Enter movie title:"
title = gets.chomp
puts " - Title Not Found - "
puts "Enter movie title (or enter to skip search):"
title = $stdin.gets.chomp
return nil if title.empty?
movies = leven_sort(title, searcher.search(title))
end

movie = auto_select(movies)
if movie.nil? or ambiguous?(movies)
puts "Please choose:"
movies.each_with_index do |movie, i|
puts "#{i}. #{movie.title} (#{movie.release_date}) (#{movie.title_distance.round(3)})"
end
title_sel = gets
puts "s. Skip"
title_sel = $stdin.gets.chomp
return nil if title_sel == 's'
movie = movies[title_sel.to_i]
end
info = SearchFactory.get("imdb").search(title)[0]

movie = Movie.new(movie, info)
movie
end

def leven_sort(search_title, movies)
movies.each do |movie|
distance = Levenshtein.normalized_distance(search_title, movie.title)
movie.title_distance = distance
end
movies.reverse.sort_by { |m| m.title_distance }
end

def auto_select(movies)
return movies[0] if (not movies.empty?) and (movies[0].title_distance < DISTANCE_THRESHOLD)
return movies[0] if (movies.size == 1) or ((not movies.empty?) and (movies[0].title_distance < ::DvdRipper::Config.instance.distance_threshold))
nil
end

def ambiguous?(movies)
return true if movies.empty?
return false if movies.size == 1

lowest_distance = movies[0].title_distance
return true if lowest_distance > DISTANCE_THRESHOLD

return true if lowest_distance > ::DvdRipper::Config.instance.distance_threshold
return true if movies.find_all { |m| m.title_distance == lowest_distance }.size > 1

false
end
end
end
5 changes: 1 addition & 4 deletions search_factory.rb → lib/dvd_ripper/search_factory.rb
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
require './search_imdb'
require './search_tmdb'

class SearchFactory
def self.get(name)
return SearchImdb.new if name == 'imdb'
return SearchTmdb.new if name == 'tmdb'
raise "Invalid Search Engine Name"
end
end
end
4 changes: 1 addition & 3 deletions search_imdb.rb → lib/dvd_ripper/search_imdb.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
require 'imdb'

class SearchImdb
def search(title)
Imdb::Search.new(title).movies
@@ -8,4 +6,4 @@ def search(title)

class Imdb::Movie
include MovieExtensions
end
end
4 changes: 1 addition & 3 deletions search_tmdb.rb → lib/dvd_ripper/search_tmdb.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
require 'themoviedb'

class SearchTmdb
def search(title)
Tmdb::Movie.find(title)
@@ -8,4 +6,4 @@ def search(title)

class Tmdb::Movie
include MovieExtensions
end
end
3 changes: 3 additions & 0 deletions lib/dvd_ripper/version.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module DvdRipper
VERSION = "0.1.0"
end
109 changes: 0 additions & 109 deletions run.rb

This file was deleted.

11 changes: 11 additions & 0 deletions spec/dvd_ripper_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
require 'spec_helper'

describe DvdRipper do
it 'has a version number' do
expect(DvdRipper::VERSION).not_to be nil
end

it 'does something useful' do
expect(false).to eq(true)
end
end
2 changes: 2 additions & 0 deletions spec/spec_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
$LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
require 'dvd_ripper'
40 changes: 0 additions & 40 deletions test.rb

This file was deleted.

0 comments on commit 70db01f

Please sign in to comment.