jphastings-jd-control 1.0.1

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.
Files changed (3) hide show
  1. data/extensions.rb +75 -0
  2. data/jd-control.rb +176 -0
  3. metadata +63 -0
data/extensions.rb ADDED
@@ -0,0 +1,75 @@
1
+ # Some crafty extenions to native ruby classes to allow some more intuitive
2
+ # mehtods and behaviours
3
+ #
4
+ # All collected from my github gists: http://gist.github.com/jphastings
5
+ require 'time'
6
+ require 'delegate'
7
+
8
+ class Time
9
+ # Gives a 'fuzzy' output of the distance to the time stored.
10
+ #
11
+ # eg. 'in 28 minutes' or '23 hours ago'
12
+ def roughly
13
+ diff = self.to_i - Time.now.to_i
14
+ ago = diff < 0
15
+ diff = diff.abs
16
+ case diff
17
+ when 0
18
+ return "now"
19
+ when 1...60
20
+ unit = "second"
21
+ when 60...3600
22
+ diff = (diff/60).round
23
+ unit = "minute"
24
+ when 3600...86400
25
+ diff = (diff/3600).round
26
+ unit = "hour"
27
+ when 86400...604800
28
+ diff = (diff/86400).round
29
+ unit = "day"
30
+ when 604800...2592000
31
+ diff = (diff/604800).round
32
+ unit = "week"
33
+ when 2592000...31557600
34
+ diff = (diff/2592000).round
35
+ unit = "month"
36
+ else
37
+ diff = (diff/31557600).round
38
+ unit = "year"
39
+ end
40
+ unit += "s" if diff != 1
41
+ return (ago) ? "#{diff} #{unit} ago" : "in #{diff} #{unit}"
42
+ end
43
+ end
44
+
45
+ # Allows relative times, most frequently used in times of arrival etc.
46
+ class ETA < Time
47
+ # Takes a number of seconds until the event
48
+ def self.new(seconds)
49
+ raise "ETA requires a number of seconds" if not seconds.is_a?(Numeric)
50
+ ETA.at Time.now + seconds
51
+ end
52
+
53
+ # Requires http://gist.github.com/116290
54
+ def to_s
55
+ self.roughly
56
+ end
57
+
58
+ # Gives a full textual representation of the time expected time of arrival (Time.rfc2822)
59
+ def eta
60
+ self.rfc2822
61
+ end
62
+
63
+ # Has the eta passed?
64
+ def arrived?
65
+ self.to_i < Time.now.to_i
66
+ end
67
+ end
68
+
69
+ # Allows percentages to be inspected and stringified in human form "33.3%", but kept in a float format for mathmatics
70
+ class Percentage < DelegateClass(Float)
71
+ def to_s(decimalplaces = 0)
72
+ (((self * 10**(decimalplaces+2)).round)/10**decimalplaces).to_s+"%"
73
+ end
74
+ alias :inspect :to_s
75
+ end
data/jd-control.rb ADDED
@@ -0,0 +1,176 @@
1
+ # Control JDownloader from a ruby script via the 'Remote Control' plugin
2
+ #
3
+ # Allows you to start, stop and pause the download queue, add new downloads and
4
+ # tinker with the bandwidth limits of the program.
5
+ require 'extensions'
6
+ require 'rubygems'
7
+ require 'httparty'
8
+
9
+ module JDownloader
10
+ # Allows control of JDownloader via the 'Remote Control' plugin
11
+ class Control
12
+ attr_accessor :limit
13
+ attr_reader :version, :speed
14
+ include HTTParty
15
+
16
+ # The ip address of the computer running JDownloader (probably 127.0.0.1)
17
+ def initialize(host = "127.0.0.1",port = 5000) # Can't remember the default port!
18
+ self.class.base_uri "http://#{host}:#{port}/"
19
+ end
20
+
21
+ # Returns the JDownloader version
22
+ def version
23
+ self.class.get("/get/version")
24
+ end
25
+
26
+ # Returns current download speed
27
+ def speed
28
+ self.class.get("/get/speed").to_i
29
+ end
30
+
31
+ # Returns the current speed limit (KBps)
32
+ def limit
33
+ self.class.get("/get/speedlimit").to_i
34
+ end
35
+
36
+ # Sets the download speed limit (KBps)
37
+ def limit=(kBps)
38
+ raise "Requires Integer KBps value" if not kBps.is_a?(Integer)
39
+ self.class.get("/action/set/download/limit/#{kBps}").to_i
40
+ end
41
+
42
+ # Starts the downloader queue
43
+ def start
44
+ return self.class.get("/action/start") == "Downloads started"
45
+ end
46
+
47
+ # Stops the downloader queue
48
+ def stop
49
+ return self.class.get("/action/stop") == "Downloads stopped"
50
+ end
51
+
52
+ # Pauses the downloader queue (how is this different to stop?)
53
+ def pause
54
+ return self.class.get("/action/pause") == "Downloads paused"
55
+ end
56
+
57
+ # Creates a new package with the given array of links
58
+ def download(links)
59
+ links = [links] if links.is_a?(String)
60
+ self.class.get("/action/add/links/grabber0/start1/"+links.join(" "))
61
+ end
62
+
63
+ # Lists the details of any download or downloads (by id) or all downloads.
64
+ def download(downloadids = nil)
65
+ downloadids = [downloadids] if downloadids.is_a?(Integer)
66
+
67
+ dls = parse_packages(self.class.get("/get/downloads/alllist"))
68
+ if downloadids.nil?
69
+ return dls
70
+ else
71
+ return dls.delete_if {|id, package| not downloadids.include?(id)}
72
+ end
73
+ end
74
+ alias :downloads :download
75
+
76
+ private
77
+ def parse_packages(string)
78
+ Hash[*string.scan(/<package package_name="(.*?)" package_id="([0-9]+?)" package_percent="([0-9]+?\.[0-9]+?)" package_linksinprogress="([0-9]+?)" package_linkstotal="([0-9]+?)" package_ETA="((?:[0-9]+:)?[0-9]{2}:(?:-1|[0-9]{2}))" package_speed="([0-9]+?) ([G|M|K]B)\/s" package_loaded="([0-9]+?\.?[0-9]*?) ([G|M|K]B)" package_size="([0-9]+?\.[0-9]+?) ([G|M|K]B)" package_todo="([0-9]+?\.?[0-9]*?) ([G|M|K]B)" ?> ?(.*?)<\/package>/).collect { |p|
79
+ m = nil
80
+ [p[1].to_i, Package.new({
81
+ :name => p[0],
82
+ :id => p[1].to_i,
83
+ :links => {
84
+ :in_progress => p[3].to_i,
85
+ :in_total => p[4].to_i
86
+ },
87
+ :eta => (p[5] == "00:-1") ? nil : p[5].split(":").reverse.inject(0) { |sum, element| m = ((m.nil?) ? 1 : m*60 ); sum + element.to_i*m },
88
+ :speed => p[6].to_i * parse_bytes(p[7]),
89
+ :completed => p[2].to_f/100,
90
+ :size => {
91
+ :loaded => p[8].to_i * parse_bytes(p[9]),
92
+ :total => p[10].to_i * parse_bytes(p[11]),
93
+ :todo => p[12].to_i * parse_bytes(p[13])
94
+ },
95
+ :files => Hash[*p[14].scan(/<file file_name="(.*?)" file_id="([0-9]+?)" file_package="([0-9]+?)" file_percent="([0-9]+?\.[0-9]+?)" file_hoster="(.*?)" file_status="(.*?)" file_speed="(-1|[0-9]+?)" ?>/).collect { |f|
96
+ [f[1].to_i,{
97
+ :name => f[0],
98
+ :id => f[1].to_i,
99
+ :package_id => f[2].to_i,
100
+ :completed => f[3].to_f/100,
101
+ :hoster => f[4],
102
+ :status => parse_status(f[5]),
103
+ :speed => (f[6] == "-1") ? nil : f[6].to_i
104
+ }]
105
+ }.flatten]
106
+
107
+ })]
108
+ }.flatten
109
+ ]
110
+ end
111
+
112
+ def parse_bytes(bytes)
113
+ case bytes
114
+ when "GB"
115
+ return 1048576
116
+ when "MB"
117
+ return 1024
118
+ when "KB"
119
+ return 1
120
+ else
121
+ raise "Unknown unit: #{bytes}"
122
+ end
123
+ end
124
+
125
+ def parse_status(status)
126
+ case status
127
+ when "[finished]"
128
+ {
129
+ :description => :finished
130
+ }
131
+ when /^Wait ([0-9]{2}):([0-9]{2}) min(?:\. for (.+))?$/
132
+ {
133
+ :description => :wait,
134
+ :wait => $3,
135
+ :time => $1.to_i * 60 + $2.to_i
136
+ }
137
+ when "[wait for new ip]"
138
+ {
139
+ :description => :wait,
140
+ :wait => :new_ip
141
+ }
142
+ when /ETA ([0-9]{2}):([0-9]{2}) @ ([0-9]+) ([M|K]B)\/s \([0-9]+\/[0-9]+\)/ # What are these last two digitas? Download slots used and available?
143
+ {
144
+ :description => :in_progress,
145
+ :time => $1.to_i * 60 + $2.to_i,
146
+ :speed => $3.to_i * parse_bytes($4)
147
+ }
148
+ when ""
149
+ {
150
+ :description => :wait,
151
+ :wait => :queued
152
+ }
153
+ else
154
+ status
155
+ end
156
+ end
157
+ end
158
+
159
+ # JDownloader packages can be accessed as objects, they're almost totally intuitive
160
+ class Package
161
+ attr_reader :name, :id, :eta, :speed, :completed, :size, :files
162
+ def initialize(p)
163
+ @name = p[:name]
164
+ @id = p[:id]
165
+ @package = p[:package_id]
166
+ @eta = (p[:completed] >= 1.0) ? "finished" : (p[:eta].nil?)? "unknown" : ETA.new(p[:eta])
167
+ @speed = p[:speed]
168
+ @completed = Percentage.new(p[:completed])
169
+ @file = p[:files]
170
+ end
171
+
172
+ def inspect
173
+ "#{@completed} of '#{@name}' ETA #{@eta}"
174
+ end
175
+ end
176
+ end
metadata ADDED
@@ -0,0 +1,63 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: jphastings-jd-control
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.1
5
+ platform: ruby
6
+ authors:
7
+ - JP Hastings-Spital
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-05-16 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: httparty
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "0"
24
+ version:
25
+ description: Control JDownloader from ruby via the 'Remote Control' plugin
26
+ email: jd-control@projects.kedakai.co.uk
27
+ executables: []
28
+
29
+ extensions: []
30
+
31
+ extra_rdoc_files: []
32
+
33
+ files:
34
+ - jd-control.rb
35
+ - extensions.rb
36
+ has_rdoc: true
37
+ homepage: http://projects.kedakai.co.uk/jd-control/
38
+ post_install_message:
39
+ rdoc_options: []
40
+
41
+ require_paths:
42
+ - .
43
+ required_ruby_version: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: "0"
48
+ version:
49
+ required_rubygems_version: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: "0"
54
+ version:
55
+ requirements: []
56
+
57
+ rubyforge_project:
58
+ rubygems_version: 1.2.0
59
+ signing_key:
60
+ specification_version: 2
61
+ summary: Control JDownloader from ruby via the 'Remote Control' plugin
62
+ test_files: []
63
+