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.
- 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
|
+
|