Skip to content
This repository was archived by the owner on Jun 26, 2018. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion Gemfile
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
source "http://rubygems.org"

gem "plist", "3.1.0"
gem "tvdb_party", "0.6.0"
gem "tvdb_party", "0.7.0"
gem "itunes"
gem "rash"
gem "trollop"

group :development do
gem "pry"
gem "rspec"
gem "bundler"
gem "jeweler"
Expand Down
30 changes: 25 additions & 5 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,15 @@ GEM
specs:
addressable (2.3.5)
builder (3.2.2)
coderay (1.1.0)
crack (0.4.2)
safe_yaml (~> 1.0.0)
descendants_tracker (0.0.3)
diff-lcs (1.2.5)
faraday (0.9.0)
multipart-post (>= 1.2, < 3)
faraday (0.8.9)
multipart-post (~> 1.2.0)
faraday_middleware (0.9.0)
faraday (>= 0.7.4, < 0.9)
git (1.2.6)
github_api (0.11.3)
addressable (~> 2.3)
Expand All @@ -23,6 +26,10 @@ GEM
httparty (0.13.0)
json (~> 1.8)
multi_xml (>= 0.5.2)
itunes (0.6.0)
faraday_middleware (~> 0.7)
multi_json (~> 1.0)
rash (~> 0.3)
jeweler (2.0.1)
builder
bundler (>= 1.0)
Expand All @@ -35,10 +42,11 @@ GEM
json (1.8.1)
jwt (0.1.11)
multi_json (>= 1.5)
method_source (0.8.2)
mini_portile (0.5.2)
multi_json (1.9.0)
multi_xml (0.5.5)
multipart-post (2.0.0)
multipart-post (1.2.0)
nokogiri (1.6.1)
mini_portile (~> 0.5.0)
oauth2 (0.9.3)
Expand All @@ -48,8 +56,14 @@ GEM
multi_xml (~> 0.5)
rack (~> 1.2)
plist (3.1.0)
pry (0.9.12.6)
coderay (~> 1.0)
method_source (~> 0.8)
slop (~> 3.4)
rack (1.5.2)
rake (10.1.1)
rash (0.4.0)
hashie (~> 2.0.0)
rdoc (4.1.1)
json (~> 1.4)
rspec (2.14.1)
Expand All @@ -61,7 +75,9 @@ GEM
diff-lcs (>= 1.1.3, < 2.0)
rspec-mocks (2.14.6)
safe_yaml (1.0.1)
tvdb_party (0.6.0)
slop (3.5.0)
trollop (2.0)
tvdb_party (0.7.0)
httparty (>= 0.6.1)
webmock (1.17.4)
addressable (>= 2.2.7)
Expand All @@ -72,8 +88,12 @@ PLATFORMS

DEPENDENCIES
bundler
itunes
jeweler
plist (= 3.1.0)
pry
rash
rspec
tvdb_party (= 0.6.0)
trollop
tvdb_party (= 0.7.0)
webmock
44 changes: 41 additions & 3 deletions bin/AtomicTV
Original file line number Diff line number Diff line change
@@ -1,19 +1,57 @@
#!/usr/bin/env ruby -rubygems

require File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib', 'AtomicTV'))
require 'trollop'
require 'readline'

include AtomicTV

def display_error(error)
$stderr.puts "! ERROR: #{error.human_message}"
end

opts = Trollop.options do
banner("Usage: AtomicTV [options]")
opt :dry_run, "Only output basic episode information for debug", type: :flag
opt :use_itunes, "Use the itunes store api instead of tvdb", type: :flag
opt :try_gsub, "Use gsub to try a filname mutation", type: :string
opt :interactive, "If we can't find a match ask for human edit", type: :flag
end

ARGV.each do |path|
begin
file_path = Pathname.new(path)
metadata = TVDBEpisode.metadata_for_filename(file_path.basename)
tagger = AtomicParsleyTagger.new(file_path, metadata)
tagger.run
series, episode = begin
TVDBEpisode.series_and_episode_for(file_path.basename)
rescue
if opts[:interactive]
Readline.pre_input_hook = -> do
Readline.insert_text file_path.basename.to_s
Readline.redisplay

