transmission-rss 0.1.3 → 0.1.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -62,5 +62,4 @@ defined by default, so the script runs as current user/group.
62
62
 
63
63
  * Timeout and error handling in +Aggregator+ and +Client+
64
64
  * Option to stop seeding after full download
65
- * Privileges configurable by GUI
66
- * Log level
65
+ * Configurable log level
@@ -1,63 +1,56 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- require( 'getoptlong' )
4
- require( 'etc' )
3
+ require 'getoptlong'
4
+ require 'etc'
5
5
 
6
- $:.unshift( File.join( File.dirname( __FILE__ ), '../lib' ) )
7
- require( 'transmission-rss' )
6
+ $:.unshift(File.dirname(__FILE__) + '/../lib')
7
+ require 'transmission-rss'
8
8
 
9
9
  include TransmissionRSS
10
10
 
11
11
  # Default config file path.
12
- configFile = '/etc/transmission-rss.conf'
12
+ config_file = '/etc/transmission-rss.conf'
13
13
 
14
14
  # Do not edit config file in Gtk GUI by default.
15
- editConfig = false
15
+ edit_config = false
16
16
 
17
17
  # Do not fork by default.
18
18
  dofork = false
19
19
 
20
- # Default not verbose.
21
- verbose = false
22
-
23
20
  # Shows a summary of the command line options.
24
- def usageMessage( configFile )
25
- $stderr << "#{File.basename( $0 )} [options]
21
+ def usage_message( config_file )
22
+ $stderr << "#{File.basename($0)} [options]
26
23
  Adds torrents from rss feeds to transmission web frontend.
27
24
 
28
- -c <file> Custom config file path. Default: #{configFile}
25
+ -c <file> Custom config file path. Default: #{config_file}
29
26
  -e Edit config file with Gtk GUI.
30
27
  -f Fork into background after startup.
31
28
  -h This help.
32
- -v Verbose mode.
33
29
 
34
30
  "
35
- exit( 1 )
31
+ exit(1)
36
32
  end
37
33
 
38
34
  # Define command-line options.
39
35
  options = GetoptLong.new(
40
- [ '-c', GetoptLong::REQUIRED_ARGUMENT ],
41
- [ '-e', GetoptLong::NO_ARGUMENT ],
42
- [ '-f', GetoptLong::NO_ARGUMENT ],
43
- [ '-h', GetoptLong::NO_ARGUMENT ],
44
- [ '-v', GetoptLong::NO_ARGUMENT ]
36
+ [ '-c', GetoptLong::REQUIRED_ARGUMENT ],
37
+ [ '-e', GetoptLong::NO_ARGUMENT ],
38
+ [ '-f', GetoptLong::NO_ARGUMENT ],
39
+ [ '-h', GetoptLong::NO_ARGUMENT ]
45
40
  )
46
41
 
47
42
  # Parse given options.
48
43
  options.each do |option, argument|
49
- case( option )
50
- when '-c'
51
- configFile = argument
52
- when '-e'
53
- editConfig = true
54
- when '-f'
55
- dofork = true
56
- when '-h'
57
- usageMessage( configFile )
58
- when '-v'
59
- verbose = true
60
- end
44
+ case(option)
45
+ when '-c'
46
+ config_file = argument
47
+ when '-e'
48
+ edit_config = true
49
+ when '-f'
50
+ dofork = true
51
+ when '-h'
52
+ usage_message(config_file)
53
+ end
61
54
  end
62
55
 
63
56
  # Seems to be necessary when called from gem installation.
@@ -65,96 +58,107 @@ end
65
58
  config = TransmissionRSS::Config.instance
66
59
 
67
60
  # Default configuration.
