protomank Posted February 10, 2008 Report Share Posted February 10, 2008 Great code you guys!I was goind to give some fixes, but m69bv3 already did (using substr instead os substring and add-url instead of get-url), great work!One sugestion I have is to add urlencode when adding a http torrent. It's better and safer. Link to comment Share on other sites More sharing options...
Miyanokouji Posted February 21, 2008 Author Report Share Posted February 21, 2008 Updated again, unfortunately I think for the last time. Read the update notice in the first post for more info. Link to comment Share on other sites More sharing options...
Ultima Posted April 1, 2008 Report Share Posted April 1, 2008 public function addTorrent($filename,&$estring = false) {... curl_setopt($ch,CURLOPT_URL,"http://".$this->host."/gui/?action=get-url&s=".urlencode($filename));...Do you mean "add-url" when you write "get-url"?Edit: Er, I guess you copied m69bv3's code incorrectly...? //$file is a number between 0 and the number of files in the torrent minus one. ( I think. might be 1-based)... public function setPriority($hash,$files,$priority) { $filenums = ""; if(is_array($files)) { foreach($files as $value) { $filenums.="&f=".$value; } } else { $filenums = "&hash=".$file; } $ch = curl_init(); curl_setopt($ch,CURLOPT_URL,"http://".$this->host."/gui/?action=setprio&hash=$hash&p=".$priority."&f=".$filenums);...The file index is zero-based Regarding the $filenums variable... it sees rather odd how you're setting the URL up. When you check whether $files is an array, and it hits the else block, you should be setting $filenums to "&f=".$file, not "&hash=".$file. Also, when you actually call curl_setopt() on CURLOPT_URL, you don't need the extra "&f=" at the end (since it's already in $filenums).Edit: Oh, nowotny already fixed it here... Not correctly fixed in the main post? public function is_online() {... $ret = curl_exec($ch); if($ret !== false) { $ret = true; } return $ret; }Would it not be easier to simply sayreturn (curl_exec($ch) !== false);?I hesitate to modify the first post for Miyanokouji because I'm only looking at it from the outside without much of any PHP experience (so I'm not sure if my suggestions/changes actually work). Link to comment Share on other sites More sharing options...
mofle Posted April 5, 2008 Report Share Posted April 5, 2008 How can i get a detailed view of only one torrent?details.phpName:Progress:Seeds:and so on... Link to comment Share on other sites More sharing options...
Ultima Posted April 6, 2008 Report Share Posted April 6, 2008 Get the data from getTorrents() and parse it accordingly? Link to comment Share on other sites More sharing options...
mofle Posted April 6, 2008 Report Share Posted April 6, 2008 Yes, that one i got figured out, but how do i do that?Thanks for your help Link to comment Share on other sites More sharing options...
Ultima Posted April 6, 2008 Report Share Posted April 6, 2008 Look at the API documentation on the ?list=1 output, and you'll find that it's rather simple. From the returned/parsed JSON, you'll get a dictionary (call it $list), then you simply access $list['torrents'] (or however you access hashtable data in PHP). From there, loop though the list, checking the first element in each item in the list to find the corresponding hash you're looking for ($list['torrents'][$i][0] or something).The looping is somewhat cumbersome, so Directrix has already proposed a change to the ?list=1 output to make it so that $list['torrents'] is actually a dictionary whose keys are the hashes (so you'd be able to access the data directly using $list['torrents'][$hash] or whatever). That hasn't been implemented yet, though. Link to comment Share on other sites More sharing options...
mofle Posted April 7, 2008 Report Share Posted April 7, 2008 Can anyone explain to me how to use the addTorrent function in the Web_api.Lets say i have a list of links, how can i add one of the links to uTorrent when i click on it? Link to comment Share on other sites More sharing options...
Lord Alderaan Posted April 7, 2008 Report Share Posted April 7, 2008 This php stuff is for developers. If you don't know php there is little chance we can explain it to you here. Link to comment Share on other sites More sharing options...
Ultima Posted April 8, 2008 Report Share Posted April 8, 2008 Indeed. The PHP API code is very simple to understand -- even for someone like me, who has an absolutely minimal amount of experience with PHP. For someone who's supposed to have coded the mUI, shouldn't this be cake?@mofle: To answer your question... If the uTorrent object is called $torrent, and you have an array of URLs called $urls, then foreach ($urls as $url) $torrent->addTorrent($url); is how you would add the torrents.@Lord Alderaan: Since you probably have plenty of experience with PHP... Are the points I brougt up earlier correct and safe to put into the first post? Link to comment Share on other sites More sharing options...
Directrix Posted April 8, 2008 Report Share Posted April 8, 2008 Just a few thoughts:Any reason why anybody would need multiple uTorrent objects? I'd make uTorrent a singleton. (atleast add a constructor)The are a few too many curl* blocks (imo) which could be made into a method, eg.:private function makeRequest($qs, &$ret = null, $options = array()) { $ch = curl_init(); curl_setopt_array($ch, $options); curl_setopt($ch, CURLOPT_URL, "http://" . $this->host . "/gui/" . $qs); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_USERPWD, $this->user.":".$this->pass); $ret = curl_exec($ch); curl_close($ch); }then getTorrents would look like:public function getTorrents() { $ret = ""; $this->makeRequest("?list=1", $ret); $obj = json_decode($ret, true); $torrents = $obj['torrents']; return $torrents; }(makeRequest could return the results instead of setting a reference aswell)You could store the labels from getTorrent in an array and then return that array in getLabels instead of making another ?list=1 request.The foreach-loops could be replaced with this one-liner:$hashes = "&hash=" . implode("&hash=", is_array($hash) ? $hash : array($hash)); Link to comment Share on other sites More sharing options...
Lord Alderaan Posted April 8, 2008 Report Share Posted April 8, 2008 @Ultima:Your right about the add-url thing.And nowotny fix of the priority thing should also be implemented.You should definitely update the first post with those.About the return thing. I usually don't make statements like that inside a return function but I agree that would be sleeker and have the same result.I also like Directx's suggestions but that would require a minor overhaul.I myself haven't delved or even used this class though. Hadn't found a need for it myself but I'm thinking about writing a shell in php that will allow multi-user stuff etc when 1.8 and the new webui are out. Link to comment Share on other sites More sharing options...
Ultima Posted April 9, 2008 Report Share Posted April 9, 2008 I've fixed the "big" problems in the first post. Didn't bother backporting tweaks (like Directrix's suggested use of implode, or my is_online() change), since I don't want to potentially break what currently works without any real testing of my own.Onto something mildly more interesting...<?phpdefine("UTORRENT_TORRENT_HASH", 0);define("UTORRENT_TORRENT_STATUS", 1);define("UTORRENT_TORRENT_NAME", 2);define("UTORRENT_TORRENT_SIZE", 3);define("UTORRENT_TORRENT_PROGRESS", 4);define("UTORRENT_TORRENT_DOWNLOADED", 5);define("UTORRENT_TORRENT_UPLOADED", 6);define("UTORRENT_TORRENT_RATIO", 7);define("UTORRENT_TORRENT_UPSPEED", 8);define("UTORRENT_TORRENT_DOWNSPEED", 9);define("UTORRENT_TORRENT_ETA", 10);define("UTORRENT_TORRENT_LABEL", 11);define("UTORRENT_TORRENT_PEERS_CONNECTED", 12);define("UTORRENT_TORRENT_PEERS_SWARM", 13);define("UTORRENT_TORRENT_SEEDS_CONNECTED", 14);define("UTORRENT_TORRENT_SEEDS_SWARM", 15);define("UTORRENT_TORRENT_AVAILABILITY", 16);define("UTORRENT_TORRENT_QUEUE_POSITION", 17);define("UTORRENT_TORRENT_REMAINING", 18);define("UTORRENT_FILEPRIORITY_HIGH", 3);define("UTORRENT_FILEPRIORITY_NORMAL", 2);define("UTORRENT_FILEPRIORITY_LOW", 1);define("UTORRENT_FILEPRIORITY_SKIP", 0);define("UTORRENT_TYPE_INTEGER", 0);define("UTORRENT_TYPE_BOOLEAN", 1);define("UTORRENT_TYPE_STRING", 2);define("UTORRENT_STATUS_STARTED", 1);define("UTORRENT_STATUS_CHECKED", 2);define("UTORRENT_STATUS_START_AFTER_CHECK", 4);class uTorrent { // class static variables private static $base = "http://%s:%s/gui/%s"; // member variables public $host; public $port; public $user; public $pass; public $token; // constructor function __construct($host = "", $port = "", $user = "", $pass = "") { $this->host = $host; $this->port = $port; $this->user = $user; $this->pass = $pass; if (!$this->getToken($this->token)) { //handle error here, don't know how to best do this yet die('could not get token'); } } // performs request private function makeRequest($request, $decode = true, $options = array()) { if (!empty($this->token)) { // Check if we have a ? if (substr($request, 0, 1) == '?') $request = preg_replace('/^\?/', '?token='.$this->token . '&', $request); } $ch = curl_init(); curl_setopt_array($ch, $options); curl_setopt($ch, CURLOPT_URL, sprintf(self::$base, $this->host, $this->port, $request)); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_USERPWD, $this->user.":".$this->pass); $req = curl_exec($ch); curl_close($ch); return ($decode ? json_decode($req, true) : $req); } // implodes given parameter with glue, whether it is an array or not private function paramImplode($glue, $param) { return $glue.implode($glue, is_array($param) ? $param : array($param)); } // gets token, returns true on success, token is stored in $token by-ref argument public function getToken(&$token) { $output = $this->makeRequest('token.html', false); if (preg_match('/<div id=\'token\'.+>(.*)<\/div>/', $output, $m)) { $token = $m[1]; return true; } return false; } // returns the uTorrent build number public function getBuild(){ $json = $this->makeRequest("?"); return $json['build']; } // returns an array of files for the specified torrent hash // TODO: // - (when implemented in API) allow multiple hashes to be specified public function getFiles($hash) { $json = $this->makeRequest("?action=getfiles&hash=".$hash); return $json['files']; } // returns an array of all labels public function getLabels(){ $json = $this->makeRequest("?list=1"); return $json['label']; } // returns an array of the properties for the specified torrent hash // TODO: // - (when implemented in API) allow multiple hashes to be specified public function getProperties($hash) { $json = $this->makeRequest("?action=getprops&hash=".$hash); return $json['props']; } // returns an array of all settings public function getSettings() { $json = $this->makeRequest("?action=getsettings"); return $json['settings']; } // returns an array of all torrent jobs and related information public function getTorrents() { $json = $this->makeRequest("?list=1"); return $json['torrents']; } // returns true if WebUI server is online and enabled, false otherwise public function is_online() { return is_array($this->makeRequest("?")); } // sets the properties for the specified torrent hash // TODO: // - allow multiple hashes, properties, and values to be set simultaneously public function setProperties($hash, $property, $value) { $this->makeRequest("?action=setprops&hash=".$hash."&s=".$property."&v=".$value, false); } // sets the priorities for the specified files in the specified torrent hash public function setPriority($hash, $files, $priority) { $this->makeRequest("?action=setprio&hash=".$hash."&p=".$priority.$this->paramImplode("&f=", $files), false); } // sets the settings // TODO: // - allow multiple settings and values to be set simultaneously public function setSetting($setting, $value) { $this->makeRequest("?action=setsetting&s=".$setting."&v=".$value, false); } // add a file to the list public function torrentAdd($filename, &$estring = false) { $split = explode(":", $filename, 2); if (count($split) > 1 && (stristr("|http|https|file|", "|".$split[0]."|") !== false)) { $this->makeRequest("?action=add-url&s=".urlencode($filename), false); } elseif (file_exists($filename)) { $json = $this->makeRequest("?action=add-file", true, array(CURLOPT_POSTFIELDS => array("torrent_file" => "@".realpath($filename)))); if (isset($json['error'])) { if ($estring !== false) $estring = $json['error']; return false; } return true; } else { if ($estring !== false) $estring = "File doesn't exist!"; return false; } } // force start the specified torrent hashes public function torrentForceStart($hash) { $this->makeRequest("?action=forcestart".$this->paramImplode("&hash=", $hash), false); } // pause the specified torrent hashes public function torrentPause($hash) { $this->makeRequest("?action=pause".$this->paramImplode("&hash=", $hash), false); } // recheck the specified torrent hashes public function torrentRecheck($hash) { $this->makeRequest("?action=recheck".$this->paramImplode("&hash=", $hash), false); } // start the specified torrent hashes public function torrentStart($hash) { $this->makeRequest("?action=start".$this->paramImplode("&hash=", $hash), false); } // stop the specified torrent hashes public function torrentStop($hash) { $this->makeRequest("?action=stop".$this->paramImplode("&hash=", $hash), false); } // remove the specified torrent hashes (and data, if $data is set to true) public function torrentRemove($hash, $data = false) { $this->makeRequest("?action=".($data ? "removedata" : "remove").$this->paramImplode("&hash=", $hash), false); }}?>Changelog[2009-08-18]Added: Rudimentary token authentication support (courtesy of saivert)[2008-04-10]Fixed: torrentAdd() wasn't making the correct request ("action=..." instead of "?action=...")Changed: __construct($host, $port, $user, $pass)Changed: Constructor parameters are now optionalChanged: is_online() makes sure server is running and webUI is actually enabled[2008-04-09]Added: __constructor($host, $user, $pass)Added: addTorrent() now calls add-url for https:// and file:// tooAdded: getBuild() (works only with µTorrent 1.8.x)Fixed: addTorrent() correctly calls add-url now instead of get-urlFixed: setPriority() had minor bugsFixed: addTorrent() uses substr() instead of substring() (which doesn't exist)Changed: *Torrent() --> torrent*() (basically, I renamed a bunch of the functions, like addTorrent --> torrentAdd, or forcestartTorrent --> torrentForceStart). I changed the function names because... well, it's more organized this way, since the function naming actually has some kind of prefix scheme.Changed: All get*() functions now return the relevant node in the JSON output rather than the full JSON output (which happened in some cases, like getFiles(), getProperties(), or getSettings())Changed: Major code cleanup (almost a complete rewrite)Changed: Some comments were removed regarding structure of returned data... the information can always be found here. I'll consider re-adding more detailed comments after this code gets a bit more feedback.Changed: The foreach loops were changed to implode() statementsThis code could probably do with a bit more error checking in various places, but uh, I don't think it's any worse off than the original version on that front. At any rate, I might've forgotten to list a few fixes/additions I made along the way. I haven't tested ANY of this, by the way... I'm going purely by instinct! I've finally decided to install XAMPP... And amazingly, it worked properly (well, besides torrentAdd(), but that's fixed now) xDFeedback, feedback, feedback!Development DiscussionI don't think the class should be made singleton... There's no real need to artificially limit the number of uTorrent objects that can be made. I mean, what if the user wants to control multiple web UIs simultaneously? At any rate, you'll notice I've added a constructor. Wewt?!I never got around to modifying getTorrents() to make it return both the labels and torrents... I think that if we're going to go that route, the function might as well be renamed to getList()... Comments? Also, should there be a way to get an updated list by inputting a CID/torrentc value? getList($cid = 0) or something?As you'll notice, there are several TODO's in the comments... For setProperty() and setSetting(), I'm not really sure how best to proceed, since I don't really like the prospect of attempting to detect/interpret the parameters... Should I simply create two new functions that take arrays as parameters instead (like setProperties() and setSettings())?I think I should change makeRequest() to makeGETRequest(), and then create a makePOSTRequest() as well. It's currently possible to peform POST requests with makeRequest() because of Directrix's foresight (the addition of the $option parameter). The only reason I think it should be further split is because I feel like the code should be made a bit more modular, so that people who don't have cURL installed can simply replace the makeGETRequest() and makePOSTRequest() methods with something that works on their server...Opinions?Edit: lol wow, didn't realize Rexxars already implemented many of these changes... approximately four months ago.Interestingly (or not?), I also considered writing a function not too different from his processHashArgument() function (albeit, a bit more generalized in that I'd also pass it the glue), just because writing"&hash=".implode("&hash=", is_array($hash) ? $hash : array($hash))in so many places is somewhat annoying... [Edit: Done with that... paramImplode()]*shrug* I guess there's only so many ways one could do this... Link to comment Share on other sites More sharing options...
abydos Posted June 8, 2008 Report Share Posted June 8, 2008 grr Nice job falks. Can I ask sheduler on/off option or function?I have created a script that pings over the local LAN, and it would turn off sheduler if most of the PCs are offline. And of course it turns the sheduler on if others may want to use the internet, but it wont work without the sheduler function Link to comment Share on other sites More sharing options...
Dygear Posted June 10, 2008 Report Share Posted June 10, 2008 You can use this to make your code smaller and neater. I might consider porting your code over to use this class anyway. Also note that this is version 0.5.0, that is due to the fact that I have not implemented any of the multi functions found in cURL as of yet. Once I do find a use for them I will implement them tho and update them here.<?php/*** @package cURL Class** @since 2008-06-10 05:30** @author Mark 'Dygear' Tomlin** @license MIT License (http://opensource.org/licenses/mit-license.php)** @copyright Copyright (C) 2006, Mark 'Dygear' Tomlin** @version 0.5.0*/if (($cURL = new cURL()) === FALSE) { trigger_error('Unable to Start new cURL session!'); // die(); // Might not want to end it there ...}class cURL { # Initialize a cURL session function __construct($url = NULL) { if (!extension_loaded('curl') && (!dl('php_curl.dll') || !dl('curl.so'))) { trigger_error('cURL: Extension Not Loaded!'); return FALSE; } if (!function_exists('curl_setopt')) { trigger_error('cURL: Functions Not Loaded!'); return FALSE; } $this->self = curl_init($url); } # Copy a cURL handle along with all of its preferences function copyHandle() { return curl_copy_handle($this->self); } # Return the last error number function errno() { return curl_errno($this->self); } # Return a string containing the last error for the current session function error() { return curl_error($this->self); } # Perform a cURL session function exec() { return curl_exec($this->self); } # Get information regarding a specific transfer function getInfo($opt = NULL) { return curl_getinfo($this->self, $opt); } # Set an option for a cURL transfer function setOpt($option, $value) { return curl_setopt($this->self, $option, $value); } # Set multiple options for a cURL transfer function setOptArray($options) { if (!function_exists('curl_setopt_array')) { function curl_setopt_array(&$ch, $curl_options) { foreach ($curl_options as $option => $value) { if (!$this->setOpt($ch, $option, $value)) { return FALSE; } } return TRUE; } } return curl_setopt_array($this->self, $options); } # function version($age = NULL) { return curl_version($age); } # Close a cURL session function __destruct() { if (isset($this->self)) { return curl_close($this->self); } }}?>Ah, I see now that your using a function to handle all of the querys, much better idea! Well, the code is there, take it or leave it! Link to comment Share on other sites More sharing options...
abydos Posted June 14, 2008 Report Share Posted June 14, 2008 Re. I wrote a simple code to schedule your torrents, and added a feature.Most of us (here) have shared internet connection so we have to care about the "others" who may want to use the bandwidth at daylight, so i decided to write a scheduler with network watcher. It simply ping the pc's on the network and if anybody is online (when download is "forbidden") stops the torrents.Uploaded the hole script (compressed into one file):http://abydos.uw.hu/dwn/scheduler.rarThe $ips array contains the ips of the CP's.The $allowed array contains the time slices.I've split the timeline to 48 pieces (to half hours), for example"Sunday" =>array(0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1)means that from 1:00-6:59, 23:00-(monday)15:30 download is allowed$label_stop="something"; means the torrents that you dont want to start$label_seed="seedme"; this torrents will start after finished (after reachin 100.0%)You can enable/disable the script by renaming/deleting a file ("enable" without extension).And it logs if anything happen (stop,start,disabled)To run the script (scheduled ) you only have to do is create a txt and place this line into it:X:\...\php\php Y:\...\htdocs\schedule.phpthan modify the extension to .bat and add it into the windows scheduler.(dont forget to create "logs" and "sets" directory near the script, and of course put your enable_* and ip_port_set.php files into the "sets" dir.)I hope its useful.edit: added the most important, if download isnt allowed but nobody is online we can start the torrent(s).TODO:-? Link to comment Share on other sites More sharing options...
sasha_gu Posted March 28, 2009 Report Share Posted March 28, 2009 help me to process a command http://[iP]:[PORT]/gui/?list=1&cid=[CACHE ID] Link to comment Share on other sites More sharing options...
Ultima Posted March 29, 2009 Report Share Posted March 29, 2009 You can't as is with the PHP API. It'll require modification, which I mentioned several posts above. Link to comment Share on other sites More sharing options...
sasha_gu Posted March 31, 2009 Report Share Posted March 31, 2009 problem disappeared Link to comment Share on other sites More sharing options...
johndoe666 Posted July 24, 2009 Report Share Posted July 24, 2009 Any chance of getting token support in the PHP class from Ultima? Link to comment Share on other sites More sharing options...
Ultima Posted July 26, 2009 Report Share Posted July 26, 2009 I thought of doing it a while back, but got lazy. And lack of time caught up to me. Link to comment Share on other sites More sharing options...
johndoe666 Posted July 27, 2009 Report Share Posted July 27, 2009 Do you have time to do it now? I have hacked token support into my code, but it would be good to have it properly in the API Link to comment Share on other sites More sharing options...
saivert Posted August 19, 2009 Report Share Posted August 19, 2009 If you feel you've done a good job adding token support simply post the code here. I don't think anyone would mind.This is a collaborative work isn't it?This is my take on it:getToken method: // gets token, returns true on success, token is stored in $token by-ref argument public function getToken(&$token) { $output = $this->makeRequest('token.html', false); if (preg_match('/<div id=\'token\'.+>(.*)<\/div>/', $output, $m)) { $token = $m[1]; return true; } return false; }}Modified constructor: // constructor function __construct($host = "", $port = "", $user = "", $pass = "") { $this->host = $host; $this->port = $port; $this->user = $user; $this->pass = $pass; if (!$this->getToken($this->token)) { //handle error here, don't know how to best do this yet die('could not get token'); } }Modified makeRequest method: // performs request private function makeRequest($request, $decode = true, $options = array()) { $ch = curl_init(); curl_setopt_array($ch, $options); if (!empty($this->token)) { // Check if we have a ? if (substr($request, 0, 1) == '?') $request = preg_replace('/^\?/', '?token='.$this->token . '&', $request); } //print "<code>$request</code>"; //DEBUG curl_setopt($ch, CURLOPT_URL, sprintf(self::$base, $this->host, $this->port, $request)); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_USERPWD, $this->user.":".$this->pass); $req = curl_exec($ch); curl_close($ch); return ($decode ? json_decode($req, true) : $req); }Also I made a package with the updated uTorrent class and a sample php script that demonstrates how to use it.Contact me for the download. Link to comment Share on other sites More sharing options...
NanaBonana Posted January 10, 2010 Report Share Posted January 10, 2010 I am having trouble with this on my website and to my local pc... I know that I can access my normal webUI from outside the network (using my iphone internet) but when I try and host this on my website, it just doesn't want to connect. I know that the IP/port/username/password are all correct.Also I am using the script from the main post, which works fine locally but I would like this to be remote.Can somebody help me out with this? Link to comment Share on other sites More sharing options...
Ultima Posted January 11, 2010 Report Share Posted January 11, 2010 I won't be able to really help much, but here's one possibility: are you sure your server has cURL installed? Link to comment Share on other sites More sharing options...
Recommended Posts
Archived
This topic is now archived and is closed to further replies.