'rTorrent', 'enabled' => strpos('personal', $this->config['license']) !== false, 'image' => 'plugins/images/tabs/rTorrent.png', 'category' => 'Downloader', 'settingsArray' => __FUNCTION__ ]; if ($infoOnly) { return $homepageInformation; } $xmlStatus = (extension_loaded('xmlrpc')) ? 'Installed' : 'Not Installed'; $homepageSettings = [ 'debug' => true, 'settings' => [ 'FYI' => [ $this->settingsOption('html', null, ['label' => '', 'override' => 12, 'html' => '
ATTENTION

This module requires XMLRPC

Status: [ ' . $xmlStatus . ' ]

Note about API URL

Organizr appends the url with /RPC2 unless the URL ends in .php
Possible URLs:
  • http://localhost:8080
  • https://domain.site/xmlrpc.php
  • https://seedbox.site/rutorrent/plugins/httprpc/action.php
  • ' ]), ], 'Enable' => [ $this->settingsOption('enable', 'homepagerTorrentEnabled'), $this->settingsOption('auth', 'homepagerTorrentAuth'), ], 'Connection' => [ $this->settingsOption('url', 'rTorrentURL'), $this->settingsOption('input', 'rTorrentURLOverride', ['label' => 'rTorrent API URL Override', 'help' => 'Only use if you cannot connect. Please make sure to use local IP address and port - You also may use local dns name too.', 'placeholder' => 'http(s)://hostname:port/xmlrpc']), $this->settingsOption('username', 'rTorrentUsername'), $this->settingsOption('password', 'rTorrentPassword'), $this->settingsOption('disable-cert-check', 'rTorrentDisableCertCheck'), $this->settingsOption('use-custom-certificate', 'rTorrentUseCustomCertificate'), ], 'Misc Options' => [ $this->settingsOption('hide-seeding', 'rTorrentHideSeeding'), $this->settingsOption('hide-completed', 'rTorrentHideCompleted'), $this->settingsOption('select', 'rTorrentSortOrder', ['label' => 'Order', 'options' => $this->rTorrentSortOptions()]), $this->settingsOption('limit', 'rTorrentLimit'), $this->settingsOption('multiple', 'rTorrentIgnoreLabel', ['label' => 'Ignore Torrent with Label(s)']), $this->settingsOption('refresh', 'rTorrentRefresh'), $this->settingsOption('combine', 'rTorrentCombine'), ], 'Test Connection' => [ $this->settingsOption('blank', null, ['label' => 'Please Save before Testing']), $this->settingsOption('test', 'rtorrent'), ] ] ]; return array_merge($homepageInformation, $homepageSettings); } public function testConnectionRTorrent() { if (empty($this->config['rTorrentURL']) && empty($this->config['rTorrentURLOverride'])) { $this->setAPIResponse('error', 'rTorrent URL is not defined', 422); return false; } try { $url = $this->rTorrentURL(); $options = $this->requestOptions($url, null, $this->config['rTorrentDisableCertCheck'], $this->config['rTorrentUseCustomCertificate']); if ($this->config['rTorrentUsername'] !== '' && $this->decrypt($this->config['rTorrentPassword']) !== '') { $credentials = array('auth' => new Requests_Auth_Digest(array($this->config['rTorrentUsername'], $this->decrypt($this->config['rTorrentPassword'])))); $options = array_merge($options, $credentials); } $data = xmlrpc_encode_request("system.listMethods", null); $response = Requests::post($url, [], $data, $options); if ($response->success) { $methods = xmlrpc_decode(str_replace('i8>', 'i4>', $response->body)); if (count($methods) !== 0) { $this->setAPIResponse('success', 'API Connection succeeded', 200); return true; } } $this->setAPIResponse('error', 'rTorrent error occurred', 500); return false; } catch (Requests_Exception $e) { $this->setLoggerChannel('rTorrent')->error($e); $this->setResponse(500, $e->getMessage()); return false; } } public function rTorrentHomepagePermissions($key = null) { $permissions = [ 'main' => [ 'enabled' => [ 'homepagerTorrentEnabled' ], 'auth' => [ 'homepagerTorrentAuth' ], 'not_empty' => [] ] ]; return $this->homepageCheckKeyPermissions($key, $permissions); } public function homepageOrderrTorrent() { if ($this->homepageItemPermissions($this->rTorrentHomepagePermissions('main'))) { $loadingBox = ($this->config['rTorrentCombine']) ? '' : '

    Loading Download Queue...

    '; $builder = ($this->config['rTorrentCombine']) ? 'buildDownloaderCombined(\'rTorrent\');' : '$("#' . __FUNCTION__ . '").html(buildDownloader("rTorrent"));'; return '
    ' . $loadingBox . '
    '; } } public function checkOverrideURL($url, $override) { if (strpos($override, $url) !== false) { return $override; } else { return $url . $override; } } public 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'; } elseif ($completed && !$state && $status == 'leech') { $state = 'Finished'; } return ($state) ?: $status; } public function getRTorrentHomepageQueue() { if (empty($this->config['rTorrentURL']) && empty($this->config['rTorrentURLOverride'])) { $this->setAPIResponse('error', 'rTorrent URL is not defined', 422); return false; } if (!$this->homepageItemPermissions($this->rTorrentHomepagePermissions('main'), true)) { return false; } try { if ($this->config['rTorrentLimit'] == '0') { $this->config['rTorrentLimit'] = '1000'; } $torrents = array(); $url = $this->rTorrentURL(); $options = $this->requestOptions($url, $this->config['rTorrentRefresh'], $this->config['rTorrentDisableCertCheck'], $this->config['rTorrentUseCustomCertificate']); if ($this->config['rTorrentUsername'] !== '' && $this->decrypt($this->config['rTorrentPassword']) !== '') { $credentials = array('auth' => new Requests_Auth_Digest(array($this->config['rTorrentUsername'], $this->decrypt($this->config['rTorrentPassword'])))); $options = array_merge($options, $credentials); } $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.timestamp.started=", "d.state=", "d.group.name=", "d.hash=", "d.complete=", "d.ratio=", "d.chunk_size=", "f.size_bytes=", "f.size_chunks=", "f.completed_chunks=", "d.custom=", "d.custom1=", "d.custom2=", "d.custom3=", "d.custom4=", "d.custom5=", ), array()); $response = Requests::post($url, [], $data, $options); if ($response->success) { $torrentList = xmlrpc_decode(str_replace('i8>', 'string>', $response->body)); if (is_array($torrentList)) { foreach ($torrentList as $key => $value) { $tempStatus = $this->rTorrentStatus($value[13], $value[10], $value[6]); if ($tempStatus == 'Seeding' && $this->config['rTorrentHideSeeding']) { //do nothing } elseif ($tempStatus == 'Finished' && $this->config['rTorrentHideCompleted']) { //do nothing } elseif (stripos($this->config['rTorrentIgnoreLabel'], $value[20]) !== false) { //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], 'label' => $value[20], 'status' => $tempStatus, 'temp' => $value[16] . ' - ' . $value[17] . ' - ' . $value[18], 'custom' => $value[19] . ' - ' . $value[20] . ' - ' . $value[21], 'custom2' => $value[22] . ' - ' . $value[23] . ' - ' . $value[24], ); } } } if (count($torrents) !== 0) { usort($torrents, function ($a, $b) { $direction = substr($this->config['rTorrentSortOrder'], -1); $sort = substr($this->config['rTorrentSortOrder'], 0, strlen($this->config['rTorrentSortOrder']) - 1); switch ($direction) { case 'a': return $a[$sort] <=> $b[$sort]; case 'd': return $b[$sort] <=> $a[$sort]; default: return $b['date'] <=> $a['date']; } }); $torrents = array_slice($torrents, 0, $this->config['rTorrentLimit']); } $api['content']['queueItems'] = $torrents; $api['content']['historyItems'] = false; } } catch (Requests_Exception $e) { $this->setLoggerChannel('rTorrent')->error($e); $this->setResponse(500, $e->getMessage()); return false; }; $api['content'] = $api['content'] ?? false; $this->setAPIResponse('success', null, 200, $api); return $api; } /** * @return string */ public function rTorrentURL(): string { $digest = (empty($this->config['rTorrentURLOverride'])) ? $this->qualifyURL($this->config['rTorrentURL'], true) : $this->qualifyURL($this->checkOverrideURL($this->config['rTorrentURL'], $this->config['rTorrentURLOverride']), true); $extraPath = (strpos($this->config['rTorrentURL'], '.php') !== false) ? '' : '/RPC2'; $extraPath = (empty($this->config['rTorrentURLOverride'])) ? $extraPath : ''; return $digest['scheme'] . '://' . $digest['host'] . $digest['port'] . $digest['path'] . $extraPath; } }