overdrive 0.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.
- data/README.markdown +57 -0
- data/Rakefile +21 -0
- data/VERSION +1 -0
- data/bin/overdrive +34 -0
- data/lib/dsl.rb +87 -0
- data/lib/feed.rb +75 -0
- data/lib/lexicon.rb +111 -0
- data/lib/options.rb +71 -0
- data/lib/torrent.rb +16 -0
- data/test/fixtures/test.rss +200 -0
- data/test/recipe.rb +2 -0
- data/test/test_helper.rb +28 -0
- data/test/unit/dsl.rb +105 -0
- data/test/unit/feed.rb +63 -0
- data/test/unit/lexicon.rb +112 -0
- data/test/unit/torrent.rb +22 -0
- metadata +103 -0
data/README.markdown
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
Overdrive
|
2
|
+
=========
|
3
|
+
|
4
|
+
Overdrive is a RSS frontend for the transmission bit torrent client. It has hooks to make downloading TV series
|
5
|
+
much easier, and allows recipes with callbacks to make filtering show much easier.
|
6
|
+
|
7
|
+
Installation
|
8
|
+
------------
|
9
|
+
|
10
|
+
Overdrive is a ruby gem that uses gemcutter. To install, simply do the following:
|
11
|
+
|
12
|
+
sudo gem install gemcutter
|
13
|
+
sudo gem tumble
|
14
|
+
|
15
|
+
then
|
16
|
+
|
17
|
+
sudo gem install overdrive
|
18
|
+
|
19
|
+
This should install the overdrive binary in your path.
|
20
|
+
|
21
|
+
Usage
|
22
|
+
-----
|
23
|
+
|
24
|
+
To do anything useful, you need to setup a recipe. You can store the recipe (in Linux) at
|
25
|
+
|
26
|
+
/etc/overdrive.rb
|
27
|
+
/var/transmission/config/overdrive.rb
|
28
|
+
$HOME/.overdrive/overdrive.rb
|
29
|
+
|
30
|
+
and you can add paths via the -c argument:
|
31
|
+
|
32
|
+
overdrive -c /path/to/recipe.rb
|
33
|
+
|
34
|
+
A sample recipe might look like this:
|
35
|
+
|
36
|
+
add_feed "http://www.mytorrents.com/torrents.rss"
|
37
|
+
add_feed "http://www.myothertorrents.com/torrents.rss"
|
38
|
+
|
39
|
+
add_title "24"
|
40
|
+
add_title "30 Rock"
|
41
|
+
add_title "Alias"
|
42
|
+
|
43
|
+
filter do |item|
|
44
|
+
parsed = parse_metadata(item)
|
45
|
+
if parsed[:title] && parsed[:series] && parsed[:episode]
|
46
|
+
title = parsed[:title].split(' ').map { |t| t[0..0].upcase + t[1..-1] }.join(' ')
|
47
|
+
|
48
|
+
if titles.include?(title)
|
49
|
+
target = "/videos/#{title}/Season #{parsed[:series].to_i.to_s}"
|
50
|
+
download(item.url, :download_dir => target)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
You can get a full list of command line arguments by running
|
56
|
+
|
57
|
+
overdrive -h
|
data/Rakefile
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
begin
|
2
|
+
require 'jeweler'
|
3
|
+
Jeweler::Tasks.new do |s|
|
4
|
+
s.name = "overdrive"
|
5
|
+
s.executables = "overdrive"
|
6
|
+
s.summary = "An RSS frontend for transmission"
|
7
|
+
s.email = "myles@madpilot.com.au"
|
8
|
+
s.homepage = "http://github.com/madpilot/overdrive"
|
9
|
+
s.description = "An RSS frontend for transmissions. It defines a basic DSL that allows you decide what you do once the files have been downloaded"
|
10
|
+
s.authors = ["Myles Eftos"]
|
11
|
+
s.files = FileList["[A-Z]*", "{bin,generators,lib,test}/**/*", 'lib/jeweler/templates/.gitignore']
|
12
|
+
|
13
|
+
s.add_dependency 'daemons'
|
14
|
+
s.add_dependency 'transmission-client'
|
15
|
+
s.add_dependency 'SyslogLogger'
|
16
|
+
|
17
|
+
Jeweler::GemcutterTasks.new
|
18
|
+
end
|
19
|
+
rescue LoadError
|
20
|
+
puts "Jeweler, or one of its dependencies, is not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
|
21
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.0
|
data/bin/overdrive
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
$:.unshift File.join(File.dirname(File.expand_path(__FILE__)), '..', 'lib')
|
3
|
+
|
4
|
+
require 'rubygems'
|
5
|
+
require 'syslog_logger'
|
6
|
+
require 'daemons'
|
7
|
+
require 'options'
|
8
|
+
require 'feed'
|
9
|
+
require 'torrent'
|
10
|
+
require 'lexicon'
|
11
|
+
require 'dsl'
|
12
|
+
require 'transmission-client'
|
13
|
+
|
14
|
+
options = Options.parse
|
15
|
+
|
16
|
+
if options[:ontop]
|
17
|
+
options[:logger] = Logger.new(STDOUT)
|
18
|
+
else
|
19
|
+
options[:logger] = SyslogLogger.new('overdrive')
|
20
|
+
end
|
21
|
+
|
22
|
+
Daemons.call(options) do
|
23
|
+
@last_run = nil
|
24
|
+
@feed = Feed.new(options)
|
25
|
+
|
26
|
+
options[:logger].info("Running every #{options[:interval].to_s} minute#{options[:interval] == 1 ? "" : "s"}")
|
27
|
+
loop {
|
28
|
+
if @last_run == nil || (@last_run.to_i + options[:interval] * 60) <= Time.now.to_i
|
29
|
+
@feed.check
|
30
|
+
@last_run = Time.now
|
31
|
+
end
|
32
|
+
sleep(1)
|
33
|
+
}
|
34
|
+
end
|
data/lib/dsl.rb
ADDED
@@ -0,0 +1,87 @@
|
|
1
|
+
require 'transmission-client'
|
2
|
+
|
3
|
+
class DSL
|
4
|
+
attr_accessor :titles
|
5
|
+
|
6
|
+
def initialize(options)
|
7
|
+
@options = options
|
8
|
+
@items, @torrents, @feeds, @titles = [], [], [], []
|
9
|
+
|
10
|
+
contents = ''
|
11
|
+
options[:filter_paths].each do |path|
|
12
|
+
begin
|
13
|
+
File.open(path, 'r') do |fh|
|
14
|
+
@options[:logger].info "Adding #{path} to recipe list"
|
15
|
+
contents += fh.read
|
16
|
+
end
|
17
|
+
rescue => e
|
18
|
+
@options[:logger].info "Couldn't add #{path} to recipe list: #{e}"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
eval <<-END
|
23
|
+
def run_dsl(obj = nil, type = nil)
|
24
|
+
@items = []
|
25
|
+
@torrents = []
|
26
|
+
|
27
|
+
case(type)
|
28
|
+
when :filter
|
29
|
+
@items = obj
|
30
|
+
when :torrent
|
31
|
+
@torrents = obj
|
32
|
+
end
|
33
|
+
|
34
|
+
#{contents}
|
35
|
+
end
|
36
|
+
END
|
37
|
+
|
38
|
+
# Prime the DSL
|
39
|
+
@primed = false
|
40
|
+
run_dsl
|
41
|
+
@primed = true
|
42
|
+
end
|
43
|
+
|
44
|
+
def perform_filter(items)
|
45
|
+
run_dsl(items, :filter)
|
46
|
+
end
|
47
|
+
|
48
|
+
def download_complete(torrents)
|
49
|
+
run_dsl(torrents, :torrent)
|
50
|
+
end
|
51
|
+
|
52
|
+
def add_feed(feed)
|
53
|
+
@feeds << feed unless @primed
|
54
|
+
end
|
55
|
+
|
56
|
+
def feeds
|
57
|
+
@feeds
|
58
|
+
end
|
59
|
+
|
60
|
+
def add_title(title)
|
61
|
+
@titles << title unless @primed
|
62
|
+
end
|
63
|
+
|
64
|
+
def parse_metadata(item)
|
65
|
+
Lexicon.parse(item)
|
66
|
+
end
|
67
|
+
|
68
|
+
def log
|
69
|
+
options[:logger]
|
70
|
+
end
|
71
|
+
|
72
|
+
def options
|
73
|
+
@options
|
74
|
+
end
|
75
|
+
|
76
|
+
def download(link, options = {})
|
77
|
+
Torrent.download(link, options, self.options)
|
78
|
+
end
|
79
|
+
|
80
|
+
def filter &block
|
81
|
+
@items.each { |item| yield(item) }
|
82
|
+
end
|
83
|
+
|
84
|
+
def after &block
|
85
|
+
@torrents.each { |torrent| yield(torrent) }
|
86
|
+
end
|
87
|
+
end
|
data/lib/feed.rb
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
require 'feedzirra'
|
2
|
+
require 'yaml'
|
3
|
+
|
4
|
+
class Feed
|
5
|
+
def initialize(options)
|
6
|
+
@options = options
|
7
|
+
@dsl = DSL.new(@options)
|
8
|
+
end
|
9
|
+
|
10
|
+
def check
|
11
|
+
@results ? update_feeds : check_feeds
|
12
|
+
check_downloads
|
13
|
+
end
|
14
|
+
|
15
|
+
def check_feeds
|
16
|
+
number_processed = 0
|
17
|
+
feeds = @dsl.feeds
|
18
|
+
feed_size = feeds.size
|
19
|
+
|
20
|
+
begin
|
21
|
+
@options[:logger].info "Fetching #{feed_size} feed#{feed_size == 1 ? "" : "s"}" if @options[:verbose]
|
22
|
+
|
23
|
+
@results = Feedzirra::Feed.fetch_and_parse(feeds)
|
24
|
+
|
25
|
+
@options[:logger].info "Processing #{feed_size} feed#{feed_size == 1 ? "" : "s"}" if @options[:verbose]
|
26
|
+
|
27
|
+
@results.each do |url, rss|
|
28
|
+
if rss.is_a?(Fixnum)
|
29
|
+
@options[:logger].error "Couldn't download #{url}"
|
30
|
+
else
|
31
|
+
@dsl.perform_filter(rss.entries)
|
32
|
+
number_processed += 1
|
33
|
+
end
|
34
|
+
end
|
35
|
+
rescue => e
|
36
|
+
@options[:logger].error "#{e}"
|
37
|
+
end
|
38
|
+
|
39
|
+
@options[:logger].info "Processed #{number_processed} out of #{feed_size} feed#{feed_size == 1 ? "" : "s"}" if @options[:verbose]
|
40
|
+
return number_processed
|
41
|
+
end
|
42
|
+
|
43
|
+
def update_feeds
|
44
|
+
number_processed = 0
|
45
|
+
number_skipped = 0
|
46
|
+
feeds = @results
|
47
|
+
feed_size = feeds.size
|
48
|
+
|
49
|
+
begin
|
50
|
+
@options[:logger].info "Fetching #{feed_size} feed#{feed_size ? "" : "s"}" if @options[:verbose]
|
51
|
+
|
52
|
+
results = Feedzirra::Feed.update(feeds.values)
|
53
|
+
@options[:logger].info "Processing #{feed_size} feed#{feed_size ? "" : "s"}" if @options[:verbose]
|
54
|
+
|
55
|
+
if results.updated?
|
56
|
+
@dsl.perform_filter(results.new_entries)
|
57
|
+
else
|
58
|
+
number_skipped += 1
|
59
|
+
end
|
60
|
+
number_processed += 1
|
61
|
+
rescue => e
|
62
|
+
@options[:logger].error "#{e}"
|
63
|
+
end
|
64
|
+
|
65
|
+
@options[:logger].info "Processed #{number_processed} out of #{feed_size} feed#{feed_size ? "" : "s"} (#{number_skipped} skipped)" if @options[:verbose]
|
66
|
+
return number_processed
|
67
|
+
end
|
68
|
+
|
69
|
+
def check_downloads
|
70
|
+
return if @options[:dry_run]
|
71
|
+
@options[:logger].info "Checking Download Status" if @options[:verbose]
|
72
|
+
t = Transmission::Client.new(@options[:transmission_server], @options[:transmission_port])
|
73
|
+
@dsl.download_complete(t.torrents)
|
74
|
+
end
|
75
|
+
end
|
data/lib/lexicon.rb
ADDED
@@ -0,0 +1,111 @@
|
|
1
|
+
class Lexicon
|
2
|
+
def self.parse(item)
|
3
|
+
if item.is_a?(String)
|
4
|
+
title = item
|
5
|
+
else
|
6
|
+
title = item.title
|
7
|
+
end
|
8
|
+
|
9
|
+
parsed = {
|
10
|
+
:title => nil,
|
11
|
+
:series => nil,
|
12
|
+
:episode => nil,
|
13
|
+
:size => nil,
|
14
|
+
:publish_date => nil,
|
15
|
+
:high_def => false
|
16
|
+
}
|
17
|
+
|
18
|
+
tokens = title.split(/\.| /)
|
19
|
+
titles = []
|
20
|
+
state = :title
|
21
|
+
|
22
|
+
while tokens.length > 0
|
23
|
+
token = tokens.shift
|
24
|
+
|
25
|
+
case(state)
|
26
|
+
when :title
|
27
|
+
if token =~ /s(\d+)e(\d+)/i
|
28
|
+
parsed[:series] = Regexp.last_match[1].to_i
|
29
|
+
parsed[:episode] = Regexp.last_match[2].to_i
|
30
|
+
state = :done
|
31
|
+
elsif token =~ /^(\d)x?(\d\d)$/i
|
32
|
+
parsed[:series] = Regexp.last_match[1].to_i
|
33
|
+
parsed[:episode] = Regexp.last_match[2].to_i
|
34
|
+
state = :done
|
35
|
+
elsif token =~ /^s(\d+)$/i
|
36
|
+
parsed[:series] = Regexp.last_match[1].to_i
|
37
|
+
state = :series
|
38
|
+
else
|
39
|
+
titles << token
|
40
|
+
end
|
41
|
+
when :series
|
42
|
+
if token =~ /^e(\d+)$/i
|
43
|
+
parsed[:episode] = Regexp.last_match[1].to_i
|
44
|
+
state = :done
|
45
|
+
end
|
46
|
+
when :done
|
47
|
+
if token =~ /HDTV|720p|1080|mkv/i
|
48
|
+
parsed[:high_def] = true
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# Reparse to look for some hd/sd info
|
54
|
+
if state != :done
|
55
|
+
tokens = title.split(/\.| /)
|
56
|
+
titles = [] if state == :title
|
57
|
+
|
58
|
+
while tokens.length > 0
|
59
|
+
token = tokens.shift
|
60
|
+
case(state)
|
61
|
+
when :title
|
62
|
+
if token =~ /HDTV|720p|1080|mkv/i
|
63
|
+
parsed[:high_def] = true
|
64
|
+
state = :done
|
65
|
+
else
|
66
|
+
titles << token
|
67
|
+
end
|
68
|
+
when :series
|
69
|
+
if token =~ /HDTV|720p|1080|mkv/i
|
70
|
+
parsed[:high_def] = true
|
71
|
+
state = :done
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
# Try to split on some common lines
|
78
|
+
if state != :done
|
79
|
+
tokens = title.split(/\.| /)
|
80
|
+
titles = [] if state == :title
|
81
|
+
|
82
|
+
while tokens.length > 0
|
83
|
+
token = tokens.shift
|
84
|
+
case(state)
|
85
|
+
when :title
|
86
|
+
if token =~ /vid|DVDRip|xvid|divx|repack|internal/i
|
87
|
+
state = :done
|
88
|
+
elsif token =~ /avi|ts|mkv|mpg/i
|
89
|
+
state = :done
|
90
|
+
else
|
91
|
+
titles << token
|
92
|
+
end
|
93
|
+
when :series
|
94
|
+
if token =~ /vid|DVDRip|xvid|divx|repack|internal/i
|
95
|
+
state = :done
|
96
|
+
elsif token =~ /avi|ts|mkv|mpg/i
|
97
|
+
state = :done
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
if state == :title
|
104
|
+
titles = title.split(/\.| /)
|
105
|
+
end
|
106
|
+
|
107
|
+
parsed[:title] = titles.join(' ')
|
108
|
+
parsed[:publish_date] = item.published if item.published
|
109
|
+
return parsed
|
110
|
+
end
|
111
|
+
end
|
data/lib/options.rb
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
|
3
|
+
class Options
|
4
|
+
def self.parse
|
5
|
+
options = {
|
6
|
+
:multiple => false
|
7
|
+
}
|
8
|
+
|
9
|
+
optparse = OptionParser.new do |opts|
|
10
|
+
opts.banner = "Usage: #{opts.program_name} [options]"
|
11
|
+
|
12
|
+
options[:verbose] = false
|
13
|
+
opts.on('-V', '--verbose', 'Be more verbose') do
|
14
|
+
options[:verbose] = true
|
15
|
+
end
|
16
|
+
|
17
|
+
options[:dry_run] = false
|
18
|
+
opts.on('-d', '--dry-run', "Don't actually queue torrents up") do |dry_run|
|
19
|
+
options[:dry_run] = true
|
20
|
+
end
|
21
|
+
|
22
|
+
options[:interval] = 15
|
23
|
+
opts.on('-i [n]', '--interval [n]', /\d+/, 'Number of minutes between checks (Default: 15)') do |interval|
|
24
|
+
options[:interval] = interval.to_i
|
25
|
+
end
|
26
|
+
|
27
|
+
opts.on('-h', '--help', "You're looking at it") do
|
28
|
+
puts opts
|
29
|
+
exit(-1)
|
30
|
+
end
|
31
|
+
|
32
|
+
options[:ontop] = false
|
33
|
+
opts.on('-f', '--foreground', "Run in the foreground") do
|
34
|
+
options[:ontop] = true
|
35
|
+
end
|
36
|
+
|
37
|
+
options[:filter_paths] = [ File.join('', File.dirname(__FILE__), '..', 'recipe.rb'), File.join('', 'etc', 'overdrive.rb'), File.join('', 'var' , 'transmission' , 'config' , 'overdrive.rb') ]
|
38
|
+
options[:filter_paths] << File.join(ENV['HOME'], '.overdrive', 'overdrive.rb') if ENV['HOME']
|
39
|
+
options[:filter_paths] += ENV['OVERDRIVE_RECIPES'].split(':') if ENV['OVERDRIVE_RECIPES']
|
40
|
+
|
41
|
+
opts.on('-r [recipe]', '--recipes [recipe]', /.+/, 'Reads in additional recipes') do |recipes|
|
42
|
+
options[:filter_paths] << recipes
|
43
|
+
end
|
44
|
+
|
45
|
+
options[:transmission_server] = 'localhost'
|
46
|
+
opts.on('-s [server]', '--transmission_server [server]', /.+/, 'Address of the transmission server (Default: localhost)') do |server|
|
47
|
+
options[:transmission_server] = server
|
48
|
+
end
|
49
|
+
|
50
|
+
options[:transmission_port] = 9091
|
51
|
+
opts.on('-p [port]', '--transmission_port', /\d+/, 'Port of the transmission server (Default: 9091)') do |port|
|
52
|
+
options[:transmission_port] = port.to_i
|
53
|
+
end
|
54
|
+
|
55
|
+
opts.on('-v', '--version') do
|
56
|
+
File.open(File.join(File.dirname(__FILE__), '..', 'VERSION')) do |fh|
|
57
|
+
puts fh.read
|
58
|
+
end
|
59
|
+
exit(0)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
begin
|
64
|
+
optparse.parse!
|
65
|
+
options
|
66
|
+
rescue OptionParser::InvalidOption => e
|
67
|
+
puts optparse
|
68
|
+
exit(-1)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
data/lib/torrent.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'open-uri'
|
2
|
+
require 'base64'
|
3
|
+
|
4
|
+
class Torrent
|
5
|
+
include OpenURI::OpenRead
|
6
|
+
|
7
|
+
def self.download(link, http_options = {}, options = {})
|
8
|
+
return if options[:dry_run]
|
9
|
+
|
10
|
+
uri = URI.parse(link)
|
11
|
+
download_dir = http_options.delete(:download_dir)
|
12
|
+
torrent = uri.read(http_options)
|
13
|
+
t = Transmission::Client.new(options[:transmission_server], options[:transmission_port])
|
14
|
+
t.add_torrent('metainfo' => Base64.encode64(torrent), 'download-dir' => download_dir)
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,200 @@
|
|
1
|
+
<?xml version="1.0" encoding="ISO-8859-1" ?>
|
2
|
+
<rss version="2.0">
|
3
|
+
<channel>
|
4
|
+
<ttl>10</ttl>
|
5
|
+
<title>My Torrent Site</title>
|
6
|
+
<link>http://www.mytorrentsite.com</link>
|
7
|
+
<description>This is a dummy torrent site</description>
|
8
|
+
<language>en-usde</language>
|
9
|
+
<item><title>dollhouse.s02e08.internal.hdtv.xvid-2hd.avi</title>
|
10
|
+
<link>http://www.mytorrentsite.com/download/dollhouse.s02e08.internal.hdtv.xvid-2hd.avi.torrent</link>
|
11
|
+
|
12
|
+
<description>
|
13
|
+
Category: Dollhouse
|
14
|
+
Size: 349.30 MB
|
15
|
+
</description>
|
16
|
+
</item>
|
17
|
+
<item><title>Ghost.Adventures.S03E07.HDTV.XviD-CRiMSON</title>
|
18
|
+
<link>http://www.mytorrentsite.com/download/ghost.adventures.s03e07.hdtv.xvid-crimson.avi.torrent</link>
|
19
|
+
<description>
|
20
|
+
Category: (Reality TV - Un-scripted)
|
21
|
+
Size: 350.15 MB
|
22
|
+
</description>
|
23
|
+
</item>
|
24
|
+
<item><title>Dollhouse.S02E08.720p.HDTV.x264-IMMERSE[NUKED]</title>
|
25
|
+
|
26
|
+
<link>http://www.mytorrentsite.com/download/dollhouse.s02e08.720p.hdtv.x264-immerse.mkv.torrent</link>
|
27
|
+
<description>
|
28
|
+
Category: Dollhouse
|
29
|
+
Size: 1.09 GB
|
30
|
+
</description>
|
31
|
+
</item>
|
32
|
+
<item><title>Sanctuary.US.S02E09.720p.HDTV.x264-ORENJi</title>
|
33
|
+
<link>http://www.mytorrentsite.com/download/sanctuary.us.s02e09.720p.hdtv.x264-orenji.mkv.torrent</link>
|
34
|
+
<description>
|
35
|
+
Category: Sanctuary
|
36
|
+
Size: 1.09 GB
|
37
|
+
</description>
|
38
|
+
|
39
|
+
</item>
|
40
|
+
<item><title>National.Geographic.Samurai.Sword.720p.HDTV.x264-DiCH</title>
|
41
|
+
<link>http://www.mytorrentsite.com/download/dich-national.geographic.ss.720p.hdtv.x264.mkv.torrent</link>
|
42
|
+
<description>
|
43
|
+
Category: (National Geographic)
|
44
|
+
Size: 1.09 GB
|
45
|
+
</description>
|
46
|
+
</item>
|
47
|
+
<item><title>Conan.O'Brien.12.11.2009.Zach.Braff.1080i.AC3.MPEG2-TSR [TS][Transport Stream]</title>
|
48
|
+
<link>http://www.mytorrentsite.com/download/conan.o%27brien.12.11.2009.zach.braff.1080i.ac3.mpeg2.tsr.ts.torrent</link>
|
49
|
+
|
50
|
+
<description>
|
51
|
+
Category: Tonight Show
|
52
|
+
Size: 4.18 GB
|
53
|
+
</description>
|
54
|
+
</item>
|
55
|
+
<item><title>Dollhouse S02E07 [reencode] [P0W4] [iPod].mp4</title>
|
56
|
+
<link>http://www.mytorrentsite.com/download/Dollhouse%20S02E07%20%5Breencode%5D%20%5BP0W4%5D%20%5BiPod%5D.mp4.torrent</link>
|
57
|
+
<description>
|
58
|
+
Category: (Portable TV Episodes)
|
59
|
+
Size: 387.05 MB
|
60
|
+
</description>
|
61
|
+
</item>
|
62
|
+
<item><title>Law.and.Order.S20E11.REPACK.720p.HDTV.x264-IMMERSE</title>
|
63
|
+
<link>http://www.mytorrentsite.com/download/law.and.order.s20e11.repack.720p.hdtv.x264-immerse.mkv.torrent</link>
|
64
|
+
|
65
|
+
<description>
|
66
|
+
Category: Law and Order
|
67
|
+
Size: 1.09 GB
|
68
|
+
</description>
|
69
|
+
</item>
|
70
|
+
<item><title>Hardcore TV (1994, HBO series)</title>
|
71
|
+
<link>http://www.mytorrentsite.com/download/Hardcore%20TV%20%281994%20HBO%20Complete%20Series%29.torrent</link>
|
72
|
+
<description>
|
73
|
+
Category: (US Comedy)
|
74
|
+
Size: 1.88 GB
|
75
|
+
</description>
|
76
|
+
</item>
|
77
|
+
<item><title>yes.virginia.hdtv.xvid-notv.avi</title>
|
78
|
+
|
79
|
+
<link>http://www.mytorrentsite.com/download/yes.virginia.hdtv.xvid-notv.avi.torrent</link>
|
80
|
+
<description>
|
81
|
+
Category: (Cartoons)
|
82
|
+
Size: 175.16 MB
|
83
|
+
</description>
|
84
|
+
</item>
|
85
|
+
<item><title>Crash.S02E12.HDTV.XviD-RED</title>
|
86
|
+
<link>http://www.mytorrentsite.com/download/Crash.S02E12.HDTV.XviD-RED.avi.torrent</link>
|
87
|
+
<description>
|
88
|
+
Category: (US Drama)
|
89
|
+
Size: 550.88 MB
|
90
|
+
</description>
|
91
|
+
|
92
|
+
</item>
|
93
|
+
<item><title>Being.Erica.S02.INTERNAL.HDTV.XviD-BitMeTV</title>
|
94
|
+
<link>http://www.mytorrentsite.com/download/Being.Erica.S02.INTERNAL.HDTV.XviD-BitMeTV.torrent</link>
|
95
|
+
<description>
|
96
|
+
Category: (Canadian TV)
|
97
|
+
Size: 4.10 GB
|
98
|
+
</description>
|
99
|
+
</item>
|
100
|
+
<item><title>Friday.Night.Lights.S04E06.HDTV.XviD-RED</title>
|
101
|
+
<link>http://www.mytorrentsite.com/download/Friday.Night.Lights.S04E06.HDTV.XviD-RED.avi.torrent</link>
|
102
|
+
|
103
|
+
<description>
|
104
|
+
Category: Friday Night Lights
|
105
|
+
Size: 350.65 MB
|
106
|
+
</description>
|
107
|
+
</item>
|
108
|
+
<item><title>National.Geographic.Inside.The.Pentagon.Xvid.DVDRip.avi</title>
|
109
|
+
<link>http://www.mytorrentsite.com/download/National.Geographic.Inside.The.Pentagon.Xvid.DVDRip.avi.torrent</link>
|
110
|
+
<description>
|
111
|
+
Category: (National Geographic)
|
112
|
+
Size: 700.17 MB
|
113
|
+
</description>
|
114
|
+
</item>
|
115
|
+
<item><title>Sanctuary.US.S02E09.Penance.HDTV.XviD-FQM</title>
|
116
|
+
<link>http://www.mytorrentsite.com/download/sanctuary.us.s02e09.hdtv.xvid-fqm.avi.torrent</link>
|
117
|
+
|
118
|
+
<description>
|
119
|
+
Category: Sanctuary
|
120
|
+
Size: 350.02 MB
|
121
|
+
</description>
|
122
|
+
</item>
|
123
|
+
<item><title>Million.Dollar.Listing.S03E03.Dolphins.Rats.and.Next.Door.Neighbors.HDTV.XviD-SAiNTS.avi</title>
|
124
|
+
<link>http://www.mytorrentsite.com/download/Million.Dollar.Listing.S03E03.Dolphins.Rats.and.Next.Door.Neighbors.HDTV.XviD-SAiNTS.avi.torrent</link>
|
125
|
+
<description>
|
126
|
+
Category: (Reality TV - Un-scripted)
|
127
|
+
Size: 349.30 MB
|
128
|
+
</description>
|
129
|
+
</item>
|
130
|
+
<item><title>Dollhouse.S02E07.Meet.Jane.Doe.720p.AC3.MPEG2-TSR [TS][Transport Stream]</title>
|
131
|
+
|
132
|
+
<link>http://www.mytorrentsite.com/download/dollhouse.s02e07.meet.jane.doe.720p.ac3.mpeg2.tsr.ts.torrent</link>
|
133
|
+
<description>
|
134
|
+
Category: Dollhouse
|
135
|
+
Size: 4.49 GB
|
136
|
+
</description>
|
137
|
+
</item>
|
138
|
+
<item><title>Dollhouse.S02E07.REPACK.720p.HDTV.x264-IMMERSE</title>
|
139
|
+
<link>http://www.mytorrentsite.com/download/dollhouse.s02e07.repack.720p.hdtv.x264-immerse.mkv.torrent</link>
|
140
|
+
<description>
|
141
|
+
Category: Dollhouse
|
142
|
+
Size: 1.09 GB
|
143
|
+
</description>
|
144
|
+
|
145
|
+
</item>
|
146
|
+
<item><title>The.Real.World.Road.Rules.Challenge.S18E10.DSR.XviD-CRiMSON</title>
|
147
|
+
<link>http://www.mytorrentsite.com/download/the.real.world.road.rules.challenge.s18e10.dsr.xvid-crimson.avi.torrent</link>
|
148
|
+
<description>
|
149
|
+
Category: (Reality TV - Competitive)
|
150
|
+
Size: 348.92 MB
|
151
|
+
</description>
|
152
|
+
</item>
|
153
|
+
<item><title>The.Real.World.Road.Rules.Challenge.S18E09.DSR.XviD-CRiMSON</title>
|
154
|
+
<link>http://www.mytorrentsite.com/download/The.Real.World.Road.Rules.Challenge.S18E09.DSR.XviD-CRiMSON.avi.torrent</link>
|
155
|
+
|
156
|
+
<description>
|
157
|
+
Category: (Reality TV - Competitive)
|
158
|
+
Size: 348.60 MB
|
159
|
+
</description>
|
160
|
+
</item>
|
161
|
+
<item><title>Ugly.Betty.S04E09.720p.HDTV.x264-CTU</title>
|
162
|
+
<link>http://www.mytorrentsite.com/download/ugly.betty.s04e09.720p.hdtv.x264-ctu.mkv.torrent</link>
|
163
|
+
<description>
|
164
|
+
Category: Ugly Betty
|
165
|
+
Size: 1.09 GB
|
166
|
+
</description>
|
167
|
+
</item>
|
168
|
+
<item><title>Ugly.Betty.S04E09.Be-Shure.HDTV.XviD-FQM</title>
|
169
|
+
<link>http://www.mytorrentsite.com/download/ugly.betty.s04e09.hdtv.xvid-fqm.avi.torrent</link>
|
170
|
+
|
171
|
+
<description>
|
172
|
+
Category: Ugly Betty
|
173
|
+
Size: 350.03 MB
|
174
|
+
</description>
|
175
|
+
</item>
|
176
|
+
<item><title>Dollhouse S02E04 [reencode] [2hd] [iPod].mp4</title>
|
177
|
+
<link>http://www.mytorrentsite.com/download/Dollhouse%20S02E04%20%5Breencode%5D%20%5B2hd%5D%20%5BiPod%5D.mp4.torrent</link>
|
178
|
+
<description>
|
179
|
+
Category: (Portable TV Episodes)
|
180
|
+
Size: 383.00 MB
|
181
|
+
</description>
|
182
|
+
</item>
|
183
|
+
<item><title>Dollhouse S02E03 [reencode] [xii] [iPod].mp4</title>
|
184
|
+
|
185
|
+
<link>http://www.mytorrentsite.com/download/Dollhouse%20S02E03%20%5Breencode%5D%20%5Bxii%5D%20%5BiPod%5D.mp4.torrent</link>
|
186
|
+
<description>
|
187
|
+
Category: (Portable TV Episodes)
|
188
|
+
Size: 388.40 MB
|
189
|
+
</description>
|
190
|
+
</item>
|
191
|
+
<item><title>Maury.2009.12.11.DSR.XviD-sHoTV</title>
|
192
|
+
<link>http://www.mytorrentsite.com/download/maury.2009.12.11.dsr.xvid-shotv.avi.torrent</link>
|
193
|
+
<description>
|
194
|
+
Category: Maury
|
195
|
+
Size: 349.14 MB
|
196
|
+
</description>
|
197
|
+
|
198
|
+
</item>
|
199
|
+
</channel>
|
200
|
+
</rss>
|
data/test/recipe.rb
ADDED
data/test/test_helper.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
$:.unshift File.join(File.dirname(File.expand_path(__FILE__)), '..', 'lib')
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'daemons'
|
5
|
+
require 'options'
|
6
|
+
require 'feed'
|
7
|
+
require 'torrent'
|
8
|
+
require 'lexicon'
|
9
|
+
require 'dsl'
|
10
|
+
|
11
|
+
require 'redgreen'
|
12
|
+
require 'test/unit'
|
13
|
+
require 'mocha'
|
14
|
+
require 'shoulda'
|
15
|
+
require 'fakefs/safe'
|
16
|
+
require 'fakeweb'
|
17
|
+
|
18
|
+
module TestHelper
|
19
|
+
def bitme_rss
|
20
|
+
File.open(File.join(File.dirname(File.expand_path(__FILE__)), 'fixtures', 'test.rss')) do |rss|
|
21
|
+
rss.read
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def filter_paths
|
26
|
+
[ File.join(File.dirname(File.expand_path(__FILE__)), '..', 'receipe.rb') ]
|
27
|
+
end
|
28
|
+
end
|
data/test/unit/dsl.rb
ADDED
@@ -0,0 +1,105 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class DslTest < Test::Unit::TestCase
|
4
|
+
include TestHelper
|
5
|
+
|
6
|
+
context '' do
|
7
|
+
setup do
|
8
|
+
@logger = Logger.new(File.open('/dev/null', 'w'))
|
9
|
+
|
10
|
+
@options = {
|
11
|
+
:logger => @logger,
|
12
|
+
:filter_paths => filter_paths
|
13
|
+
}
|
14
|
+
|
15
|
+
@feed = Feed.new(@options)
|
16
|
+
@dsl = DSL.new(@options)
|
17
|
+
|
18
|
+
FakeWeb.register_uri(:get, "http://www.mytorrentsite.com/feed.rss", :body => bitme_rss)
|
19
|
+
end
|
20
|
+
|
21
|
+
context 'setup' do
|
22
|
+
should 'prime the DSL on initialize' do
|
23
|
+
assert @dsl.instance_variable_get(:@primed)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
context 'loader' do
|
28
|
+
should 'define run_dsl dynamically' do
|
29
|
+
assert @dsl.respond_to?(:run_dsl)
|
30
|
+
end
|
31
|
+
|
32
|
+
should 'map perform_filter to run_dsl' do
|
33
|
+
@items = []
|
34
|
+
@dsl.expects(:run_dsl).with(@items, :filter)
|
35
|
+
@dsl.perform_filter(@items)
|
36
|
+
end
|
37
|
+
|
38
|
+
should 'map download_complete to run_dsl' do
|
39
|
+
@items = []
|
40
|
+
@dsl.expects(:run_dsl).with(@items, :torrent)
|
41
|
+
@dsl.download_complete(@items)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
context 'add_title' do
|
46
|
+
should 'register a title if @primed is false' do
|
47
|
+
@dsl.instance_variable_set(:@primed, false)
|
48
|
+
assert 2, @dsl.instance_variable_get(:@titles).size
|
49
|
+
@dsl.add_title('Test Title 3')
|
50
|
+
assert 3, @dsl.instance_variable_get(:@titles).size
|
51
|
+
end
|
52
|
+
|
53
|
+
should 'not register a title if @primed is true' do
|
54
|
+
@dsl.instance_variable_set(:@primed, true)
|
55
|
+
assert 2, @dsl.instance_variable_get(:@titles).size
|
56
|
+
@dsl.add_title('Test Title 3')
|
57
|
+
assert 2, @dsl.instance_variable_get(:@titles).size
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
context 'add_feed' do
|
62
|
+
should 'register a feed if @primed is false' do
|
63
|
+
@dsl.instance_variable_set(:@primed, false)
|
64
|
+
assert 2, @dsl.instance_variable_get(:@feeds).size
|
65
|
+
@dsl.add_title('http://www.feedsfeedsfeeds.com/feed.rss')
|
66
|
+
assert 3, @dsl.instance_variable_get(:@feeds).size
|
67
|
+
end
|
68
|
+
|
69
|
+
should 'not register a title if @primed is true' do
|
70
|
+
@dsl.instance_variable_set(:@primed, true)
|
71
|
+
assert 2, @dsl.instance_variable_get(:@feeds).size
|
72
|
+
@dsl.add_title('http://www.feedsfeedsfeeds.com/feed.rss')
|
73
|
+
assert 2, @dsl.instance_variable_get(:@feeds).size
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
context 'parse_metadata' do
|
78
|
+
should 'call Lexicon::parse' do
|
79
|
+
item = mock
|
80
|
+
ret = mock
|
81
|
+
Lexicon.expects(:parse).with(item).returns(ret)
|
82
|
+
assert_equal ret, @dsl.parse_metadata(item)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
context 'download' do
|
87
|
+
should 'call Torrent::download' do
|
88
|
+
link = mock
|
89
|
+
options = mock
|
90
|
+
@dsl.stubs(:options).returns({})
|
91
|
+
Torrent.expects(:download).with(link, options, {})
|
92
|
+
@dsl.download(link, options)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
context 'log' do
|
97
|
+
should 'logs' do
|
98
|
+
logger = mock
|
99
|
+
options = {:logger => logger}
|
100
|
+
@dsl.stubs(:options).returns(options)
|
101
|
+
assert_equal logger, @dsl.log
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
data/test/unit/feed.rb
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'logger'
|
3
|
+
|
4
|
+
class FeedTest < Test::Unit::TestCase
|
5
|
+
include TestHelper
|
6
|
+
|
7
|
+
context '' do
|
8
|
+
setup do
|
9
|
+
@feed_urls = [ 'http://www.mytorrentsite.com/feed.rss' ]
|
10
|
+
DSL.any_instance.stubs(:feeds).returns(@feed_urls)
|
11
|
+
|
12
|
+
@logger = Logger.new(File.open('/dev/null', 'w'))
|
13
|
+
@feed = Feed.new(
|
14
|
+
{
|
15
|
+
:on_top => true,
|
16
|
+
:filter_paths => filter_paths,
|
17
|
+
:logger => @logger
|
18
|
+
})
|
19
|
+
|
20
|
+
feed = Feedzirra::Feed.parse(bitme_rss)
|
21
|
+
feed_ret = {}
|
22
|
+
@feed_urls.each { |f| feed_ret[f] = feed }
|
23
|
+
Feedzirra::Feed.stubs(:fetch_and_parse).returns(feed_ret)
|
24
|
+
end
|
25
|
+
|
26
|
+
context 'check' do
|
27
|
+
setup do
|
28
|
+
@transmission_client = mock
|
29
|
+
Transmission::Client.stubs(:new).returns(@transmission_client)
|
30
|
+
@transmission_client.stubs(:torrents).returns([])
|
31
|
+
end
|
32
|
+
|
33
|
+
should 'call check_feed' do
|
34
|
+
DSL.any_instance.expects(:download_complete).with([])
|
35
|
+
@feed.expects(:check_feeds)
|
36
|
+
@feed.check
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
context 'check_feed' do
|
41
|
+
should 'download each RSS feed' do
|
42
|
+
DSL.any_instance.expects(:perform_filter).times(@feed_urls.size)
|
43
|
+
@logger.expects(:error).never
|
44
|
+
assert_equal @feed_urls.size, @feed.check_feeds
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
context 'update_feed' do
|
49
|
+
should 'do nothing if there is no updated entries' do
|
50
|
+
feed = Feedzirra::Feed.parse(bitme_rss)
|
51
|
+
feed.entries.stubs(:values).returns([])
|
52
|
+
@feed.instance_variable_set(:@results, feed.entries)
|
53
|
+
Feedzirra::Feed.stubs(:update).returns(feed)
|
54
|
+
Feedzirra::Feed.stubs(:updated?).returns(false)
|
55
|
+
Feedzirra::Feed.stubs(:new_entries).returns([])
|
56
|
+
|
57
|
+
DSL.any_instance.expects(:perform_filter).never
|
58
|
+
@logger.expects(:error).never
|
59
|
+
assert_equal 1, @feed.update_feeds
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class LexiconTest < Test::Unit::TestCase
|
4
|
+
include TestHelper
|
5
|
+
|
6
|
+
context '' do
|
7
|
+
setup do
|
8
|
+
@item = mock
|
9
|
+
@item.stubs(:published).returns(DateTime.now)
|
10
|
+
end
|
11
|
+
|
12
|
+
should 'parse dollhouse.s02e08.internal.hdtv.xvid-2hd.avi' do
|
13
|
+
@item.stubs(:title).returns('dollhouse.s02e08.internal.hdtv.xvid-2hd.avi')
|
14
|
+
|
15
|
+
parsed = Lexicon::parse(@item)
|
16
|
+
assert_equal 'dollhouse', parsed[:title]
|
17
|
+
assert_equal 2, parsed[:series]
|
18
|
+
assert_equal 8, parsed[:episode]
|
19
|
+
assert parsed[:high_def]
|
20
|
+
end
|
21
|
+
|
22
|
+
should 'parse Ghost.Adventures.S03E07.HDTV.XviD-CRiMSON' do
|
23
|
+
@item.stubs(:title).returns('Ghost.Adventures.S03E07.HDTV.XviD-CRiMSON')
|
24
|
+
|
25
|
+
parsed = Lexicon::parse(@item)
|
26
|
+
assert_equal 'Ghost Adventures', parsed[:title]
|
27
|
+
assert_equal 3, parsed[:series]
|
28
|
+
assert_equal 7, parsed[:episode]
|
29
|
+
assert parsed[:high_def]
|
30
|
+
end
|
31
|
+
|
32
|
+
should 'parse National.Geographic.Samurai.Sword.720p.HDTV.x264-DiCH' do
|
33
|
+
@item.stubs(:title).returns('National.Geographic.Samurai.Sword.720p.HDTV.x264-DiCH')
|
34
|
+
|
35
|
+
parsed = Lexicon::parse(@item)
|
36
|
+
assert_equal 'National Geographic Samurai Sword', parsed[:title]
|
37
|
+
assert_equal nil, parsed[:series]
|
38
|
+
assert_equal nil, parsed[:episode]
|
39
|
+
assert parsed[:high_def]
|
40
|
+
end
|
41
|
+
|
42
|
+
should 'parse Hardcore TV (1994, HBO series)' do
|
43
|
+
@item.stubs(:title).returns('Hardcore TV (1994, HBO series)')
|
44
|
+
|
45
|
+
parsed = Lexicon::parse(@item)
|
46
|
+
assert_equal 'Hardcore TV (1994, HBO series)', parsed[:title]
|
47
|
+
assert_equal nil, parsed[:series]
|
48
|
+
assert_equal nil, parsed[:episode]
|
49
|
+
assert !parsed[:high_def]
|
50
|
+
end
|
51
|
+
|
52
|
+
should 'parse Being.Erica.S02.INTERNAL.HDTV.XviD-BitMeTV' do
|
53
|
+
@item.stubs(:title).returns('Being.Erica.S02.INTERNAL.HDTV.XviD-BitMeTV')
|
54
|
+
|
55
|
+
parsed = Lexicon::parse(@item)
|
56
|
+
assert_equal 'Being Erica', parsed[:title]
|
57
|
+
assert_equal 2, parsed[:series]
|
58
|
+
assert_equal nil, parsed[:episode]
|
59
|
+
assert parsed[:high_def]
|
60
|
+
end
|
61
|
+
|
62
|
+
should 'parse National.Geographic.Inside.The.Pentagon.Xvid.DVDRip.avi' do
|
63
|
+
@item.stubs(:title).returns('National.Geographic.Inside.The.Pentagon.Xvid.DVDRip.avi')
|
64
|
+
|
65
|
+
parsed = Lexicon::parse(@item)
|
66
|
+
assert_equal 'National Geographic Inside The Pentagon', parsed[:title]
|
67
|
+
assert_equal nil, parsed[:series]
|
68
|
+
assert_equal nil, parsed[:episode]
|
69
|
+
assert !parsed[:high_def]
|
70
|
+
end
|
71
|
+
|
72
|
+
should 'parse i.want.to.work.for.diddy.206.hdtv.xvid-sys.avi' do
|
73
|
+
@item.stubs(:title).returns('i.want.to.work.for.diddy.206.hdtv.xvid-sys.avi')
|
74
|
+
|
75
|
+
parsed = Lexicon::parse(@item)
|
76
|
+
assert_equal 'i want to work for diddy', parsed[:title]
|
77
|
+
assert_equal 2, parsed[:series]
|
78
|
+
assert_equal 6, parsed[:episode]
|
79
|
+
assert parsed[:high_def]
|
80
|
+
end
|
81
|
+
|
82
|
+
should 'parse Dollhouse S02E08 [reencode] [internal] [2hd] [iPod].mp4' do
|
83
|
+
@item.stubs(:title).returns('Dollhouse S02E08 [reencode] [internal] [2hd] [iPod].mp4')
|
84
|
+
|
85
|
+
parsed = Lexicon::parse(@item)
|
86
|
+
assert_equal 'Dollhouse', parsed[:title]
|
87
|
+
assert_equal 2, parsed[:series]
|
88
|
+
assert_equal 8, parsed[:episode]
|
89
|
+
assert !parsed[:high_def]
|
90
|
+
end
|
91
|
+
|
92
|
+
should 'parse The.Jeff.Dunham.Show.S01.E06.HDTV.XviD-RNR.avi' do
|
93
|
+
@item.stubs(:title).returns('The.Jeff.Dunham.Show.S01.E06.HDTV.XviD-RNR.avi')
|
94
|
+
|
95
|
+
parsed = Lexicon::parse(@item)
|
96
|
+
assert_equal 'The Jeff Dunham Show', parsed[:title]
|
97
|
+
assert_equal 1, parsed[:series]
|
98
|
+
assert_equal 6, parsed[:episode]
|
99
|
+
assert parsed[:high_def]
|
100
|
+
end
|
101
|
+
|
102
|
+
should 'parse Mouth To Mouth.1x04.Devine.REPACK.WS PDTV XviD-FoV' do
|
103
|
+
@item.stubs(:title).returns('Mouth To Mouth.1x04.Devine.REPACK.WS PDTV XviD-FoV')
|
104
|
+
|
105
|
+
parsed = Lexicon::parse(@item)
|
106
|
+
assert_equal 'Mouth To Mouth', parsed[:title]
|
107
|
+
assert_equal 1, parsed[:series]
|
108
|
+
assert_equal 4, parsed[:episode]
|
109
|
+
assert !parsed[:high_def]
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'base64'
|
3
|
+
|
4
|
+
class DslTest < Test::Unit::TestCase
|
5
|
+
include TestHelper
|
6
|
+
|
7
|
+
context '' do
|
8
|
+
setup do
|
9
|
+
@fake_torrent_file = "This really isn't a torrent file"
|
10
|
+
@transmission_client = mock
|
11
|
+
Transmission::Client.stubs(:new).returns(@transmission_client)
|
12
|
+
FakeWeb.register_uri(:get, "http://www.mytorrentsite.com/tv_show.torrent", :body => @fake_torrent_file)
|
13
|
+
end
|
14
|
+
|
15
|
+
context 'download' do
|
16
|
+
should 'pass a base64 encoded version of the supplied data and the download directory' do
|
17
|
+
@transmission_client.stubs(:add_torrent).with('metainfo' => Base64.encode64(@fake_torrent_file), 'download-dir' => '/Downloads')
|
18
|
+
Torrent.download('http://www.mytorrentsite.com/tv_show.torrent', :download_dir => '/Downloads')
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
metadata
ADDED
@@ -0,0 +1,103 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: overdrive
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Myles Eftos
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-12-20 00:00:00 +08:00
|
13
|
+
default_executable: overdrive
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: daemons
|
17
|
+
type: :runtime
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: "0"
|
24
|
+
version:
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: transmission-client
|
27
|
+
type: :runtime
|
28
|
+
version_requirement:
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: "0"
|
34
|
+
version:
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: SyslogLogger
|
37
|
+
type: :runtime
|
38
|
+
version_requirement:
|
39
|
+
version_requirements: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: "0"
|
44
|
+
version:
|
45
|
+
description: An RSS frontend for transmissions. It defines a basic DSL that allows you decide what you do once the files have been downloaded
|
46
|
+
email: myles@madpilot.com.au
|
47
|
+
executables:
|
48
|
+
- overdrive
|
49
|
+
extensions: []
|
50
|
+
|
51
|
+
extra_rdoc_files:
|
52
|
+
- README.markdown
|
53
|
+
files:
|
54
|
+
- README.markdown
|
55
|
+
- Rakefile
|
56
|
+
- VERSION
|
57
|
+
- bin/overdrive
|
58
|
+
- lib/dsl.rb
|
59
|
+
- lib/feed.rb
|
60
|
+
- lib/lexicon.rb
|
61
|
+
- lib/options.rb
|
62
|
+
- lib/torrent.rb
|
63
|
+
- test/fixtures/test.rss
|
64
|
+
- test/recipe.rb
|
65
|
+
- test/test_helper.rb
|
66
|
+
- test/unit/dsl.rb
|
67
|
+
- test/unit/feed.rb
|
68
|
+
- test/unit/lexicon.rb
|
69
|
+
- test/unit/torrent.rb
|
70
|
+
has_rdoc: true
|
71
|
+
homepage: http://github.com/madpilot/overdrive
|
72
|
+
licenses: []
|
73
|
+
|
74
|
+
post_install_message:
|
75
|
+
rdoc_options:
|
76
|
+
- --charset=UTF-8
|
77
|
+
require_paths:
|
78
|
+
- lib
|
79
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - ">="
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: "0"
|
84
|
+
version:
|
85
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: "0"
|
90
|
+
version:
|
91
|
+
requirements: []
|
92
|
+
|
93
|
+
rubyforge_project:
|
94
|
+
rubygems_version: 1.3.5
|
95
|
+
signing_key:
|
96
|
+
specification_version: 3
|
97
|
+
summary: An RSS frontend for transmission
|
98
|
+
test_files:
|
99
|
+
- test/test_helper.rb
|
100
|
+
- test/unit/feed.rb
|
101
|
+
- test/unit/lexicon.rb
|
102
|
+
- test/unit/dsl.rb
|
103
|
+
- test/unit/torrent.rb
|