feed_torrents 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.document +4 -0
- data/.gitignore +5 -0
- data/.rspec +1 -0
- data/ChangeLog.rdoc +4 -0
- data/Gemfile +3 -0
- data/LICENSE.txt +20 -0
- data/README.md +134 -0
- data/Rakefile +36 -0
- data/bin/feed_torrents +25 -0
- data/examples/feed_torrents.yml +35 -0
- data/feed_torrents.gemspec +27 -0
- data/lib/feed_torrents/configuration.rb +54 -0
- data/lib/feed_torrents/feed/download.rb +54 -0
- data/lib/feed_torrents/feed/factory.rb +21 -0
- data/lib/feed_torrents/feed/list.rb +87 -0
- data/lib/feed_torrents/feed/magnet-uri.rb +33 -0
- data/lib/feed_torrents/log_functions.rb +18 -0
- data/lib/feed_torrents/reactor.rb +62 -0
- data/lib/feed_torrents/store.rb +51 -0
- data/lib/feed_torrents/version.rb +4 -0
- data/lib/feed_torrents.rb +11 -0
- data/spec/feed_torrents_spec.rb +8 -0
- data/spec/spec_helper.rb +4 -0
- metadata +181 -0
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
data/.gitignore
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--colour --format documentation
|
data/ChangeLog.rdoc
ADDED
data/Gemfile
ADDED
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 (2014) - 40 [720p][AAC].mp4
|
82
|
+
I, [2015-01-10T20:32:25.061733 #21457] INFO -- : FeedTorrents::Feed::Download#process: Downloading torrent for '[DeadFish] Fairy Tail (2014) - 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 (2014) - 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,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'
|
data/spec/spec_helper.rb
ADDED
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
|