junkie 0.0.3 → 0.0.4

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.
data/junkie.gemspec CHANGED
@@ -25,4 +25,5 @@ Gem::Specification.new do |gem|
25
25
  gem.add_runtime_dependency(%q<sjunkieex>, [">= 0.0.1"])
26
26
  gem.add_runtime_dependency(%q<sindex>, [">= 0.0.1"])
27
27
  gem.add_runtime_dependency(%q<logging>, ["~> 1.8.0"])
28
+ gem.add_runtime_dependency(%q<twitter>, ["~> 4.4.0"])
28
29
  end
data/lib/junkie.rb CHANGED
@@ -8,10 +8,15 @@ require 'junkie/helper'
8
8
  require 'junkie/patched/sjunkieex'
9
9
  require 'junkie/pyload/api'
10
10
  require 'junkie/pyload/observer'
11
+ require 'junkie/notification/twitter'
11
12
  require 'logging'
12
13
 
14
+ Logging.appenders.stdout(
15
+ 'stdout',
16
+ :level => :debug,
17
+ :layout => Logging.layouts.pattern(:pattern => '[%d] %-5l: %m\n')
18
+ )
13
19
  Logging.logger.root.appenders = Logging.appenders.stdout
14
- Logging.logger.root.level = :debug
15
20
 
16
21
  module Junkie
17
22
 
@@ -5,7 +5,7 @@ module Junkie
5
5
 
6
6
  class Episode
7
7
  attr_reader :id, :series, :found_at, :link
8
- attr_accessor :description, :status
8
+ attr_accessor :description, :status, :pid
9
9
 
10
10
  def initialize(series, link, description=nil)
11
11
  @series = series
@@ -0,0 +1,68 @@
1
+ require 'twitter'
2
+
3
+ module Junkie
4
+ module Notification
5
+
6
+ class Twitter
7
+ include Log, Config
8
+
9
+ DEFAULT_CONFIG = {
10
+ twitter_enabled: false,
11
+ consumer_key: "",
12
+ consumer_secret: "",
13
+ oauth_token: "",
14
+ oauth_token_secret: "",
15
+ }
16
+
17
+ def initialize(channels)
18
+ @channels = channels
19
+ @config = Config.get_config(self)
20
+
21
+ if @config[:twitter_enabled]
22
+
23
+ # check the configuration
24
+ [:consumer_key, :consumer_secret, :oauth_token,
25
+ :oauth_token_secret].each do |key|
26
+
27
+ unless @config[key] && @config[key].match(/\w+/)
28
+ raise InvalidConfigError, "#{key} option is missing"
29
+ end
30
+ end
31
+
32
+ # configure
33
+ ::Twitter.configure do |config|
34
+ config.consumer_key = @config[:consumer_key]
35
+ config.consumer_secret = @config[:consumer_secret]
36
+ config.oauth_token = @config[:oauth_token]
37
+ config.oauth_token_secret = @config[:oauth_token_secret]
38
+ end
39
+
40
+ # bind to channel
41
+ @channels[:notifications].subscribe do |episode|
42
+ next unless episode.status == :extracted
43
+
44
+ log.info("Received an episode from channel. I will tweet about this")
45
+ send_notification(episode)
46
+ end
47
+
48
+ else
49
+ log.info("Twitter support is disabled")
50
+ end
51
+ end
52
+
53
+ private
54
+
55
+ # Sends a formatted message out through Twitter
56
+ #
57
+ # @param [Junkie::Episode] episode that has been downloaded
58
+ def send_notification(episode)
59
+ begin
60
+ mess = "A new episode of #{episode} has been downloaded #junkie"
61
+ ::Twitter.update(mess)
62
+ rescue Exception => e
63
+ log.error(e)
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
@@ -11,18 +11,31 @@ module Junkie
11
11
  watchdog_refresh: 10, # interval the watchdog_timer is fired
12
12
  }
13
13
 
14
- def initialize(config={})
14
+ def initialize(channels)
15
15
  @config = Config.get_config(self)
16
16
 
17
17
  @api = Junkie::Pyload::Api.new
18
18
 
19
+ @channels = channels
20
+
21
+ @found_episodes = Array.new
22
+
23
+ @active_episode = nil
24
+
19
25
  @ready_for_new_links = true
20
26
  @watchdog_enabled = false
21
- @active_downloads = Hash.new
22
-
23
27
  @skipped_timer_at_first_complete_detection = false
28
+ @should_send_it_on_channel = false
29
+
30
+ @channels[:episodes].subscribe do |episode|
31
+ next unless episode.status == :found
32
+
33
+ log.info("Got episode from Channel: #{episode}")
34
+ @found_episodes.push(episode)
35
+ end
24
36
  end
25
37
 
38
+
26
39
  # is a method that is called once from inside the reactor and allows us