68
- config.load( {
69
- 'feeds' => [],
70
- 'update_interval' => 600,
71
- 'add_paused' => false,
72
- 'server' => {
73
- 'host' => 'localhost',
74
- 'port' => 9091
75
- },
76
- 'log_target' => $stderr,
77
- 'privileges' => {}
78
- } )
79
-
80
- # Initialize a log instance, configure it and run the consumer in a subthread.
61
+ config.load({
62
+ 'feeds' => [],
63
+ 'update_interval' => 600,
64
+ 'add_paused' => false,
65
+ 'server' => {
66
+ 'host' => 'localhost',
67
+ 'port' => 9091
68
+ },
69
+ 'log_target' => $stderr,
70
+ 'privileges' => {}
71
+ })
72
+
73
+ # Initialize a log instance and configure it.
81
74
  log = Log.instance
82
- log.verbose = verbose
83
75
  log.target = config.log_target
84
- tLog = Thread.start do log.run end
76
+ log.level = Logger::DEBUG
77
+ log.formatter = proc do |sev, time, prog, msg|
78
+ "#{time.to_i}(#{sev.downcase}) #{msg}\n"
79
+ end
85
80
 
86
81
  # Load config file (default or given by argument).
87
82
  begin
88
- config.load( configFile )
83
+ config.load(config_file)
84
+ log.target = config.log_target
89
85
  rescue Errno::ENOENT
90
- log.add( configFile + ' not found' )
86
+ log.error(config_file + ' not found')
91
87
  end
92
- log.add( config )
88
+ log.debug(config)
93
89
 
94
90
  # Drop privileges, if section is given in config file.
95
- if( not config.privileges.empty? )
96
- Process::Sys.setgid(
97
- Etc.getgrnam( config.privileges.group ).gid
98
- )
99
-
100
- Process::Sys.setuid(
101
- Etc.getpwnam( config.privileges.user ).uid
102
- )
103
-
104
- log.add(
105
- 'dropped privileges ' +
106
- config.privileges.user +
107
- ':' +
108
- config.privileges.group
109
- )
91
+ if(not config.privileges.empty?)
92
+ Process::Sys.setgid(
93
+ Etc.getgrnam(config.privileges.group).gid
94
+ )
95
+
96
+ Process::Sys.setuid(
97
+ Etc.getpwnam(config.privileges.user).uid
98
+ )
99
+
100
+ log.debug(
101
+ 'dropped privileges ' +
102
+ config.privileges.user +
103
+ ':' +
104
+ config.privileges.group
105
+ )
110
106
  else
111
- log.add( 'no privilege dropping' )
107
+ log.debug('no privilege dropping')
108
+ end
109
+
110
+ # Warn if no feeds are given.
111
+ if(config.feeds.empty?)
112
+ log.warn('no feeds given')
112
113
  end
113
114
 
114
115
  # Start GUI if config edit option is given.
115
- if( editConfig )
116
- require( 'transmission-rss/config-editor' )
116
+ if(edit_config)
117
+ require 'transmission-rss/config-editor'
117
118
 
118
- Gtk.init
119
+ Gtk.init
119
120
 
120
- ConfigEditor.new( configFile, config )
121
- Gtk.main
121
+ ConfigEditor.new(config_file, config)
122
+ Gtk.main
122
123
 
123
- exit( 0 )
124
+ exit(0)
124
125
  end
125
126
 
126
127
  # Connect reload of config file to SIGHUP.
127
- trap( 'HUP' ) do
128
- config.load( configFile )
129
- log.add( 'got hup', config )
128
+ trap('HUP') do
129
+ config.load(config_file)
130
+ log.info('got hup', config)
130
131
  end
131
132
 
132
133
  # Initialize feed aggregator.
133
134
  aggregator = Aggregator.new
134
135
 
135
136
  # Initialize communication to transmission.
136
- client = Client.new( config.server.host, config.server.port )
137
+ client = Client.new(config.server.host, config.server.port)
137
138
 
138
139
  # Add feeds from config file to +Aggregator+ class.
139
- aggregator.feeds.concat( config.feeds )
140
+ aggregator.feeds.concat(config.feeds)
140
141
 
141
142
  # Callback for a new item on one of the feeds.
142
143
  aggregator.on_new_item do |torrentFile|
143
- Thread.start do
144
- client.addTorrent( torrentFile, config.add_paused )
145
- end
144
+ Thread.start do
145
+ client.addTorrent(torrentFile, config.add_paused)
146
+ end
146
147
  end
