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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 920904c2e1205bfbfa74c6baacc111aa545c55d9
4
- data.tar.gz: 1c3c0d44afa9284d4720b7226f9efefa91387427
3
+ metadata.gz: 4799fb595553fef0cf552adf93216b4ce6c7d265
4
+ data.tar.gz: 64c6d7ffb5dca02e58195b27bd0185ef321773e7
5
5
  SHA512:
6
- metadata.gz: efa71a1a7bca7c4a303380311d9611818cc63ea1b366f5489fb2bca248e4d2503141cae312645e268ae51d36674cdf7fcd000349cc27bef5721f4f617edb44fd
7
- data.tar.gz: 6ea5f5a54e3120b4cd5ca03fa821c73cefc6f645fe51964783c036acdb86940b9235fb1ad29b16dee69f5ff393e513c15be4ca92e739d9cc60ead79ce1120267
6
+ metadata.gz: 452d464189a7d4df88827296741410572f5550aa96c8ed684e8cda79f37296dddc01c01757e074a6c31fb85fbba2d04e5783f2a06e9aa66a9c7f5e4f157e40ce
7
+ data.tar.gz: e3ed1575e0b955b4be00ecd0f724b351036d06ea6026af5b390781598f4c17e09e59f42073ea05079559edd713ab9d32c6c7ca790d468265933a0c25c31e97f2
data/README.md CHANGED
@@ -73,6 +73,5 @@ not defined by default, so the script runs as current user/group.
73
73
  TODO
74
74
  ----
75
75
 
76
- * Better library abilities.
77
76
  * Option to stop seeding after full download.
78
77
  * Configurable log level.
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} [option]..
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
- [ '-c', GetoptLong::REQUIRED_ARGUMENT ],
37
- [ '-f', GetoptLong::NO_ARGUMENT ],
38
- [ '-p', GetoptLong::REQUIRED_ARGUMENT ],
39
- [ '-h', GetoptLong::NO_ARGUMENT ]
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
 
@@ -1,7 +1,7 @@
1
1
  $:.unshift(File.dirname(__FILE__))
2
2
 
3
3
  module TransmissionRSS
4
- VERSION = '0.1.14'
4
+ VERSION = '0.1.16'
5
5
  end
6
6
 
7
7
  Dir.glob($:.first + '/**/*.rb').each do |lib|
@@ -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
- # Class for aggregating torrent files through RSS feeds.
7
- class TransmissionRSS::Aggregator
8
- attr_accessor :feeds
7
+ libdir = File.dirname(__FILE__)
8
+ require File.join(libdir, 'log')
9
+ require File.join(libdir, 'callback')
9
10
 
10
- def initialize(feeds = [])
11
- @feeds = feeds
12
- @seen = []
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
- # Initialize log instance.
15
- @log = Log.instance
17
+ attr_accessor :feeds
16
18
 
17
- # Declare callback for new items.
18
- callback :on_new_item
19
+ def initialize(feeds = [])
20
+ @feeds = feeds
21
+ @seen = []
19
22
 
20
- # Generate path for seen torrents store file.
21
- @seenfile = File.join \
22
- Etc.getpwuid.dir,
23
- '/.config/transmission/seen-torrents.conf'
23
+ # Initialize log instance.
24
+ @log = Log.instance
24
25
 
25
- # Make directories in path if they are not existing.
26
- FileUtils.mkdir_p File.dirname(@seenfile)
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
- # Touch seen torrents store file.
29
- unless File.exists? @seenfile
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
- # Open file, read torrent URLs and add to +@seen+.
34
- open(@seenfile).readlines.each do |line|
35
- @seen.push line.chomp
36
- end
34
+ # Touch seen torrents store file.
35
+ unless File.exists? @seenfile
36
+ FileUtils.touch @seenfile
37
+ end
37
38
 
