transmission-rss 0.1.14 → 0.1.16
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.
- checksums.yaml +4 -4
- data/README.md +0 -1
- data/bin/transmission-rss +13 -8
- data/lib/transmission-rss.rb +1 -1
- data/lib/transmission-rss/aggregator.rb +80 -88
- data/lib/transmission-rss/callback.rb +19 -0
- data/lib/transmission-rss/client.rb +55 -51
- data/lib/transmission-rss/config.rb +18 -16
- data/lib/transmission-rss/log.rb +17 -15
- metadata +24 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 4799fb595553fef0cf552adf93216b4ce6c7d265
|
|
4
|
+
data.tar.gz: 64c6d7ffb5dca02e58195b27bd0185ef321773e7
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 452d464189a7d4df88827296741410572f5550aa96c8ed684e8cda79f37296dddc01c01757e074a6c31fb85fbba2d04e5783f2a06e9aa66a9c7f5e4f157e40ce
|
|
7
|
+
data.tar.gz: e3ed1575e0b955b4be00ecd0f724b351036d06ea6026af5b390781598f4c17e09e59f42073ea05079559edd713ab9d32c6c7ca790d468265933a0c25c31e97f2
|
data/README.md
CHANGED
data/bin/transmission-rss
CHANGED
|
@@ -19,13 +19,14 @@ pid_file = false
|
|
|
19
19
|
|
|
20
20
|
# Shows a summary of the command line options.
|
|
21
21
|
def usage_message(config_file)
|
|
22
|
-
$stderr << "#{File.basename $0} [
|
|
22
|
+
$stderr << "#{File.basename $0} [options]
|
|
23
23
|
Adds torrents from rss feeds to transmission web frontend.
|
|
24
24
|
|
|
25
25
|
-c <file> Custom config file path. Default: #{config_file}
|
|
26
26
|
-f Fork into background after startup.
|
|
27
|
-
-p <file> Write PID to file.
|
|
28
27
|
-h This help.
|
|
28
|
+
-p <file> Write PID to file.
|
|
29
|
+
-v Show program version and exit.
|
|
29
30
|
|
|
30
31
|
"
|
|
31
32
|
exit(1)
|
|
@@ -33,10 +34,11 @@ end
|
|
|
33
34
|
|
|
34
35
|
# Define command-line options.
|
|
35
36
|
options = GetoptLong.new \
|
|
36
|
-
[
|
|
37
|
-
[
|
|
38
|
-
[
|
|
39
|
-
[
|
|
37
|
+
['-c', GetoptLong::REQUIRED_ARGUMENT],
|
|
38
|
+
['-f', GetoptLong::NO_ARGUMENT],
|
|
39
|
+
['-h', GetoptLong::NO_ARGUMENT],
|
|
40
|
+
['-p', GetoptLong::REQUIRED_ARGUMENT],
|
|
41
|
+
['-v', GetoptLong::NO_ARGUMENT]
|
|
40
42
|
|
|
41
43
|
# Parse given options.
|
|
42
44
|
options.each do |option, argument|
|
|
@@ -45,10 +47,13 @@ options.each do |option, argument|
|
|
|
45
47
|
config_file = argument
|
|
46
48
|
when '-f'
|
|
47
49
|
dofork = true
|
|
48
|
-
when '-p'
|
|
49
|
-
pid_file = argument
|
|
50
50
|
when '-h'
|
|
51
51
|
usage_message config_file
|
|
52
|
+
when '-p'
|
|
53
|
+
pid_file = argument
|
|
54
|
+
when '-v'
|
|
55
|
+
puts TransmissionRSS::VERSION
|
|
56
|
+
exit
|
|
52
57
|
end
|
|
53
58
|
end
|
|
54
59
|
|
data/lib/transmission-rss.rb
CHANGED
|
@@ -1,115 +1,107 @@
|
|
|
1
1
|
require 'etc'
|
|
2
2
|
require 'fileutils'
|
|
3
3
|
require 'open-uri'
|
|
4
|
+
require 'open_uri_redirections'
|
|
4
5
|
require 'rss'
|
|
5
6
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
libdir = File.dirname(__FILE__)
|
|
8
|
+
require File.join(libdir, 'log')
|
|
9
|
+
require File.join(libdir, 'callback')
|
|
9
10
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
module TransmissionRSS
|
|
12
|
+
# Class for aggregating torrent files through RSS feeds.
|
|
13
|
+
class Aggregator
|
|
14
|
+
extend Callback
|
|
15
|
+
callback :on_new_item # Declare callback for new items.
|
|
13
16
|
|
|
14
|
-
|
|
15
|
-
@log = Log.instance
|
|
17
|
+
attr_accessor :feeds
|
|
16
18
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
+
def initialize(feeds = [])
|
|
20
|
+
@feeds = feeds
|
|
21
|
+
@seen = []
|
|
19
22
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
Etc.getpwuid.dir,
|
|
23
|
-
'/.config/transmission/seen-torrents.conf'
|
|
23
|
+
# Initialize log instance.
|
|
24
|
+
@log = Log.instance
|
|
24
25
|
|
|
25
|
-
|
|
26
|
-
|
|
26
|
+
# Generate path for seen torrents store file.
|
|
27
|
+
@seenfile = File.join \
|
|
28
|
+
Etc.getpwuid.dir,
|
|
29
|
+
'/.config/transmission/seen-torrents.conf'
|
|
27
30
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
FileUtils.touch @seenfile
|
|
31
|
-
end
|
|
31
|
+
# Make directories in path if they are not existing.
|
|
32
|
+
FileUtils.mkdir_p File.dirname(@seenfile)
|
|
32
33
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
34
|
+
# Touch seen torrents store file.
|
|
35
|
+
unless File.exists? @seenfile
|
|
36
|
+
FileUtils.touch @seenfile
|
|
37
|
+
end
|
|
37
38
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
39
|
+
# Open file, read torrent URLs and add to +@seen+.
|
|
40
|
+
open(@seenfile).readlines.each do |line|
|
|
41
|
+
@seen.push line.chomp
|
|
42
|
+
end
|
|
41
43
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
44
|
+
# Log number of +@seen+ URIs.
|
|
45
|
+
@log.debug @seen.size.to_s + ' uris from seenfile'
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Get file enclosures from all feeds items and call on_new_item callback
|
|
49
|
+
# with torrent file URL as argument.
|
|
50
|
+
def run(interval = 600)
|
|
51
|
+
@log.debug 'aggregator start'
|
|
52
|
+
|
|
53
|
+
while true
|
|
54
|
+
feeds.each do |url|
|
|
55
|
+
url = URI.encode(url)
|
|
56
|
+
@log.debug 'aggregate ' + url
|
|
57
|
+
|
|
58
|
+
begin
|
|
59
|
+
content = open(url, allow_redirections: :safe).read
|
|
60
|
+
items = RSS::Parser.parse(content, false).items
|
|
61
|
+
rescue Exception => e
|
|
62
|
+
@log.debug "retrieval error (#{e.message})"
|
|
63
|
+
next
|
|
64
|
+
end
|
|
58
65
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
#
|
|
75
|
-
|
|
76
|
-
|
|
66
|
+
items.each do |item|
|
|
67
|
+
link = item.enclosure.url rescue item.link
|
|
68
|
+
|
|
69
|
+
# Item contains no link.
|
|
70
|
+
next if link.nil?
|
|
71
|
+
|
|
72
|
+
# Link is not a String directly.
|
|
73
|
+
link = link.href if link.class != String
|
|
74
|
+
|
|
75
|
+
# The link is not in +@seen+ Array.
|
|
76
|
+
unless seen? link
|
|
77
|
+
@log.debug 'on_new_item event ' + link
|
|
78
|
+
begin
|
|
79
|
+
on_new_item link
|
|
80
|
+
rescue Errno::ECONNREFUSED
|
|
81
|
+
# @log.debug 'not added to seenfile'
|
|
82
|
+
else
|
|
83
|
+
add_seen link
|
|
84
|
+
end
|
|
77
85
|
end
|
|
78
86
|
end
|
|
79
87
|
end
|
|
80
|
-
end
|
|
81
88
|
|
|
82
|
-
|
|
89
|
+
sleep interval
|
|
90
|
+
end
|
|
83
91
|
end
|
|
84
|
-
end
|
|
85
92
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
93
|
+
# To add a link into the list of seen links.
|
|
94
|
+
def add_seen(link)
|
|
95
|
+
@seen.push link
|
|
89
96
|
|
|
90
|
-
|
|
91
|
-
|
|
97
|
+
File.open(@seenfile, 'w') do |file|
|
|
98
|
+
file.write @seen.join("\n")
|
|
99
|
+
end
|
|
92
100
|
end
|
|
93
|
-
end
|
|
94
101
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
end
|
|
99
|
-
|
|
100
|
-
# Method to define callback methods.
|
|
101
|
-
def callback(*names)
|
|
102
|
-
names.each do |name|
|
|
103
|
-
eval <<-EOF
|
|
104
|
-
@#{name} = false
|
|
105
|
-
def #{name}(*args, &block)
|
|
106
|
-
if block
|
|
107
|
-
@#{name} = block
|
|
108
|
-
elsif @#{name}
|
|
109
|
-
@#{name}.call *args
|
|
110
|
-
end
|
|
111
|
-
end
|
|
112
|
-
EOF
|
|
102
|
+
# To test if a link is in the list of seen links.
|
|
103
|
+
def seen?(link)
|
|
104
|
+
@seen.include? link
|
|
113
105
|
end
|
|
114
106
|
end
|
|
115
107
|
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
module TransmissionRSS
|
|
2
|
+
module Callback
|
|
3
|
+
# Define callback method.
|
|
4
|
+
def callback(*names)
|
|
5
|
+
names.each do |name|
|
|
6
|
+
self.class_eval do
|
|
7
|
+
define_method name, ->(*args, &block) do
|
|
8
|
+
@callbacks ||= {}
|
|
9
|
+
if block
|
|
10
|
+
@callbacks[name] = block
|
|
11
|
+
elsif @callbacks[name]
|
|
12
|
+
@callbacks[name].call *args
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -2,72 +2,76 @@ require 'net/http'
|
|
|
2
2
|
require 'json'
|
|
3
3
|
require 'base64'
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
class TransmissionRSS::Client
|
|
7
|
-
def initialize(host = 'localhost', port = 9091, timeout: 5)
|
|
8
|
-
@host, @port, @timeout = host, port, timeout
|
|
9
|
-
@log = Log.instance
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
# POST json packed torrent add command.
|
|
13
|
-
def add_torrent(file, type, paused = false)
|
|
14
|
-
hash = {
|
|
15
|
-
'method' => 'torrent-add',
|
|
16
|
-
'arguments' => {
|
|
17
|
-
'paused' => paused
|
|
18
|
-
}
|
|
19
|
-
}
|
|
5
|
+
require File.join(File.dirname(__FILE__), 'log')
|
|
20
6
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
raise ArgumentError.new 'type has to be :url or :file.'
|
|
7
|
+
module TransmissionRSS
|
|
8
|
+
# Class for communication with transmission utilizing the RPC web interface.
|
|
9
|
+
class Client
|
|
10
|
+
def initialize(host = 'localhost', port = 9091, timeout: 5)
|
|
11
|
+
@host, @port, @timeout = host, port, timeout
|
|
12
|
+
@log = TransmissionRSS::Log.instance
|
|
28
13
|
end
|
|
29
14
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
'
|
|
34
|
-
'
|
|
15
|
+
# POST json packed torrent add command.
|
|
16
|
+
def add_torrent(file, type, paused = false)
|
|
17
|
+
hash = {
|
|
18
|
+
'method' => 'torrent-add',
|
|
19
|
+
'arguments' => {
|
|
20
|
+
'paused' => paused
|
|
21
|
+
}
|
|
35
22
|
}
|
|
36
23
|
|
|
37
|
-
|
|
24
|
+
case type
|
|
25
|
+
when :url
|
|
26
|
+
hash.arguments.filename = file
|
|
27
|
+
when :file
|
|
28
|
+
hash.arguments.metainfo = Base64.encode64(File.read(file))
|
|
29
|
+
else
|
|
30
|
+
raise ArgumentError.new 'type has to be :url or :file.'
|
|
31
|
+
end
|
|
38
32
|
|
|
39
|
-
|
|
33
|
+
post = Net::HTTP::Post.new \
|
|
34
|
+
'/transmission/rpc',
|
|
35
|
+
initheader = {
|
|
36
|
+
'Content-Type' => 'application/json',
|
|
37
|
+
'X-Transmission-Session-Id' => get_session_id
|
|
38
|
+
}
|
|
40
39
|
|
|
41
|
-
|
|
40
|
+
post.body = hash.to_json
|
|
42
41
|
|
|
43
|
-
|
|
44
|
-
end
|
|
42
|
+
response = request post
|
|
45
43
|
|
|
46
|
-
|
|
47
|
-
def get_session_id
|
|
48
|
-
get = Net::HTTP::Get.new '/transmission/rpc'
|
|
49
|
-
response = request get
|
|
44
|
+
result = JSON.parse(response.body).result
|
|
50
45
|
|
|
51
|
-
|
|
46
|
+
@log.debug 'add_torrent result: ' + result
|
|
47
|
+
end
|
|
52
48
|
|
|
53
|
-
|
|
49
|
+
# Get transmission session id.
|
|
50
|
+
def get_session_id
|
|
51
|
+
get = Net::HTTP::Get.new '/transmission/rpc'
|
|
52
|
+
response = request get
|
|
54
53
|
|
|
55
|
-
|
|
56
|
-
|
|
54
|
+
id = response.header['x-transmission-session-id']
|
|
55
|
+
|
|
56
|
+
@log.debug 'got session id ' + id
|
|
57
|
+
|
|
58
|
+
id
|
|
59
|
+
end
|
|
57
60
|
|
|
58
|
-
|
|
61
|
+
private
|
|
59
62
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
63
|
+
def request(data)
|
|
64
|
+
Timeout::timeout(@timeout) do
|
|
65
|
+
Net::HTTP.new(@host, @port).start do |http|
|
|
66
|
+
http.request data
|
|
67
|
+
end
|
|
64
68
|
end
|
|
69
|
+
rescue Errno::ECONNREFUSED
|
|
70
|
+
@log.debug 'connection refused'
|
|
71
|
+
raise
|
|
72
|
+
rescue Timeout::Error
|
|
73
|
+
@log.debug 'connection timeout'
|
|
74
|
+
raise
|
|
65
75
|
end
|
|
66
|
-
rescue Errno::ECONNREFUSED
|
|
67
|
-
@log.debug 'connection refused'
|
|
68
|
-
raise
|
|
69
|
-
rescue Timeout::Error
|
|
70
|
-
@log.debug 'connection timeout'
|
|
71
|
-
raise
|
|
72
76
|
end
|
|
73
77
|
end
|
|
@@ -1,25 +1,27 @@
|
|
|
1
1
|
require 'singleton'
|
|
2
2
|
require 'yaml'
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
module TransmissionRSS
|
|
5
|
+
# Class handles configuration parameters.
|
|
6
|
+
class Config < Hash
|
|
7
|
+
# This is a singleton class.
|
|
8
|
+
include Singleton
|
|
8
9
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
10
|
+
# Merges a Hash or YAML file (containing a Hash) with itself.
|
|
11
|
+
def load(config)
|
|
12
|
+
case config.class.to_s
|
|
13
|
+
when 'Hash'
|
|
14
|
+
self.merge! config
|
|
15
|
+
when 'String'
|
|
16
|
+
self.merge_yaml! config
|
|
17
|
+
else
|
|
18
|
+
raise ArgumentError.new 'Could not load config.'
|
|
19
|
+
end
|
|
14
20
|
end
|
|
15
21
|
|
|
16
|
-
|
|
17
|
-
|
|
22
|
+
# Merge Config Hash with Hash from YAML file.
|
|
23
|
+
def merge_yaml!(path)
|
|
24
|
+
self.merge! YAML.load_file(path)
|
|
18
25
|
end
|
|
19
26
|
end
|
|
20
|
-
|
|
21
|
-
# Merge Config Hash with Hash from YAML file.
|
|
22
|
-
def merge_yaml!(path)
|
|
23
|
-
self.merge! YAML.load_file(path)
|
|
24
|
-
end
|
|
25
27
|
end
|
data/lib/transmission-rss/log.rb
CHANGED
|
@@ -1,24 +1,26 @@
|
|
|
1
1
|
require 'logger'
|
|
2
2
|
require 'singleton'
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
class
|
|
6
|
-
|
|
4
|
+
module TransmissionRSS
|
|
5
|
+
# Encapsulates Logger as a singleton class.
|
|
6
|
+
class Log
|
|
7
|
+
include Singleton
|
|
7
8
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
# Change log target (IO or path to a file as String).
|
|
10
|
+
def target=(target)
|
|
11
|
+
old_logger = @logger
|
|
12
|
+
@logger = Logger.new target
|
|
12
13
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
if old_logger
|
|
15
|
+
@logger.level = old_logger.level
|
|
16
|
+
@logger.formatter = old_logger.formatter
|
|
17
|
+
end
|
|
16
18
|
end
|
|
17
|
-
end
|
|
18
19
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
20
|
+
# If this class misses a method, call it on the encapsulated Logger class.
|
|
21
|
+
def method_missing(sym, *args)
|
|
22
|
+
@logger ||= Logger.new $stderr
|
|
23
|
+
@logger.send sym, *args
|
|
24
|
+
end
|
|
23
25
|
end
|
|
24
26
|
end
|
metadata
CHANGED
|
@@ -1,15 +1,35 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: transmission-rss
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.16
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- henning mueller
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2014-
|
|
12
|
-
dependencies:
|
|
11
|
+
date: 2014-04-15 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: open_uri_redirections
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - "~>"
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '0.1'
|
|
20
|
+
- - ">="
|
|
21
|
+
- !ruby/object:Gem::Version
|
|
22
|
+
version: 0.1.4
|
|
23
|
+
type: :runtime
|
|
24
|
+
prerelease: false
|
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
26
|
+
requirements:
|
|
27
|
+
- - "~>"
|
|
28
|
+
- !ruby/object:Gem::Version
|
|
29
|
+
version: '0.1'
|
|
30
|
+
- - ">="
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: 0.1.4
|
|
13
33
|
description: |-
|
|
14
34
|
transmission-rss is basically a workaround for
|
|
15
35
|
transmission's lack of the ability to monitor RSS feeds and
|
|
@@ -26,6 +46,7 @@ files:
|
|
|
26
46
|
- bin/transmission-rss
|
|
27
47
|
- lib/transmission-rss.rb
|
|
28
48
|
- lib/transmission-rss/aggregator.rb
|
|
49
|
+
- lib/transmission-rss/callback.rb
|
|
29
50
|
- lib/transmission-rss/client.rb
|
|
30
51
|
- lib/transmission-rss/config.rb
|
|
31
52
|
- lib/transmission-rss/hash.rb
|