jphastings-jd-control 1.0.1

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