# Remove the hook right away.
Readline.pre_input_hook = nil
end

filename = Readline.readline("Couldn't find the series/episode try something different?> ", false)
TVDBEpisode.series_and_episode_for(filename)
elsif opts[:try_gsub]
filename = file_path.basename.to_s.gsub(*opts[:try_gsub].split('|'))
TVDBEpisode.series_and_episode_for(filename)
else
raise
end
end
itunes_episode = ItunesEpisode.episode_for(file_path.basename) if opts[:use_itunes]
metadata = EpisodeMetadata.new(series, episode, itunes_episode)

if opts[:dry_run]
require 'pp'
pp metadata
else
tagger = AtomicParsleyTagger.new(file_path, metadata)
tagger.run
end
puts "* Tagged: #{file_path.basename}"
rescue AtomicParsleyTagger::AtomicParsleyUnavailable => error
display_error(error)
Expand Down
4 changes: 3 additions & 1 deletion lib/AtomicTV.rb
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
require 'fileutils'
require 'hashie'
require 'open-uri'
require 'pathname'
require 'tmpdir'

require 'plist'
require 'tvdb_party'
require 'itunes'

module AtomicTV
class AtomicTVError < StandardError; end
end

['atomic_parsley_tagger', 'episode_metadata', 'filename_parser', 'tvdb_episode'].each do |file|
['atomic_parsley_tagger', 'episode_metadata', 'filename_parser', 'tvdb_episode', 'itunes_episode'].each do |file|
require File.expand_path(File.join(File.dirname(__FILE__), 'AtomicTV', file))
end
44 changes: 24 additions & 20 deletions lib/AtomicTV/atomic_parsley_tagger.rb
Original file line number Diff line number Diff line change
@@ -1,50 +1,50 @@
module AtomicTV
class AtomicParsleyTagger

class AtomicParsleyUnavailable < ::AtomicTV::AtomicTVError
def human_message
'AtomicParsley is not installed or could not be found. Try checking your PATH.'
end
end

class FileNotFound < ::AtomicTV::AtomicTVError
def initialize(file_path)
@file_path = file_path
end

attr_reader :file_path

def human_message
"File not found: #{file_path}"
end
end

class TaggingError < ::AtomicTV::AtomicTVError
def initialize(command)
@command = command
end

attr_reader :command

def human_message
"A tagging error occured: #{command}."
end

end

def self.executable
path = Pathname.new(`which AtomicParsley`.chomp)
raise AtomicParsleyUnavailable unless path.executable?
path
end

def initialize(file_path, metadata)
@file_path = file_path
raise FileNotFound.new(file_path) unless file_path.exist?

@metadata = metadata
end

def cast_metadata
format_names = lambda {|name| {'name' => name}}
{
Expand All @@ -53,7 +53,7 @@ def cast_metadata
'screenwriters' => metadata.writers.map(&format_names)
}.to_plist
end

def run
options = {
'stik' => metadata.media_type,
Expand All @@ -69,31 +69,35 @@ def run
'TVSeasonNum' => metadata.tv_season_number,
'TVEpisodeNum' => metadata.tv_episode_number,
'tracknum' => metadata.track_number,
'year' => metadata.air_date
'year' => metadata.air_date,
'contentRating' => metadata.content_advisory_rating,
'advisory' => metadata.track_is_clean ? 'clean' : 'explicit',
'cnID' => metadata.track_id,
}

metadata.with_loaded_posters do
command = %Q{#{self.class.executable} }
command << %Q{"#{file_path}" }
command << %Q{--overWrite }
command << %Q{--rDNSatom "#{escape_double_quotes(cast_metadata)}" name=iTunMOVI domain=com.apple.iTunes }
command << %Q{--artwork REMOVE_ALL }
metadata.posters.each do |poster|
command << %Q{--artwork #{poster.path} }
end
command << options.map {|option, value| %Q{--#{option} "#{escape_double_quotes(value)}"}}.join(' ')

`#{command}`
raise TaggingError.new(command) unless $?.success?
end
end

private

attr_reader :file_path, :metadata

def escape_double_quotes(str)
str.to_s.gsub('"', '\"')
end

end
end
Loading