jphastings-jd-control 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/extensions.rb +75 -0
- data/jd-control.rb +176 -0
- 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
|
+
|