38
- # Log number of +@seen+ URIs.
39
- @log.debug @seen.size.to_s + ' uris from seenfile'
40
- end
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
- # Get file enclosures from all feeds items and call on_new_item callback
43
- # with torrent file URL as argument.
44
- def run(interval = 600)
45
- @log.debug 'aggregator start'
46
-
47
- while true
48
- feeds.each do |url|
49
- @log.debug 'aggregate ' + url
50
-
51
- begin
52
- content = open(url).readlines.join("\n")
53
- items = RSS::Parser.parse(content, false).items
54
- rescue
55
- @log.debug 'retrieval error'
56
- next
57
- end
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
- items.each do |item|
60
- link = item.enclosure.url rescue item.link
61
-
62
- # Item contains no link.
63
- next if link.nil?
64
-
65
- # Link is not a String directly.
66
- link = link.href if link.class != String
67
-
68
- # The link is not in +@seen+ Array.
69
- unless seen? link
70
- @log.debug 'on_new_item event ' + link
71
- begin
72
- on_new_item link
73
- rescue Errno::ECONNREFUSED
74
- # @log.debug 'not added to seenfile'
75
- else
76
- add_seen link
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
- sleep interval
89
+ sleep interval
90
+ end
83
91
  end
84
- end
85
92
 
86
- # To add a link into the list of seen links.
87
- def add_seen(link)
88
- @seen.push link
93
+ # To add a link into the list of seen links.
94
+ def add_seen(link)
95
+ @seen.push link
89
96
 
90
- File.open(@seenfile, 'w') do |file|
91
- file.write @seen.join("\n")
97
+ File.open(@seenfile, 'w') do |file|
98
+ file.write @seen.join("\n")
99
+ end
92
100
  end
93
- end
94
101
 
95
- # To test if a link is in the list of seen links.
96
- def seen?(link)
97
- @seen.include? link
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
- # Class for communication with transmission utilizing the RPC web interface.
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
- case type
22
- when :url
23
- hash.arguments.filename = file
24
- when :file
25
- hash.arguments.metainfo = Base64.encode64(File.read(file))
26
- else
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
- post = Net::HTTP::Post.new \
31
- '/transmission/rpc',
32
- initheader = {
33
- 'Content-Type' => 'application/json',
34
- 'X-Transmission-Session-Id' => get_session_id
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
- post.body = hash.to_json
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
- response = request post
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
- result = JSON.parse(response.body).result
40
+ post.body = hash.to_json
42
41
 
43
- @log.debug 'add_torrent result: ' + result
44
- end
42
+ response = request post
45
43
 
46
- # Get transmission session id.
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
- id = response.header['x-transmission-session-id']
46
+ @log.debug 'add_torrent result: ' + result
47
+ end
52
48
 
53
- @log.debug 'got session id ' + id
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
- id
56
- end
54
+ id = response.header['x-transmission-session-id']
55
+
56
+ @log.debug 'got session id ' + id
57
+
58
+ id
59
+ end
57
60
 
58
- private
61
+ private
59
62
 
60
- def request(data)
61
- Timeout::timeout(@timeout) do
62
- Net::HTTP.new(@host, @port).start do |http|
63
- http.request data
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
- # Class handles configuration parameters.
5
- class TransmissionRSS::Config < Hash
6
- # This is a singleton class.
7
- include Singleton
4
+ module TransmissionRSS
5
+ # Class handles configuration parameters.
6
+ class Config < Hash
7
+ # This is a singleton class.
8
+ include Singleton
8
9
 
9
- # Merges a Hash or YAML file (containing a Hash) with itself.
10
- def load(config)
11
- if config.class == Hash
12
- self.merge! config
13
- return
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
- unless config.nil?
17
- self.merge_yaml! config
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
@@ -1,24 +1,26 @@
1
1
  require 'logger'
2
2
  require 'singleton'
3
3
 
4
- # Encapsulates Logger as a singleton class.
5
- class TransmissionRSS::Log
6
- include Singleton
4
+ module TransmissionRSS
5
+ # Encapsulates Logger as a singleton class.
6
+ class Log
7
+ include Singleton
7
8
 
8
- # Change log target (IO or path to a file as String).
9
- def target=(target)
10
- old_logger = @logger
11
- @logger = Logger.new target
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
- if old_logger
14
- @logger.level = old_logger.level
15
- @logger.formatter = old_logger.formatter
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
- # If this class misses a method, call it on the encapsulated Logger class.
20
- def method_missing(sym, *args)
21
- @logger ||= Logger.new $stderr
22
- @logger.send sym, *args
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.14
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-03-08 00:00:00.000000000 Z
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