├── README.md
├── composer.json
└── uTorrent
├── Api.php
└── model
└── Filter.php
/README.md:
--------------------------------------------------------------------------------
1 | What?
2 | ----
3 | This library lets you control uTorrent using PHP.
4 |
5 | * List Torrents
6 | * Add Torrents
7 | * Start / Stop / Pause torrents
8 | * Add / edit RSS favourites
9 |
10 | How?
11 | ----
12 | Enable the web UI in utorrent: http://www.utorrent.com/help/guides/webui
13 |
14 | $utorrent = new \uTorrent\Api($host, $port, $user, $pass);
15 | $utorrent->getTorrents();
16 |
17 | Who?
18 | ----
19 | * Originally by Miyanokouji http://forum.utorrent.com/viewtopic.php?id=27414&p=1
20 | * Upgraded by Ultima http://forum.utorrent.com/viewtopic.php?pid=320049#p320049
21 |
22 | I've added this to github to aid any future collaboration, add composer support and make it easier for people to find.
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "tboothman/utorrent-api",
3 | "autoload": {
4 | "psr-0": {"uTorrent\\": ""}
5 | }
6 | }
--------------------------------------------------------------------------------
/uTorrent/Api.php:
--------------------------------------------------------------------------------
1 | host = $host;
51 | $this->port = $port;
52 | $this->user = $user;
53 | $this->pass = $pass;
54 |
55 | if (!$this->getToken()) {
56 | //handle error here, don't know how to best do this yet
57 | die('could not get token');
58 | }
59 | }
60 |
61 | // performs request
62 | private function makeRequest($request, $decode = true, $options = array()) {
63 | $request = preg_replace('/^\?/', '?token='.$this->token . '&', $request);
64 |
65 | $ch = curl_init();
66 | curl_setopt_array($ch, $options);
67 | curl_setopt($ch, CURLOPT_URL, sprintf(self::$base, $this->host, $this->port, $request));
68 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
69 | curl_setopt($ch, CURLOPT_USERPWD, $this->user.":".$this->pass);
70 | curl_setopt($ch, CURLOPT_COOKIE, "GUID=".$this->guid);
71 |
72 | $req = curl_exec($ch);
73 | curl_close($ch);
74 |
75 | return ($decode ? json_decode($req, true) : $req);
76 | }
77 |
78 | // implodes given parameter with glue, whether it is an array or not
79 | private function paramImplode($glue, $param) {
80 | return $glue.implode($glue, is_array($param) ? $param : array($param));
81 | }
82 |
83 | // gets token, returns true on success
84 | private function getToken() {
85 | $ch = curl_init();
86 | curl_setopt($ch, CURLOPT_URL, sprintf(self::$base, $this->host, $this->port, 'token.html'));
87 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
88 | curl_setopt($ch, CURLOPT_USERPWD, $this->user.":".$this->pass);
89 | curl_setopt($ch, CURLOPT_HEADER, true);
90 |
91 | $output = curl_exec($ch);
92 | $info = curl_getinfo($ch);
93 | curl_close($ch);
94 |
95 | $headers = substr($output, 0, $info['header_size']);
96 |
97 | if (preg_match("@Set-Cookie: GUID=([^;]+);@i", $headers, $matches)) {
98 | $this->guid = $matches[1];
99 | }
100 |
101 | if (preg_match('/
(.*)<\/div>/', $output, $m)) {
102 | $this->token = $m[1];
103 | return true;
104 | }
105 | return false;
106 | }
107 |
108 | // returns the uTorrent build number
109 | public function getBuild(){
110 | $json = $this->makeRequest("?");
111 | return $json['build'];
112 | }
113 |
114 | // returns an array of files for the specified torrent hash
115 | // TODO:
116 | // - (when implemented in API) allow multiple hashes to be specified
117 | public function getFiles($hash) {
118 | $json = $this->makeRequest("?action=getfiles&hash=".$hash);
119 | return $json['files'];
120 | }
121 |
122 | // returns an array of all labels
123 | public function getLabels(){
124 | $json = $this->makeRequest("?list=1");
125 | return $json['label'];
126 | }
127 |
128 | // returns an array of the properties for the specified torrent hash
129 | // TODO:
130 | // - (when implemented in API) allow multiple hashes to be specified
131 | public function getProperties($hash) {
132 | $json = $this->makeRequest("?action=getprops&hash=".$hash);
133 | return $json['props'];
134 | }
135 |
136 | // returns an array of all settings
137 | public function getSettings() {
138 | $json = $this->makeRequest("?action=getsettings");
139 | return $json['settings'];
140 | }
141 |
142 | // returns an array of all torrent jobs and related information
143 | public function getTorrents() {
144 | $json = $this->makeRequest("?list=1");
145 | return $json['torrents'];
146 | }
147 |
148 | /**
149 | * Get all the RSS favourites/filters
150 | * @return model\Filter[]
151 | */
152 | public function getRSSFilters() {
153 | $json = $this->makeRequest("?list=1");
154 | $filters = array();
155 | foreach ($json['rssfilters'] as $filter) {
156 | $filters[] = model\Filter::fromData($filter);
157 | }
158 | return $filters;
159 | }
160 |
161 | /**
162 | * Update an RSS filter as retrieved from getRSSFilters
163 | * @param \uTorrent\model\Filter $filter
164 | */
165 | public function setRSSFilter(model\Filter $filter) {
166 | $request = array_merge(array('action' => 'filter-update'), $filter->toParams());
167 | return $this->makeRequest('?'.http_build_query($request));
168 | }
169 |
170 | /**
171 | * Add a new RSS filter
172 | * Requires a utorrent > 2.2.1 (not sure which version exactly)
173 | * @param \uTorrent\model\Filter $filter
174 | * @return int ID of the new filter
175 | */
176 | public function addRSSFilter(model\Filter $filter) {
177 | $filter->filterId = -1;
178 | $resp = $this->setRSSFilter($filter);
179 | if (!empty($resp['filter_ident'])) {
180 | return $resp['filter_ident'];
181 | } else {
182 | return 0;
183 | }
184 | }
185 |
186 | // returns true if WebUI server is online and enabled, false otherwise
187 | public function is_online() {
188 | return is_array($this->makeRequest("?"));
189 | }
190 |
191 | // sets the properties for the specified torrent hash
192 | // TODO:
193 | // - allow multiple hashes, properties, and values to be set simultaneously
194 | public function setProperties($hash, $property, $value) {
195 | $this->makeRequest("?action=setprops&hash=".$hash."&s=".$property."&v=".$value, false);
196 | }
197 |
198 | // sets the priorities for the specified files in the specified torrent hash
199 | public function setPriority($hash, $files, $priority) {
200 | $this->makeRequest("?action=setprio&hash=".$hash."&p=".$priority.$this->paramImplode("&f=", $files), false);
201 | }
202 |
203 | // sets the settings
204 | // TODO:
205 | // - allow multiple settings and values to be set simultaneously
206 | public function setSetting($setting, $value) {
207 | $this->makeRequest("?action=setsetting&s=".$setting."&v=".$value, false);
208 | }
209 |
210 | // add a file to the list
211 | public function torrentAdd($filename, &$estring = false) {
212 | $split = explode(":", $filename, 2);
213 | if (count($split) > 1 && (stristr("|http|https|file|magnet|", "|".$split[0]."|") !== false)) {
214 | $this->makeRequest("?action=add-url&s=".urlencode($filename), false);
215 | }
216 | elseif (file_exists($filename)) {
217 | $json = $this->makeRequest("?action=add-file", true, array(CURLOPT_POSTFIELDS => array("torrent_file" => "@".realpath($filename))));
218 |
219 | if (isset($json['error'])) {
220 | if ($estring !== false) $estring = $json['error'];
221 | return false;
222 | }
223 | return true;
224 | }
225 | else {
226 | if ($estring !== false) $estring = "File doesn't exist!";
227 | return false;
228 | }
229 | }
230 |
231 | // force start the specified torrent hashes
232 | public function torrentForceStart($hash) {
233 | $this->makeRequest("?action=forcestart".$this->paramImplode("&hash=", $hash), false);
234 | }
235 |
236 | // pause the specified torrent hashes
237 | public function torrentPause($hash) {
238 | $this->makeRequest("?action=pause".$this->paramImplode("&hash=", $hash), false);
239 | }
240 |
241 | // recheck the specified torrent hashes
242 | public function torrentRecheck($hash) {
243 | $this->makeRequest("?action=recheck".$this->paramImplode("&hash=", $hash), false);
244 | }
245 |
246 | // start the specified torrent hashes
247 | public function torrentStart($hash) {
248 | $this->makeRequest("?action=start".$this->paramImplode("&hash=", $hash), false);
249 | }
250 |
251 | // stop the specified torrent hashes
252 | public function torrentStop($hash) {
253 | $this->makeRequest("?action=stop".$this->paramImplode("&hash=", $hash), false);
254 | }
255 |
256 | // remove the specified torrent hashes (and data, if $data is set to true)
257 | public function torrentRemove($hash, $data = false) {
258 | $this->makeRequest("?action=".($data ? "removedata" : "remove").$this->paramImplode("&hash=", $hash), false);
259 | }
260 | }
261 |
--------------------------------------------------------------------------------
/uTorrent/model/Filter.php:
--------------------------------------------------------------------------------
1 | filterId = $data[0];
84 | // Bitmask for settings:
85 | // 1 = enabled. Not sure how to disable it. UI doesn't seem to support it
86 | $filter->origname = (bool)(2 & $data[1]);
87 | $filter->prio = (bool)(4 & $data[1]);
88 | $filter->smartEpFilter = (bool)(8 & $data[1]);
89 | $filter->addStopped = (bool)(16 & $data[1]);
90 |
91 | $filter->name = $data[2];
92 | $filter->filter = $data[3];
93 | $filter->notFilter = $data[4];
94 | $filter->saveIn = $data[5];
95 | $filter->feedId = $data[6];
96 | $filter->quality = $data[7];
97 | $filter->label = $data[8];
98 | return $filter;
99 | }
100 |
101 | /**
102 | * Turn model into an array of parameters for the api
103 | * @return array
104 | */
105 | public function toParams() {
106 | $params = array();
107 | foreach (array('filterId', 'origname', 'prio', 'smartEpFilter', 'addStopped',
108 | 'name', 'filter', 'notFilter', 'saveIn', 'feedId', 'quality', 'label') as $field) {
109 | if ($this->$field !== null) {
110 | $paramName = preg_replace_callback('/[A-Z]/', function($match){
111 | return '-'.strtolower($match[0]);
112 | }, $field);
113 | $params[$paramName] = $this->$field;
114 | }
115 | }
116 | return $params;
117 | }
118 | }
--------------------------------------------------------------------------------