147
148
 
148
149
  # Start the aggregation process.
149
150
  begin
150
- if( dofork )
151
- pid = fork do
152
- aggregator.run( config.update_interval )
153
- end
154
-
155
- puts( 'forked ' + pid.to_s )
156
- else
157
- aggregator.run( config.update_interval )
158
- end
151
+ if(dofork)
152
+ pid = fork do
153
+ aggregator.run(config.update_interval)
154
+ end
155
+
156
+ puts('forked ' + pid.to_s)
157
+ else
158
+ aggregator.run(config.update_interval)
159
+ end
159
160
  rescue Interrupt
161
+ log.info('interrupt caught')
160
162
  end
163
+
164
+ log.close
@@ -1,7 +1,7 @@
1
- $:.unshift( File.dirname( __FILE__ ) )
1
+ $:.unshift(File.dirname(__FILE__))
2
2
 
3
3
  module TransmissionRSS
4
- VERSION = '0.1.3'
4
+ VERSION = '0.1.5'
5
5
  end
6
6
 
7
7
  dir = 'transmission-rss'
@@ -14,6 +14,6 @@ blacklist.map! do |name|
14
14
  $:.first + '/' + dir + '/' + name + '.rb'
15
15
  end
16
16
 
17
- ( Dir.glob( $:.first + '/' + dir + '/*.rb' ) - blacklist ).each do |lib|
18
- require( lib )
17
+ (Dir.glob($:.first + '/' + dir + '/*.rb') - blacklist).each do |lib|
18
+ require lib
19
19
  end
@@ -1,114 +1,116 @@
1
- require( 'etc' )
2
- require( 'fileutils' )
3
- require( 'open-uri' )
4
- require( 'rss' )
1
+ require 'etc'
2
+ require 'fileutils'
3
+ require 'open-uri'
4
+ require 'rss'
5
5
 
6
6
  # Class for aggregating torrent files through RSS feeds.
7
7
  class TransmissionRSS::Aggregator
8
- attr_accessor :feeds
9
-
10
- def initialize( feeds = [] )
11
- @feeds = feeds
12
- @seen = []
13
-
14
- # Initialize log instance.
15
- @log = Log.instance
16
-
17
- # Declare callback for new items.
18
- callback( :on_new_item )
19
-
20
- # Generate path for seen torrents store file.
21
- @seenfile = File.join(
22
- Etc.getpwuid.dir,
23
- '/.config/transmission/seen-torrents.conf'
24
- )
25
-
26
- # Make directories in path if they are not existing.
27
- FileUtils.mkdir_p( File.dirname( @seenfile ) )
28
-
29
- # Touch seen torrents store file.
30
- if( not File.exists?( @seenfile ) )
31
- FileUtils.touch( @seenfile )
32
- end
33
-
34
- # Open file, read torrent URLs and add to +@seen+.
35
- open( @seenfile ).readlines.each do |line|
36
- @seen.push( line.chomp )
37
- @log.add( 'from seenfile ' + line.chomp )
38
- end
39
- end
40
-
41
- # Get file enclosures from all feeds items and call on_new_item callback
42
- # with torrent file URL as argument.
43
- def run( interval = 600 )
44
- @log.add( 'aggregator start' )
45
-
46
- while( true )
47
- feeds.each do |url|
48
- # @log.add( 'aggregate ' + url )
49
-
50
- begin
51
- content = open( url ).readlines.join( "\n" )
52
- items = RSS::Parser.parse( content, false ).items
53
- rescue
54
- @log.add( 'retrieval error' )
55
- next
56
- end
57
-
58
- items.each do |item|
59
- link = item.link
8
+ attr_accessor :feeds
9
+
10
+ def initialize(feeds = [])
11
+ @feeds = feeds
12
+ @seen = []
13
+
14
+ # Initialize log instance.
15
+ @log = Log.instance
16
+
17
+ # Declare callback for new items.
18
+ callback(:on_new_item)
19
+
20
+ # Generate path for seen torrents store file.
21
+ @seenfile = File.join(
22
+ Etc.getpwuid.dir,
23
+ '/.config/transmission/seen-torrents.conf'
24
+ )
25
+
26
+ # Make directories in path if they are not existing.
27
+ FileUtils.mkdir_p(File.dirname(@seenfile))
28
+
29
+ # Touch seen torrents store file.
30
+ if(not File.exists?(@seenfile))
31
+ FileUtils.touch(@seenfile)
32
+ end
33
+
34
+ # Open file, read torrent URLs and add to +@seen+.
35
+ open(@seenfile).readlines.each do |line|
36
+ @seen.push(line.chomp)
37
+ end
38
+
39
+ # Log number of +@seen+ URIs.
40
+ @log.debug(@seen.size.to_s + ' uris from seenfile')
41
+ end
42
+
43
+ # Get file enclosures from all feeds items and call on_new_item callback
44
+ # with torrent file URL as argument.
45
+ def run(interval = 600)
46
+ @log.debug('aggregator start')
47
+
48
+ while(true)
49
+ feeds.each do |url|
50
+ @log.debug('aggregate ' + url)
51
+
52
+ begin
53
+ content = open(url).readlines.join("\n")
54
+ items = RSS::Parser.parse(content, false).items
55
+ rescue
56
+ @log.debug('retrieval error')
57
+ next
58
+ end
59
+
60
+ items.each do |item|
61
+ link = item.link
60
62
 
