Browse Source

Started work on rTorrent Homepage Item

causefx 7 years ago
parent
commit
ad22fc8d29

+ 7 - 7
api/composer.lock

@@ -137,16 +137,16 @@
         },
         {
             "name": "guzzlehttp/guzzle",
-            "version": "6.3.0",
+            "version": "6.3.3",
             "source": {
                 "type": "git",
                 "url": "https://github.com/guzzle/guzzle.git",
-                "reference": "f4db5a78a5ea468d4831de7f0bf9d9415e348699"
+                "reference": "407b0cb880ace85c9b63c5f9551db498cb2d50ba"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/guzzle/guzzle/zipball/f4db5a78a5ea468d4831de7f0bf9d9415e348699",
-                "reference": "f4db5a78a5ea468d4831de7f0bf9d9415e348699",
+                "url": "https://api.github.com/repos/guzzle/guzzle/zipball/407b0cb880ace85c9b63c5f9551db498cb2d50ba",
+                "reference": "407b0cb880ace85c9b63c5f9551db498cb2d50ba",
                 "shasum": ""
             },
             "require": {
@@ -156,7 +156,7 @@
             },
             "require-dev": {
                 "ext-curl": "*",
-                "phpunit/phpunit": "^4.0 || ^5.0",
+                "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.4 || ^7.0",
                 "psr/log": "^1.0"
             },
             "suggest": {
@@ -165,7 +165,7 @@
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "6.2-dev"
+                    "dev-master": "6.3-dev"
                 }
             },
             "autoload": {
@@ -198,7 +198,7 @@
                 "rest",
                 "web service"
             ],