27
40
  # to register custom actions into the reactor
28
41
  def setup
@@ -32,32 +45,53 @@ module Junkie
32
45
  }
33
46
 
34
47
  EM.add_periodic_timer(@config[:watchdog_refresh]) do
48
+
49
+ # temporary fix for the SystemStackError
50
+ if @should_send_it_on_channel
51
+ log.info("Sending complete episode out on the channel")
52
+ @channels[:episodes].push(@active_episode)
53
+ @active_episode = nil
54
+
55
+ @should_send_it_on_channel = false
56
+ end
57
+
35
58
  monitor_progress if @watchdog_enabled
59
+
60
+ in_fiber {
61
+ add_next_episode_to_pyload
62
+ }
36
63
  end
37
64
  end
38
65
 
39
- # Adds new episode to Pyload which downloads the episode and extracts it
40
- #
41
- # @param [Junkie::Episode] episode which should be downloaded
66
+
67
+ # Add next episode to Pyload which downloads the episode and extracts it
42
68
  #
43
69
  # @note should only be called if `is_ready?` returns true
44
- def add_episode(episode)
45
- raise InvalidStateError, "Observer is not ready" unless is_ready?
46
- @ready_for_new_links = false
70
+ def add_next_episode_to_pyload
71
+
72
+ # detect if we cann add a new episode
73
+ return unless is_ready?
74
+ return if @found_episodes.empty?
75
+
76
+ @active_episode = @found_episodes.shift
77
+ episode = @active_episode
47
78
 
79
+ @ready_for_new_links = false
48
80
  episode.status = :downloading
49
81
 
50
82
  package = "%s@%s" % [ episode.id, episode.series ]
51
83
 
52
- pid = @api.call(:addPackage, {name: package, links: [episode.link]})
84
+ pid = @api.call(:addPackage,
85
+ { name: package, links: [episode.link] })
53
86
 
54
- @active_downloads[pid] = episode
87
+ episode.pid = pid
55
88
 
56
89
  log.info("Added #{episode} to Pyload, Pid=#{pid}")
57
90
 
58
91
  (@watchdog_enabled = true) unless @watchdog_enabled
59
92
  end
60
93
 
94
+
61
95
  # checks if the Observer is ready to add new episodes to Pyload
62
96
  #
63
97
  # @returns [Boolean] true if new links can be added
@@ -72,7 +106,6 @@ module Junkie
72
106
  # It monitors the download process and reacts depending on the results
73
107
  def monitor_progress
74
108
  log.debug("Watchdog timer has been fired")
75
-
76
109
  in_fiber {
77
110
  catch(:break) {
78
111
  queue_data = @api.call(:getQueueData)
@@ -97,10 +130,22 @@ module Junkie
97
130
 
98
131
  if not pids.empty?
99
132
  if @skipped_timer_at_first_complete_detection
133
+
134
+ # post process complete active download and send it out on the
135
+ # channel
136
+ if pids.include? @active_episode.pid
137
+ log.info("'#{@active_episode}' is extracted completely")
138
+ @active_episode.pid = nil
139
+ @active_episode.status = :extracted
140
+
141
+ @should_send_it_on_channel = true
142
+ end
143
+
144
+ # remove all complete packages
100
145
  @api.call(:deletePackages, {pids: pids})
101
146
  log.info("Complete packages are removed from Pyload Queue")
102
- @skipped_timer_at_first_complete_detection = false
103
147
 
148
+ @skipped_timer_at_first_complete_detection = false
104
149
  @ready_for_new_links = true
105
150
  else
106
151
  # If a package is complete, we are sometimes so fast to remove
@@ -114,6 +159,7 @@ module Junkie
114
159
  }
115
160
  end
116
161
 
162
+
117
163
  # Searches for failed links in the pyload queue
118
164
  #
119
165
  # @param [Array] queue_data returned from :getQueueData api method
@@ -130,6 +176,7 @@ module Junkie
130
176
  false
131
177
  end
132
178
 
179
+
133
180
  # Looks for complete downloads and returns their pids
134
181
  #
135
182
  # @param [Array] queue_data returned from :getQueueData api method
@@ -169,12 +216,11 @@ module Junkie
169
216
  def update_package_ids(queue_data)
170
217
  queue_data.each do |package|
171
218
  pid = package['pid']
172
- next if @active_downloads.has_key? pid
219
+ next if @active_episode.pid == pid
173
220
 
174
- if @active_downloads.has_key? pid-1
221
+ if @active_episode.pid == pid-1
175
222
  log.info("Package ID has been changed, I will correct this")
176
- @active_downloads[pid] = @active_downloads[pid-1]
177
- @active_downloads.delete(pid-1)
223
+ @active_episode.pid = pid
178
224
  next
179
225
  end
180
226
 
@@ -18,7 +18,6 @@ module Junkie
18
18
  :hd_enabled => false,
19
19
  :hoster_id => "ul",
20
20
  :series_index_file => File.join(Dir.home, '.sindex/seriesindex.xml'),
21
- :episode_queue_timer_refresh => 5, # in seconds
22
21
  :episode_search_refresh => 15, # in minutes
23
22
  }
