From ea74b962934176b8e901531e02eaecbd39016818 Mon Sep 17 00:00:00 2001 From: "iyuu.cn" <367013672@qq.com> Date: Sat, 15 Feb 2020 19:23:54 +0800 Subject: [PATCH] =?UTF-8?q?windows=E5=A4=A7=E5=B0=8F=E5=86=99=E4=B8=8D?= =?UTF-8?q?=E6=95=8F=E6=84=9F=EF=BC=8C=E5=88=A0=E9=99=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/Client/Transmission/Transmission.php | 759 ------------------ .../Transmission/TransmissionRPCException.php | 48 -- config/config.sample.php | 5 +- 3 files changed, 3 insertions(+), 809 deletions(-) delete mode 100644 app/Client/Transmission/Transmission.php delete mode 100644 app/Client/Transmission/TransmissionRPCException.php diff --git a/app/Client/Transmission/Transmission.php b/app/Client/Transmission/Transmission.php deleted file mode 100644 index 71bf719..0000000 --- a/app/Client/Transmission/Transmission.php +++ /dev/null @@ -1,759 +0,0 @@ -, - * Bryce Chidester - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -/** - * PHP version specific information - * version_compare() (PHP 4 >= 4.1.0, PHP 5) - * ctype_digit() (PHP 4 >= 4.0.4, PHP 5) - * stream_context_create (PHP 4 >= 4.3.0, PHP 5) - * PHP Class support (PHP 5) (PHP 4 might work, untested) - */ - -namespace IYUU\Client\transmission; - -use IYUU\Client\AbstractClient; - -/** - * A friendly little version check... - */ -if (version_compare(PHP_VERSION, '5.2.10', '<')) { - die("The TransmissionRPC class requires PHP version 5.2.10 or above." . PHP_EOL); -} - -/** - * Transmission bittorrent client/daemon RPC communication class - * - * Usage example: - * - * $rpc = new TransmissionRPC($rpc_url); - * $result = $rpc->add_file( $url_or_path_to_torrent, $target_folder ); - * - * - */ -class transmission extends AbstractClient -{ - /** - * User agent used in all http communication - */ - const HTTP_UA = 'TransmissionRPC for PHP/0.3'; - - /** - * The URL to the bittorent client you want to communicate with - * the port (default: 9091) can be set in you Transmission preferences - * @var string - */ - public $url = ''; - - /** - * If your Transmission RPC requires authentication, supply username here - * @var string - */ - public $username = ''; - - /** - * If your Transmission RPC requires authentication, supply password here - * @var string - */ - public $password = ''; - - /** - * Print debugging information, default is off - * @var bool - */ - public $debug = false; - - /** - * Transmission RPC version - * @var int - */ - protected $rpc_version = 0; - - /** - * Transmission uses a session id to prevent CSRF attacks - * @var string - */ - protected $session_id = ''; - - /** - * Default values for stream context - * @var array - */ - private $default_context_opts = array( - 'http' => array( - 'user_agent' => self::HTTP_UA, - 'timeout' => '60', // Don't want to be too slow - 'ignore_errors' => true, // Leave the error parsing/handling to the code - ), - "ssl"=>array( - "verify_peer"=>false, - "verify_peer_name"=>false, - ) - ); - - /** - * Constants for torrent status - */ - const TR_STATUS_STOPPED = 0; - const TR_STATUS_CHECK_WAIT = 1; - const TR_STATUS_CHECK = 2; - const TR_STATUS_DOWNLOAD_WAIT = 3; - const TR_STATUS_DOWNLOAD = 4; - const TR_STATUS_SEED_WAIT = 5; - const TR_STATUS_SEED = 6; - - const RPC_LT_14_TR_STATUS_CHECK_WAIT = 1; - const RPC_LT_14_TR_STATUS_CHECK = 2; - const RPC_LT_14_TR_STATUS_DOWNLOAD = 4; - const RPC_LT_14_TR_STATUS_SEED = 8; - const RPC_LT_14_TR_STATUS_STOPPED = 16; - - /** - * Takes the connection parameters - * - * @param string $url - * @param string $username - * @param string $password - */ - public function __construct($url = 'http://127.0.0.1:9091/transmission/rpc', $username = null, $password = null) - { - $this->url = $url; - $this->username = $username; - $this->password = $password; - } - - /** - * Start one or more torrents - * - * @param int|array ids A list of transmission torrent ids - * @return mixed - * @throws TransmissionRPCException - */ - public function start($ids) - { - if (!is_array($ids)) { - $ids = array($ids); - } - $request = array("ids" => $ids); - return $this->request("torrent-start", $request); - } - - /** - * Stop one or more torrents - * - * @param int|array ids A list of transmission torrent ids - * @return mixed - * @throws TransmissionRPCException - */ - public function stop($ids) - { - if (!is_array($ids)) { - $ids = array($ids); - } - $request = array("ids" => $ids); - return $this->request("torrent-stop", $request); - } - - /** - * Reannounce one or more torrents - * - * @param int|array ids A list of transmission torrent ids - * @return mixed - * @throws TransmissionRPCException - */ - public function reannounce($ids) - { - if (!is_array($ids)) { - $ids = array($ids); - } - $request = array("ids" => $ids); - return $this->request("torrent-reannounce", $request); - } - - /** - * Verify one or more torrents - * - * @param int|array ids A list of transmission torrent ids - * @return mixed - * @throws TransmissionRPCException - */ - public function verify($ids) - { - if (!is_array($ids)) { - $ids = array($ids); - } - $request = array("ids" => $ids); - return $this->request("torrent-verify", $request); - } - - /** - * Get information on torrents in transmission, if the ids parameter is - * empty all torrents will be returned. The fields array can be used to return certain - * fields. Default fields are: "id", "name", "status", "doneDate", "haveValid", "totalSize". - * See https://github.com/transmission/transmission/blob/2.9x/extras/rpc-spec.txt for available fields - * - * @param array fields An array of return fields - * @param int|array ids A list of transmission torrent ids - * - * Request: - * { - * "arguments": { - * "fields": [ "id", "name", "totalSize" ], - * "ids": [ 7, 10 ] - * }, - * "method": "torrent-get", - * "tag": 39693 - * } - * - * Response: - * { - * "arguments": { - * "torrents": [ - * { - * "id": 10, - * "name": "Fedora x86_64 DVD", - * "totalSize": 34983493932, - * }, - * { - * "id": 7, - * "name": "Ubuntu x86_64 DVD", - * "totalSize", 9923890123, - * } - * ] - * }, - * "result": "success", - * "tag": 39693 - * } - * @return mixed - * @throws TransmissionRPCException - */ - public function get($ids = array(), $fields = array()) - { - if (!is_array($ids)) { - $ids = array($ids); - } // Convert $ids to an array if only a single id was passed - if (count($fields) == 0) { - $fields = array("id", "name", "status", "doneDate", "haveValid", "totalSize"); - } // Defaults - $request = array( - "fields" => $fields, - "ids" => $ids - ); - return $this->request("torrent-get", $request); - } - - /** - * Set properties on one or more torrents, available fields are: - * "bandwidthPriority" | number this torrent's bandwidth tr_priority_t - * "downloadLimit" | number maximum download speed (in K/s) - * "downloadLimited" | boolean true if "downloadLimit" is honored - * "files-wanted" | array indices of file(s) to download - * "files-unwanted" | array indices of file(s) to not download - * "honorsSessionLimits" | boolean true if session upload limits are honored - * "ids" | array torrent list, as described in 3.1 - * "location" | string new location of the torrent's content - * "peer-limit" | number maximum number of peers - * "priority-high" | array indices of high-priority file(s) - * "priority-low" | array indices of low-priority file(s) - * "priority-normal" | array indices of normal-priority file(s) - * "seedRatioLimit" | double session seeding ratio - * "seedRatioMode" | number which ratio to use. See tr_ratiolimit - * "uploadLimit" | number maximum upload speed (in K/s) - * "uploadLimited" | boolean true if "uploadLimit" is honored - * See https://github.com/transmission/transmission/blob/2.9x/extras/rpc-spec.txt for more information - * - * @param array arguments An associative array of arguments to set - * @param int|array ids A list of transmission torrent ids - * @return mixed - * @throws TransmissionRPCException - */ - public function set($ids = array(), $arguments = array()) - { - // See https://github.com/transmission/transmission/blob/2.9x/extras/rpc-spec.txt for available fields - if (!is_array($ids)) { - $ids = array($ids); - } // Convert $ids to an array if only a single id was passed - if (!isset($arguments['ids'])) { - $arguments['ids'] = $ids; - } // Any $ids given in $arguments overrides the method parameter - return $this->request("torrent-set", $arguments); - } - - /** - * Add a new torrent - * - * Available extra options: - * key | value type & description - * ---------------------+------------------------------------------------- - * "download-dir" | string path to download the torrent to - * "filename" | string filename or URL of the .torrent file - * "metainfo" | string base64-encoded .torrent content - * "paused" | boolean if true, don't start the torrent - * "peer-limit" | number maximum number of peers - * "bandwidthPriority" | number torrent's bandwidth tr_priority_t - * "files-wanted" | array indices of file(s) to download - * "files-unwanted" | array indices of file(s) to not download - * "priority-high" | array indices of high-priority file(s) - * "priority-low" | array indices of low-priority file(s) - * "priority-normal" | array indices of normal-priority file(s) - * - * Either "filename" OR "metainfo" MUST be included. - * All other arguments are optional. - * - * @param string $torrent_location The URL or path to the torrent file - * @param string $save_path Folder to save torrent in - * @param array $extra_options Optional extra torrent options - * @return mixed - * @throws TransmissionRPCException - */ - public function add_file($torrent_location, $save_path = '', $extra_options = array()) - { - if (!empty($save_path)) { - $extra_options['download-dir'] = $save_path; - } - $extra_options['filename'] = $torrent_location; - - return $this->request("torrent-add", $extra_options); - } - - /* Add a new torrent using a file path or a URL (For backwards compatibility) - * @param torrent_location The URL or path to the torrent file - * @param save_path Folder to save torrent in - * @param extra options Optional extra torrent options - */ - public function add($torrent_location, $save_path = '', $extra_options = array()) - { - return $this->add_file($torrent_location, $save_path, $extra_options); - } - - /** - * Add a torrent using the raw torrent data - * - * @param string $torrent_metainfo The raw, unencoded contents (metainfo) of a torrent - * @param string $save_path Folder to save torrent in - * @param array $extra_options Optional extra torrent options - * @return mixed - * @throws TransmissionRPCException - */ - public function add_metainfo($torrent_metainfo, $save_path = '', $extra_options = array()) - { - if (!empty($save_path)) { - $extra_options['download-dir'] = $save_path; - } - $extra_options['metainfo'] = base64_encode($torrent_metainfo); - - return $this->request("torrent-add", $extra_options); - } - - /** - * Remove torrent from transmission - * - * @param bool delete_local_data Also remove local data? - * @param int|array ids A list of transmission torrent ids - * @return mixed - * @throws TransmissionRPCException - */ - public function delete($ids, $delete_local_data = false) - { - if (!is_array($ids)) { - $ids = array($ids); - } // Convert $ids to an array if only a single id was passed - $request = array( - "ids" => $ids, - "delete-local-data" => $delete_local_data - ); - return $this->request("torrent-remove", $request); - } - - /** - * Move local storage location - * - * @param int|array ids A list of transmission torrent ids - * @param string target_location The new storage location - * @param string move_existing_data Move existing data or scan new location for available data - * @return mixed - * @throws TransmissionRPCException - */ - public function move($ids, $target_location, $move_existing_data = true) - { - if (!is_array($ids)) { - $ids = array($ids); - } // Convert $ids to an array if only a single id was passed - $request = array( - "ids" => $ids, - "location" => $target_location, - "move" => $move_existing_data - ); - return $this->request("torrent-set-location", $request); - } - - /** - * 3.7. Renaming a Torrent's Path - * - * Method name: "torrent-rename-path" - * - * For more information on the use of this function, see the transmission.h - * documentation of tr_torrentRenamePath(). In particular, note that if this - * call succeeds you'll want to update the torrent's "files" and "name" field - * with torrent-get. - * - * Request arguments: - * - * string | value type & description - * ---------------------------------+------------------------------------------------- - * "ids" | array the torrent torrent list, as described in 3.1 - * | (must only be 1 torrent) - * "path" | string the path to the file or folder that will be renamed - * "name" | string the file or folder's new name - * Response arguments: "path", "name", and "id", holding the torrent ID integer - * - * @param int|array ids A 1-element list of transmission torrent ids - * @param string path The path to the file or folder that will be renamed - * @param string name The file or folder's new name - * @return mixed - * @throws TransmissionRPCException - */ - public function rename($ids, $path, $name) - { - if (!is_array($ids)) { - $ids = array($ids); - } // Convert $id to an array if only a single id was passed - if (count($ids) !== 1) { - throw new TransmissionRPCException('A single id is accepted', TransmissionRPCException::E_INVALIDARG); - } - - $request = array( - "ids" => $ids, - "path" => $path, - "name" => $name - ); - return $this->request("torrent-rename-path", $request); - } - - - /** - * Retrieve session statistics - * - * @returns array of statistics - */ - public function sstats() - { - return $this->request("session-stats", array()); - } - - /** - * Retrieve all session variables - * - * @returns array of session information - */ - public function sget() - { - return $this->request("session-get", array()); - } - - /** - * Set session variable(s) - * - * @param array of session variables to set - * @return mixed - * @throws TransmissionRPCException - */ - public function sset($arguments) - { - return $this->request("session-set", $arguments); - } - - /** - * Return the interpretation of the torrent status - * - * @param int The integer "torrent status" - * @returns string The translated meaning - * @return string - */ - public function getStatusString($intstatus) - { - if ($this->rpc_version < 14) { - if ($intstatus == self::RPC_LT_14_TR_STATUS_CHECK_WAIT) { - return "Waiting to verify local files"; - } - if ($intstatus == self::RPC_LT_14_TR_STATUS_CHECK) { - return "Verifying local files"; - } - if ($intstatus == self::RPC_LT_14_TR_STATUS_DOWNLOAD) { - return "Downloading"; - } - if ($intstatus == self::RPC_LT_14_TR_STATUS_SEED) { - return "Seeding"; - } - if ($intstatus == self::RPC_LT_14_TR_STATUS_STOPPED) { - return "Stopped"; - } - } else { - if ($intstatus == self::TR_STATUS_CHECK_WAIT) { - return "Waiting to verify local files"; - } - if ($intstatus == self::TR_STATUS_CHECK) { - return "Verifying local files"; - } - if ($intstatus == self::TR_STATUS_DOWNLOAD) { - return "Downloading"; - } - if ($intstatus == self::TR_STATUS_SEED) { - return "Seeding"; - } - if ($intstatus == self::TR_STATUS_STOPPED) { - return "Stopped"; - } - if ($intstatus == self::TR_STATUS_SEED_WAIT) { - return "Queued for seeding"; - } - if ($intstatus == self::TR_STATUS_DOWNLOAD_WAIT) { - return "Queued for download"; - } - } - return "Unknown"; - } - - - - /** - * Here be dragons (Internal methods) - */ - - - /** - * Clean up the request array. Removes any empty fields from the request - * - * @param array array The request associative array to clean - * @returns array The cleaned array - * @return array|null - */ - protected function cleanRequestData($array) - { - if (!is_array($array) || count($array) == 0) { - return null; - } // Nothing to clean - setlocale(LC_NUMERIC, 'en_US.utf8'); // Override the locale - if the system locale is wrong, then 12.34 will encode as 12,34 which is invalid JSON - foreach ($array as $index => $value) { - if (is_object($value)) { - $array[$index] = $value->toArray(); - } // Convert objects to arrays so they can be JSON encoded - if (is_array($value)) { - $array[$index] = $this->cleanRequestData($value); - } // Recursion - if (empty($value) && $value !== 0) { // Remove empty members - unset($array[$index]); - continue; // Skip the rest of the tests - they may re-add the element. - } - if (is_numeric($value)) { - $array[$index] = $value + 0; - } // Force type-casting for proper JSON encoding (+0 is a cheap way to maintain int/float/etc) - if (is_bool($value)) { - $array[$index] = ($value ? 1 : 0); - } // Store boolean values as 0 or 1 - if (is_string($value)) { - $type = mb_detect_encoding($value, "auto"); - if ($type !== 'UTF-8') { - $array[$index] = mb_convert_encoding($value, "UTF-8"); - //utf8_encode( $value ); // Make sure all data is UTF-8 encoded for Transmission - } - } - } - return $array; - } - - /** - * 执行 rpc 请求 - * - * @param string $method 请求类型/方法, 详见 $this->allowMethods - * @param array $arguments 附加参数, 可选 - * @return array - * @throws TransmissionRPCException - */ - protected function request($method, $arguments = array()) - { - // Check the parameters - if (!is_scalar($method)) { - throw new TransmissionRPCException('Method name has no scalar value', TransmissionRPCException::E_INVALIDARG); - } - if (!is_array($arguments)) { - throw new TransmissionRPCException('Arguments must be given as array', TransmissionRPCException::E_INVALIDARG); - } - - $arguments = $this->cleanRequestData($arguments); // Sanitize input - - // Grab the X-Transmission-Session-Id if we don't have it already - if (!$this->session_id) { - if (!$this->GetSessionID()) { - throw new TransmissionRPCException('Unable to acquire X-Transmission-Session-Id', TransmissionRPCException::E_SESSIONID); - } - } - - $data = array( - 'method' => $method, - 'arguments' => $arguments - ); - - $header = array( - 'Content-Type: application/json', - 'Authorization: Basic ' . base64_encode(sprintf("%s:%s", $this->username, $this->password)), - 'X-Transmission-Session-Id: ' . $this->session_id - ); - - $ch = curl_init(); - curl_setopt($ch, CURLOPT_URL, $this->url); - curl_setopt($ch, CURLOPT_HTTPHEADER, $header); - curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); - curl_setopt($ch, CURLOPT_USERPWD, $this->username . ':' . $this->password); - curl_setopt($ch, CURLOPT_HEADER, false); - curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); - curl_setopt($ch, CURLOPT_POST, true); - curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data)); - curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 60); - curl_setopt($ch, CURLOPT_TIMEOUT, 600); - $content = curl_exec($ch); - curl_close($ch); - - if (!$content) { - $content = array('result' => 'failed'); - } - return json_decode($content, true); - } - - /** - * Performs an empty GET on the Transmission RPC to get the X-Transmission-Session-Id - * and store it in $this->session_id - * - * @return string - * @throws TransmissionRPCException - */ - public function GetSessionID() - { - if (!$this->url) { - throw new TransmissionRPCException("Class must be initialized before GetSessionID() can be called.", TransmissionRPCException::E_INVALIDARG); - } - - // Setup the context - $contextopts = $this->default_context_opts; // Start with the defaults - - // Make sure it's blank/empty (reset) - $this->session_id = null; - - // Setup authentication (if provided) - if ($this->username && $this->password) { - $contextopts['http']['header'] = sprintf("Authorization: Basic %s\r\n", base64_encode($this->username . ':' . $this->password)); - } - - if ($this->debug) { - echo "TRANSMISSIONRPC_DEBUG:: GetSessionID():: Stream context created with options:" . - PHP_EOL . print_r($contextopts, true); - } - - $context = stream_context_create($contextopts); // Create the context for this request - if (!$fp = @fopen($this->url, 'r', false, $context)) { // Open a filepointer to the data, and use fgets to get the result - throw new TransmissionRPCException('Unable to connect to ' . $this->url, TransmissionRPCException::E_CONNECTION); - } - - // Check the response (headers etc) - $stream_meta = stream_get_meta_data($fp); - fclose($fp); - if ($this->debug) { - echo "TRANSMISSIONRPC_DEBUG:: GetSessionID():: Stream meta info: " . - PHP_EOL . print_r($stream_meta, true); - } - if ($stream_meta['timed_out']) { - throw new TransmissionRPCException("Timed out connecting to {$this->url}", TransmissionRPCException::E_CONNECTION); - } - if (substr($stream_meta['wrapper_data'][0], 9, 3) == "401") { - throw new TransmissionRPCException("Invalid username/password.", TransmissionRPCException::E_AUTHENTICATION); - } elseif (substr($stream_meta['wrapper_data'][0], 9, 3) == "409") { // This is what we're hoping to find - // Loop through the returned headers and extract the X-Transmission-Session-Id - foreach ($stream_meta['wrapper_data'] as $header) { - if (strpos($header, 'X-Transmission-Session-Id: ') === 0) { - if ($this->debug) { - echo "TRANSMISSIONRPC_DEBUG:: GetSessionID():: Session-Id header: " . - PHP_EOL . print_r($header, true); - } - $this->session_id = trim(substr($header, 27)); - break; - } - } - if (!$this->session_id) { // Didn't find a session_id - throw new TransmissionRPCException("Unable to retrieve X-Transmission-Session-Id", TransmissionRPCException::E_SESSIONID); - } - } else { - throw new TransmissionRPCException("Unexpected response from Transmission RPC: " . $stream_meta['wrapper_data'][0]); - } - return $this->session_id; - } - - /** - * 抽象方法,子类实现 - */ - public function status() - { - $rs = $this->sstats(); - return isset($rs['result']) ? $rs['result'] : 'error'; - } - - /** - * 抽象方法,子类实现 - */ - public function getList(&$move = array()) - { - $ids = array(); - $fields = array( "id", "status", "name", "hashString", "downloadDir", "torrentFile" ); - $res = $this->get($ids, $fields); - if (isset($res['result']) && $res['result'] == 'success') { - // 成功 - } else { - // 失败 - echo "获取种子列表失败,可能transmission暂时无响应,请稍后重试!".PHP_EOL; - return array(); - } - if (empty($res['arguments']['torrents'])) { - echo "未获取到正常做种数据,请多保种,然后重试!".PHP_EOL; - return array(); - } - $res = $res['arguments']['torrents']; - // 过滤,只保留正常做种 - $res = array_filter($res, function ($v) { - return isset($v['status']) && $v['status']===6; - }, ARRAY_FILTER_USE_BOTH); - - if (empty($res)) { - echo "未获取到正常做种数据,请多保种,然后重试!".PHP_EOL; - return array(); - } - // 提取数组:hashString - $info_hash = array_column($res, 'hashString'); - // 升序排序 - sort($info_hash); - $json = json_encode($info_hash, JSON_UNESCAPED_UNICODE); - // 去重 应该从文件读入,防止重复提交 - $sha1 = sha1($json); - // 组装返回数据 - $hashArray['hash'] = $json; - $hashArray['sha1'] = $sha1; - // 变换数组:hashString为键 - $hashArray['hashString'] = array_column($res, "downloadDir", 'hashString'); - $move = array_column($res, null, 'hashString'); - return $hashArray; - } -} diff --git a/app/Client/Transmission/TransmissionRPCException.php b/app/Client/Transmission/TransmissionRPCException.php deleted file mode 100644 index 770e03a..0000000 --- a/app/Client/Transmission/TransmissionRPCException.php +++ /dev/null @@ -1,48 +0,0 @@ -=')) { - parent::__construct($message, $code, $previous); - } else { - parent::__construct($message, $code); - } - } -} diff --git a/config/config.sample.php b/config/config.sample.php index ca3b439..f0f505e 100644 --- a/config/config.sample.php +++ b/config/config.sample.php @@ -33,7 +33,7 @@ return array( 'host' => 'http://127.0.0.1:9091/transmission/rpc', // 警告!注意:transmission/rpc这段别动,你只需要修改 127.0.0.1:9091 'username' => '', 'password' => '', - 'BT_backup' => '/var/lib/transmission/torrents', // 如果脚本与当前客户端不在一台机器,必须配置 + 'BT_backup' => '/var/lib/transmission/torrents', // 移动做种:如果脚本与当前客户端不在一台机器,必须配置 #'move' => 0, // 0不移动,1移动并辅种,2移动仅辅种自身,3未定义,4未定义 ), # 结束 @@ -43,12 +43,13 @@ return array( 'host' => 'http://127.0.0.1:8083', 'username' => '', 'password' => '', - 'BT_backup' => 'C:\Users\ASUS\AppData\Local\qBittorrent\BT_backup', // 必须配置 + 'BT_backup' => 'C:\Users\ASUS\AppData\Local\qBittorrent\BT_backup', // 移动做种:必须配置 #'move' => 0, // 0不移动,1移动并辅种,2移动仅辅种自身,3未定义,4未定义 ), # 结束 // 全局客户端设置 结束 ), + // 移动做种必须配置 'move' =>array( 'type' => 0, // 0保持不变,1减,2加,3替换 'path' =>array(