-            "time": "2017-06-22T18:50:49+00:00"
+            "time": "2018-04-22T15:46:56+00:00"
         },
         {
             "name": "guzzlehttp/promises",

+ 10 - 0
api/config/default.php

@@ -72,6 +72,13 @@ return array(
 	'qBittorrentHideCompleted' => false,
 	'qBittorrentSortOrder' => 'eta',
 	'qBittorrentReverseSorting' => false,
+	'rTorrentURL' => '',
+	'rTorrentUsername' => '',
+	'rTorrentPassword' => '',
+	'rTorrentHideSeeding' => false,
+	'rTorrentHideCompleted' => false,
+	'rTorrentSortOrder' => 'datea',
+	'rTorrentReverseSorting' => false,
 	'homepageCalendarEnabled' => 'true',
 	'homepageCalendarAuth' => '4',
 	'calendariCal' => '',
@@ -97,6 +104,8 @@ return array(
 	'homepageTransmissionAuth' => '1',
 	'homepageqBittorrentEnabled' => false,
 	'homepageqBittorrentAuth' => '1',
+	'homepagerTorrentEnabled' => false,
+	'homepagerTorrentAuth' => '1',
 	'homepageNzbgetEnabled' => false,
 	'homepageNzbgetAuth' => '1',
 	'homepagePlexEnabled' => false,
@@ -122,6 +131,7 @@ return array(
 	'homepageOrderembyrecent' => '12',
 	'homepageOrderombi' => '13',
 	'homepageOrdercalendar' => '14',
+	'homepageOrderrTorrent' => '15',
 	'homepageShowStreamNames' => false,
 	'homepageShowStreamNamesAuth' => '1',
 	'homepageStreamRefresh' => '60000',

+ 108 - 0
api/functions/homepage-connect-functions.php

@@ -39,6 +39,9 @@ function homepageConnect($array)
 		case 'getqBittorrent':
 			return qBittorrentConnect();
 			break;
+		case 'getrTorrent':
+			return rTorrentConnect();
+			break;
 		case 'getDeluge':
 			return delugeConnect();
 			break;
@@ -766,6 +769,111 @@ function transmissionConnect()
 	return false;
 }
 
+function rTorrentStatus($completed, $state, $status)
+{
+	if ($completed && $state && $status == 'seed') {
+		$state = 'Seeding';
+	} elseif (!$completed && !$state && $status == 'leech') {
+		$state = 'Stopped';
+	} elseif (!$completed && $state && $status == 'leech') {
+		$state = 'Downloading';
+	} elseif ($completed && !$state && $status == 'seed') {
+		$state = 'Finished';
+	}
+	return $state;
+}
+
+function rTorrentConnect()
+{
+	if ($GLOBALS['homepagerTorrentEnabled'] && !empty($GLOBALS['rTorrentURL']) && qualifyRequest($GLOBALS['homepagerTorrentAuth'])) {
+		try {
+			$torrents = array();
+			$digest = qualifyURL($GLOBALS['rTorrentURL'], true);
+			$url = $digest['scheme'] . '://' . $digest['host'] . $digest['port'] . $digest['path'] . '/RPC2';
+			$options = (localURL($url)) ? array('verify' => false) : array();
+			$data = xmlrpc_encode_request("d.multicall2", array(
+				"",
+				"main",
+				"d.name=",
+				"d.base_path=",
+				"d.up.total=",
+				"d.size_bytes=",
+				"d.down.total=",
+				"d.completed_bytes=",
+				"d.connection_current=",
+				"d.down.rate=",
+				"d.up.rate=",
+				"d.creation_date=",
+				"d.state=",
+				"d.group.name=",
+				"d.hash=",
+				"d.complete=",
+				"d.ratio=",
+				"d.chunk_size=",
+				"f.size_bytes=",
+				"f.size_chunks=",
+				"f.completed_chunks=",
+			), array());
+			$response = Requests::post($url, array(), $data, $options);
+			if ($response->success) {
+				$torrentList = xmlrpc_decode(str_replace('i8>', 'i4>', $response->body));
+				foreach ($torrentList as $key => $value) {
+					$tempStatus = rTorrentStatus($value[13], $value[10], $value[6]);
+					if ($tempStatus == 'Seeding' && $GLOBALS['rTorrentHideSeeding']) {
+						//do nothing
+					} elseif ($tempStatus == 'Finished' && $GLOBALS['rTorrentHideCompleted']) {
+						//do nothing
+					} else {
+						$torrents[$key] = array(
+							'name' => $value[0],
+							'base' => $value[1],
+							'upTotal' => $value[2],
+							'size' => $value[3],
+							'downTotal' => $value[4],
+							'downloaded' => $value[5],
+							'connectionState' => $value[6],
+							'leech' => $value[7],
+							'seed' => $value[8],
+							'date' => $value[9],
+							'state' => ($value[10]) ? 'on' : 'off',
+							'group' => $value[11],
+							'hash' => $value[12],
+							'complete' => ($value[13]) ? 'yes' : 'no',
+							'ratio' => $value[14],
+							'status' => $tempStatus,
+							'temp' => $value[16] . ' - ' . $value[17] . ' - ' . $value[18],
+						);
+					}
+				}
+				if (count($torrents) !== 0) {
+					usort($torrents, function ($a, $b) {
+						$direction = substr($GLOBALS['rTorrentSortOrder'], -1);
+						$sort = substr($GLOBALS['rTorrentSortOrder'], 0, strlen($GLOBALS['rTorrentSortOrder']) - 1);
+						switch ($direction) {
+							case 'a':
+								return $a[$sort] <=> $b[$sort];
+								break;
+							case 'd':
+								return $b[$sort] <=> $a[$sort];
+								break;
+							default:
+								return $b['date'] <=> $a['date'];
+						}
+					});
+				}
+				$api['content']['queueItems'] = $torrents;
+				$api['content']['historyItems'] = false;
+			}
+		} catch
+		(Requests_Exception $e) {
+			writeLog('error', 'rTorrent Connect Function - Error: ' . $e->getMessage(), 'SYSTEM');
+		};
+		$api['content'] = isset($api['content']) ? $api['content'] : false;
+		return $api;
+	}
+	return false;
+}
+
 function qBittorrentConnect()
 {
 	if ($GLOBALS['homepageqBittorrentEnabled'] && !empty($GLOBALS['qBittorrentURL']) && qualifyRequest($GLOBALS['homepageqBittorrentAuth'])) {

+ 142 - 1
api/functions/homepage-functions.php

@@ -17,6 +17,7 @@ function homepageOrder()
 		"homepageOrdertransmission" => $GLOBALS['homepageOrdertransmission'],
 		"homepageOrderqBittorrent" => $GLOBALS['homepageOrderqBittorrent'],
 		"homepageOrderdeluge" => $GLOBALS['homepageOrderdeluge'],
+		"homepageOrderrTorrent" => $GLOBALS['homepageOrderrTorrent'],
 	);
 	asort($homepageOrder);
 	return $homepageOrder;
@@ -59,6 +60,18 @@ function buildHomepageItem($homepageItem)
                 homepageDownloader("qBittorrent", "' . $GLOBALS['homepageDownloadRefresh'] . '");
                 // End homepageOrderqBittorrent
                 </script>
+                ';
+			}
+			break;
+		case 'homepageOrderrTorrent':
+			if ($GLOBALS['homepagerTorrentEnabled']) {
+				$item .= '<div class="white-box"><h2 class="text-center" lang="en">Loading Download Queue...</h2></div>';
+				$item .= '
+                <script>
+                // homepageOrderrTorrent
+                homepageDownloader("rTorrent", "' . $GLOBALS['homepageDownloadRefresh'] . '");
+                // End homepageOrderrTorrent
+                </script>
                 ';
 			}
 			break;
@@ -326,6 +339,32 @@ function getHomepageList()
 			'value' => 'H:mm'
 		)
 	);
+	$rTorrentSortOptions = array(
+		array(
+			'name' => 'Hash Desc',
+			'value' => 'hashd'
+		),
+		array(
+			'name' => 'Hash Asc',
+			'value' => 'hasha'
+		),
+		array(
+			'name' => 'Name Desc',
+			'value' => 'named'
+		),
+		array(
+			'name' => 'Name Asc',
+			'value' => 'namea'
+		),
+		array(
+			'name' => 'Size Desc',
+			'value' => 'sized'
+		),
+		array(
+			'name' => 'Size Asc',
+			'value' => 'sizea'
+		),
+	);
 	$qBittorrentSortOptions = array(
 		array(
 			'name' => 'Hash',
@@ -388,6 +427,7 @@ function getHomepageList()
 			'value' => 'category'
 		)
 	);
+	$xmlStatus = (extension_loaded('xmlrpc')) ? 'Installed' : 'Not Installed';
 	return array(array(
 		'name' => 'Calendar',
 		'enabled' => (strpos('personal', $GLOBALS['license']) !== false) ? true : false,
@@ -1077,6 +1117,100 @@ function getHomepageList()
 				)
 			)
 		),
