feed_torrents 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 2ab95c88a022529d22ef12ba2e63243d30c75ab9
4
+ data.tar.gz: d633d34caee9592a45156d20b61f9a4c3db3a7bb
5
+ SHA512:
6
+ metadata.gz: 1a2d78dc6761e530ae6e0672fd027b63de38671274f0bfdabdcc2317ab783de6b9c53f7724b5659d4b403c2d05985baa485a64cfec570a327a7cfe9562dd85d3
7
+ data.tar.gz: 5f0f736ab30488b1c4d779ecf917829ef3054cdab06a849859e7913bea8a74db93f8abf42634a1f8a2a9e73307bbe2f4dddaa656f5c149d4c75be30ac5ed0599
data/.document ADDED
@@ -0,0 +1,4 @@
1
+ lib/**/*.rb
2
+ README.rdoc
3
+ ChangeLog.rdoc
4
+ LICENSE.txt
data/.gitignore ADDED
@@ -0,0 +1,5 @@
1
+ Gemfile.lock
2
+ html/
3
+ pkg/
4
+ vendor/cache/*.gem
5
+ .idea/
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --colour --format documentation
data/ChangeLog.rdoc ADDED
@@ -0,0 +1,4 @@
1
+ === 0.1.0 / 2015-01-10
2
+
3
+ * Initial release:
4
+
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2015 Tom van Leeuwen
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.md ADDED
@@ -0,0 +1,134 @@
1
+ # FeedTorrents
2
+
3
+ [![Gem Version](https://badge.fury.io/rb/feed_torrents.png)](http://rubygems.org/gems/feed_torrents)
4
+
5
+ ## Install
6
+
7
+ Install with Rubygems:
8
+
9
+ gem install feed_torrents
10
+
11
+ If you use bundler, add it to your Gemfile:
12
+
13
+ gem "feed_torrents", "~>0.1.0"
14
+
15
+ ## Usage
16
+
17
+ Create a configuration file: /tmp/feed_torrents.yml
18
+ ```yaml
19
+ log:
20
+ :out: STDOUT # or some file path
21
+ :rotate: 5
22
+ :size: 1048576 # 1MB
23
+ :level: DEBUG
24
+ :format: '%Y-%m-%d %H:%M:%S'
25
+
26
+ datastore: /tmp/feed_torrents.store
27
+
28
+ # Default configuration items for a feed
29
+ default_feed: &default_feed
30
+ :enabled: true
31
+ :interval: 900 # 900 seconds is 15 minutes
32
+ :timeout: 30
33
+ :directory: /tmp/incoming_torrents
34
+ :regex_filters:
35
+ - '.*'
36
+
37
+ # Interval is in seconds
38
+ feeds:
39
+ showrss:
40
+ <<: *default_feed
41
+ :url: 'http://showrss.info/rss.php?user_id=0000'
42
+ :interval: 900
43
+ :enabled: true
44
+
45
+ nyaa:
46
+ <<: *default_feed
47
+ :url: 'http://www.nyaa.se/?page=rss&cats=1_37'
48
+ :interval: 1800
49
+ :enabled: true
50
+ :regex_filters:
51
+ - 'HorribleSubs.*Fairy Tail S2 .*720p'
52
+ - 'HorribleSubs.*Magic Kaito .*1080p'
53
+ - '\[DeadFish\]'
54
+ ```
55
+
56
+ Now simply start the application:
57
+ ```bash
58
+ feed_torrents /tmp/feed_torrents.yml
59
+ I, [2015-01-10T20:32:24.171075 #21457] INFO -- : FeedTorrents::Reactor#initialize: Initialize new Reactor version 0.1.0
60
+ I, [2015-01-10T20:32:24.171184 #21457] INFO -- : FeedTorrents::Reactor#start: Starting eventmachine loop
61
+ I, [2015-01-10T20:32:24.171450 #21457] INFO -- : FeedTorrents::Feed::List#initialize: showrss (enabled: true interval: 900 link: http://showrss.info/rss.php?user_id=0000)
62
+ I, [2015-01-10T20:32:24.171484 #21457] INFO -- : FeedTorrents::Feed::List#initialize: nyaa (enabled: true interval: 1800 link: http://www.nyaa.se/?page=rss&cats=1_37)
63
+ I, [2015-01-10T20:32:24.171540 #21457] INFO -- : FeedTorrents::Feed::List#download_new_items: feed showrss
64
+ I, [2015-01-10T20:32:24.182937 #21457] INFO -- : FeedTorrents::Feed::List#download_new_items: feed nyaa
65
+ I, [2015-01-10T20:32:24.321911 #21457] INFO -- : FeedTorrents::Feed::List#process: Processing: American Horror Story 4x11 Magical Thinking 720p
66
+ I, [2015-01-10T20:32:24.322063 #21457] INFO -- : FeedTorrents::Feed::Download#process: Downloading torrent for 'American Horror Story 4x11 Magical Thinking 720p' (http://reflektor.karmorra.info/torrent/54D7C99225897595AF1E4F85B5B317FEEF0119C5.torrent)
67
+ I, [2015-01-10T20:32:24.352748 #21457] INFO -- : FeedTorrents::Feed::List#process: Processing: American Horror Story 4x10 Orphans 720p
68
+ I, [2015-01-10T20:32:24.352990 #21457] INFO -- : FeedTorrents::Feed::Download#process: Downloading torrent for 'American Horror Story 4x10 Orphans 720p' (http://reflektor.karmorra.info/torrent/CA85592A0850E361AC0840ED510A036FA2A1828C.torrent)
69
+ I, [2015-01-10T20:32:24.971696 #21457] INFO -- : FeedTorrents::Feed::List#process: Processing: [DeadFish] Tokyo Ghoul √A - 01 [720p][AAC].mp4
70
+ I, [2015-01-10T20:32:24.971757 #21457] INFO -- : FeedTorrents::Feed::Download#process: Downloading torrent for '[DeadFish] Tokyo Ghoul √A - 01 [720p][AAC].mp4' (http://www.nyaa.se/?page=download&tid=643972)
71
+ I, [2015-01-10T20:32:24.987967 #21457] INFO -- : FeedTorrents::Feed::List#process: Processing: [HorribleSubs] Magic Kaito 1412 - 06 [1080p].mkv
72
+ I, [2015-01-10T20:32:24.988158 #21457] INFO -- : FeedTorrents::Feed::Download#process: Downloading torrent for '[HorribleSubs] Magic Kaito 1412 - 06 [1080p].mkv' (http://www.nyaa.se/?page=download&tid=643846)
73
+ I, [2015-01-10T20:32:25.003946 #21457] INFO -- : FeedTorrents::Feed::List#process: Processing: [HorribleSubs] Magic Kaito 1412 - 05 [1080p].mkv
74
+ I, [2015-01-10T20:32:25.004167 #21457] INFO -- : FeedTorrents::Feed::Download#process: Downloading torrent for '[HorribleSubs] Magic Kaito 1412 - 05 [1080p].mkv' (http://www.nyaa.se/?page=download&tid=643845)
75
+ I, [2015-01-10T20:32:25.019271 #21457] INFO -- : FeedTorrents::Feed::List#process: Processing: [HorribleSubs] Magic Kaito 1412 - 13 [1080p].mkv
76
+ I, [2015-01-10T20:32:25.019460 #21457] INFO -- : FeedTorrents::Feed::Download#process: Downloading torrent for '[HorribleSubs] Magic Kaito 1412 - 13 [1080p].mkv' (http://www.nyaa.se/?page=download&tid=643830)
77
+ I, [2015-01-10T20:32:25.032232 #21457] INFO -- : FeedTorrents::Feed::List#process: Processing: [HorribleSubs] Magic Kaito 1412 - 12 [1080p].mkv
78
+ I, [2015-01-10T20:32:25.032379 #21457] INFO -- : FeedTorrents::Feed::Download#process: Downloading torrent for '[HorribleSubs] Magic Kaito 1412 - 12 [1080p].mkv' (http://www.nyaa.se/?page=download&tid=643758)
79
+ I, [2015-01-10T20:32:25.047954 #21457] INFO -- : FeedTorrents::Feed::List#process: Processing: [DeadFish] Beast Saga - 23 [720p][AAC].mp4
80
+ I, [2015-01-10T20:32:25.048285 #21457] INFO -- : FeedTorrents::Feed::Download#process: Downloading torrent for '[DeadFish] Beast Saga - 23 [720p][AAC].mp4' (http://www.nyaa.se/?page=download&tid=643723)
81
+ I, [2015-01-10T20:32:25.061514 #21457] INFO -- : FeedTorrents::Feed::List#process: Processing: [DeadFish] Fairy Tail &#40;2014&#41; - 40 [720p][AAC].mp4
82
+ I, [2015-01-10T20:32:25.061733 #21457] INFO -- : FeedTorrents::Feed::Download#process: Downloading torrent for '[DeadFish] Fairy Tail &#40;2014&#41; - 40 [720p][AAC].mp4' (http://www.nyaa.se/?page=download&tid=643722)
83
+ I, [2015-01-10T20:32:25.094340 #21457] INFO -- : FeedTorrents::Feed::List#process: Processing: [HorribleSubs] Fairy Tail S2 - 40 [720p].mkv
84
+ I, [2015-01-10T20:32:25.094561 #21457] INFO -- : FeedTorrents::Feed::Download#process: Downloading torrent for '[HorribleSubs] Fairy Tail S2 - 40 [720p].mkv' (http://www.nyaa.se/?page=download&tid=643668)
85
+ I, [2015-01-10T20:32:25.108556 #21457] INFO -- : FeedTorrents::Feed::List#process: Processing: [DeadFish] Military! - 01v2 [720p][AAC].mp4
86
+ I, [2015-01-10T20:32:25.108750 #21457] INFO -- : FeedTorrents::Feed::Download#process: Downloading torrent for '[DeadFish] Military! - 01v2 [720p][AAC].mp4' (http://www.nyaa.se/?page=download&tid=643646)
87
+ I, [2015-01-10T20:32:25.275709 #21457] INFO -- : FeedTorrents::Feed::Download#block in process: Downloading torrent for American Horror Story 4x10 Orphans 720p completed
88
+ I, [2015-01-10T20:32:25.289581 #21457] INFO -- : FeedTorrents::Feed::Download#block in process: Downloading torrent for [DeadFish] Beast Saga - 23 [720p][AAC].mp4 completed
89
+ I, [2015-01-10T20:32:25.337757 #21457] INFO -- : FeedTorrents::Feed::Download#block in process: Downloading torrent for [DeadFish] Military! - 01v2 [720p][AAC].mp4 completed
90
+ I, [2015-01-10T20:32:25.345284 #21457] INFO -- : FeedTorrents::Feed::Download#block in process: Downloading torrent for [DeadFish] Tokyo Ghoul √A - 01 [720p][AAC].mp4 completed
91
+ I, [2015-01-10T20:32:25.394842 #21457] INFO -- : FeedTorrents::Feed::Download#block in process: Downloading torrent for [DeadFish] Fairy Tail &#40;2014&#41; - 40 [720p][AAC].mp4 completed
92
+ I, [2015-01-10T20:32:25.413424 #21457] INFO -- : FeedTorrents::Feed::Download#block in process: Downloading torrent for [HorribleSubs] Fairy Tail S2 - 40 [720p].mkv completed
93
+ I, [2015-01-10T20:32:25.441256 #21457] INFO -- : FeedTorrents::Feed::Download#block in process: Downloading torrent for [HorribleSubs] Magic Kaito 1412 - 06 [1080p].mkv completed
94
+ I, [2015-01-10T20:32:25.445882 #21457] INFO -- : FeedTorrents::Feed::Download#block in process: Downloading torrent for [HorribleSubs] Magic Kaito 1412 - 13 [1080p].mkv completed
95
+ I, [2015-01-10T20:32:25.468350 #21457] INFO -- : FeedTorrents::Feed::Download#block in process: Downloading torrent for [HorribleSubs] Magic Kaito 1412 - 05 [1080p].mkv completed
96
+ I, [2015-01-10T20:32:25.475861 #21457] INFO -- : FeedTorrents::Feed::Download#block in process: Downloading torrent for [HorribleSubs] Magic Kaito 1412 - 12 [1080p].mkv completed
97
+ I, [2015-01-10T20:32:30.767287 #21457] INFO -- : FeedTorrents::Feed::Download#block in process: Downloading torrent for American Horror Story 4x11 Magical Thinking 720p completed
98
+ ```
99
+
100
+ My qbittorrent-nox headless torrent client with webui loves this!
101
+
102
+ ## Upstart script
103
+
104
+ Tested this on my ubuntu-14.04 server.
105
+ Put these contents in /etc/init/feed_torrents.conf:
106
+ ```bash
107
+ start on (started networking)
108
+ stop on runlevel [!023456]
109
+
110
+ setuid tom
111
+ setgid tom
112
+
113
+ exec /usr/local/bin/feed_torrents /tmp/feed_torrents.yml
114
+ ```
115
+
116
+ And start it
117
+
118
+ ```bash
119
+ sudo start feed_torrents
120
+ ```
121
+
122
+ ## Issues
123
+
124
+ If you have found a bug then please raise an issue here on github.
125
+
126
+ ## Authors
127
+
128
+ - [Tom van Leeuwen](http://github.com/TvL2386) - Initial author.
129
+
130
+ ## Copyright
131
+
132
+ Copyright (c) 2015 Tom van Leeuwen
133
+
134
+ See LICENSE.txt for details.
data/Rakefile ADDED
@@ -0,0 +1,36 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+
5
+ begin
6
+ require 'bundler'
7
+ rescue LoadError => e
8
+ warn e.message
9
+ warn "Run `gem install bundler` to install Bundler."
10
+ exit -1
11
+ end
12
+
13
+ begin
14
+ Bundler.setup(:development)
15
+ rescue Bundler::BundlerError => e
16
+ warn e.message
17
+ warn "Run `bundle install` to install missing gems."
18
+ exit e.status_code
19
+ end
20
+
21
+ require 'rake'
22
+
23
+ require 'rubygems/tasks'
24
+ Gem::Tasks.new
25
+
26
+ require 'rdoc/task'
27
+ RDoc::Task.new do |rdoc|
28
+ rdoc.title = "feed_torrents"
29
+ end
30
+ task :doc => :rdoc
31
+
32
+ require 'rspec/core/rake_task'
33
+ RSpec::Core::RakeTask.new
34
+
35
+ task :test => :spec
36
+ task :default => :spec
data/bin/feed_torrents ADDED
@@ -0,0 +1,25 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ root = File.expand_path(File.join(File.dirname(__FILE__),'..'))
4
+ if File.directory?(File.join(root,'.git'))
5
+ Dir.chdir(root) do
6
+ begin
7
+ require 'bundler/setup'
8
+ rescue LoadError => e
9
+ warn e.message
10
+ warn "Run `gem install bundler` to install Bundler"
11
+ exit -1
12
+ end
13
+ end
14
+ end
15
+
16
+ require 'feed_torrents'
17
+
18
+ if ARGV.length != 1
19
+ puts "Usage: #{$0} <configfile>"
20
+ exit 1
21
+ else
22
+ FeedTorrents.configuration.yaml_from_file ARGV[0]
23
+ end
24
+
25
+ FeedTorrents::Reactor.start!
@@ -0,0 +1,35 @@
1
+ log:
2
+ :out: STDOUT # or some file path
3
+ :rotate: 5
4
+ :size: 10485760 # 10MB
5
+ :level: INFO
6
+ :format: '%Y-%m-%d %H:%M:%S'
7
+
8
+ datastore: /tmp/feed_torrents.store
9
+
10
+ # Default configuration items for a feed
11
+ default_feed: &default_feed
12
+ :enabled: true
13
+ :interval: 900 # 900 seconds is 15 minutes
14
+ :timeout: 30
15
+ :directory: /tmp/incoming_torrents
16
+ :regex_filters:
17
+ - '.*'
18
+
19
+ # Interval is in seconds
20
+ feeds:
21
+ showrss:
22
+ <<: *default_feed
23
+ :url: 'http://showrss.info/rss.php?user_id=0000'
24
+ :interval: 900
25
+ :enabled: true
26
+
27
+ tokyo_ghoul_s2:
28
+ <<: *default_feed
29
+ :url: 'http://www.nyaa.se/?page=rss&cats=1_37'
30
+ :interval: 1800
31
+ :enabled: true
32
+ :regex_filters:
33
+ - 'HorribleSubs.*Fairy Tail S2 .*720p'
34
+ - 'HorribleSubs.*Magic Kaito .*1080p'
35
+ - '\[DeadFish\]'
@@ -0,0 +1,27 @@
1
+ require File.expand_path('../lib/feed_torrents/version', __FILE__)
2
+
3
+ Gem::Specification.new do |gem|
4
+ gem.name = "feed_torrents"
5
+ gem.version = FeedTorrents::VERSION
6
+ gem.summary = %q{Follow configurable feeds and download torrents, even from magnet urls}
7
+ gem.description = %q{Follow configurable feeds and download torrents, even from magnet urls}
8
+ gem.license = "MIT"
9
+ gem.authors = ["Tom van Leeuwen"]
10
+ gem.email = "tom@vleeuwen.eu"
11
+ gem.homepage = "https://rubygems.org/gems/feed_torrents"
12
+
13
+ gem.files = `git ls-files`.split($/)
14
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
15
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
16
+ gem.require_paths = ['lib']
17
+
18
+ gem.add_dependency 'eventmachine', '~> 1.0'
19
+ gem.add_dependency 'simple-rss', '~> 1.3'
20
+ gem.add_dependency 'em-http-request', '~> 1.1'
21
+
22
+ gem.add_development_dependency 'bundler', '~> 1.5'
23
+ gem.add_development_dependency 'rake', '~> 10.4'
24
+ gem.add_development_dependency 'rdoc', '~> 4.1'
25
+ gem.add_development_dependency 'rspec', '~> 3.1'
26
+ gem.add_development_dependency 'rubygems-tasks', '~> 0.2'
27
+ end
@@ -0,0 +1,54 @@
1
+ require 'singleton'
2
+ require 'ostruct'
3
+ require 'yaml'
4
+ require 'logger'
5
+ require 'pstore'
6
+
7
+ module FeedTorrents
8
+ def self.configuration
9
+ Configuration.instance
10
+ end
11
+
12
+ def self.logger
13
+ configuration.logger
14
+ end
15
+
16
+ class Configuration
17
+ include Singleton
18
+
19
+ def yaml_from_file(file)
20
+ set_config YAML.load_file(File.expand_path(file))
21
+ nil
22
+ end
23
+
24
+ def set_config(hash)
25
+ @source = OpenStruct.new(hash)
26
+ end
27
+
28
+ def logger
29
+ @logger ||= create_logger
30
+ end
31
+
32
+ def method_missing(method, *args, &block)
33
+ @source.send(method, *args, &block)
34
+ end
35
+
36
+ private
37
+
38
+ def source
39
+ @source ||= OpenStruct.new
40
+ end
41
+
42
+ def create_logger
43
+ if self.log and self.log[:out] == 'STDOUT'
44
+ obj = Logger.new(STDOUT)
45
+ else
46
+ obj = Logger.new(File.expand_path(self.log[:out]), self.log[:rotate], self.log[:size])
47
+ obj.level = Logger.const_get(self.log[:level])
48
+ obj.datetime_format = self.log[:format]
49
+ end
50
+
51
+ obj
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,54 @@
1
+ require 'pathname'
2
+
3
+ module FeedTorrents
4
+ module Feed
5
+ class Download
6
+ include LogFunctions
7
+
8
+ def initialize(title, link, timeout, directory)
9
+ @title, @link, @timeout, @directory = title, link, timeout, directory
10
+ end
11
+
12
+ def process
13
+ info "Downloading torrent for '#{@title}' (#{torrent_link})"
14
+ http = EM::HttpRequest.new(torrent_link, inactivity_timeout: @timeout).get
15
+ fh = File.new(file,'wb')
16
+
17
+ http.stream { |chunk| fh.write chunk }
18
+
19
+ http.errback do
20
+ error "failure retrieving torrent for '#{@title}' (#{torrent_link})"
21
+ end
22
+
23
+ http.callback do
24
+ info "Downloading torrent for #{@title} completed"
25
+ fh.close
26
+ FeedTorrents.store.persist(@link)
27
+ end
28
+ end
29
+
30
+ private
31
+
32
+ def torrent_link
33
+ @torrent_link ||= determine_link
34
+ end
35
+
36
+ def determine_link
37
+ if is_magnet?
38
+ MagnetURI.new(@link).reflektor_link
39
+ else
40
+ @link
41
+ end
42
+ end
43
+
44
+ def is_magnet?
45
+ @link =~ /^magnet:\?/
46
+ end
47
+
48
+ def file
49
+ Pathname.new(@directory).join("#{@title}.torrent").expand_path
50
+ end
51
+ end
52
+ end
53
+ end
54
+
@@ -0,0 +1,21 @@
1
+ module FeedTorrents
2
+ module Feed
3
+ class Factory
4
+ include LogFunctions
5
+
6
+ def initialize
7
+ end
8
+
9
+ def lists
10
+ return @lists if defined?(@lists)
11
+
12
+ @lists = Array.new
13
+ FeedTorrents.configuration.feeds.each do |name,options|
14
+ @lists << List.new(name, options)
15
+ end
16
+
17
+ @lists
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,87 @@
1
+ require 'simple-rss'
2
+ require 'em-http'
3
+
4
+ module FeedTorrents
5
+ module Feed
6
+ class List
7
+ include LogFunctions
8
+
9
+ attr_reader :name
10
+
11
+ def initialize(name, options)
12
+ @name = name
13
+ @options = options
14
+
15
+ info "#{name} (enabled: #{enabled?} interval: #{interval} link: #{url})"
16
+ end
17
+
18
+ def interval
19
+ @options[:interval].to_i >= 1 ? @options[:interval].to_i : 3600
20
+ end
21
+
22
+ def enabled?
23
+ @options[:enabled]
24
+ end
25
+
26
+ def download_new_items
27
+ info "feed #{name}"
28
+
29
+ case url
30
+ when /^file:\/\/(.*)$/
31
+ process_raw(File.read($1))
32
+ when /^https?:\/\//
33
+ http = EM::HttpRequest.new(url, inactivity_timeout: timeout).get
34
+
35
+ http.errback do
36
+ error "failure retrieving #{name}"
37
+ end
38
+
39
+ http.callback do
40
+ process_raw http.response
41
+ end
42
+ end
43
+ end
44
+
45
+ private
46
+
47
+ def url
48
+ @options[:url]
49
+ end
50
+
51
+ def timeout
52
+ @options[:timeout].to_i || 30
53
+ end
54
+
55
+ def process_raw(contents)
56
+ rss = SimpleRSS.parse contents
57
+
58
+ rss.items.each do |item|
59
+ link = CGI.unescapeHTML(item.link)
60
+ process(item.title, link) if !already_processed?(link) and matches_filter?(item.title)
61
+ end
62
+ end
63
+
64
+ def process(title, link)
65
+ info "Processing: #{title}"
66
+
67
+ Download.new(title, link, timeout, @options[:directory]).process
68
+ end
69
+
70
+ def regex_filters
71
+ @options[:regex_filters].map { |regex| /#{regex}/ }
72
+ end
73
+
74
+ def matches_filter?(title)
75
+ regex_filters.each do |filter|
76
+ return true if title =~ filter
77
+ end
78
+
79
+ false
80
+ end
81
+
82
+ def already_processed?(item)
83
+ FeedTorrents.store.present?(item)
84
+ end
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,33 @@
1
+ # Blatently copied from: https://github.com/prep/magnet-uri
2
+
3
+ require 'cgi'
4
+ require 'uri'
5
+
6
+ module FeedTorrents
7
+ module Feed
8
+ class MagnetURI
9
+ def initialize(uri)
10
+ raise ArgumentError, 'bad argument (expected magnet URI)' unless uri =~ /^magnet:\?/
11
+
12
+ uri = CGI.unescapeHTML(uri)
13
+
14
+ scheme, params = uri.split('?', 2)
15
+
16
+ @params = {}.tap do |param|
17
+ CGI.parse(URI.decode(params)).each do |name, value|
18
+ name = name.to_sym
19
+ value = (value.size == 1 ? value.first : value)
20
+
21
+ param[name] = value
22
+ end
23
+ end
24
+
25
+ @info_hash = @params[:xt].split(':').last
26
+ end
27
+
28
+ def reflektor_link
29
+ "http://reflektor.karmorra.info/torrent/#{@info_hash}.torrent"
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,18 @@
1
+ module FeedTorrents
2
+ module LogFunctions
3
+ def log
4
+ FeedTorrents.logger
5
+ end
6
+
7
+ def log_caller
8
+ caller[1][/`.*'/][1..-2]
9
+ end
10
+
11
+ [:debug, :info, :warn, :error, :fatal].each do |sym|
12
+ define_method(sym) do |arg|
13
+ arg = "#{self.class.to_s}##{log_caller}: #{arg}"
14
+ log.send(sym, arg)
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,62 @@
1
+ require 'eventmachine'
2
+
3
+ module FeedTorrents
4
+ class Reactor
5
+ include LogFunctions
6
+
7
+ def self.start!
8
+ new.start
9
+ end
10
+
11
+ def initialize
12
+ info "Initialize new Reactor version #{FeedTorrents::VERSION}"
13
+ end
14
+
15
+ def start
16
+ info 'Starting eventmachine loop'
17
+
18
+ EventMachine.run do
19
+ factory.lists.each do |list|
20
+ next unless list.enabled?
21
+
22
+ EM.add_periodic_timer(list.interval) { list.download_new_items }
23
+
24
+ EM.schedule { list.download_new_items }
25
+ end
26
+
27
+ EM.add_periodic_timer(1800) { debug '-- MARK --' }
28
+
29
+ EM.add_periodic_timer(3600) do
30
+ FeedTorrents.store.prune
31
+ end
32
+
33
+ # EM.add_timer(3) do
34
+ # puts 'I waited 3 seconds'
35
+ # # EM.stop_event_loop
36
+ # end
37
+
38
+ stop_block = Proc.new do
39
+ EM.add_timer(0) do
40
+ EventMachine.stop
41
+ end
42
+ end
43
+
44
+ Signal.trap('INT') do
45
+ info 'received sigint signal'
46
+ stop_block.call
47
+ end
48
+
49
+ Signal.trap('TERM') do
50
+ info 'received sigterm signal'
51
+ stop_block.call
52
+ end
53
+ end
54
+ end
55
+
56
+ private
57
+
58
+ def factory
59
+ @factory ||= Feed::Factory.new
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,51 @@
1
+ require 'pstore'
2
+
3
+ module FeedTorrents
4
+ def self.store
5
+ Store.instance
6
+ end
7
+
8
+ class Store
9
+ include Singleton
10
+ include LogFunctions
11
+
12
+ def present?(item)
13
+ pstore.transaction(true) { return !!pstore[item] }
14
+ end
15
+
16
+ def persist(item)
17
+ pstore.transaction { pstore[item] = Time.now.to_i }
18
+ end
19
+
20
+ def prune
21
+ prune_count = 0
22
+
23
+ pstore.transaction do
24
+ pstore.roots.each do |item|
25
+ if outdated?(item)
26
+ pstore.delete(item)
27
+ prune_count += 1
28
+ end
29
+ end
30
+ end
31
+
32
+ if prune_count > 0
33
+ info "Pruned #{prune_count} items"
34
+ end
35
+ end
36
+
37
+ private
38
+
39
+ def pstore
40
+ @pstore ||= PStore.new(pstore_file)
41
+ end
42
+
43
+ def pstore_file
44
+ File.expand_path(FeedTorrents.configuration.datastore)
45
+ end
46
+
47
+ def outdated?(time)
48
+ (Time.now.to_i - time < 7776000) # older than 90 days is outdated
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,4 @@
1
+ module FeedTorrents
2
+ # feed_torrents version
3
+ VERSION = "0.1.0"
4
+ end
@@ -0,0 +1,11 @@
1
+ require 'feed_torrents/log_functions'
2
+ require 'feed_torrents/configuration'
3
+
4
+ require 'feed_torrents/version'
5
+ require 'feed_torrents/store'
6
+ require 'feed_torrents/reactor'
7
+
8
+ require 'feed_torrents/feed/factory'
9
+ require 'feed_torrents/feed/list'
10
+ require 'feed_torrents/feed/download'
11
+ require 'feed_torrents/feed/magnet-uri'
@@ -0,0 +1,8 @@
1
+ require 'spec_helper'
2
+ require 'feed_torrents'
3
+
4
+ describe FeedTorrents do
5
+ it "should have a VERSION constant" do
6
+ subject.const_get('VERSION').should_not be_empty
7
+ end
8
+ end
@@ -0,0 +1,4 @@
1
+ require 'rspec'
2
+ require 'feed_torrents/version'
3
+
4
+ include FeedTorrents
metadata ADDED
@@ -0,0 +1,181 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: feed_torrents
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Tom van Leeuwen
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-01-10 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: eventmachine
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: simple-rss
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.3'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.3'
41
+ - !ruby/object:Gem::Dependency
42
+ name: em-http-request
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.1'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.1'
55
+ - !ruby/object:Gem::Dependency
56
+ name: bundler
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '1.5'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '1.5'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rake
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '10.4'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '10.4'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rdoc
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '4.1'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '4.1'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rspec
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '3.1'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '3.1'
111
+ - !ruby/object:Gem::Dependency
112
+ name: rubygems-tasks
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '0.2'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '0.2'
125
+ description: Follow configurable feeds and download torrents, even from magnet urls
126
+ email: tom@vleeuwen.eu
127
+ executables:
128
+ - feed_torrents
129
+ extensions: []
130
+ extra_rdoc_files: []
131
+ files:
132
+ - ".document"
133
+ - ".gitignore"
134
+ - ".rspec"
135
+ - ChangeLog.rdoc
136
+ - Gemfile
137
+ - LICENSE.txt
138
+ - README.md
139
+ - Rakefile
140
+ - bin/feed_torrents
141
+ - examples/feed_torrents.yml
142
+ - feed_torrents.gemspec
143
+ - lib/feed_torrents.rb
144
+ - lib/feed_torrents/configuration.rb
145
+ - lib/feed_torrents/feed/download.rb
146
+ - lib/feed_torrents/feed/factory.rb
147
+ - lib/feed_torrents/feed/list.rb
148
+ - lib/feed_torrents/feed/magnet-uri.rb
149
+ - lib/feed_torrents/log_functions.rb
150
+ - lib/feed_torrents/reactor.rb
151
+ - lib/feed_torrents/store.rb
152
+ - lib/feed_torrents/version.rb
153
+ - spec/feed_torrents_spec.rb
154
+ - spec/spec_helper.rb
155
+ homepage: https://rubygems.org/gems/feed_torrents
156
+ licenses:
157
+ - MIT
158
+ metadata: {}
159
+ post_install_message:
160
+ rdoc_options: []
161
+ require_paths:
162
+ - lib
163
+ required_ruby_version: !ruby/object:Gem::Requirement
164
+ requirements:
165
+ - - ">="
166
+ - !ruby/object:Gem::Version
167
+ version: '0'
168
+ required_rubygems_version: !ruby/object:Gem::Requirement
169
+ requirements:
170
+ - - ">="
171
+ - !ruby/object:Gem::Version
172
+ version: '0'
173
+ requirements: []
174
+ rubyforge_project:
175
+ rubygems_version: 2.2.0
176
+ signing_key:
177
+ specification_version: 4
178
+ summary: Follow configurable feeds and download torrents, even from magnet urls
179
+ test_files:
180
+ - spec/feed_torrents_spec.rb
181
+ - spec/spec_helper.rb