61
- # Item contains no link.
62
- if( link.nil? )
63
- next
64
- end
65
-
66
- # Link is not a String directly.
67
- if( link.class != String )
68
- link = link.href
69
- end
70
-
71
- # The link is not in +@seen+ Array.
72
- if( not seen?( link ) )
73
- on_new_item( link )
74
- @log.add( 'on_new_item event ' + link )
75
-
76
- add_seen( link )
77
- end
78
- end
79
- end
80
-
81
- sleep( interval )
82
- end
83
- end
84
-
85
- # To add a link into the list of seen links.
86
- def add_seen( link )
87
- @seen.push( link )
88
-
89
- File.open( @seenfile, 'w' ) do |file|
90
- file.write( @seen.join( "\n" ) )
91
- end
92
- end
93
-
94
- # To test if a link is in the list of seen links.
95
- def seen?( link )
96
- @seen.include?( link )
97
- end
98
-
99
- # Method to define callback methods.
100
- def callback( *names )
101
- names.each do |name|
102
- eval <<-EOF
103
- @#{name} = false
104
- def #{name}( *args, &block )
105
- if( block )
106
- @#{name} = block
107
- elsif( @#{name} )
108
- @#{name}.call( *args )
109
- end
110
- end
111
- EOF
112
- end
113
- end
63
+ # Item contains no link.
64
+ if(link.nil?)
65
+ next
66
+ end
67
+
68
+ # Link is not a String directly.
69
+ if(link.class != String)
70
+ link = link.href
71
+ end
72
+
73
+ # The link is not in +@seen+ Array.
74
+ if(not seen?(link))
75
+ on_new_item(link)
76
+ @log.debug('on_new_item event ' + link)
77
+
78
+ add_seen(link)
79
+ end
80
+ end
81
+ end
82
+
83
+ sleep(interval)
84
+ end
85
+ end
86
+
87
+ # To add a link into the list of seen links.
88
+ def add_seen(link)
89
+ @seen.push(link)
90
+
91
+ File.open(@seenfile, 'w') do |file|
92
+ file.write(@seen.join("\n"))
93
+ end
94
+ end
95
+
96
+ # To test if a link is in the list of seen links.
97
+ def seen?(link)
98
+ @seen.include?(link)
99
+ end
100
+
101
+ # Method to define callback methods.
102
+ def callback(*names)
103
+ names.each do |name|
104
+ eval <<-EOF
105
+ @#{name} = false
106
+ def #{name}(*args, &block)
107
+ if(block)
108
+ @#{name} = block
109
+ elsif(@#{name})
110
+ @#{name}.call(*args)
111
+ end
112
+ end
113
+ EOF
114
+ end
115
+ end
114
116
  end