+		array(
+			'name' => 'rTorrent',
+			'enabled' => (strpos('personal', $GLOBALS['license']) !== false) ? true : false,
+			'image' => 'plugins/images/tabs/ruTorrent.png',
+			'category' => 'Downloader',
+			'settings' => array(
+				'FYI' => array(
+					array(
+						'type' => 'html',
+						'label' => '',
+						'override' => 12,
+						'html' => '
+						<div class="row">
+						    <div class="col-lg-12">
+						        <div class="panel panel-info">
+						            <div class="panel-heading">
+						                <span lang="en">This module requires XMLRPC</span>
+						            </div>
+						            <div class="panel-wrapper collapse in" aria-expanded="true">
+						                <div class="panel-body">
+						                    <span lang="en">Status: [ <b>' . $xmlStatus . '</b> ]</span>
+						                </div>
+						            </div>
+						        </div>
+						    </div>
+						</div>
+						'
+					)
+				),
+				'Enable' => array(
+					array(
+						'type' => 'switch',
+						'name' => 'homepagerTorrentEnabled',
+						'label' => 'Enable',
+						'value' => $GLOBALS['homepagerTorrentEnabled']
+					),
+					array(
+						'type' => 'select',
+						'name' => 'homepagerTorrentAuth',
+						'label' => 'Minimum Authentication',
+						'value' => $GLOBALS['homepagerTorrentAuth'],
+						'options' => $groups
+					)
+				),
+				'Connection' => array(
+					array(
+						'type' => 'input',
+						'name' => 'rTorrentURL',
+						'label' => 'URL',
+						'value' => $GLOBALS['rTorrentURL'],
+						'placeholder' => 'http(s)://hostname:port'
+					),
+					array(
+						'type' => 'input',
+						'name' => 'rTorrentUsername',
+						'label' => 'Username',
+						'value' => $GLOBALS['rTorrentUsername']
+					),
+					array(
+						'type' => 'password',
+						'name' => 'rTorrentPassword',
+						'label' => 'Password',
+						'value' => $GLOBALS['rTorrentPassword']
+					)
+				),
+				'Misc Options' => array(
+					array(
+						'type' => 'switch',
+						'name' => 'rTorrentHideSeeding',
+						'label' => 'Hide Seeding',
+						'value' => $GLOBALS['rTorrentHideSeeding']
+					), array(
+						'type' => 'switch',
+						'name' => 'rTorrentHideCompleted',
+						'label' => 'Hide Completed',
+						'value' => $GLOBALS['rTorrentHideCompleted']
+					),
+					array(
+						'type' => 'select',
+						'name' => 'rTorrentSortOrder',
+						'label' => 'Order',
+						'value' => $GLOBALS['rTorrentSortOrder'],
+						'options' => $rTorrentSortOptions
+					),
+					array(
+						'type' => 'select',
+						'name' => 'homepageDownloadRefresh',
+						'label' => 'Refresh Seconds',
+						'value' => $GLOBALS['homepageDownloadRefresh'],
+						'options' => optionTime()
+					)
+				)
+			)
+		),
 		array(
 			'name' => 'Deluge',
 			'enabled' => (strpos('personal', $GLOBALS['license']) !== false) ? true : false,
@@ -1093,7 +1227,7 @@ function getHomepageList()
                             <div class="panel-wrapper collapse in" aria-expanded="true">
                                 <div class="panel-body">
 									<ul class="list-icons">
-                                        <li><i class="fa fa-chevron-right text-danger"></i> <a href="https://github.com/idlesign/deluge-webapi/raw/master/dist/WebAPI-0.2.1-py2.7.egg" target="_blank">Download Plugin</a></li>
+                                        <li><i class="fa fa-chevron-right text-danger"></i> <a href="https://github.com/idlesign/deluge-webapi/tree/master/dist" target="_blank">Download Plugin</a></li>
                                         <li><i class="fa fa-chevron-right text-danger"></i> Open Deluge Web UI, go to "Preferences -> Plugins -> Install plugin" and choose egg file.</li>
                                         <li><i class="fa fa-chevron-right text-danger"></i> Activate WebAPI plugin </li>
                                     </ul>
@@ -1829,6 +1963,13 @@ function buildHomepageSettings()
 					$class .= ' faded';
 				}
 				break;
+			case 'homepageOrderrTorrent':
+				$class = 'bg-qbit';
+				$image = 'plugins/images/tabs/ruTorrent.png';
+				if (!$GLOBALS['homepagerTorrentEnabled']) {
+					$class .= ' faded';
+				}
+				break;
 			case 'homepageOrderplexnowplaying':
 			case 'homepageOrderplexrecent':
 			case 'homepageOrderplexplaylist':