24
23
 
@@ -26,9 +25,19 @@ module Junkie
26
25
  def initialize
27
26
  @config = Config.get_config(self)
28
27
 
29
- @pyload_observer = Junkie::Pyload::Observer.new()
28
+ log.info("Starting Junkie #{Junkie::VERSION}")
29
+
30
+ episode_channel = EM::Channel.new
31
+ notification_channel = EM::Channel.new
32
+
33
+ @channels = {
34
+ episodes: episode_channel,
35
+ notifications: notification_channel
36
+ }
37
+
38
+ @pyload_observer = Junkie::Pyload::Observer.new(@channels)
39
+ @twitter_notification = Junkie::Notification::Twitter.new(@channels)
30
40
 
31
- @episode_queue = EM::Queue.new
32
41
  @found_episodes = Hash.new
33
42
  build_procs # has to be called here
34
43
  end
@@ -52,37 +61,28 @@ module Junkie
52
61
 
53
62
  if not @found_episodes.has_key? identifier
54
63
  log.info("Found new episode '#{episode}'")
55
- @episode_queue.push(episode)
64
+
65
+ @channels[:episodes].push(episode)
56
66
  @found_episodes[identifier] = episode
57
67
  end
58
68
  end
59
69
  }
60
70
  }
61
-
62
- # Proc that checks is Pyload-Observer is ready for new episodes and the
63
- # episode_queue contains new episodes.
64
- #
65
- # @note Is called from within the reactor
66
- @add_episodes_to_pyload = Proc.new do
67
- if @pyload_observer.is_ready?
68
- @episode_queue.pop do |episode|
69
- log.info("Popped episode '#{episode}' from queue")
70
- in_fiber {
71
- @pyload_observer.add_episode(episode)
72
- }
73
- end
74
- end
75
- end
76
71
  end
77
72
 
78
73
  ###########################################################################
79
74
  #################### The Reactor ##########################################
80
75
  ###########################################################################
81
76
  def start
82
- log.info("Starting Junkie #{Junkie::VERSION}")
83
77
 
84
78
  EM.run do
85
79
 
80
+ @channels[:episodes].subscribe do |episode|
81
+ next unless episode.status == :extracted
82
+
83
+ @channels[:notifications].push(episode)
84
+ end
85
+
86
86
  # do some initialization work
87
87
  @pyload_observer.setup
88
88
 
@@ -96,13 +96,6 @@ module Junkie
96
96
  end
97
97
  end
98
98
 
99
- # Add found episodes into Pyload if there are any episodes and pyload
100
- # is ready
101
- EM.add_periodic_timer(
102
- @config[:episode_queue_timer_refresh], @add_episodes_to_pyload)
103
-
104
- # for determining blocking operations
105
- # EM.add_periodic_timer(1) { puts Time.now.to_i }
106
99
  end
107
100
  end
108
101
  end
@@ -1,3 +1,3 @@
1
1
  module Junkie
2
- VERSION = "0.0.3"
2
+ VERSION = "0.0.4"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: junkie
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.4
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-12-02 00:00:00.000000000 Z
12
+ date: 2012-12-04 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: eventmachine
@@ -155,6 +155,22 @@ dependencies:
155
155
  - - ~>
156
156
  - !ruby/object:Gem::Version
157
157
  version: 1.8.0
158
+ - !ruby/object:Gem::Dependency
159
+ name: twitter
160
+ requirement: !ruby/object:Gem::Requirement
161
+ none: false
162
+ requirements:
163
+ - - ~>
164
+ - !ruby/object:Gem::Version
165
+ version: 4.4.0
166
+ type: :runtime
167
+ prerelease: false
168
+ version_requirements: !ruby/object:Gem::Requirement
169
+ none: false
170
+ requirements:
171
+ - - ~>
172
+ - !ruby/object:Gem::Version
173
+ version: 4.4.0
158
174
  description: TV series management application
159
175
  email:
160
176
  - philipp-boehm@live.de
@@ -178,6 +194,7 @@ files:
178
194
  - lib/junkie/errors.rb
179
195
  - lib/junkie/helper.rb
180
196
  - lib/junkie/log.rb
197
+ - lib/junkie/notification/twitter.rb
181
198
  - lib/junkie/patched/sjunkieex.rb
182
199
  - lib/junkie/pyload/api.rb
183
200
  - lib/junkie/pyload/observer.rb