transmission-rss 0.1.14 → 0.1.16

Sign up to get free protection for your applications and to get access to all the features.
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