+ 67 - 67
api/vendor/composer/installed.json

@@ -483,73 +483,6 @@
             "url"
         ]
     },
-    {
-        "name": "guzzlehttp/guzzle",
-        "version": "6.3.0",
-        "version_normalized": "6.3.0.0",
-        "source": {
-            "type": "git",
-            "url": "https://github.com/guzzle/guzzle.git",
-            "reference": "f4db5a78a5ea468d4831de7f0bf9d9415e348699"
-        },
-        "dist": {
-            "type": "zip",
-            "url": "https://api.github.com/repos/guzzle/guzzle/zipball/f4db5a78a5ea468d4831de7f0bf9d9415e348699",
-            "reference": "f4db5a78a5ea468d4831de7f0bf9d9415e348699",
-            "shasum": ""
-        },
-        "require": {
-            "guzzlehttp/promises": "^1.0",
-            "guzzlehttp/psr7": "^1.4",
-            "php": ">=5.5"
-        },
-        "require-dev": {
-            "ext-curl": "*",
-            "phpunit/phpunit": "^4.0 || ^5.0",
-            "psr/log": "^1.0"
-        },
-        "suggest": {
-            "psr/log": "Required for using the Log middleware"
-        },
-        "time": "2017-06-22T18:50:49+00:00",
-        "type": "library",
-        "extra": {
-            "branch-alias": {
-                "dev-master": "6.2-dev"
-            }
-        },
-        "installation-source": "dist",
-        "autoload": {
-            "files": [
-                "src/functions_include.php"
-            ],
-            "psr-4": {
-                "GuzzleHttp\\": "src/"
-            }
-        },
-        "notification-url": "https://packagist.org/downloads/",
-        "license": [
-            "MIT"
-        ],
-        "authors": [
-            {
-                "name": "Michael Dowling",
-                "email": "mtdowling@gmail.com",
-                "homepage": "https://github.com/mtdowling"
-            }
-        ],
-        "description": "Guzzle is a PHP HTTP client library",
-        "homepage": "http://guzzlephp.org/",
-        "keywords": [
-            "client",
-            "curl",
-            "framework",
-            "http",
-            "http client",
-            "rest",
-            "web service"
-        ]
-    },
     {
         "name": "kryptonit3/sonarr",
         "version": "1.0.6.1",
@@ -1138,5 +1071,72 @@
             "google2fa",
             "laravel"
         ]
+    },
+    {
+        "name": "guzzlehttp/guzzle",
+        "version": "6.3.3",
+        "version_normalized": "6.3.3.0",
+        "source": {
+            "type": "git",
+            "url": "https://github.com/guzzle/guzzle.git",
+            "reference": "407b0cb880ace85c9b63c5f9551db498cb2d50ba"
+        },
+        "dist": {
+            "type": "zip",
+            "url": "https://api.github.com/repos/guzzle/guzzle/zipball/407b0cb880ace85c9b63c5f9551db498cb2d50ba",
+            "reference": "407b0cb880ace85c9b63c5f9551db498cb2d50ba",
+            "shasum": ""
+        },
+        "require": {
+            "guzzlehttp/promises": "^1.0",
+            "guzzlehttp/psr7": "^1.4",
+            "php": ">=5.5"
+        },
+        "require-dev": {
+            "ext-curl": "*",
+            "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.4 || ^7.0",
+            "psr/log": "^1.0"
+        },
+        "suggest": {
+            "psr/log": "Required for using the Log middleware"
+        },
+        "time": "2018-04-22T15:46:56+00:00",
+        "type": "library",
+        "extra": {
+            "branch-alias": {
+                "dev-master": "6.3-dev"
+            }
+        },
+        "installation-source": "dist",
+        "autoload": {
+            "files": [
+                "src/functions_include.php"
+            ],
+            "psr-4": {
+                "GuzzleHttp\\": "src/"
+            }
+        },
+        "notification-url": "https://packagist.org/downloads/",
+        "license": [
+            "MIT"
+        ],
+        "authors": [
+            {
+                "name": "Michael Dowling",
+                "email": "mtdowling@gmail.com",
+                "homepage": "https://github.com/mtdowling"
+            }
+        ],
+        "description": "Guzzle is a PHP HTTP client library",
+        "homepage": "http://guzzlephp.org/",
+        "keywords": [
+            "client",
+            "curl",
+            "framework",
+            "http",
+            "http client",
+            "rest",
+            "web service"
+        ]
     }
 ]

+ 24 - 1
api/vendor/guzzlehttp/guzzle/CHANGELOG.md

