mirror of
				https://gitee.com/ledc/IYUUAutoReseed
				synced 2025-10-31 00:39:50 +00:00 
			
		
		
		
	IYUUAutoReseed初始化版本库v0.2.0
This commit is contained in:
		
							
								
								
									
										141
									
								
								app/Class/Bencode.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										141
									
								
								app/Class/Bencode.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,141 @@ | ||||
| <?php | ||||
| /** | ||||
|  * Created by PhpStorm. | ||||
|  * User: Rhilip | ||||
|  * Date: 2019/4/21 | ||||
|  * Time: 21:12 | ||||
|  */ | ||||
| class Bencode | ||||
| { | ||||
|     /** | ||||
|      * Decodes a BEncoded string to the following values: | ||||
|      * - Dictionary (starts with d, ends with e) | ||||
|      * - List (starts with l, ends with e | ||||
|      * - Integer (starts with i, ends with e | ||||
|      * - String (starts with number denoting number of characters followed by : and then the string) | ||||
|      * | ||||
|      * @see https://wiki.theory.org/index.php/BitTorrentSpecification | ||||
|      * | ||||
|      * @param string $data | ||||
|      * @param int $pos | ||||
|      * @return mixed | ||||
|      */ | ||||
|     public static function decode($data, &$pos = 0) | ||||
|     { | ||||
|         $start_decode = ($pos === 0); | ||||
|         if ($data[$pos] === 'd') { | ||||
|             $pos++; | ||||
|             $return = []; | ||||
|             while ($data[$pos] !== 'e') { | ||||
|                 $key = self::decode($data, $pos); | ||||
|                 $value = self::decode($data, $pos); | ||||
|                 if ($key === null || $value === null) { | ||||
|                     break; | ||||
|                 } | ||||
|                 if (!is_string($key)) { | ||||
|                     throw new RuntimeException('Invalid key type, must be string: ' . gettype($key)); | ||||
|                 } | ||||
|                 $return[$key] = $value; | ||||
|             } | ||||
|             ksort($return); | ||||
|             $pos++; | ||||
|         } elseif ($data[$pos] === 'l') { | ||||
|             $pos++; | ||||
|             $return = []; | ||||
|             while ($data[$pos] !== 'e') { | ||||
|                 $value = self::decode($data, $pos); | ||||
|                 $return[] = $value; | ||||
|             } | ||||
|             $pos++; | ||||
|         } elseif ($data[$pos] === 'i') { | ||||
|             $pos++; | ||||
|             $digits = strpos($data, 'e', $pos) - $pos; | ||||
|             $return = substr($data, $pos, $digits); | ||||
|             if ($return === '-0') { | ||||
|                 throw new RuntimeException('Cannot have integer value -0'); | ||||
|             } | ||||
|             $multiplier = 1; | ||||
|             if ($return[0] === '-') { | ||||
|                 $multiplier = -1; | ||||
|                 $return = substr($return, 1); | ||||
|             } | ||||
|             if (!ctype_digit($return)) { | ||||
|                 throw new RuntimeException('Cannot have non-digit values in integer number: ' . $return); | ||||
|             } | ||||
|             $return = $multiplier * ((int)$return); | ||||
|             $pos += $digits + 1; | ||||
|         } else { | ||||
|             $digits = strpos($data, ':', $pos) - $pos; | ||||
|             $len = (int)substr($data, $pos, $digits); | ||||
|             $pos += ($digits + 1); | ||||
|             $return = substr($data, $pos, $len); | ||||
|             $pos += $len; | ||||
|         } | ||||
|         if ($start_decode) { | ||||
|             if ($pos !== strlen($data)) { | ||||
|                 throw new RuntimeException('Could not fully decode bencode string'); | ||||
|             } | ||||
|         } | ||||
|         return $return; | ||||
|     } | ||||
|     /** | ||||
|      * @param mixed $data | ||||
|      * @return string | ||||
|      */ | ||||
|     public static function encode($data) | ||||
|     { | ||||
|         if (is_array($data)) { | ||||
|             $return = ''; | ||||
|             $check = -1; | ||||
|             $list = true; | ||||
|             foreach ($data as $key => $value) { | ||||
|                 if ($key !== ++$check) { | ||||
|                     $list = false; | ||||
|                     break; | ||||
|                 } | ||||
|             } | ||||
|             if ($list) { | ||||
|                 $return .= 'l'; | ||||
|                 foreach ($data as $value) { | ||||
|                     $return .= self::encode($value); | ||||
|                 } | ||||
|             } else { | ||||
|                 $return .= 'd'; | ||||
|                 foreach ($data as $key => $value) { | ||||
|                     $return .= self::encode(strval($key)); | ||||
|                     $return .= self::encode($value); | ||||
|                 } | ||||
|             } | ||||
|             $return .= 'e'; | ||||
|         } elseif (is_integer($data)) { | ||||
|             $return = 'i' . $data . 'e'; | ||||
|         } else { | ||||
|             $return = strlen($data) . ':' . $data; | ||||
|         } | ||||
|         return $return; | ||||
|     } | ||||
|     /** | ||||
|      * Given a path to a file, decode the contents of it | ||||
|      * | ||||
|      * @param string $path | ||||
|      * @return mixed | ||||
|      */ | ||||
|     public static function load($path) | ||||
|     { | ||||
|         if (is_file($path)) { | ||||
|             return self::decode(file_get_contents($path)); | ||||
|         } | ||||
|         return null; | ||||
|     } | ||||
|     /** | ||||
|      * Given a path for a file, encode the contents of it | ||||
|      * | ||||
|      * @param string $path | ||||
|      * @param $data | ||||
|      * @return mixed | ||||
|      */ | ||||
|     public static function dump($path, $data) | ||||
|     { | ||||
|         return file_put_contents($path, self::encode($data)); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										313
									
								
								app/Class/Function.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										313
									
								
								app/Class/Function.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,313 @@ | ||||
| <?php | ||||
| /** | ||||
|  * 调试函数 | ||||
|  */ | ||||
| function p($data, $echo=true){ | ||||
| 	$str='******************************'."\n"; | ||||
| 	// 如果是boolean或者null直接显示文字;否则print | ||||
| 	if (is_bool($data)) { | ||||
| 		$show_data=$data ? 'true' : 'false'; | ||||
| 	}elseif (is_null($data)) { | ||||
| 		$show_data='null'; | ||||
| 	}else{ | ||||
| 		$show_data=print_r($data,true); | ||||
| 	} | ||||
| 	$str.=$show_data; | ||||
| 	$str.="\n".'******************************'."\n"; | ||||
| 	if($echo){ | ||||
| 		echo $str; | ||||
| 		return null; | ||||
| 	} | ||||
| 	return $str; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * 微信推送Server酱 | ||||
|  */ | ||||
| function sc($text='', $desp='') | ||||
| { | ||||
| 	global $configALL; | ||||
| 	$token = $configALL['sc.ftqq.com']; | ||||
| 	$desp = ($desp=='')?date("Y-m-d H:i:s") :$desp; | ||||
| 	$postdata = http_build_query(array( | ||||
| 			'text' => $text, | ||||
| 			'desp' => $desp | ||||
| 		)); | ||||
| 	$opts = array('http' =>	array( | ||||
| 			'method'  => 'POST', | ||||
| 			'header'  => 'Content-type: application/x-www-form-urlencoded', | ||||
| 			'content' => $postdata | ||||
| 		)); | ||||
| 	$context  = stream_context_create($opts); | ||||
| 	$result = file_get_contents('http://sc.ftqq.com/'.$token.'.send', false, $context); | ||||
| 	return  $result; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * 微信推送 爱语飞飞 | ||||
|  */ | ||||
| function ff($text='', $desp='') | ||||
| { | ||||
| 	global $configALL; | ||||
| 	$token = $configALL['iyuu.cn']; | ||||
| 	$desp = ($desp=='')?date("Y-m-d H:i:s") :$desp; | ||||
| 	$postdata = http_build_query(array( | ||||
| 			'text' => $text, | ||||
| 			'desp' => $desp | ||||
| 		)); | ||||
| 	$opts = array('http' =>	array( | ||||
| 			'method'  => 'POST', | ||||
| 			'header'  => 'Content-type: application/x-www-form-urlencoded', | ||||
| 			'content' => $postdata | ||||
| 		)); | ||||
| 	$context  = stream_context_create($opts); | ||||
| 	$result = file_get_contents('http://iyuu.cn/'.$token.'.send', false, $context); | ||||
| 	return  $result; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * 微信推送 爱语飞飞 | ||||
|  * @param array  $torrent 种子数组 | ||||
| 		Array | ||||
| 		( | ||||
| 			[id] => 118632 | ||||
| 			[h1] => CCTV5+ 2019 ATP Men's Tennis Final 20191115B HDTV 1080i H264-HDSTV | ||||
| 			[title] => 央视体育赛事频道 2019年ATP男子网球年终总决赛 单打小组赛 纳达尔VS西西帕斯 20191115[优惠剩余时间:4时13分] | ||||
| 			[details] => https://xxx.me/details.php?id=118632 | ||||
| 			[download] => https://xxx.me/download.php?id=118632 | ||||
| 			[filename] => 118632.torrent | ||||
| 			[type] => 0 | ||||
| 			[sticky] => 1 | ||||
| 			[time] => Array | ||||
| 				( | ||||
| 					[0] => "2019-11-16 20:41:53">4时13分 | ||||
| 					[1] => "2019-11-16 14:41:53">1时<br />46分 | ||||
| 				) | ||||
| 			[comments] => 0 | ||||
| 			[size] => 5232.64MB | ||||
| 			[seeders] => 69 | ||||
| 			[leechers] => 10 | ||||
| 			[completed] => 93 | ||||
| 			[percentage] => 100% | ||||
| 			[owner] => 匿名 | ||||
| 		) | ||||
|  */ | ||||
| function send($site = '', $torrent = array()) | ||||
| { | ||||
| 	$br = "\r\n"; | ||||
| 	$text = $site. ' 免费:' .$torrent['filename']. ',添加成功'; | ||||
| 	$desp = '主标题:'.$torrent['h1'] . $br; | ||||
|  | ||||
| 	if ( isset($torrent['title']) ) { | ||||
| 		$desp .= '副标题:'.$torrent['title']. $br; | ||||
| 	} | ||||
| 	if ( isset($torrent['size']) ) { | ||||
| 		$desp .= '大小:'.$torrent['size']. $br; | ||||
| 	} | ||||
| 	if ( isset($torrent['seeders']) ) { | ||||
| 		$desp .= '做种数:'.$torrent['seeders']. $br; | ||||
| 	} | ||||
| 	if ( isset($torrent['leechers']) ) { | ||||
| 		$desp .= '下载数:'.$torrent['leechers']. $br; | ||||
| 	} | ||||
| 	if ( isset($torrent['owner']) ) { | ||||
| 		$desp .= '发布者:'.$torrent['owner']. $br; | ||||
| 	} | ||||
| 	return ff($text, $desp); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * @brief 下载种子 | ||||
|  * @param string $url 种子URL | ||||
|  * @param string  $cookies 模拟登陆的cookie | ||||
|  * @return mixed 返回的数据 | ||||
|  */ | ||||
| function download($url, $cookies, $useragent, $method = 'GET') | ||||
| { | ||||
| 	$header = array( | ||||
| 		"Content-Type:application/x-www-form-urlencoded", | ||||
| 		'User-Agent: '.$useragent); | ||||
| 	$ch = curl_init(); | ||||
| 	if($method === 'POST'){ | ||||
| 		curl_setopt($ch, CURLOPT_POST, true ); | ||||
| 	} | ||||
| 	if(stripos($url, 'https://') !== FALSE) { | ||||
| 		curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE); | ||||
| 		curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE); | ||||
| 		curl_setopt($ch, CURLOPT_SSLVERSION, 1); | ||||
| 	} | ||||
| 	curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); | ||||
| 	curl_setopt($ch, CURLOPT_HTTPHEADER,$header); | ||||
| 	curl_setopt($ch, CURLOPT_COOKIE,$cookies); | ||||
| 	curl_setopt($ch, CURLOPT_URL, $url); | ||||
| 	curl_setopt($ch, CURLOPT_CONNECTTIMEOUT,60); | ||||
| 	curl_setopt($ch, CURLOPT_TIMEOUT,600); | ||||
| 	$data = curl_exec($ch); | ||||
| 	$status = curl_getinfo($ch); | ||||
| 	curl_close($ch); | ||||
| 	if (isset($status['http_code']) && $status['http_code'] == 200) { | ||||
| 		return $data; | ||||
| 	} | ||||
| 	if (isset($status['http_code']) && $status['http_code'] == 302) { | ||||
| 		return download($status['redirect_url'], $cookies, $useragent); | ||||
| 	} | ||||
| 	return $data; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * @brief 文件大小格式化为MB | ||||
|  * @param string $from 文件大小 | ||||
|  * @return int 单位MB | ||||
|  */ | ||||
| function convertToMB($from){ | ||||
|     $number=substr($from,0,-2); | ||||
|     switch(strtoupper(substr($from,-2))){ | ||||
|         case "KB": | ||||
|             return $number/1024; | ||||
|         case "MB": | ||||
|             return $number; | ||||
|         case "GB": | ||||
|             return $number*pow(1024,1); | ||||
|         case "TB": | ||||
|             return $number*pow(1024,2); | ||||
|         case "PB": | ||||
|             return $number*pow(1024,3); | ||||
|         default: | ||||
|             return $from; | ||||
|     } | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * @brief 种子过滤器 | ||||
|  * @param string $site 站点标识 | ||||
|  * @param array  $torrent 种子数组 | ||||
|  * 	Array | ||||
| 	( | ||||
| 		[id] => 118632 | ||||
| 		[h1] => CCTV5+ 2019 ATP Men's Tennis Final 20191115B HDTV 1080i H264-HDSTV | ||||
| 		[title] => 央视体育赛事频道 2019年ATP男子网球年终总决赛 单打小组赛 纳达尔VS西西帕斯 20191115[优惠剩余时间:4时13分] | ||||
| 		[details] => https://xxx.me/details.php?id=118632 | ||||
| 		[download] => https://xxx.me/download.php?id=118632 | ||||
| 		[filename] => 118632.torrent | ||||
| 		[type] => 0 | ||||
| 		[sticky] => 1 | ||||
| 		[time] => Array | ||||
| 			( | ||||
| 				[0] => "2019-11-16 20:41:53">4时13分 | ||||
| 				[1] => "2019-11-16 14:41:53">1时<br />46分 | ||||
| 			) | ||||
| 		[comments] => 0 | ||||
| 		[size] => 5232.64MB | ||||
| 		[seeders] => 69 | ||||
| 		[leechers] => 10 | ||||
| 		[completed] => 93 | ||||
| 		[percentage] => 100% | ||||
| 		[owner] => 匿名 | ||||
| 	) | ||||
|  * @return bool 或 string 	false不过滤 | ||||
|  */ | ||||
| function filter($site = '', $torrent = array()){ | ||||
| 	global $configALL; | ||||
| 	$config = $configALL[$site]; | ||||
| 	$filter = array(); | ||||
| 	// 读取配置 | ||||
| 	if (isset($configALL['default']['filter']) || isset($config['filter'])) { | ||||
| 		$filter = isset($config['filter']) && $config['filter'] ? $config['filter'] : $configALL['default']['filter']; | ||||
| 	}else { | ||||
| 		return false; | ||||
| 	} | ||||
| 	$filename = $torrent['filename']; | ||||
|  | ||||
| 	// 兼容性 | ||||
| 	if ( empty($torrent['size']) ) { | ||||
| 		return false; | ||||
| 	} | ||||
| 	// 大小过滤 | ||||
| 	$size = convertToMB($torrent['size']); | ||||
| 	$min = isset($filter['size']['min']) ? convertToMB($filter['size']['min']) : 0; | ||||
| 	$max = isset($filter['size']['max']) ? convertToMB($filter['size']['max']) : 2097152;	//默认 2097152MB = 2TB | ||||
| 	if ($min > $size || $size > $max) { | ||||
| 		return $filename. ' ' .$size. 'MB,被大小过滤'; | ||||
| 	} | ||||
|  | ||||
| 	// 兼容性 | ||||
| 	if ( empty($torrent['seeders']) ) { | ||||
| 		return false; | ||||
| 	} | ||||
| 	// 种子数过滤 | ||||
| 	$seeders = $torrent['seeders']; | ||||
| 	$min = isset($filter['seeders']['min']) ? $filter['seeders']['min'] : 1;	//默认 1 | ||||
| 	$max = isset($filter['seeders']['max']) ? $filter['seeders']['max'] : 3;	//默认 3 | ||||
| 	if ($min > $seeders || $seeders > $max) { | ||||
| 		return $filename. ' 当前做种' .$seeders. '人,被过滤'; | ||||
| 	} | ||||
|  | ||||
| 	// 兼容性 | ||||
| 	if ( empty($torrent['leechers']) ) { | ||||
| 		return false; | ||||
| 	} | ||||
| 	// 下载数过滤 | ||||
| 	$leechers = $torrent['leechers']; | ||||
| 	$min = isset($filter['leechers']['min']) ? $filter['leechers']['min'] : 0;		//默认 | ||||
| 	$max = isset($filter['leechers']['max']) ? $filter['leechers']['max'] : 30000;	//默认 | ||||
| 	if ($min > $leechers || $leechers > $max) { | ||||
| 		return $filename. ' 当前下载' .$leechers. '人,被过滤'; | ||||
| 	} | ||||
|  | ||||
| 	// 兼容性 | ||||
| 	if ( empty($torrent['completed']) ) { | ||||
| 		return false; | ||||
| 	} | ||||
| 	// 完成数过滤 | ||||
| 	$completed = $torrent['completed']; | ||||
| 	$min = isset($filter['completed']['min']) ? $filter['completed']['min'] : 0;		//默认 | ||||
| 	$max = isset($filter['completed']['max']) ? $filter['completed']['max'] : 30000;	//默认 | ||||
| 	if ($min > $completed || $completed > $max) { | ||||
| 		return $filename. ' 已完成数' .$completed. '人,被过滤'; | ||||
| 	} | ||||
|  | ||||
| 	return false; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * 奇数 | ||||
|  */ | ||||
| function oddFilter($var) | ||||
| { | ||||
|     // 返回$var最后一个二进制位, | ||||
|     // 为1则保留(奇数的二进制的最后一位肯定是1) | ||||
|     return($var & 1); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * 偶数 | ||||
|  */ | ||||
| function evenFilter($var) | ||||
| { | ||||
| 	// 返回$var最后一个二进制位, | ||||
|     // 为0则保留(偶数的二进制的最后一位肯定是0) | ||||
| 	return(!($var & 1)); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * 发布员签名 | ||||
|  * 注意:同时配置iyuu.cn与secret时,优先使用secret。 | ||||
|  */ | ||||
| function sign( $timestamp ){ | ||||
| 	global $configALL; | ||||
| 	// 爱语飞飞 | ||||
| 	$token = isset($configALL['iyuu.cn']) && $configALL['iyuu.cn'] ? $configALL['iyuu.cn'] : ''; | ||||
| 	// 鉴权 | ||||
| 	$token = isset($configALL['secret']) && $configALL['secret'] ? $configALL['secret'] : $token; | ||||
| 	return sha1($timestamp . $token); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * @brief 分离token中的用户uid | ||||
|  * token算法:IYUU + uid + T + sha1(openid+time+盐) | ||||
|  * @param string $token		用户请求token | ||||
|  */ | ||||
| function getUid($token){ | ||||
| 	//验证是否IYUU开头,strpos($token,'T')<15,token总长度小于60(40+10+5) | ||||
| 	return (strlen($token)<60)&&(strpos($token,'IYUU')===0)&&(strpos($token,'T')<15) ? substr($token,4,strpos($token,'T')-4): false; | ||||
| } | ||||
							
								
								
									
										332
									
								
								app/Class/IFile.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										332
									
								
								app/Class/IFile.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,332 @@ | ||||
| <?php | ||||
| /** | ||||
|  * @brief 文件处理 | ||||
|  * @version 0.6 | ||||
|  */ | ||||
|  | ||||
| /** | ||||
|  * @class IFile | ||||
|  * @brief IFile 文件处理类 | ||||
|  */ | ||||
| class IFile | ||||
| { | ||||
| 	private $resource = null; //文件资源句柄 | ||||
|  | ||||
| 	/** | ||||
| 	 * @brief 构造函数,打开资源流,并独占锁定 | ||||
| 	 * @param String $fileName 文件路径名 | ||||
| 	 * @param String $mode     操作方式,默认为读操作,可供选择的项为:r,r+,w+,w+,a,a+ | ||||
| 	 * @note $mod,'r'  只读方式打开,将文件指针指向文件头 | ||||
| 	 *             'r+' 读写方式打开,将文件指针指向文件头 | ||||
| 	 * 			   'w'  写入方式打开,将文件指针指向文件头并将文件大小截为零。如果文件不存在则尝试创建之。 | ||||
| 	 * 			   'w+' 读写方式打开,将文件指针指向文件头并将文件大小截为零。如果文件不存在则尝试创建之。 | ||||
| 	 * 			   'a'  写入方式打开,将文件指针指向文件末尾。如果文件不存在则尝试创建之。 | ||||
| 	 * 			   'a+' 读写方式打开,将文件指针指向文件末尾。如果文件不存在则尝试创建之。 | ||||
| 	 */ | ||||
| 	function __construct($fileName,$mode='r') | ||||
| 	{ | ||||
| 		$dirName  = dirname($fileName); | ||||
| 		$baseName = basename($fileName); | ||||
|  | ||||
| 		//检查并创建文件夹 | ||||
| 		self::mkdir($dirName); | ||||
|  | ||||
| 		$this->resource = fopen($fileName,$mode.'b'); | ||||
| 		if($this->resource) | ||||
| 		{ | ||||
| 			flock($this->resource,LOCK_EX); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * @brief 获取文件内容 | ||||
| 	 * @return String 文件内容 | ||||
| 	 */ | ||||
| 	public function read() | ||||
| 	{ | ||||
| 		$content = null; | ||||
| 		while(!feof($this->resource)) | ||||
| 		{ | ||||
| 			$content.= fread($this->resource,1024); | ||||
| 		} | ||||
| 		return $content; | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * @brief 文件写入操作 | ||||
| 	 * @param  String $content 要写入的文件内容 | ||||
| 	 * @return Int or false    写入的字符数; false:写入失败; | ||||
| 	 */ | ||||
| 	public function write($content) | ||||
| 	{ | ||||
| 		$worldsnum = fwrite($this->resource,$content); | ||||
| 		$this->save(); | ||||
| 		return is_bool($worldsnum) ? false : $worldsnum; | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * @brief  清空目录下的所有文件 | ||||
| 	 * @return bool false:失败; true:成功; | ||||
| 	 */ | ||||
| 	public static function clearDir($dir) | ||||
| 	{ | ||||
| 		if($dir[0] != '.' && is_dir($dir) && is_writable($dir)) | ||||
| 		{ | ||||
| 			$dirRes = opendir($dir); | ||||
| 			while( false !== ($fileName = readdir($dirRes)) ) | ||||
| 			{ | ||||
| 				if($fileName[0] !== '.') | ||||
| 				{ | ||||
| 					$fullpath = $dir.'/'.$fileName; | ||||
| 					if(is_file($fullpath)) | ||||
| 					{ | ||||
| 						self::unlink($fullpath); | ||||
| 					} | ||||
| 					else | ||||
| 					{ | ||||
| 						self::clearDir($fullpath); | ||||
| 						rmdir($fullpath); | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 			closedir($dirRes); | ||||
| 			return true; | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			return false; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * @brief 获取文件信息 | ||||
| 	 * @param String $fileName 文件路径 | ||||
| 	 * @return array or null   array:文件信息; null:文件不存在; | ||||
| 	 */ | ||||
| 	public static function getInfo($fileName) | ||||
| 	{ | ||||
| 		if(is_file($fileName)) | ||||
| 			return stat($fileName); | ||||
|  | ||||
| 		else | ||||
| 			return null; | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * @brief  创建文件夹 | ||||
| 	 * @param String $path  路径 | ||||
| 	 * @param int    $chmod 文件夹权限 | ||||
| 	 * @note  $chmod 参数不能是字符串(加引号),否则linux会出现权限问题 | ||||
| 	 */ | ||||
| 	public static function mkdir($path,$chmod=0777) | ||||
| 	{ | ||||
| 		return is_dir($path) or (self::mkdir(dirname($path),$chmod) and mkdir($path,$chmod)); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * @brief 复制文件 | ||||
| 	 * @param String $from 源文件路径 | ||||
| 	 * @param String $to   目标文件路径 | ||||
| 	 * @param String $mod  操作模式,c:复制(默认); x:剪切(删除$from文件) | ||||
| 	 * @return bool  操作结果 true:成功; false:失败; | ||||
| 	 */ | ||||
| 	public static function copy($from,$to,$mode = 'c') | ||||
| 	{ | ||||
| 		$dir = dirname($to); | ||||
|  | ||||
| 		//创建目录 | ||||
| 		self::mkdir($dir); | ||||
|  | ||||
| 		copy($from,$to); | ||||
|  | ||||
| 		if(is_file($to)) | ||||
| 		{ | ||||
| 			if($mode == 'x') | ||||
| 			{ | ||||
| 				self::unlink($from); | ||||
| 			} | ||||
| 			return true; | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			return false; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * @brief 删除文件 | ||||
| 	 * @param String $fileName 文件路径 | ||||
| 	 * @return bool  操作结果 false:删除失败; | ||||
| 	 */ | ||||
| 	public static function unlink($fileName) | ||||
| 	{ | ||||
| 		if(is_file($fileName) && is_writable($fileName)) | ||||
| 		{ | ||||
| 			return unlink($fileName); | ||||
| 		} | ||||
| 		else | ||||
| 			return false; | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * @brief  删除$dir文件夹 或者 其下所有文件 | ||||
| 	 * @param  String $dir       文件路径 | ||||
| 	 * @param  bool   $recursive 是否强制删除,如果强制删除则递归删除该目录下的全部文件,默认为false | ||||
| 	 * @return bool true:删除成功; false:删除失败; | ||||
| 	 */ | ||||
| 	public static function rmdir($dir,$recursive = false) | ||||
| 	{ | ||||
| 		if(is_dir($dir) && is_writable($dir)) | ||||
| 		{ | ||||
| 			//强制删除 | ||||
| 			if($recursive == true) | ||||
| 			{ | ||||
| 				self::clearDir($dir); | ||||
| 				return self::rmdir($dir,false); | ||||
| 			} | ||||
|  | ||||
| 			//非强制删除 | ||||
| 			else | ||||
| 			{ | ||||
| 				if(rmdir($dir)) | ||||
| 				{ | ||||
| 					return true; | ||||
| 				} | ||||
| 				else | ||||
| 				{ | ||||
| 					return false; | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * @brief 获取文件类型 | ||||
| 	 * @param  String $fileName  文件名 | ||||
| 	 * @return String $filetype  文件类型 | ||||
| 	 * @note 如果文件不存在,返回false,如果文件后缀名不在识别列表之内,返回NULL,对于docx及elsx格式文档识别在会出现识别为ZIP格式的错误,这是office2007的bug目前尚未修复,请谨慎使用 | ||||
| 	 */ | ||||
| 	public static function getFileType($fileName) | ||||
| 	{ | ||||
| 		$filetype = null; | ||||
| 		if(!is_file($fileName)) | ||||
| 		{ | ||||
| 			return false; | ||||
| 		} | ||||
|  | ||||
| 		$fileRes = fopen($fileName,"rb"); | ||||
| 	    if(!$fileRes) | ||||
| 		{ | ||||
| 			return false; | ||||
| 		} | ||||
|         $bin= fread($fileRes, 2); | ||||
|         fclose($fileRes); | ||||
|  | ||||
|         if($bin != null) | ||||
|         { | ||||
|         	$strInfo  = unpack("C2chars", $bin); | ||||
| 	        $typeCode = intval($strInfo['chars1'].$strInfo['chars2']); | ||||
| 			$typelist = self::getTypeList(); | ||||
| 			foreach($typelist as $val) | ||||
| 			{ | ||||
| 				if(strtolower($val[0]) == strtolower($typeCode)) | ||||
| 				{ | ||||
| 					if($val[0] == 8075) | ||||
| 					{ | ||||
| 						return array('zip','docx','xlsx'); | ||||
| 					} | ||||
| 					else | ||||
| 					{ | ||||
| 						return $val[1]; | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
|         } | ||||
| 		return $filetype; | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * @brief 获取文件类型映射关系 | ||||
|      * @return array 文件类型映射关系数组 | ||||
|      */ | ||||
|     public static function getTypeList() | ||||
|     { | ||||
|     	return array( | ||||
| 	    	array('255216','jpg'), | ||||
| 			array('13780','png'), | ||||
| 			array('7173','gif'), | ||||
| 			array('6677','bmp'), | ||||
| 			array('6063','xml'), | ||||
| 			array('60104','html'), | ||||
| 			array('208207','xls/doc'), | ||||
| 			array('8075','zip'), | ||||
| 			array('8075','docx'), | ||||
| 			array('8075','xlsx'), | ||||
| 			array("8297","rar"), | ||||
|     	); | ||||
|     } | ||||
|  | ||||
| 	/** | ||||
| 	 * @brief 获取文件大小 | ||||
| 	 * @param  String $fileName 文件名 | ||||
| 	 * @return Int    文件大小的字节数,如果文件无效则返回 NULL | ||||
| 	 */ | ||||
| 	public static function getFileSize($fileName) | ||||
| 	{ | ||||
| 		return is_file($fileName) ? filesize($fileName):null; | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * @brief 检测文件夹是否为空 | ||||
| 	 * @param String $dir 路径地址 | ||||
| 	 * @return bool true:$dir为空目录; false:$dir为非空目录; | ||||
| 	 */ | ||||
| 	public static function isEmptyDir($dir) | ||||
| 	{ | ||||
| 		if(is_dir($dir)) | ||||
| 		{ | ||||
| 			$isEmpty = true; | ||||
| 			$dirRes  = opendir($dir); | ||||
| 			while(false !== ($fileName = readdir($dirRes))) | ||||
| 			{ | ||||
| 				if($fileName!='.' && $fileName!='..') | ||||
| 				{ | ||||
| 					$isEmpty = false; | ||||
| 					break; | ||||
| 				} | ||||
| 			} | ||||
| 			closedir($dirRes); | ||||
| 			return $isEmpty; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * @brief 释放文件锁定 | ||||
| 	 */ | ||||
| 	public function save() | ||||
| 	{ | ||||
| 		flock($this->resource,LOCK_UN); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * @brief  获取文件扩展名 | ||||
| 	 * @param  String $fileName  文件名 | ||||
| 	 * @return String 文件后缀名 | ||||
| 	 */ | ||||
| 	public static function getFileSuffix($fileName) | ||||
| 	{ | ||||
| 		$fileInfoArray = pathinfo($fileName); | ||||
| 		return $fileInfoArray['extension']; | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * @brief 析构函数,释放文件连接句柄 | ||||
| 	 */ | ||||
| 	function __destruct() | ||||
| 	{ | ||||
| 		if(is_resource($this->resource)) | ||||
| 		{ | ||||
| 			fclose($this->resource); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										71
									
								
								app/Class/Oauth.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								app/Class/Oauth.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,71 @@ | ||||
| <?php | ||||
| /** | ||||
|  * IYUU用户注册、认证 | ||||
|  */ | ||||
| use Curl\Curl; | ||||
| class Oauth{ | ||||
|     // 合作的站点 | ||||
|     public static $sites = ['ourbits']; | ||||
|     // 爱语飞飞token | ||||
|     public static $token = ''; | ||||
|     // 合作站点用户id | ||||
|     public static $user_id = 0; | ||||
|     // 合作站点密钥 | ||||
|     public static $passkey = ''; | ||||
|     // 合作站名字 | ||||
|     public static $site = ''; | ||||
|     /** | ||||
|      * 初始化配置 | ||||
|      */ | ||||
|     public static function init(){ | ||||
|         global $configALL; | ||||
|         foreach (self::$sites as $name) { | ||||
|             if (isset($configALL[$name]['passkey']) && $configALL[$name]['passkey'] && isset($configALL[$name]['id']) && $configALL[$name]['id'] ) { | ||||
|                 self::$token = self::getSign(); | ||||
|                 self::$user_id = $configALL[$name]['id']; | ||||
|                 self::$passkey =  sha1( $configALL[$name]['passkey'] );     // 避免泄露用户passkey秘钥 | ||||
|                 self::$site = $name; | ||||
|                 return true; | ||||
|             } | ||||
|         } | ||||
|         echo "-----缺少合作站点登录参数:token, user_id, passkey, site \n"; | ||||
|         echo "-----当前正在使用测试接口,功能可能会受到限制! \n\n"; | ||||
|         return false; | ||||
|     } | ||||
|     /** | ||||
|      * 从配置文件内读取爱语飞飞token作为鉴权参数 | ||||
|      */ | ||||
|     public static function getSign(){ | ||||
|         global $configALL; | ||||
|         // 爱语飞飞 | ||||
|         $token = isset($configALL['iyuu.cn']) && $configALL['iyuu.cn'] ? $configALL['iyuu.cn'] : ''; | ||||
|         if (empty($token) || strlen($token)<46) { | ||||
|             echo "缺少辅种接口请求参数:爱语飞飞token \n"; | ||||
|             echo "请访问https://iyuu.cn 用微信扫码申请,并填入配置文件config.php内。\n\n"; | ||||
|             exit(1); | ||||
|         } | ||||
|         return $token; | ||||
|     } | ||||
|     /** | ||||
|      * 用户注册与登录 | ||||
|      * 作用:在服务器端实现微信用户与合作站点用户id的关联 | ||||
|      * 参数:爱语飞飞token + 合作站点用户id + sha1(合作站点密钥passkey) + 合作站点标识 | ||||
|      */ | ||||
|     public static function login($apiUrl = ''){ | ||||
|         $is_oauth = self::init(); | ||||
|         if ( $is_oauth ) { | ||||
|             $curl = new Curl(); | ||||
|             $curl->setOpt(CURLOPT_SSL_VERIFYPEER, false); | ||||
|             $data = [ | ||||
|                 'token'  => self::$token, | ||||
|                 'id'     => self::$user_id, | ||||
|                 'passkey'=> self::$passkey, | ||||
|                 'site'   => self::$site, | ||||
|             ]; | ||||
|             $res = $curl->get($apiUrl, $data); | ||||
|             p($res->response); | ||||
|             return true; | ||||
|         } | ||||
|         return false;         | ||||
|     } | ||||
| } | ||||
							
								
								
									
										368
									
								
								app/Class/Rpc.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										368
									
								
								app/Class/Rpc.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,368 @@ | ||||
| <?php | ||||
| /** | ||||
|  * Rpc操作类 | ||||
|  */ | ||||
| class Rpc | ||||
| { | ||||
| 	/** | ||||
|      * 版本号 | ||||
|      * @var string | ||||
|      */ | ||||
|     const VER = '0.0.1'; | ||||
|  | ||||
| 	// 下载种子的请求类型 GET POST | ||||
| 	public static $method = 'GET'; | ||||
| 	// RPC连接池 | ||||
| 	public static $links = array(); | ||||
| 	/** | ||||
|      * cookie | ||||
|      */ | ||||
|     public static $cookies = ''; | ||||
| 	/** | ||||
|      * 浏览器 User-Agent | ||||
|      */ | ||||
|     public static $userAgent = ''; | ||||
| 	/** | ||||
|      * passkey | ||||
|      */ | ||||
|     public static $passkey = ''; | ||||
| 	/** | ||||
|      * 客户端配置 | ||||
|      */ | ||||
|     public static $clients = ''; | ||||
| 	/** | ||||
|      * 监控目录 | ||||
|      */ | ||||
|     public static $watch = ''; | ||||
| 	/** | ||||
|      * 种子存放路径 | ||||
|      */ | ||||
|     public static $torrentDir = ''; | ||||
| 	/** | ||||
|      * 工作模式 | ||||
|      */ | ||||
|     public static $workingMode = ''; | ||||
| 	// 站点标识 | ||||
| 	public static $site = ''; | ||||
| 	/** | ||||
|      * 负载均衡 控制变量 | ||||
|      */ | ||||
|     public static $RPC_Key = 0; | ||||
| 	/** | ||||
|      * 退出状态码 | ||||
|      */ | ||||
| 	public static $ExitCode = 0; | ||||
| 	/** | ||||
|      * 初始化 | ||||
|      */ | ||||
| 	public static function init($site = '', $method = 'GET'){ | ||||
| 		global $configALL; | ||||
|  | ||||
| 		self::$site = $site; | ||||
| 		self::$method = strtoupper($method); | ||||
|  | ||||
| 		$config = $configALL[$site]; | ||||
| 		self::$cookies = $config['cookie']; | ||||
| 		self::$userAgent = isset($config['userAgent']) && $config['userAgent'] ? $config['userAgent'] : $configALL['default']['userAgent']; | ||||
| 		self::$clients = isset($config['clients']) && $config['clients'] ? $config['clients'] : $configALL['default']['clients']; | ||||
| 		self::$workingMode = isset($config['workingMode']) && $config['workingMode'] ? $config['workingMode'] : 0; | ||||
| 		$watch = isset($config['watch']) && $config['watch'] ? $config['watch'] : $configALL['default']['watch']; | ||||
| 		self::$watch = rtrim($watch,'/') . DS; | ||||
| 		self::$torrentDir = TORRENT_PATH . $site . DS; | ||||
| 		// 建立目录 | ||||
| 		IFile::mkdir(self::$torrentDir); | ||||
| 		 | ||||
| 		self::links(); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
|      * 连接远端RPC服务器 | ||||
|      * | ||||
|      * @param string | ||||
|      * @return array | ||||
|      */ | ||||
|     public static function links() | ||||
|     { | ||||
|         if(self::$workingMode === 1 && empty(self::$links)){ | ||||
| 			foreach ( self::$clients as $k => $v ){ | ||||
| 				// 跳过未配置的客户端 | ||||
| 				if (empty($v['username']) || empty( $v['password'])) { | ||||
| 					unset(self::$clients[$k]); | ||||
| 					echo "clients_".$k." 用户名或密码未配置,已跳过 \n\n"; | ||||
| 					continue; | ||||
| 				} | ||||
| 				try | ||||
| 				{ | ||||
| 					switch($v['type']){ | ||||
| 						case 'transmission': | ||||
| 							self::$links[$k]['rpc'] = new TransmissionRPC($v['host'], $v['username'], $v['password']); | ||||
| 							$result = self::$links[$k]['rpc']->sstats(); | ||||
| 							print $v['type'].':'.$v['host']." Rpc连接成功 [{$result->result}] \n"; | ||||
| 							break; | ||||
| 						case 'qBittorrent': | ||||
| 							self::$links[$k]['rpc'] = new qBittorrent($v['host'], $v['username'], $v['password']); | ||||
| 							$result = self::$links[$k]['rpc']->appVersion(); | ||||
| 							print $v['type'].':'.$v['host']." Rpc连接成功 [{$result}] \n"; | ||||
| 							break; | ||||
| 						case 'uTorrent': | ||||
| 							self::$links[$k]['rpc'] = new uTorrent($v['host'], $v['username'], $v['password']); | ||||
| 							$result = self::$links[$k]['rpc']->getBuild(); | ||||
| 							print $v['type'].':'.$v['host']." Rpc连接 [{$result}] \n"; | ||||
| 							break; | ||||
| 						default: | ||||
| 							echo '[ERROR] '.$v['type']; | ||||
| 							exit(1); | ||||
| 							break; | ||||
| 					} | ||||
| 					self::$links[$k]['type'] = $v['type']; | ||||
| 					self::$links[$k]['downloadDir'] = $v['downloadDir']; | ||||
| 				} catch (Exception $e) { | ||||
| 					echo '[ERROR] ' . $e->getMessage() . PHP_EOL; | ||||
| 					exit(1); | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		return true; | ||||
|     } | ||||
|  | ||||
| 	/** | ||||
| 	 * @brief 添加下载任务 | ||||
| 	 * @param string $torrent 种子元数据 | ||||
| 	 * @param string $save_path 保存路径 | ||||
| 	 * @return bool | ||||
| 	 */ | ||||
|     public static function add($torrent, $save_path = '', $extra_options = array()) | ||||
|     { | ||||
| 		switch( (int)self::$workingMode ){ | ||||
| 			case 0:		// watch默认工作模式 | ||||
| 				// 复制到watch目录 | ||||
| 				copy($torrent,$save_path); | ||||
| 				if(is_file($save_path)){ | ||||
| 					print "********watch模式,下载任务添加成功 \n\n"; | ||||
| 					return true; | ||||
| 				}else { | ||||
| 					print "-----watch模式,下载任务添加失败!!! \n\n"; | ||||
| 				} | ||||
| 				break; | ||||
| 			case 1:		//负载均衡模式 | ||||
| 				try | ||||
| 				{ | ||||
| 					$is_url = false; | ||||
| 					if( (strpos($torrent,'http://')===0) || (strpos($torrent,'https://')===0) || (strpos($torrent,'magnet:?xt=urn:btih:')===0) ){ | ||||
| 						$is_url = true; | ||||
| 					} | ||||
| 					// 负载均衡 | ||||
| 					$rpcKey = self::$RPC_Key; | ||||
| 					echo '选中:负载均衡'.$rpcKey."\n"; | ||||
| 					self::rpcSelect();					 | ||||
| 					// 调试 | ||||
| 					#p($result); | ||||
| 					// 下载服务器类型 判断 | ||||
| 					$type = self::$links[$rpcKey]['type']; | ||||
| 					switch($type){ | ||||
| 						case 'transmission': | ||||
| 							if( $is_url ){ | ||||
| 								echo 'add'; | ||||
| 								$result = self::$links[$rpcKey]['rpc']->add( $torrent, self::$links[$rpcKey]['downloadDir'], $extra_options );			// 种子URL添加下载任务 | ||||
| 							}else{ | ||||
| 								echo 'add_metainfo'; | ||||
| 								$result = self::$links[$rpcKey]['rpc']->add_metainfo( $torrent, self::$links[$rpcKey]['downloadDir'], $extra_options );	// 种子文件添加下载任务 | ||||
| 							} | ||||
| 							$id = $name = ''; | ||||
| 							if( isset($result->arguments->torrent_duplicate) ){ | ||||
| 								$id = $result->arguments->torrent_duplicate->id; | ||||
| 								$name = $result->arguments->torrent_duplicate->name; | ||||
| 							}elseif( isset($result->arguments->torrent_added) ){ | ||||
| 								$id = $result->arguments->torrent_added->id; | ||||
| 								$name = $result->arguments->torrent_added->name; | ||||
| 							} | ||||
| 							if(!$id){ | ||||
| 								print "-----RPC添加种子任务,失败 [{$result->result}] \n\n"; | ||||
| 							}else{ | ||||
| 								print "********RPC添加下载任务成功 [{$result->result}] (id=$id) \n\n"; | ||||
| 								// 新添加的任务,开始 | ||||
| 								self::$links[$rpcKey]['rpc']->start( $id ); | ||||
| 								return true; | ||||
| 							} | ||||
| 							break; | ||||
| 						case 'qBittorrent': | ||||
| 							if( $is_url ){ | ||||
| 								echo 'add'; | ||||
| 								$result = self::$links[$rpcKey]['rpc']->add( $torrent, self::$links[$rpcKey]['downloadDir'], $extra_options );			// 种子URL添加下载任务 | ||||
| 							}else{ | ||||
| 								echo 'add_metainfo'; | ||||
| 								$result = self::$links[$rpcKey]['rpc']->add_metainfo( $torrent, self::$links[$rpcKey]['downloadDir'], $extra_options );	// 种子文件添加下载任务 | ||||
| 							} | ||||
| 							if ($result === 'Ok.') { | ||||
| 								print "********RPC添加下载任务成功 [{$result}] \n\n"; | ||||
| 								return true; | ||||
| 							} else { | ||||
| 								print "-----RPC添加种子任务,失败 [{$result}] \n\n"; | ||||
| 							} | ||||
| 							break; | ||||
| 						default: | ||||
| 							echo '[ERROR] '.$type; | ||||
| 							break; | ||||
| 					} | ||||
| 				} catch (Exception $e) { | ||||
| 					die('[ERROR] ' . $e->getMessage() . PHP_EOL); | ||||
| 				} | ||||
| 				break; | ||||
| 			case 2: | ||||
| 				echo "\n\n"; | ||||
| 				# 暂未开放 | ||||
| 				break; | ||||
| 			default: | ||||
| 				echo "\n\n"; | ||||
| 				break; | ||||
| 		} | ||||
| 		return false; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 负载均衡 选择算法 | ||||
|      * | ||||
|      * @param | ||||
|      * @return | ||||
|      */ | ||||
|     public static function rpcSelect() | ||||
|     { | ||||
| 		$clientsConut = count(self::$clients); | ||||
| 		if( $clientsConut > 1 ){ | ||||
| 			if( $clientsConut > (self::$RPC_Key+1) ){ | ||||
| 				self::$RPC_Key++; | ||||
| 			}else{ | ||||
| 				self::$RPC_Key = 0; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	/** | ||||
| 	 * @brief 种子处理函数 | ||||
| 	 * @param array $data 种子数组 | ||||
| 	 * Array | ||||
| 		( | ||||
| 			[id] => 118632 | ||||
| 			[h1] => CCTV5+ 2019 ATP Men's Tennis Final 20191115B HDTV 1080i H264-HDxxx | ||||
| 			[title] => 央视体育赛事频道 2019年ATP男子网球年终总决赛 单打小组赛 纳达尔VS西西帕斯 20191115[优惠剩余时间:4时13分] | ||||
| 			[details] => https://XXX.me/details.php?id=118632 | ||||
| 			[download] => https://XXX.me/download.php?id=118632 | ||||
| 			[filename] => 118632.torrent | ||||
| 			[type] => 0 | ||||
| 			[sticky] => 1 | ||||
| 			[time] => Array | ||||
| 				( | ||||
| 					[0] => "2019-11-16 20:41:53">4时13分 | ||||
| 					[1] => "2019-11-16 14:41:53">1时<br />46分 | ||||
| 				) | ||||
| 			[comments] => 0 | ||||
| 			[size] => 5232.64MB | ||||
| 			[seeders] => 69 | ||||
| 			[leechers] => 10 | ||||
| 			[completed] => 93 | ||||
| 			[percentage] => 100% | ||||
| 			[owner] => 匿名 | ||||
| 		) | ||||
| 	 * @return | ||||
| 	 */ | ||||
| 	public static function call($data = array()) | ||||
| 	{ | ||||
| 		foreach ($data as $key => $value) { | ||||
| 			// 控制台打印 | ||||
| 			echo '主标题:'.$value['h1']."\n"; | ||||
| 			echo '副标题:'.$value['title']."\n"; | ||||
| 			echo '详情页:'.$value['details']."\n"; | ||||
| 			if ( $value['type'] != 0 ) { | ||||
| 				echo "-----非免费,已忽略! \n\n"; | ||||
| 				continue; | ||||
| 			} | ||||
| 			if ( isset($value['hr']) && ($value['hr'] == 1) ) { | ||||
| 				echo "-----HR种子,已忽略! \n\n"; | ||||
| 				continue; | ||||
| 			} | ||||
| 			// 下载任务的可选参数 | ||||
| 			$extra_options = array(); | ||||
| 			// 保存的文件名 | ||||
| 			$filename = $value['id'] . '.torrent'; | ||||
| 			// 默认watch工作模式,复制到此目录 | ||||
| 			$to = self::$watch . $filename; | ||||
| 			// 种子完整存放路径 | ||||
| 			$torrentFile = self::$torrentDir . $filename; | ||||
| 			if(is_file($torrentFile)){ | ||||
| 				$fileSize = filesize($torrentFile);		//失败会返回false 或 0(0代表上次下载失败) | ||||
| 				if ( !empty($fileSize) ) { | ||||
| 					//种子已经存在 | ||||
| 					echo '-----存在旧种子:'.$filename."\n\n"; | ||||
| 					continue; | ||||
| 				} | ||||
| 				// 删除下载错误的文件 | ||||
| 				IFile::unlink($torrentFile); | ||||
| 			} | ||||
| 			 | ||||
| 			// 调用过滤函数 | ||||
| 			$isFilter = filter(self::$site, $value); | ||||
| 			if ( is_string( $isFilter ) ) { | ||||
| 				echo "-----" .$isFilter. "\n\n"; | ||||
| 				continue; | ||||
| 			} | ||||
| 			//种子不存在 | ||||
| 			echo '正在下载新种子... '.$value['download']." \n"; | ||||
| 			// 创建文件、下载种子以二进制写入 | ||||
| 			$content = ''; | ||||
| 			$content = download($value['download'], self::$cookies, self::$userAgent, self::$method); | ||||
| 			#p($content); | ||||
| 			// 文件句柄 | ||||
| 			$resource = fopen($torrentFile, "wb"); | ||||
| 			// 成功:返回写入字节数,失败返回false | ||||
| 			$worldsnum = fwrite($resource, $content); | ||||
| 			// 关闭 | ||||
| 			fclose($resource); | ||||
| 			// 判断 | ||||
| 			if(is_bool($worldsnum)){ | ||||
| 				print "种子下载失败!!! \n\n"; | ||||
| 				IFile::unlink($torrentFile); | ||||
| 				continue; | ||||
| 			}else{ | ||||
| 				print "成功下载种子" . $filename . ',共计:' . $worldsnum . "字节 \n"; | ||||
| 				sleep(mt_rand(2,10)); | ||||
| 				$ret = false; | ||||
| 				$rpcKey = self::$RPC_Key; | ||||
| 				switch( (int)self::$workingMode ){ | ||||
| 					case 0:		//默认工作模式 | ||||
| 						$ret = self::add($torrentFile, $to); | ||||
| 						break; | ||||
| 					case 1:		//负载均衡模式 | ||||
| 						$type = self::$links[$rpcKey]['type']; | ||||
| 						// 下载服务器类型 | ||||
| 						switch ($type) { | ||||
| 							case 'transmission': | ||||
| 								# code... | ||||
| 								break; | ||||
| 							case 'qBittorrent': | ||||
| 								$extra_options['name'] = 'torrents'; | ||||
| 								$extra_options['filename'] = $filename; | ||||
| 								$extra_options['autoTMM'] = 'false';	//关闭自动种子管理 | ||||
| 								break; | ||||
| 							default: | ||||
| 								# code... | ||||
| 								break; | ||||
| 						} | ||||
| 						// 种子文件添加下载任务 | ||||
| 						$ret = self::add($content, $to, $extra_options); | ||||
| 						break; | ||||
| 					case 2: | ||||
| 						echo "\n\n"; | ||||
| 						# 暂未开放 | ||||
| 						break; | ||||
| 					default: | ||||
| 						echo "\n\n"; | ||||
| 						break; | ||||
| 				} | ||||
| 				global $configALL; | ||||
| 				if( isset($configALL['iyuu.cn']) && ($ret === true) ){ | ||||
| 					send(self::$site, $value); | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		return true; | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										708
									
								
								app/Class/TransmissionRPC.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										708
									
								
								app/Class/TransmissionRPC.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,708 @@ | ||||
| <?php | ||||
| /** | ||||
|  * Transmission bittorrent client/daemon RPC communication class | ||||
|  * Copyright (C) 2010 Johan Adriaans <johan.adriaans@gmail.com>, | ||||
|  *                    Bryce Chidester <bryce@cobryce.com> | ||||
|  * | ||||
|  * 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 <http://www.gnu.org/licenses/>. | ||||
|  */ | ||||
|  | ||||
| /** | ||||
|  * 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) | ||||
|  */ | ||||
|  | ||||
| /** | ||||
|  * A friendly little version check... | ||||
|  */ | ||||
| if ( version_compare( PHP_VERSION, TransmissionRPC::MIN_PHPVER, '<' ) ) | ||||
|   die( "The TransmissionRPC class requires PHP version {TransmissionRPC::TRANSMISSIONRPC_MIN_PHPVER} or above." . PHP_EOL ); | ||||
|  | ||||
| /** | ||||
|  * Transmission bittorrent client/daemon RPC communication class | ||||
|  * | ||||
|  * Usage example: | ||||
|  * <code> | ||||
|  *   $rpc = new TransmissionRPC($rpc_url); | ||||
|  *   $result = $rpc->add_file( $url_or_path_to_torrent, $target_folder ); | ||||
|  * </code> | ||||
|  * | ||||
|  */ | ||||
| class TransmissionRPC | ||||
| { | ||||
|   /** | ||||
|    * User agent used in all http communication | ||||
|    */ | ||||
|   const HTTP_UA = 'TransmissionRPC for PHP/0.3'; | ||||
|  | ||||
|   /** | ||||
|    * Minimum PHP version required | ||||
|    * 5.2.10 implemented the required http stream ignore_errors option | ||||
|    */ | ||||
|   const MIN_PHPVER = '5.2.10'; | ||||
|  | ||||
|   /** | ||||
|    * 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 = ''; | ||||
|  | ||||
|   /** | ||||
|    * Return results as an array, or an object (default) | ||||
|    * @var bool | ||||
|    */ | ||||
|   public $return_as_array = false; | ||||
|  | ||||
|   /** | ||||
|    * 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 | ||||
|                                          ) | ||||
|                                        ); | ||||
|  | ||||
|   /** | ||||
|    * 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; | ||||
|  | ||||
|   /** | ||||
|    * Start one or more torrents | ||||
|    * | ||||
|    * @param int|array ids A list of transmission torrent ids | ||||
|    */ | ||||
|   public function start ( $ids ) | ||||
|   { | ||||
|     if ( !is_array( $ids ) ) $ids = array( $ids );	// Convert $ids to an array if only a single id was passed | ||||
|     $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 | ||||
|    */ | ||||
|   public function stop ( $ids ) | ||||
|   { | ||||
|     if ( !is_array( $ids ) ) $ids = array( $ids );	// Convert $ids to an array if only a single id was passed | ||||
|     $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 | ||||
|    */ | ||||
|   public function reannounce ( $ids ) | ||||
|   { | ||||
|     if ( !is_array( $ids ) ) $ids = array( $ids );	// Convert $ids to an array if only a single id was passed | ||||
|     $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 | ||||
|    */ | ||||
|   public function verify ( $ids ) | ||||
|   { | ||||
|     if ( !is_array( $ids ) ) $ids = array( $ids );	// Convert $ids to an array if only a single id was passed | ||||
|     $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 | ||||
|       } | ||||
|    */ | ||||
|   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 | ||||
|    */   | ||||
|   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 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_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 torrent using the raw torrent data | ||||
|    * | ||||
|    * @param torrent_metainfo The raw, unencoded contents (metainfo) of a torrent | ||||
|    * @param save_path Folder to save torrent in | ||||
|    * @param extra options Optional extra torrent options | ||||
|    */ | ||||
|   public function add_metainfo ( $torrent_metainfo, $save_path = '', $extra_options = array() ) | ||||
|   { | ||||
|     $extra_options['download-dir'] = $save_path; | ||||
|     $extra_options['metainfo'] = base64_encode( $torrent_metainfo ); | ||||
|      | ||||
|     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 ); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Remove torrent from transmission | ||||
|    * | ||||
|    * @param bool delete_local_data Also remove local data? | ||||
|    * @param int|array ids A list of transmission torrent ids | ||||
|    */ | ||||
|   public function remove ( $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 | ||||
|    */ | ||||
|   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 | ||||
|    */ | ||||
|   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 | ||||
|    */ | ||||
|   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 | ||||
|    */   | ||||
|   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 | ||||
|    */   | ||||
|   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 ) ) { | ||||
|         if ( mb_detect_encoding($value,"auto") !== '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; | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Clean up the result object. Replaces all minus(-) characters in the object properties with underscores | ||||
|    * and converts any object with any all-digit property names to an array. | ||||
|    * | ||||
|    * @param object The request result to clean | ||||
|    * @returns array The cleaned object | ||||
|    */   | ||||
|   protected function cleanResultObject ( $object ) | ||||
|   { | ||||
|     // Prepare and cast object to array | ||||
|     $return_as_array = false; | ||||
|     $array = $object; | ||||
|     if ( !is_array( $array ) ) $array = (array) $array; | ||||
|     foreach ( $array as $index => $value ) | ||||
|     { | ||||
|       if( is_array( $array[$index] ) || is_object( $array[$index] ) ) | ||||
|       { | ||||
|         $array[$index] = $this->cleanResultObject( $array[$index] );	// Recursion | ||||
|       } | ||||
|       if ( strstr( $index, '-' ) ) | ||||
|       { | ||||
|         $valid_index = str_replace( '-', '_', $index ); | ||||
|         $array[$valid_index] = $array[$index];  | ||||
|         unset( $array[$index] ); | ||||
|         $index = $valid_index; | ||||
|       } | ||||
|       // Might be an array, check index for digits, if so, an array should be returned | ||||
|       if ( ctype_digit( (string) $index ) ) { $return_as_array = true; } | ||||
|       if ( empty( $value ) ) unset( $array[$index] ); | ||||
|     } | ||||
|     // Return array cast to object | ||||
|     return $return_as_array ? $array : (object) $array; | ||||
|   } | ||||
|    | ||||
|   /** | ||||
|    * 执行 rpc 请求 | ||||
|    * | ||||
|    * @param $method 请求类型/方法, 详见 $this->allowMethods | ||||
|    * @param array $arguments 附加参数, 可选 | ||||
|    * @return mixed | ||||
|    */ | ||||
|   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 = json_encode(array('result' => 'failed')); | ||||
|     return $this->return_as_array ? json_decode( $content, true ) : $this->cleanResultObject( json_decode( $content ) );	// Return the sanitized result | ||||
|   } | ||||
|   /** | ||||
|    * Performs an empty GET on the Transmission RPC to get the X-Transmission-Session-Id | ||||
|    * and store it in $this->session_id | ||||
|    * | ||||
|    * @return string | ||||
|    */ | ||||
|   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; | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Takes the connection parameters | ||||
|    * | ||||
|    * TODO: Sanitize username, password, and URL | ||||
|    * | ||||
|    * @param string $url | ||||
|    * @param string $username | ||||
|    * @param string $password | ||||
|    */ | ||||
|   public function __construct( $url = 'http://localhost:9091/transmission/rpc', $username = null, $password = null, $return_as_array = false ) | ||||
|   { | ||||
|     // server URL | ||||
|     $this->url = $url; | ||||
|      | ||||
|     // Username & password | ||||
|     $this->username = $username; | ||||
|     $this->password = $password; | ||||
|      | ||||
|     // Get the Transmission RPC_version | ||||
|     $this->rpc_version = self::sget()->arguments->rpc_version; | ||||
|      | ||||
|     // Return As Array | ||||
|     $this->return_as_array = $return_as_array; | ||||
|      | ||||
|     // Reset X-Transmission-Session-Id so we (re)fetch one | ||||
|     $this->session_id = null; | ||||
|   } | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * This is the type of exception the TransmissionRPC class will throw | ||||
|  */ | ||||
| class TransmissionRPCException extends Exception | ||||
| { | ||||
|   /** | ||||
|    * Exception: Invalid arguments | ||||
|    */ | ||||
|   const E_INVALIDARG = -1; | ||||
|  | ||||
|   /** | ||||
|    * Exception: Invalid Session-Id | ||||
|    */ | ||||
|   const E_SESSIONID = -2; | ||||
|  | ||||
|   /** | ||||
|    * Exception: Error while connecting | ||||
|    */ | ||||
|   const E_CONNECTION = -3; | ||||
|  | ||||
|   /** | ||||
|    * Exception: Error 401 returned, unauthorized | ||||
|    */ | ||||
|   const E_AUTHENTICATION = -4; | ||||
|  | ||||
|   /** | ||||
|    * Exception constructor | ||||
|    */ | ||||
|   public function __construct( $message = null, $code = 0, Exception $previous = null ) | ||||
|   { | ||||
|     // PHP version 5.3.0 and above support Exception linking | ||||
|     if ( version_compare( PHP_VERSION, '5.3.0', '>=' ) ) | ||||
|       parent::__construct( $message, $code, $previous ); | ||||
|     else | ||||
|       parent::__construct( $message, $code ); | ||||
|   } | ||||
| } | ||||
|  | ||||
| ?> | ||||
							
								
								
									
										288
									
								
								app/Class/qBittorrent.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										288
									
								
								app/Class/qBittorrent.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,288 @@ | ||||
| <?php | ||||
| use Curl\Curl; | ||||
| /** | ||||
|  * https://github.com/qbittorrent/qBittorrent/wiki/Web-API-Documentation | ||||
|  */ | ||||
| class qBittorrent | ||||
| { | ||||
|     private $debug; | ||||
|     private $url; | ||||
|     private $api_version; | ||||
|     private $curl; | ||||
|     protected $delimiter; | ||||
|     private $endpoints = [ | ||||
|         'login' => [ | ||||
|             '1' => '/login', | ||||
|             '2' => '/api/v2/auth/login' | ||||
|         ], | ||||
|         'app_version' => [ | ||||
|             '1' => '/version/qbittorrent', | ||||
|             '2' => '/api/v2/app/version' | ||||
|         ], | ||||
|         'api_version' => [ | ||||
|             '1' => '/version/api', | ||||
|             '2' => '/api/v2/app/webapiVersion' | ||||
|         ], | ||||
|         'build_info' => [ | ||||
|             '1' => null, | ||||
|             '2' => '/api/v2/app/buildInfo' | ||||
|         ], | ||||
|         'preferences' => [ | ||||
|             '1' => null, | ||||
|             '2' => '/api/v2/app/preferences' | ||||
|         ], | ||||
|         'setPreferences' => [ | ||||
|             '1' => null, | ||||
|             '2' => '/api/v2/app/setPreferences' | ||||
|         ], | ||||
| 		'defaultSavePath' => [ | ||||
|             '1' => null, | ||||
|             '2' => '/api/v2/app/defaultSavePath' | ||||
|         ], | ||||
|         'torrent_list' => [ | ||||
|             '1' => null, | ||||
|             '2' => '/api/v2/torrents/info' | ||||
|         ], | ||||
|         'torrent_add' => [ | ||||
|             '1' => null, | ||||
|             '2' => '/api/v2/torrents/add' | ||||
|         ], | ||||
|         'torrent_delete' => [ | ||||
|             '1' => null, | ||||
|             '2' => '/api/v2/torrents/delete' | ||||
|         ], | ||||
|         'torrent_pause' => [ | ||||
|             '1' => null, | ||||
|             '2' => '/api/v2/torrents/pause' | ||||
|         ], | ||||
|         'torrent_resume' => [ | ||||
|             '1' => null, | ||||
|             '2' => '/api/v2/torrents/resume' | ||||
|         ], | ||||
|         'set_torrent_location' => [ | ||||
|             '1' => null, | ||||
|             '2' => '/api/v2/torrents/setLocation' | ||||
|         ], | ||||
|         'maindata' => [ | ||||
|             '1' => null, | ||||
|             '2' => '/api/v2/sync/maindata' | ||||
|         ] | ||||
|     ]; | ||||
|  | ||||
|     public function __construct($url='', $username='', $password='', $api_version = 2, $debug = false) | ||||
|     { | ||||
|         $this->debug = $debug; | ||||
|         $this->url = rtrim($url,'/'); | ||||
|         $this->username = $username; | ||||
|         $this->password = $password; | ||||
|         $this->api_version = $api_version; | ||||
|         $this->curl = new Curl(); | ||||
|         $this->curl->setOpt(CURLOPT_SSL_VERIFYPEER, false); // 禁止验证证书 | ||||
|         $this->curl->setOpt(CURLOPT_SSL_VERIFYHOST, false); // 不检查证书 | ||||
|         $this->curl->setOpt(CURLOPT_CONNECTTIMEOUT, 60);    // 超时 | ||||
|         $this->curl->setOpt(CURLOPT_TIMEOUT, 600);          // 超时 | ||||
|         // Authenticate and get cookie, else throw exception | ||||
|         if (!$this->authenticate()) { | ||||
|             throw new \Exception("Unable to authenticate with Web Api."); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public function appVersion() | ||||
|     { | ||||
|         return $this->getData('app_version'); | ||||
|     } | ||||
|  | ||||
|     public function apiVersion() | ||||
|     { | ||||
|         return $this->getData('api_version'); | ||||
|     } | ||||
|  | ||||
|     public function buildInfo() | ||||
|     { | ||||
|         return $this->getData('build_info'); | ||||
|     } | ||||
|  | ||||
|     public function preferences($data = null) | ||||
|     { | ||||
|         if (!empty($data)) { | ||||
|             return $this->postData('setPreferences', ['json' => json_encode($data)]); | ||||
|         } | ||||
|  | ||||
|         return $this->getData('preferences'); | ||||
|     } | ||||
|  | ||||
|     public function torrentList() | ||||
|     { | ||||
|         return $this->getData('torrent_list'); | ||||
|     } | ||||
|     /** | ||||
|      * @param array $extra_options | ||||
|         array( | ||||
|             'urls'    =>  '', | ||||
|             'savepath'    =>  '', | ||||
|             'cookie'    =>  '', | ||||
|             'category'    =>  '', | ||||
|             'skip_checking'    =>  true, | ||||
|             'paused'    =>  true, | ||||
|             'root_folder'    =>  true, | ||||
|         ) | ||||
|      *  @return array | ||||
|      */ | ||||
|     public function add($torrent_url, $save_path = '', $extra_options = array()) | ||||
|     { | ||||
| 		if(!empty($save_path)) $extra_options['savepath'] = $save_path; | ||||
|         $extra_options['urls'] = $torrent_url; | ||||
|         #$extra_options['skip_checking'] = 'true';    //跳校验 | ||||
|         // 关键 上传文件流 multipart/form-data【严格按照api文档编写】 | ||||
|         $post_data = $this->buildUrls($extra_options); | ||||
|         #p($post_data); | ||||
|         // 设置请求头 | ||||
|         $this->curl->setHeader('Content-Type','multipart/form-data; boundary='.$this->delimiter); | ||||
|         $this->curl->setHeader('Content-Length',strlen($post_data)); | ||||
|         return $this->postData('torrent_add', $post_data); | ||||
|     } | ||||
|  | ||||
| 	public function add_metainfo($torrent_metainfo, $save_path = '', $extra_options = array()) | ||||
|     { | ||||
| 		if(!empty($save_path)) $extra_options['savepath'] = $save_path; | ||||
|         $extra_options['torrents'] = $torrent_metainfo; | ||||
|         #$extra_options['skip_checking'] = 'true';    //跳校验 | ||||
|         // 关键 上传文件流 multipart/form-data【严格按照api文档编写】 | ||||
|         $post_data = $this->buildData($extra_options); | ||||
|         #p($post_data); | ||||
|         // 设置请求头 | ||||
|         $this->curl->setHeader('Content-Type','multipart/form-data; boundary='.$this->delimiter); | ||||
|         $this->curl->setHeader('Content-Length',strlen($post_data)); | ||||
|         return $this->postData('torrent_add', $post_data); | ||||
|     } | ||||
|  | ||||
|     public function torrentDelete($hash='', $deleteFiles = false) | ||||
|     { | ||||
|         return $this->postData('torrent_delete', ['hashes' => $hash, 'deleteFiles' => $deleteFiles ? 'true':'false']); | ||||
|     } | ||||
|  | ||||
|     public function torrentDeleteAll($deleteFiles = false) | ||||
|     { | ||||
|         $torrents = json_decode($this->torrentList()); | ||||
|         $response = ''; | ||||
|         foreach ($torrents as $torrent) { | ||||
|             $response .= $this->torrentDelete($torrent->hash, $deleteFiles); | ||||
|         } | ||||
|  | ||||
|         return $response; | ||||
|     } | ||||
|  | ||||
|     public function torrentPause($hash) | ||||
|     { | ||||
|         return $this->postData('torrent_pause', ['hashes' => $hash]); | ||||
|     } | ||||
|  | ||||
|     public function torrentResume($hash) | ||||
|     { | ||||
|         return $this->postData('torrent_resume', ['hashes' => $hash]); | ||||
|     } | ||||
|  | ||||
|     public function setTorrentLocation($hash, $location) | ||||
|     { | ||||
|         return $this->postData('set_torrent_location', ['hashes' => $hash, 'location' => $location]); | ||||
|     } | ||||
|  | ||||
|     private function getData($endpoint) | ||||
|     { | ||||
|         $this->curl->get($this->url . $this->endpoints[$endpoint][$this->api_version]); | ||||
|  | ||||
|         if ($this->debug) { | ||||
|             var_dump($this->curl->request_headers); | ||||
|             var_dump($this->curl->response_headers); | ||||
|         } | ||||
|  | ||||
|         if ($this->curl->error) { | ||||
|             return $this->errorMessage(); | ||||
|         } | ||||
|  | ||||
|         return $this->curl->response; | ||||
|     } | ||||
|  | ||||
|     private function postData($endpoint, $data) | ||||
|     { | ||||
|         $this->curl->post($this->url . $this->endpoints[$endpoint][$this->api_version], $data); | ||||
|  | ||||
|         if ($this->debug) { | ||||
|             var_dump($this->curl->request_headers); | ||||
|             var_dump($this->curl->response_headers); | ||||
|         } | ||||
|  | ||||
|         if ($this->curl->error) { | ||||
|             return $this->errorMessage(); | ||||
|         } | ||||
|  | ||||
|         return $this->curl->response; | ||||
|     } | ||||
|  | ||||
|     private function authenticate() | ||||
|     { | ||||
|         $this->curl->post($this->url . $this->endpoints['login'][$this->api_version], [ | ||||
|             'username' => $this->username, | ||||
|             'password' => $this->password | ||||
|         ]); | ||||
|  | ||||
|         if ($this->debug) { | ||||
|             var_dump($this->curl->request_headers); | ||||
|             var_dump($this->curl->response_headers); | ||||
|         } | ||||
|  | ||||
|         // Find authentication cookie and set in curl connection | ||||
|         foreach ($this->curl->response_headers as $header) { | ||||
|             if (preg_match('/SID=(\S[^;]+)/', $header, $matches)) { | ||||
|                 $this->curl->setHeader('Cookie', $matches[0]); | ||||
|                 return true; | ||||
|             } | ||||
|         }; | ||||
|  | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     private function errorMessage() | ||||
|     { | ||||
|         return 'Curl Error Code: ' . $this->curl->error_code . ' (' . $this->curl->response . ')'; | ||||
|     } | ||||
|     /** | ||||
|      * 拼接种子urls multipart/form-data | ||||
|      * https://github.com/qbittorrent/qBittorrent/wiki/Web-API-Documentation#add-new-torrent | ||||
|      */ | ||||
|     private function buildUrls($param){ | ||||
|         $this->delimiter = uniqid(); | ||||
|         $eol = "\r\n"; | ||||
|         $data = ''; | ||||
|         // 拼接文件流 | ||||
|         foreach ($param as $name => $content) { | ||||
|             $data .= "--" . $this->delimiter . $eol; | ||||
|             $data .= 'Content-Disposition: form-data; name' . '="' .$name. '"' . "\r\n\r\n"; | ||||
|             $data .= $content . $eol; | ||||
|         } | ||||
|         $data .= "--" . $this->delimiter . "--" . $eol; | ||||
|         return $data; | ||||
|     } | ||||
|     /** | ||||
|      * 拼接种子上传文件流 multipart/form-data | ||||
|      * https://github.com/qbittorrent/qBittorrent/wiki/Web-API-Documentation#add-new-torrent | ||||
|      */ | ||||
|     private function buildData($param){ | ||||
|         $this->delimiter = uniqid(); | ||||
|         $eol = "\r\n"; | ||||
|         $data = ''; | ||||
|         $torrents = $param['torrents']; | ||||
|         unset($param['torrents']); | ||||
|         // 拼接文件流 | ||||
|         $data .= "--" . $this->delimiter . $eol | ||||
|         . 'Content-Disposition: form-data; '; | ||||
|         foreach ($param as $name => $content) { | ||||
|             $data.= $name . '="' . $content.'"; '; | ||||
|         } | ||||
|         $data .= $eol; | ||||
|         $data .= 'Content-Type: application/x-bittorrent'."\r\n\r\n"; | ||||
|         $data .= $torrents . $eol; | ||||
|         $data .= "--" . $this->delimiter . "--" . $eol; | ||||
|         return $data; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										255
									
								
								app/Class/uTorrent.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										255
									
								
								app/Class/uTorrent.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,255 @@ | ||||
| <?php | ||||
| define("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 = "%s/gui/%s"; | ||||
|  | ||||
|     // member variables | ||||
|     public $host; | ||||
|     public $user; | ||||
|     public $pass; | ||||
|  | ||||
|     protected $token; | ||||
|     protected $guid; | ||||
|  | ||||
|     // constructor | ||||
|     function __construct($host = "", $user = "", $pass = "") { | ||||
|         $this->host = rtrim($host,'/'); | ||||
|         $this->user = $user; | ||||
|         $this->pass = $pass; | ||||
|  | ||||
|         if (!$this->getToken()) { | ||||
|             //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()) { | ||||
|         $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, $request)); | ||||
|         curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); | ||||
|         curl_setopt($ch, CURLOPT_USERPWD, $this->user.":".$this->pass); | ||||
|         curl_setopt($ch, CURLOPT_COOKIE, "GUID=".$this->guid); | ||||
|  | ||||
|         $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 | ||||
|     private function getToken() { | ||||
|         $url = sprintf(self::$base, $this->host, 'token.html'); | ||||
|         $ch = curl_init(); | ||||
|         curl_setopt($ch, CURLOPT_URL, $url); | ||||
|         curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); | ||||
|         curl_setopt($ch, CURLOPT_USERPWD, $this->user.":".$this->pass); | ||||
|         curl_setopt($ch, CURLOPT_HEADER, true); | ||||
|         $output = curl_exec($ch); | ||||
|         $info = curl_getinfo($ch); | ||||
|         curl_close($ch); | ||||
|  | ||||
|         $headers = substr($output, 0, $info['header_size']); | ||||
|  | ||||
|         if (preg_match("@Set-Cookie: GUID=([^;]+);@i", $headers, $matches)) { | ||||
|             $this->guid = $matches[1]; | ||||
|         } | ||||
|  | ||||
|         if (preg_match('/<div id=\'token\'.+>(.*)<\/div>/', $output, $m)) { | ||||
|             $this->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']; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Get all the RSS favourites/filters | ||||
|      * @return model\Filter[] | ||||
|      */ | ||||
|     public function getRSSFilters() { | ||||
|         $json = $this->makeRequest("?list=1"); | ||||
|         $filters = array(); | ||||
|         foreach ($json['rssfilters'] as $filter) { | ||||
|             $filters[] = model\Filter::fromData($filter); | ||||
|         } | ||||
|         return $filters; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Update an RSS filter as retrieved from getRSSFilters | ||||
|      * @param \uTorrent\model\Filter $filter | ||||
|      */ | ||||
|     public function setRSSFilter(model\Filter $filter) { | ||||
|         $request = array_merge(array('action' => 'filter-update'), $filter->toParams()); | ||||
|         return $this->makeRequest('?'.http_build_query($request)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Add a new RSS filter | ||||
|      * Requires a utorrent > 2.2.1 (not sure which version exactly) | ||||
|      * @param \uTorrent\model\Filter $filter | ||||
|      * @return int ID of the new filter | ||||
|      */ | ||||
|     public function addRSSFilter(model\Filter $filter) { | ||||
|         $filter->filterId = -1; | ||||
|         $resp = $this->setRSSFilter($filter); | ||||
|         if (!empty($resp['filter_ident'])) { | ||||
|             return $resp['filter_ident']; | ||||
|         } else { | ||||
|             return 0; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     // 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|magnet|", "|".$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); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										352
									
								
								app/config/config.sample.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										352
									
								
								app/config/config.sample.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,352 @@ | ||||
| <?php | ||||
| /** | ||||
|  * 技术讨论及后续更新,请加入QQ群!!!!!!! | ||||
| 	群名称:IYUU自动辅种交流 | ||||
| 	QQ群号:859882209 | ||||
|  * 手动配置方法,请查看:https://www.iyuu.cn/archives/324/ | ||||
|  */ | ||||
| return array( | ||||
| 	// 1.爱语飞飞 微信通知配置 | ||||
| 	'iyuu.cn'		=> 'IYUU', | ||||
| 	// 2.server酱 微信通知配置 | ||||
| 	'sc.ftqq.com'   => '', | ||||
| 	// 3.发布员鉴权 | ||||
| 	'secret' 		=> '', | ||||
| 	// 4.全局默认配置 | ||||
|     'default'      => array( | ||||
| 		// 5.【必须配置】浏览器UA,打开http://demo.iyuu.cn 复制过来即可 | ||||
| 		'userAgent'     => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36', | ||||
| 		// 6.【自动辅种必须配置】全局客户端设置(条目不够可以复制,用不到的请删除) | ||||
|         'clients'   => array( | ||||
| 			// 全局客户端设置 开始 | ||||
|             array( | ||||
| 				'type'	=>	'transmission',	// 支持:transmission、qBittorrent | ||||
| 				'host'	=>	'http://127.0.0.1:9091/transmission/rpc', | ||||
| 				'username'	=>	'', | ||||
| 				'password'	=>	'', | ||||
| 				//'move' =>array( | ||||
| 				//	'type' => 2,		// 0保持不变,1减,2加, 3直接替换 | ||||
| 				//	'path' =>array( | ||||
| 				//		'/sda1' => '/volume1', | ||||
| 				//	), | ||||
| 				//), | ||||
| 			), | ||||
| 			// (条目不够可以复制,用不到的请删除) | ||||
| 			array( | ||||
| 				'type'	=>	'qBittorrent',	// 支持:transmission、qBittorrent | ||||
| 				'host'	=>	'http://www.baidu.com:8083', | ||||
| 				'username'	=>	'', | ||||
| 				'password'	=>	'', | ||||
| 			), | ||||
| 			// 全局客户端设置 结束 | ||||
| 		), | ||||
| 		'CONNECTTIMEOUT'=> 60, | ||||
|         'TIMEOUT'       => 600, | ||||
| 	), | ||||
| 	/** | ||||
| 	 * 以下为各站点的独立配置(互不影响、互不冲突) | ||||
| 	 * 自动辅种:需要配置各站的passkey(没有配置passkey的站点会自动跳过) | ||||
| 	 */ | ||||
|     // m-team 序号:1 | ||||
|     'm-team'      => array( | ||||
| 		// 14.m-team的cookie	如果需要用下载免费种脚本,须配置(只是自动辅种,可以不配置此项) | ||||
| 		'cookie'        => 'tp=', | ||||
| 		// 15.m-team的passkey	【必须配置】 | ||||
| 		'passkey'       => '', | ||||
| 		// 种子Tracker的IP地址选择 可选:ipv4,ipv6 | ||||
| 		'ip_type'		=> 'ipv4', | ||||
|     ), | ||||
|     // keepfrds 序号:2 | ||||
|     'keepfrds'      => array( | ||||
| 		// 如果需要用下载免费种脚本,须配置(只是自动辅种,可以不配置此项) | ||||
| 		'cookie'        => '', | ||||
| 		// 如果需要自动辅种,必须配置 | ||||
|         'passkey'       => '', | ||||
| 	), | ||||
| 	// ourbits 序号:3 | ||||
| 	'ourbits'      => array( | ||||
| 		// 如果需要用下载免费种脚本,须配置(只是自动辅种,可以不配置此项) | ||||
| 		'cookie'        => '', | ||||
| 		// 如果需要自动辅种,必须配置 | ||||
| 		'passkey'       => '', | ||||
| 		'id' => 0,					// 用户ID | ||||
| 		'is_vip'		=> 0,		// 是否具有VIP或特殊权限?0 普通,1 VIP | ||||
|     ), | ||||
|     // HDSky 序号:4 | ||||
|     'hdsky'      => array( | ||||
| 		// 如果需要用下载免费种脚本,须配置(只是自动辅种,可以不配置此项) | ||||
| 		'cookie'        => '', | ||||
| 		// 如果需要自动辅种,必须配置 | ||||
|         'passkey'       => '', | ||||
|     ), | ||||
| 	// pter 序号:5 | ||||
| 	'pter'      => array( | ||||
| 		// 如果需要用下载免费种脚本,须配置(只是自动辅种,可以不配置此项) | ||||
| 		'cookie'        => '', | ||||
| 		// 如果需要自动辅种,必须配置 | ||||
|         'passkey'       => '', | ||||
|     ), | ||||
| 	// tjupt 序号:6 | ||||
| 	'tjupt'      => array( | ||||
| 		// 如果需要用下载免费种脚本,须配置(只是自动辅种,可以不配置此项) | ||||
| 		'cookie'        => '', | ||||
| 		// 如果需要自动辅种,必须配置 | ||||
|         'passkey'       => '', | ||||
|     ), | ||||
| 	// hdhome 序号:7 | ||||
| 	'hdhome'      => array( | ||||
| 		// 如果需要用下载免费种脚本,须配置(只是自动辅种,可以不配置此项) | ||||
| 		'cookie'        => '', | ||||
| 		// 如果需要自动辅种,必须配置 | ||||
|         'passkey'       => '', | ||||
|     ), | ||||
| 	// btschool 序号:8 | ||||
| 	'btschool'      => array( | ||||
| 		// 如果需要用下载免费种脚本,须配置(只是自动辅种,可以不配置此项) | ||||
| 		'cookie'        => '', | ||||
| 		// 如果需要自动辅种,必须配置 | ||||
|         'passkey'       => '', | ||||
| 	), | ||||
| 	// PTHome 序号:9 | ||||
|     'pthome'      => array( | ||||
| 		// 如果需要用下载免费种脚本,须配置(只是自动辅种,可以不配置此项) | ||||
| 		'cookie'        => '', | ||||
| 		// 如果需要自动辅种,必须配置 | ||||
|         'passkey'       => '', | ||||
|     ), | ||||
| 	// hddolby 序号:10 | ||||
| 	'hddolby'      => array( | ||||
| 		// 如果需要用下载免费种脚本,须配置(只是自动辅种,可以不配置此项) | ||||
| 		'cookie'        => '', | ||||
| 		// 如果需要自动辅种,必须配置 | ||||
|         'passkey'       => '', | ||||
|     ), | ||||
| 	// TorrentCCF 序号:11 | ||||
|     'torrentccf'      => array( | ||||
| 		// 如果需要用下载免费种脚本,须配置(只是自动辅种,可以不配置此项) | ||||
| 		'cookie'        => '', | ||||
| 		// 如果需要自动辅种,必须配置 | ||||
|         'passkey'       => '', | ||||
|     ), | ||||
| 	// PTMSG 序号:12 | ||||
|     'ptmsg'      => array( | ||||
| 		// 如果需要用下载免费种脚本,须配置(只是自动辅种,可以不配置此项) | ||||
| 		'cookie'        => '', | ||||
| 		// 如果需要自动辅种,必须配置 | ||||
|         'passkey'       => '', | ||||
|     ), | ||||
| 	// MoeCat 序号:13 | ||||
|     'moecat'      => array( | ||||
| 		// 如果需要用下载免费种脚本,须配置(只是自动辅种,可以不配置此项) | ||||
| 		'cookie'        => '', | ||||
| 		// 如果需要自动辅种,必须配置 | ||||
| 		'passkey'       => '', | ||||
| 		// 种子Tracker的IP地址选择 可选:ipv4,ipv6 | ||||
| 		'ip_type'		=> 'ipv4', | ||||
|     ), | ||||
|     // totheglory 序号:14 | ||||
|     'ttg'      => array( | ||||
| 		// 如果需要用下载免费种脚本,须配置(只是自动辅种,可以不配置此项) | ||||
| 		'cookie'        => '', | ||||
| 		// 如果需要自动辅种,必须配置 | ||||
|         'passkey'       => '', | ||||
|     ), | ||||
| 	// nanyangpt 序号:15 | ||||
|     'nanyangpt'      => array( | ||||
| 		// 如果需要用下载免费种脚本,须配置(只是自动辅种,可以不配置此项) | ||||
| 		'cookie'        => '', | ||||
| 		// 如果需要自动辅种,必须配置 | ||||
|         'passkey'       => '', | ||||
| 	), | ||||
| 	// springsunday.net 序号:16 | ||||
|     'ssd'      => array( | ||||
| 		// 如果需要用下载免费种脚本,须配置(只是自动辅种,可以不配置此项) | ||||
| 		'cookie'        => '', | ||||
| 		// 如果需要自动辅种,必须配置 | ||||
|         'passkey'       => '', | ||||
| 	), | ||||
| 	// yingk 序号:17 | ||||
|     'yingk'      => array( | ||||
| 		// 如果需要用下载免费种脚本,须配置(只是自动辅种,可以不配置此项) | ||||
| 		'cookie'        => '', | ||||
| 		// 如果需要自动辅种,必须配置 | ||||
|         'passkey'       => '', | ||||
| 	), | ||||
| 	// hdcity 序号:18 | ||||
|     'hdcity'      => array( | ||||
| 		// 如果需要用下载免费种脚本,须配置(只是自动辅种,可以不配置此项) | ||||
| 		'cookie'        => '', | ||||
| 		// 如果需要自动辅种,必须配置	cuhash | ||||
|         'passkey'       => '', | ||||
| 	), | ||||
| 	// 52pt.site 序号:19 | ||||
|     '52pt'      => array( | ||||
| 		// 如果需要用下载免费种脚本,须配置(只是自动辅种,可以不配置此项) | ||||
| 		'cookie'        => '', | ||||
| 		// 如果需要自动辅种,必须配置 | ||||
|         'passkey'       => '', | ||||
| 	), | ||||
| 	// brobits.cc 序号:20 | ||||
|     'brobits'      => array( | ||||
| 		// 如果需要用下载免费种脚本,须配置(只是自动辅种,可以不配置此项) | ||||
| 		'cookie'        => '', | ||||
| 		// 如果需要自动辅种,必须配置 | ||||
|         'passkey'       => '', | ||||
| 	), | ||||
| 	// www.beitai.pt 序号:21 | ||||
|     'beitai'      => array( | ||||
| 		// 如果需要用下载免费种脚本,须配置(只是自动辅种,可以不配置此项) | ||||
| 		'cookie'        => '', | ||||
| 		// 如果需要自动辅种,必须配置 | ||||
|         'passkey'       => '', | ||||
| 	), | ||||
| 	// pt.eastgame.org 序号:22 | ||||
|     'eastgame'      => array( | ||||
| 		// 如果需要用下载免费种脚本,须配置(只是自动辅种,可以不配置此项) | ||||
| 		'cookie'        => '', | ||||
| 		// 如果需要自动辅种,必须配置 | ||||
|         'passkey'       => '', | ||||
| 	), | ||||
| 	// pt.soulvoice.club 序号:23 | ||||
|     'soulvoice'      => array( | ||||
| 		// 如果需要用下载免费种脚本,须配置(只是自动辅种,可以不配置此项) | ||||
| 		'cookie'        => '', | ||||
| 		// 如果需要自动辅种,必须配置 | ||||
|         'passkey'       => '', | ||||
| 	), | ||||
| 	// chdbits 序号:24 | ||||
|     'chdbits'      => array( | ||||
| 		// 如果需要用下载免费种脚本,须配置(只是自动辅种,可以不配置此项) | ||||
| 		'cookie'        => '', | ||||
| 		// 如果需要自动辅种,必须配置 | ||||
|         'passkey'       => '', | ||||
| 	), | ||||
| 	// leaguehd 序号:25 | ||||
|     'leaguehd'      => array( | ||||
| 		// 如果需要用下载免费种脚本,须配置(只是自动辅种,可以不配置此项) | ||||
| 		'cookie'        => '', | ||||
| 		// 如果需要自动辅种,必须配置 | ||||
|         'passkey'       => '', | ||||
| 	), | ||||
| 	// ptsbao.club 序号:26 | ||||
| 	'ptsbao'      => array( | ||||
| 		// 如果需要用下载免费种脚本,须配置(只是自动辅种,可以不配置此项) | ||||
| 		'cookie'        => '', | ||||
| 		// 如果需要自动辅种,必须配置 | ||||
| 		'passkey'       => '', | ||||
| 	), | ||||
| 	// hdchina 序号:27 | ||||
| 	'hdchina'      => array( | ||||
| 		// 如果需要用下载免费种脚本,须配置(只是自动辅种,可以不配置此项) | ||||
| 		'cookie'        => '', | ||||
| 		// 如果需要自动辅种,必须配置 | ||||
| 		'passkey'       => '', | ||||
| 	), | ||||
| 	// hdarea 序号:28 | ||||
| 	'hdarea'      => array( | ||||
| 		// 如果需要用下载免费种脚本,须配置(只是自动辅种,可以不配置此项) | ||||
| 		'cookie'        => '', | ||||
| 		// 如果需要自动辅种,必须配置 | ||||
| 		'passkey'       => '', | ||||
| 	), | ||||
| 	// hdtime 序号:29 | ||||
| 	'hdtime'      => array( | ||||
| 		// 如果需要用下载免费种脚本,须配置(只是自动辅种,可以不配置此项) | ||||
| 		'cookie'        => '', | ||||
| 		// 如果需要自动辅种,必须配置 | ||||
| 		'passkey'       => '', | ||||
| 	), | ||||
| 	// 1ptba 序号:30 | ||||
| 	'1ptba'      => array( | ||||
| 		// 如果需要用下载免费种脚本,须配置(只是自动辅种,可以不配置此项) | ||||
| 		'cookie'        => '', | ||||
| 		// 如果需要自动辅种,必须配置 | ||||
| 		'passkey'       => '', | ||||
| 	), | ||||
| 	// hd4fans 序号:31 | ||||
| 	'hd4fans'      => array( | ||||
| 		// 如果需要用下载免费种脚本,须配置(只是自动辅种,可以不配置此项) | ||||
| 		'cookie'        => '', | ||||
| 		// 如果需要自动辅种,必须配置 | ||||
| 		'passkey'       => '', | ||||
| 	), | ||||
| 	// hdbug 序号:32 | ||||
| 	'hdbug'      => array( | ||||
| 		// 如果需要用下载免费种脚本,须配置(只是自动辅种,可以不配置此项) | ||||
| 		'cookie'        => '', | ||||
| 		// 如果需要自动辅种,必须配置 | ||||
| 		'passkey'       => '', | ||||
| 	), | ||||
| 	// opencd 序号:33 | ||||
| 	'opencd'      => array( | ||||
| 		// 如果需要用下载免费种脚本,须配置(只是自动辅种,可以不配置此项) | ||||
| 		'cookie'        => '', | ||||
| 		// 如果需要自动辅种,必须配置 | ||||
| 		'passkey'       => '', | ||||
| 	), | ||||
| 	// hdstreet 序号:34 | ||||
| 	'hdstreet'      => array( | ||||
| 		// 如果需要用下载免费种脚本,须配置(只是自动辅种,可以不配置此项) | ||||
| 		'cookie'        => '', | ||||
| 		// 如果需要自动辅种,必须配置 | ||||
| 		'passkey'       => '', | ||||
| 	), | ||||
| 	// joyhd 序号:35 | ||||
| 	'joyhd'      => array( | ||||
| 		// 如果需要用下载免费种脚本,须配置(只是自动辅种,可以不配置此项) | ||||
| 		'cookie'        => '', | ||||
| 		// 如果需要自动辅种,必须配置 | ||||
| 		'passkey'       => '', | ||||
| 	), | ||||
| 	// dmhy 序号:36 | ||||
| 	'dmhy'      => array( | ||||
| 		// 如果需要用下载免费种脚本,须配置(只是自动辅种,可以不配置此项) | ||||
| 		'cookie'        => '', | ||||
| 		// 如果需要自动辅种,必须配置 | ||||
| 		'passkey'       => '', | ||||
| 	), | ||||
| 	// upxin 序号:37 | ||||
| 	'upxin'      => array( | ||||
| 		// 如果需要用下载免费种脚本,须配置(只是自动辅种,可以不配置此项) | ||||
| 		'cookie'        => '', | ||||
| 		// 如果需要自动辅种,必须配置 | ||||
| 		'passkey'       => '', | ||||
| 	), | ||||
| 	// oshen 序号:38 | ||||
| 	'oshen'      => array( | ||||
| 		// 如果需要用下载免费种脚本,须配置(只是自动辅种,可以不配置此项) | ||||
| 		'cookie'        => '', | ||||
| 		// 如果需要自动辅种,必须配置 | ||||
| 		'passkey'       => '', | ||||
| 	), | ||||
| 	// discfan 序号:39 | ||||
| 	'discfan'      => array( | ||||
| 		// 如果需要用下载免费种脚本,须配置(只是自动辅种,可以不配置此项) | ||||
| 		'cookie'        => '', | ||||
| 		// 如果需要自动辅种,必须配置 | ||||
| 		'passkey'       => '', | ||||
| 	), | ||||
| 	// hdzone 序号:40 | ||||
| 	'hdzone'      => array( | ||||
| 		// 如果需要用下载免费种脚本,须配置(只是自动辅种,可以不配置此项) | ||||
| 		'cookie'        => '', | ||||
| 		// 如果需要自动辅种,必须配置 | ||||
| 		'passkey'       => '', | ||||
| 	), | ||||
| 	// cnscg 序号:41 | ||||
| 	'cnscg'      => array( | ||||
| 		// 如果需要用下载免费种脚本,须配置(只是自动辅种,可以不配置此项) | ||||
| 		'cookie'        => '', | ||||
| 		// 如果需要自动辅种,必须配置 | ||||
| 		'passkey'       => '', | ||||
| 	), | ||||
| 	// nicept 序号:42 | ||||
| 	'nicept'      => array( | ||||
| 		// 如果需要用下载免费种脚本,须配置(只是自动辅种,可以不配置此项) | ||||
| 		'cookie'        => '', | ||||
| 		// 如果需要自动辅种,必须配置 | ||||
| 		'passkey'       => '', | ||||
| 	), | ||||
|  | ||||
| 	// 配置文件结束 | ||||
| ); | ||||
							
								
								
									
										1
									
								
								app/config/version.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								app/config/version.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| <?php return '20191224.1010'; | ||||
							
								
								
									
										42
									
								
								app/init.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								app/init.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,42 @@ | ||||
| <?php | ||||
| //---------------------------------- | ||||
| // 公共入口文件 | ||||
| //---------------------------------- | ||||
| // 定义目录 | ||||
| defined('ROOT_PATH') or define("ROOT_PATH",  dirname(__DIR__)); | ||||
| defined('APP_PATH') or define('APP_PATH', __DIR__); | ||||
| define('DS', DIRECTORY_SEPARATOR); | ||||
| define('TORRENT_PATH', APP_PATH.DS.'torrent'.DS); | ||||
|  | ||||
| // 严格开发模式 | ||||
| error_reporting( E_ALL ); | ||||
| #ini_set('display_errors', 1); | ||||
|  | ||||
| // 永不超时 | ||||
| ini_set('max_execution_time', 0); | ||||
| set_time_limit(0); | ||||
| // 内存限制,如果外面设置的内存比 /etc/php/php-cli.ini 大,就不要设置了 | ||||
| if (intval(ini_get("memory_limit")) < 1024) | ||||
| { | ||||
|     ini_set('memory_limit', '1024M'); | ||||
| } | ||||
|  | ||||
| if( PHP_SAPI != 'cli' ) | ||||
| { | ||||
|     exit("You must run the CLI environment\n"); | ||||
| } | ||||
|  | ||||
| // 设置时区 | ||||
| date_default_timezone_set('Asia/Shanghai'); | ||||
|  | ||||
| // 系统配置 | ||||
| if( file_exists( APP_PATH."/config/config.php" ) ) | ||||
| { | ||||
|     // 配置(全局变量) | ||||
|     $configALL = require_once APP_PATH."/config/config.php"; | ||||
| }else{ | ||||
|     // 示例配置 | ||||
|     $configALL = require_once APP_PATH . '/config/config.sample.php'; | ||||
| } | ||||
|  | ||||
| require_once ROOT_PATH . '/vendor/autoload.php'; | ||||
		Reference in New Issue
	
	Block a user