@@ -1,4 +1,27 @@
-# CHANGELOG
+# Change Log
+
+## 6.3.3 - 2018-04-22
+
+* Fix: Default headers when decode_content is specified
+
+
+## 6.3.2 - 2018-03-26
+
+* Fix: Release process
+
+
+## 6.3.1 - 2018-03-26
+
+* Bug fix: Parsing 0 epoch expiry times in cookies [#2014](https://github.com/guzzle/guzzle/pull/2014)
+* Improvement: Better ConnectException detection [#2012](https://github.com/guzzle/guzzle/pull/2012)
+* Bug fix: Malformed domain that contains a "/" [#1999](https://github.com/guzzle/guzzle/pull/1999)
+* Bug fix: Undefined offset when a cookie has no first key-value pair [#1998](https://github.com/guzzle/guzzle/pull/1998)
+* Improvement: Support PHPUnit 6 [#1953](https://github.com/guzzle/guzzle/pull/1953)
+* Bug fix: Support empty headers [#1915](https://github.com/guzzle/guzzle/pull/1915)
+* Bug fix: Ignore case during header modifications [#1916](https://github.com/guzzle/guzzle/pull/1916)
+
++ Minor code cleanups, documentation fixes and clarifications.
+
 
 ## 6.3.0 - 2017-06-22
 

+ 1 - 1
api/vendor/guzzlehttp/guzzle/LICENSE

@@ -1,4 +1,4 @@
-Copyright (c) 2011-2016 Michael Dowling, https://github.com/mtdowling <mtdowling@gmail.com>
+Copyright (c) 2011-2018 Michael Dowling, https://github.com/mtdowling <mtdowling@gmail.com>
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal

+ 3 - 1
api/vendor/guzzlehttp/guzzle/README.md

@@ -1,7 +1,9 @@
 Guzzle, PHP HTTP client
 =======================
 
-[![Build Status](https://travis-ci.org/guzzle/guzzle.svg?branch=master)](https://travis-ci.org/guzzle/guzzle)
+[![Latest Version](https://img.shields.io/github/release/guzzle/guzzle.svg?style=flat-square)](https://github.com/guzzle/guzzle/releases)
+[![Build Status](https://img.shields.io/travis/guzzle/guzzle.svg?style=flat-square)](https://travis-ci.org/guzzle/guzzle)
+[![Total Downloads](https://img.shields.io/packagist/dt/guzzlehttp/guzzle.svg?style=flat-square)](https://packagist.org/packages/guzzlehttp/guzzle)
 
 Guzzle is a PHP HTTP client that makes it easy to send HTTP requests and
 trivial to integrate with web services.

+ 2 - 2
api/vendor/guzzlehttp/guzzle/composer.json

@@ -19,7 +19,7 @@
     },
     "require-dev": {
         "ext-curl": "*",
-        "phpunit/phpunit": "^4.0 || ^5.0",
+        "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.4 || ^7.0",
         "psr/log": "^1.0"
     },
     "autoload": {
@@ -38,7 +38,7 @@
     },
     "extra": {
         "branch-alias": {
-            "dev-master": "6.2-dev"
+            "dev-master": "6.3-dev"
         }
     }
 }

+ 18 - 10
api/vendor/guzzlehttp/guzzle/src/Client.php

@@ -290,7 +290,14 @@ class Client implements ClientInterface
      */
     private function applyOptions(RequestInterface $request, array &$options)
     {
-        $modify = [];
+        $modify = [
+            'set_headers' => [],
+        ];
+
+        if (isset($options['headers'])) {
+            $modify['set_headers'] = $options['headers'];
+            unset($options['headers']);
+        }
 
         if (isset($options['form_params'])) {
             if (isset($options['multipart'])) {
@@ -302,6 +309,8 @@ class Client implements ClientInterface
             }
             $options['body'] = http_build_query($options['form_params'], '', '&');
             unset($options['form_params']);
+            // Ensure that we don't have the header in different case and set the new value.
+            $options['_conditional'] = Psr7\_caseless_remove(['Content-Type'], $options['_conditional']);
             $options['_conditional']['Content-Type'] = 'application/x-www-form-urlencoded';
         }
 
@@ -313,24 +322,19 @@ class Client implements ClientInterface
         if (isset($options['json'])) {
             $options['body'] = \GuzzleHttp\json_encode($options['json']);
             unset($options['json']);
+            // Ensure that we don't have the header in different case and set the new value.
+            $options['_conditional'] = Psr7\_caseless_remove(['Content-Type'], $options['_conditional']);
             $options['_conditional']['Content-Type'] = 'application/json';
         }
 
         if (!empty($options['decode_content'])
             && $options['decode_content'] !== true
         ) {
+            // Ensure that we don't have the header in different case and set the new value.
+            $options['_conditional'] = Psr7\_caseless_remove(['Accept-Encoding'], $options['_conditional']);
             $modify['set_headers']['Accept-Encoding'] = $options['decode_content'];
         }
 
-        if (isset($options['headers'])) {
-            if (isset($modify['set_headers'])) {
-                $modify['set_headers'] = $options['headers'] + $modify['set_headers'];
-            } else {
-                $modify['set_headers'] = $options['headers'];
-            }
-            unset($options['headers']);
-        }
-
         if (isset($options['body'])) {
             if (is_array($options['body'])) {
                 $this->invalidBody();
@@ -344,6 +348,8 @@ class Client implements ClientInterface
             $type = isset($value[2]) ? strtolower($value[2]) : 'basic';
             switch ($type) {
                 case 'basic':
+                    // Ensure that we don't have the header in different case and set the new value.
+                    $modify['set_headers'] = Psr7\_caseless_remove(['Authorization'], $modify['set_headers']);
                     $modify['set_headers']['Authorization'] = 'Basic '
                         . base64_encode("$value[0]:$value[1]");
                     break;
@@ -382,6 +388,8 @@ class Client implements ClientInterface
         $request = Psr7\modify_request($request, $modify);
         if ($request->getBody() instanceof Psr7\MultipartStream) {
             // Use a multipart/form-data POST if a Content-Type is not set.
+            // Ensure that we don't have the header in different case and set the new value.
+            $options['_conditional'] = Psr7\_caseless_remove(['Content-Type'], $options['_conditional']);
             $options['_conditional']['Content-Type'] = 'multipart/form-data; boundary='
                 . $request->getBody()->getBoundary();
         }

+ 1 - 1
api/vendor/guzzlehttp/guzzle/src/ClientInterface.php

@@ -12,7 +12,7 @@ use Psr\Http\Message\UriInterface;
  */
 interface ClientInterface
 {
-    const VERSION = '6.2.1';
+    const VERSION = '6.3.3';
 
     /**
      * Send an HTTP request.

+ 3 - 3
api/vendor/guzzlehttp/guzzle/src/Cookie/CookieJar.php

@@ -95,11 +95,11 @@ class CookieJar implements CookieJarInterface
     public function getCookieByName($name)
     {
         // don't allow a null name
-        if($name === null) {
+        if ($name === null) {
             return null;
         }
-        foreach($this->cookies as $cookie) {
-            if($cookie->getName() !== null && strcasecmp($cookie->getName(), $name) === 0) {
+        foreach ($this->cookies as $cookie) {
+            if ($cookie->getName() !== null && strcasecmp($cookie->getName(), $name) === 0) {
                 return $cookie;
             }
         }

+ 1 - 1
api/vendor/guzzlehttp/guzzle/src/Cookie/SessionCookieJar.php

@@ -15,7 +15,7 @@ class SessionCookieJar extends CookieJar
     /**
      * Create a new SessionCookieJar object
      *
-     * @param string $sessionKey        Session key name to store the cookie 
+     * @param string $sessionKey        Session key name to store the cookie
      *                                  data in session
      * @param bool $storeSessionCookies Set to true to store session cookies
      *                                  in the cookie jar.

+ 6 - 7
api/vendor/guzzlehttp/guzzle/src/Cookie/SetCookie.php

@@ -35,14 +35,13 @@ class SetCookie
         $data = self::$defaults;
         // Explode the cookie string using a series of semicolons
         $pieces = array_filter(array_map('trim', explode(';', $cookie)));
-        // The name of the cookie (first kvp) must include an equal sign.
-        if (empty($pieces) || !strpos($pieces[0], '=')) {
+        // The name of the cookie (first kvp) must exist and include an equal sign.
+        if (empty($pieces[0]) || !strpos($pieces[0], '=')) {
             return new self($data);
         }
 
         // Add the cookie pieces into the parsed data array
         foreach ($pieces as $part) {
-
             $cookieParts = explode('=', $part, 2);
             $key = trim($cookieParts[0]);
             $value = isset($cookieParts[1])
@@ -349,7 +348,7 @@ class SetCookie
             return false;
         }
 
-        return (bool) preg_match('/\.' . preg_quote($cookieDomain) . '$/', $domain);
+        return (bool) preg_match('/\.' . preg_quote($cookieDomain, '/') . '$/', $domain);
     }
 
     /**
@@ -359,7 +358,7 @@ class SetCookie
      */
     public function isExpired()
     {
-        return $this->getExpires() && time() > $this->getExpires();
+        return $this->getExpires() !== null && time() > $this->getExpires();
     }
 
     /**
@@ -378,8 +377,8 @@ class SetCookie
         // Check if any of the invalid characters are present in the cookie name
         if (preg_match(
             '/[\x00-\x20\x22\x28-\x29\x2c\x2f\x3a-\x40\x5c\x7b\x7d\x7f]/',
-            $name)
-        ) {
+            $name
+        )) {
             return 'Cookie name must not contain invalid characters: ASCII '
                 . 'Control characters (0-31;127), space, tab and the '
                 . 'following characters: ()<>@,;:\"/?={}';

+ 9 - 0
api/vendor/guzzlehttp/guzzle/src/Exception/GuzzleException.php

@@ -1,4 +1,13 @@
 <?php
 namespace GuzzleHttp\Exception;
 
+/**
+ * @method string getMessage()
+ * @method \Throwable|null getPrevious()
+ * @method mixed getCode()
+ * @method string getFile()
+ * @method int getLine()
+ * @method array getTrace()
+ * @method string getTraceAsString()
+ */
 interface GuzzleException {}

+ 9 - 3
api/vendor/guzzlehttp/guzzle/src/Handler/CurlFactory.php

@@ -4,7 +4,6 @@ namespace GuzzleHttp\Handler;
 use GuzzleHttp\Exception\RequestException;
 use GuzzleHttp\Exception\ConnectException;
 use GuzzleHttp\Promise\FulfilledPromise;
-use GuzzleHttp\Promise\RejectedPromise;
 use GuzzleHttp\Psr7;
 use GuzzleHttp\Psr7\LazyOpenStream;
 use GuzzleHttp\TransferStats;
@@ -288,7 +287,14 @@ class CurlFactory implements CurlFactoryInterface
     {
         foreach ($conf['_headers'] as $name => $values) {
             foreach ($values as $value) {
-                $conf[CURLOPT_HTTPHEADER][] = "$name: $value";
+                $value = (string) $value;
+                if ($value === '') {
+                    // cURL requires a special format for empty headers.
+                    // See https://github.com/guzzle/guzzle/issues/1882 for more details.
+                    $conf[CURLOPT_HTTPHEADER][] = "$name;";
+                } else {
+                    $conf[CURLOPT_HTTPHEADER][] = "$name: $value";
+                }
             }
         }
 
@@ -388,7 +394,7 @@ class CurlFactory implements CurlFactoryInterface
         if (isset($options['force_ip_resolve'])) {
             if ('v4' === $options['force_ip_resolve']) {
                 $conf[CURLOPT_IPRESOLVE] = CURL_IPRESOLVE_V4;
-            } else if ('v6' === $options['force_ip_resolve']) {
+            } elseif ('v6' === $options['force_ip_resolve']) {
                 $conf[CURLOPT_IPRESOLVE] = CURL_IPRESOLVE_V6;
             }
         }

+ 3 - 1
api/vendor/guzzlehttp/guzzle/src/Handler/CurlMultiHandler.php

@@ -65,7 +65,9 @@ class CurlMultiHandler
 
         $promise = new Promise(
             [$this, 'execute'],
-            function () use ($id) { return $this->cancel($id); }
+            function () use ($id) {
+                return $this->cancel($id);
+            }
         );
 
         $this->addRequest(['easy' => $easy, 'deferred' => $promise]);

+ 3 - 4
api/vendor/guzzlehttp/guzzle/src/Handler/StreamHandler.php

@@ -4,7 +4,6 @@ namespace GuzzleHttp\Handler;
 use GuzzleHttp\Exception\RequestException;
 use GuzzleHttp\Exception\ConnectException;
 use GuzzleHttp\Promise\FulfilledPromise;
-use GuzzleHttp\Promise\RejectedPromise;
 use GuzzleHttp\Promise\PromiseInterface;
 use GuzzleHttp\Psr7;
 use GuzzleHttp\TransferStats;
@@ -61,6 +60,7 @@ class StreamHandler
             if (strpos($message, 'getaddrinfo') // DNS lookup failed
                 || strpos($message, 'Connection refused')
                 || strpos($message, "couldn't connect to host") // error on HHVM
+                || strpos($message, "connection attempt failed")
             ) {
                 $e = new ConnectException($e->getMessage(), $request, $e);
             }
@@ -103,7 +103,7 @@ class StreamHandler
         $status = $parts[1];
         $reason = isset($parts[2]) ? $parts[2] : null;
         $headers = \GuzzleHttp\headers_from_lines($hdrs);
-        list ($stream, $headers) = $this->checkDecode($options, $headers, $stream);
+        list($stream, $headers) = $this->checkDecode($options, $headers, $stream);
         $stream = Psr7\stream_for($stream);
         $sink = $stream;
 
@@ -276,7 +276,7 @@ class StreamHandler
         }
 
         $params = [];
-        $context = $this->getDefaultContext($request, $options);
+        $context = $this->getDefaultContext($request);
 
         if (isset($options['on_headers']) && !is_callable($options['on_headers'])) {
             throw new \InvalidArgumentException('on_headers must be callable');
@@ -307,7 +307,6 @@ class StreamHandler
             && isset($options['auth'][2])
             && 'ntlm' == $options['auth'][2]
         ) {
-
             throw new \InvalidArgumentException('Microsoft NTLM authentication only supported with curl handler');
         }
 

+ 1 - 1
api/vendor/guzzlehttp/guzzle/src/HandlerStack.php

@@ -22,7 +22,7 @@ class HandlerStack
      * Creates a default handler stack that can be used by clients.
      *
      * The returned handler will wrap the provided handler or use the most
-     * appropriate default handler for you system. The returned HandlerStack has
+     * appropriate default handler for your system. The returned HandlerStack has
      * support for cookies, redirects, HTTP error exceptions, and preparing a body
      * before sending.
      *

+ 0 - 2
api/vendor/guzzlehttp/guzzle/src/MessageFormatter.php

@@ -19,7 +19,6 @@ use Psr\Http\Message\ResponseInterface;
  * - {host}:           Host of the request
  * - {method}:         Method of the request
  * - {uri}:            URI of the request
- * - {host}:           Host of the request
  * - {version}:        Protocol version
  * - {target}:         Request target of the request (path + query + fragment)
  * - {hostname}:       Hostname of the machine that sent the request
@@ -74,7 +73,6 @@ class MessageFormatter
         return preg_replace_callback(
             '/{\s*([A-Za-z_\-\.0-9]+)\s*}/',
             function (array $matches) use ($request, $response, $error, &$cache) {
-
                 if (isset($cache[$matches[1]])) {
                     return $cache[$matches[1]];
                 }

+ 6 - 5
api/vendor/guzzlehttp/guzzle/src/Middleware.php

@@ -34,10 +34,11 @@ final class Middleware
                 $cookieJar = $options['cookies'];
                 $request = $cookieJar->withCookieHeader($request);
                 return $handler($request, $options)
-                    ->then(function ($response) use ($cookieJar, $request) {
-                        $cookieJar->extractCookies($request, $response);
-                        return $response;
-                    }
+                    ->then(
+                        function ($response) use ($cookieJar, $request) {
+                            $cookieJar->extractCookies($request, $response);
+                            return $response;
+                        }
                 );
             };
         };
@@ -72,7 +73,7 @@ final class Middleware
     /**
      * Middleware that pushes history data to an ArrayAccess container.
      *
-     * @param array $container Container to hold the history (by reference).
+     * @param array|\ArrayAccess $container Container to hold the history (by reference).
      *
      * @return callable Returns a function that accepts the next handler.
      * @throws \InvalidArgumentException if container is not an array or ArrayAccess.

+ 0 - 4
api/vendor/guzzlehttp/guzzle/src/UriTemplate.php

@@ -107,7 +107,6 @@ class UriTemplate
         $useQuery = self::$operatorHash[$parsed['operator']]['query'];
 
         foreach ($parsed['values'] as $value) {
-
             if (!isset($this->variables[$value['value']])) {
                 continue;
             }
@@ -117,11 +116,9 @@ class UriTemplate
             $expanded = '';
 
             if (is_array($variable)) {
-
                 $isAssoc = $this->isAssoc($variable);
                 $kvp = [];
                 foreach ($variable as $key => $var) {
-
                     if ($isAssoc) {
                         $key = rawurlencode($key);
                         $isNestedArray = is_array($var);
@@ -179,7 +176,6 @@ class UriTemplate
                     }
                     $expanded = implode(',', $kvp);
                 }
-
             } else {
                 if ($value['modifier'] === ':') {
                     $variable = substr($variable, 0, $value['position']);

+ 4 - 2
api/vendor/guzzlehttp/guzzle/src/functions.php

@@ -302,7 +302,8 @@ function json_decode($json, $assoc = false, $depth = 512, $options = 0)
     $data = \json_decode($json, $assoc, $depth, $options);
     if (JSON_ERROR_NONE !== json_last_error()) {
         throw new \InvalidArgumentException(
-            'json_decode error: ' . json_last_error_msg());
+            'json_decode error: ' . json_last_error_msg()
+        );
     }
 
     return $data;
@@ -324,7 +325,8 @@ function json_encode($value, $options = 0, $depth = 512)
     $json = \json_encode($value, $options, $depth);
     if (JSON_ERROR_NONE !== json_last_error()) {
         throw new \InvalidArgumentException(
-            'json_encode error: ' . json_last_error_msg());
+            'json_encode error: ' . json_last_error_msg()
+        );
     }
 
     return $json;

+ 36 - 0
js/functions.js

@@ -4168,6 +4168,39 @@ function buildDownloaderItem(array, source, type='none'){
 
 			}
 			break;
+        case 'rTorrent':
+            switch (type) {
+                case 'queue':
+                    if(array == 0){
+                        return '<tr><td class="max-texts" lang="en">Nothing in queue</td></tr>';
+                    }
+                    console.log(array);
+
+                    $.each(array, function(i,v) {
+                        var percent = Math.floor((v.downloaded / v.size) * 100);
+                        var size = v.size != -1 ? humanFileSize(v.size,false) : "?";
+                        var upload = v.seed !== '' ? humanFileSize(v.seed,true) : "0 B";
+                        var download = v.leech !== '' ? humanFileSize(v.leech,true) : "0 B";
+                        items += `
+						<tr>
+							<td class="max-texts">`+v.name+`</td>
+							<td class="hidden-xs">`+v.status+`</td>
+							<td class="hidden-xs"><i class="fa fa-download"></i>&nbsp;`+download+`</td>
+							<td class="hidden-xs"><i class="fa fa-upload"></i>&nbsp;`+upload+`</td>
+							<td class="hidden-xs">`+size+`</td>
+							<td class="text-right">
+								<div class="progress progress-lg m-b-0">
+									<div class="progress-bar progress-bar-info" style="width: `+percent+`%;" role="progressbar">`+percent+`%</div>
+								</div>
+							</td>
+						</tr>
+						`;
+                    });
+                    break;
+                default:
+
+            }
+            break;
 
 		case 'qBittorrent':
 			switch (type) {
@@ -4484,6 +4517,9 @@ function homepageDownloader(type, timeout){
 		case 'deluge':
 			var action = 'getDeluge';
 			break;
+        case 'rTorrent':
+            var action = 'getrTorrent';
+            break;
 		default:
 
 	}

BIN
plugins/images/tabs/rtorrent.png