diff --git a/appinfo/application.php b/appinfo/application.php index 7294a6f..8b0fb40 100644 --- a/appinfo/application.php +++ b/appinfo/application.php @@ -29,7 +29,8 @@ class Application extends App }); $container->registerService('Aria2', function (IContainer $container) { - return new Aria2(Helper::getAria2Config($this->uid)); + $config = Helper::getAria2Config($this->uid); + return new Aria2($config); }); $container->registerService('Ytdl', function (IContainer $container) { @@ -93,5 +94,4 @@ class Application extends App }); } } - } diff --git a/appinfo/routes.php b/appinfo/routes.php index 81f5a08..def087a 100644 --- a/appinfo/routes.php +++ b/appinfo/routes.php @@ -15,17 +15,17 @@ return [ ['name' => 'Ytdl#Redownload', 'url' => '/ytdl/redownload', 'verb' => 'POST'], ['name' => 'Search#Execute', 'url' => '/search', 'verb' => 'POST'], // AdminSettings - ['name' => 'Settings#Admin', 'url' => '/admin/save', 'verb' => 'POST'], - ['name' => 'Settings#saveAria2Admin', 'url' => '/admin/aria2/save', 'verb' => 'POST'], - ['name' => 'Settings#getAria2Admin', 'url' => '/admin/aria2/get', 'verb' => 'GET'], + ['name' => 'Settings#saveAdmin', 'url' => '/admin/save', 'verb' => 'POST'], + ['name' => 'Settings#saveGlobalAria2', 'url' => '/admin/aria2/save', 'verb' => 'POST'], + ['name' => 'Settings#getGlobalAria2', 'url' => '/admin/aria2/get', 'verb' => 'GET'], // PersonalSettings - ['name' => 'Settings#Personal', 'url' => '/personal/save', 'verb' => 'POST'], - ['name' => 'Settings#aria2Get', 'url' => '/personal/aria2/get', 'verb' => 'POST'], - ['name' => 'Settings#aria2Save', 'url' => '/personal/aria2/save', 'verb' => 'POST'], - ['name' => 'Settings#aria2Delete', 'url' => '/personal/aria2/delete', 'verb' => 'POST'], - ['name' => 'Settings#ytdlGet', 'url' => '/personal/ytdl/get', 'verb' => 'POST'], - ['name' => 'Settings#ytdlSave', 'url' => '/personal/ytdl/save', 'verb' => 'POST'], - ['name' => 'Settings#ytdlDelete', 'url' => '/personal/ytdl/delete', 'verb' => 'POST'], + ['name' => 'Settings#saveCustom', 'url' => '/personal/save', 'verb' => 'POST'], + ['name' => 'Settings#getCustomAria2', 'url' => '/personal/aria2/get', 'verb' => 'POST'], + ['name' => 'Settings#saveCustomAria2', 'url' => '/personal/aria2/save', 'verb' => 'POST'], + ['name' => 'Settings#deleteCustomAria2', 'url' => '/personal/aria2/delete', 'verb' => 'POST'], + ['name' => 'Settings#getYtdl', 'url' => '/personal/ytdl/get', 'verb' => 'POST'], + ['name' => 'Settings#saveYtdl', 'url' => '/personal/ytdl/save', 'verb' => 'POST'], + ['name' => 'Settings#deleteYtdl', 'url' => '/personal/ytdl/delete', 'verb' => 'POST'], ['name' => 'Settings#getSettings', 'url' => '/getsettings', 'verb' => 'POST'], ], ]; diff --git a/lib/Aria2/Aria2.php b/lib/Aria2/Aria2.php index d159ffb..da5e59f 100644 --- a/lib/Aria2/Aria2.php +++ b/lib/Aria2/Aria2.php @@ -9,6 +9,8 @@ use OCA\NCDownloader\Tools\Helper; class Aria2 { + //global Aria2 Config + private $config = []; //extra Aria2 download options private $options = array(); //optional token for authenticating with Aria2 @@ -25,18 +27,33 @@ class Aria2 private $filterResponse = true; //absolute download path private $downloadDir; + //top-level aria2 configuration dir + private $confDir; + //aria2 session file + private $sessionFile; + //aria2 rpc url + private $rpcUrl; + //php binary path; + private $php; public function __construct($options = array()) { - $options += array( - 'host' => '127.0.0.1', - 'port' => 6800, + $options += [ + 'rpcHost' => '127.0.0.1', + 'rpcPort' => 6800, 'dir' => '/tmp/Downloads', - 'torrents_dir' => '/tmp/Torrents', - 'token' => null, - 'conf_dir' => '/tmp/aria2', - 'completeHook' => $_SERVER['DOCUMENT_ROOT'] . "/apps/ncdownloader/hooks/completeHook.sh", + 'torrentsDir' => '/tmp/Torrents', + 'token' => 'ncdownloader123', + 'confDir' => '/tmp/aria2', + //settings for each aria2 downloads 'settings' => [], - ); + //options wich which aria2c starts + 'aria2Conf' => [] + ]; + //set the hooks if no user-defined equivalents + $options["aria2Conf"] += [ + 'on-download-complete' => $_SERVER['DOCUMENT_ROOT'] . "/apps/ncdownloader/hooks/completeHook.sh", + 'on-download-start' => $_SERVER['DOCUMENT_ROOT'] . "/apps/ncdownloader/hooks/startHook.sh", + ]; //turn keys in $options into variables extract($options); if (isset($binary) && $this->isExecutable($binary)) { @@ -47,27 +64,12 @@ class Aria2 if ($this->isInstalled() && !$this->isExecutable()) { chmod($this->bin, 0744); } - $this->setDownloadDir($dir); - $this->setTorrentsDir($torrents_dir); - if (!empty($settings)) { - foreach ($settings as $key => $value) { - $this->setOption($key, $value); - } - } + $this->confDir = $confDir; $this->php = Helper::findBinaryPath('php'); - $this->completeHook = $completeHook; - $this->startHook = $startHook; - $this->rpcUrl = sprintf("http://%s:%s/jsonrpc", $host, $port); - $this->tokenString = $token ?? 'ncdownloader123'; - $this->rpcPort = $rpcPort ?? 6800; - $this->dlSpeed = $dlSpeed ?? 0; - $this->upSpeed = $upSpeed ?? "1M"; - $this->logLevel = $logLevel ?? 'warn'; - $this->setToken($this->tokenString); - $this->confDir = $conf_dir; - $this->sessionFile = $this->confDir . "/aria2.session"; - //$this->confFile = $this->confDir . "/aria2.conf"; - $this->logFile = $this->confDir . "/aria2.log"; + $this->rpcUrl = sprintf("http://%s:%s/jsonrpc", $rpcHost, $rpcPort); + $this->sessionFile = $sessionFile ?? $this->confDir . "/aria2.session"; + $this->configureGlobalAria2($options); + $this->configureLocalAria2($options); } public function init() { @@ -81,6 +83,32 @@ class Aria2 $this->configure(); } + private function configureLocalAria2(array $options) + { + $this->setDownloadDir($options["dir"]); + $this->setTorrentsDir($options["torrentsDir"]); + $this->setToken($options["token"]); + if (!empty($options["settings"])) { + foreach ($options["settings"] as $key => $value) { + $this->setOption($key, $value); + } + } + } + + private function configureGlobalAria2(array $options) + { + $runOptions = new RunOptions($options["aria2Conf"]); + + $runOptions->add("--rpc-secret=" . $options["token"]); + $runOptions->add("--rpc-listen-port=" . $options["rpcPort"]); + $runOptions->add("--save-session=" . $this->sessionFile); + $runOptions->add("--input-file=" . $this->sessionFile); + $runOptions->add("--log=" . $this->confDir . "/aria2.log"); + + //$this->logFile = $this->confDir . "/aria2.log"; + $this->config = $runOptions->getOptions(); + } + public function setonDownloadStart($path) { $this->onDownloadStart = $path; @@ -284,11 +312,6 @@ class Aria2 { return $this->tellStatus($gid); } - public function restart() - { - $this->stop(); - $this->start(); - } public function download(String $url) { @@ -325,35 +348,19 @@ class Aria2 return false; } - public function getDefaults() + public function restart() { - return [ - '--continue', - '--daemon=true', - '--enable-rpc=true', - '--rpc-secret=' . $this->tokenString, - '--listen-port=51413', - '--save-session=' . $this->sessionFile, - '--input-file=' . $this->sessionFile, - '--log=' . $this->logFile, - '--rpc-listen-port=' . $this->rpcPort, - '--follow-torrent=true', - '--enable-dht=true', - '--enable-peer-exchange=true', - '--peer-id-prefix=-TR2770-', - '--user-agent=Transmission/2.77', - '--log-level=' . $this->logLevel, - '--seed-ratio=1.0', - '--bt-seed-unverified=true', - '--max-overall-upload-limit=' . $this->upSpeed, - '--max-overall-download-limit=' . $this->dlSpeed, - '--max-connection-per-server=4', - '--max-concurrent-downloads=10', - '--check-certificate=false', - '--on-download-complete=' . $this->completeHook, - '--on-download-start=' . $this->startHook, - ]; + $this->stop(); + $this->start(); } + + public function stop() + { + $resp = $this->shutdown(); + sleep(3); + return $resp ?? null; + } + public function start($bin = null) { //aria2c refuses to start with no errors when input-file is set but missing @@ -362,9 +369,8 @@ class Aria2 } //$process = new Process([$this->bin, "--conf-path=" . $this->confFile]); - $defaults = $this->getDefaults(); - array_unshift($defaults, $this->bin); - $process = new Process($defaults); + array_unshift($this->config, $this->bin); + $process = new Process($this->config); try { $process->mustRun(); $output = $process->getOutput(); @@ -399,10 +405,4 @@ class Aria2 { return $this->bin; } - public function stop() - { - $resp = $this->shutdown(); - sleep(3); - return $resp ?? null; - } } diff --git a/lib/Aria2/RunOptions.php b/lib/Aria2/RunOptions.php new file mode 100644 index 0000000..2c98920 --- /dev/null +++ b/lib/Aria2/RunOptions.php @@ -0,0 +1,82 @@ +upSpeed, + // '--max-overall-download-limit=' . $this->dlSpeed, + '--max-connection-per-server=4', + '--max-concurrent-downloads=10', + '--check-certificate=false', + ]; + + public function __construct($options) + { + foreach ($options as $name => $value) { + $name = trim($name); + $value = trim($value); + if (!str_starts_with($value, "--")) { + $name = "--" . $name; + } + if ($value) { + $option = $name . "=" . $value; + } else { + $option = $name; + } + $this->add($option); + } + } + + public function add($option) + { + $option = trim($option); + if ($i = $this->find($option)) { + $this->options[$i] = $option; + return $this; + } + array_push($this->options, $option); + return $this; + } + protected function find($option) + { + if (!str_starts_with($option, "--")) { + $option = "--" . $option; + } + if (($i = stripos($option, '=')) === false) { + return $i; + } + $name = substr($option, 0, $i); + foreach ($this->options as $index => $value) { + list($optionName,) = explode("=", $value); + if ($name == $optionName) { + return $index; + } + } + return false; + } + public function has($option) + { + return (bool) array_search($option, $this->options); + } + + public function getOptions() + { + return $this->options; + } +} diff --git a/lib/Controller/MainController.php b/lib/Controller/MainController.php index ae00a86..08c00fa 100644 --- a/lib/Controller/MainController.php +++ b/lib/Controller/MainController.php @@ -42,7 +42,7 @@ class MainController extends Controller $this->ytdl = $ytdl; $this->isAdmin = \OC_User::isAdminUser($this->uid); $this->hideError = Helper::getSettings("ncd_hide_errors", false); - $this->disable_bt_nonadmin = Helper::getSettings("ncd_disable_bt", false, Settings::TYPE["SYSTEM"]); + $this->disable_bt_nonadmin = Helper::getAdminSettings("ncd_disable_bt"); $this->accessDenied = $this->l10n->t("Sorry,only admin users can download files via BT!"); } /** @@ -117,6 +117,7 @@ class MainController extends Controller 'ncd_hide_errors' => $this->hideError, 'ncd_disable_bt' => $this->disable_bt_nonadmin, 'ncd_downloader_dir' => Helper::getSettings("ncd_downloader_dir"), + 'disallow_aria2_settings' => Helper::getAdminSettings('disallow_aria2_settings'), ]); return $params; } @@ -159,7 +160,7 @@ class MainController extends Controller 'type' => Helper::DOWNLOADTYPE['ARIA2'], 'filename' => empty($filename) ? "unknown" : $filename, 'timestamp' => time(), - 'data' => serialize(['link' => $url,'path' => Helper::getDownloadDir()]), + 'data' => serialize(['link' => $url, 'path' => Helper::getDownloadDir()]), ]; $this->dbconn->save($data); $resp = ['message' => $filename, 'result' => $result, 'file' => $filename]; @@ -217,5 +218,4 @@ class MainController extends Controller $counter = $this->counters->getCounters(); return new JSONResponse(['counter' => $counter]); } - } diff --git a/lib/Controller/SettingsController.php b/lib/Controller/SettingsController.php index 1d7b9dc..b9bbf4d 100644 --- a/lib/Controller/SettingsController.php +++ b/lib/Controller/SettingsController.php @@ -41,7 +41,7 @@ class SettingsController extends Controller * @NoAdminRequired * @NoCSRFRequired */ - public function personal() + public function saveCustom() { $params = $this->request->getParams(); foreach ($params as $key => $value) { @@ -54,31 +54,33 @@ class SettingsController extends Controller * @NoAdminRequired * @NoCSRFRequired */ - public function aria2Get() + public function getCustomAria2() { $data = json_decode($this->settings->get("custom_aria2_settings")); return new JSONResponse($data); } - public function admin() + public function saveAdmin() { - $this->settings->setType($this->settings::TYPE['SYSTEM']); $params = $this->request->getParams(); + $data = $this->settings->setType(Settings::TYPE["SYSTEM"])->get("ncd_admin_settings", []); foreach ($params as $key => $value) { - $resp = $this->save($key, $value); + if (substr($key, 0, 1) == '_') { + continue; + } + $data[$key] = $value; } + $resp = $this->save("ncd_admin_settings", $data, Settings::TYPE["SYSTEM"]); + return new JSONResponse($resp); } - public function saveAria2Admin() + public function saveGlobalAria2() { - $this->settings->setType($this->settings::TYPE['SYSTEM']); $params = $this->request->getParams(); - $data = Helper::filterData($params, Helper::aria2Options()); - Helper::log($data); - $resp = $this->settings->save("admin_aria2_settings", $data); + $resp = $this->save("global_aria2_config", $data, $this->settings::TYPE['SYSTEM']); return new JSONResponse($resp); } @@ -86,16 +88,21 @@ class SettingsController extends Controller * * @NoCSRFRequired */ - public function getAria2Admin() + public function getGlobalAria2() { - return new JSONResponse(Helper::getSettings("admin_aria2_settings", "", $this->settings::TYPE['SYSTEM'])); + return new JSONResponse(Helper::getSettings("global_aria2_config", "", $this->settings::TYPE['SYSTEM'])); } /** * @NoAdminRequired * @NoCSRFRequired */ - public function aria2Save() + public function saveCustomAria2() { + $noAria2Settings = (bool) Helper::getAdminSettings("disallow_aria2_settings"); + if (!$noAria2Settings) { + $resp = ["error" => "forbidden", "status" => false]; + return new JSONResponse($resp); + } $params = $this->request->getParams(); $data = Helper::filterData($params, Helper::aria2Options()); $resp = $this->settings->save("custom_aria2_settings", json_encode($data)); @@ -105,7 +112,7 @@ class SettingsController extends Controller * @NoAdminRequired * @NoCSRFRequired */ - public function aria2Delete() + public function deleteCustomAria2() { $saved = json_decode($this->settings->get("custom_aria2_settings"), 1); $params = $this->request->getParams(); @@ -121,13 +128,13 @@ class SettingsController extends Controller * @NoAdminRequired * @NoCSRFRequired */ - public function ytdlGet() + public function getYtdl() { $data = json_decode($this->settings->get("custom_ytdl_settings")); return new JSONResponse($data); } - public function ytdlSave() + public function saveYtdl() { $params = $this->request->getParams(); $data = array_filter($params, function ($key) { @@ -140,7 +147,7 @@ class SettingsController extends Controller * @NoAdminRequired * @NoCSRFRequired */ - public function ytdlDelete() + public function deleteYtdl() { $saved = json_decode($this->settings->get("custom_ytdl_settings"), 1); $params = $this->request->getParams(); @@ -150,15 +157,22 @@ class SettingsController extends Controller $resp = $this->settings->save("custom_ytdl_settings", json_encode($saved)); return new JSONResponse($resp); } - public function save($key, $value) + public function save($key, $value, $type = Settings::TYPE["USER"]) { //key starting with _ is invalid if (substr($key, 0, 1) == '_') { return; } $key = Helper::sanitize($key); - $value = Helper::sanitize($value); + if (is_array($value)) { + foreach ($value as $k => &$v) { + $value[$k] = Helper::sanitize($v); + } + } else { + $value = Helper::sanitize($value); + } try { + $this->settings->setType($type); $this->settings->save($key, $value); } catch (\Exception $e) { return ['error' => $e->getMessage(), "status" => false]; diff --git a/lib/Settings/Admin.php b/lib/Settings/Admin.php index 662591a..cd815a4 100644 --- a/lib/Settings/Admin.php +++ b/lib/Settings/Admin.php @@ -8,6 +8,8 @@ use OCP\IConfig; use OCP\IDBConnection; use OCP\Settings\ISettings; use OCA\NCDownloader\Db\Settings; +use OCA\NCDownloader\Tools\Helper; + class Admin implements ISettings { @@ -36,16 +38,13 @@ class Admin implements ISettings */ public function getForm() { - $this->settings->setType($this->settings::TYPE['SYSTEM']); + $settings = Helper::getAllAdminSettings(); + $settings += [ + "path" => "/apps/ncdownloader/admin/save", + + ]; $parameters = [ - 'settings' => [ - "path" => "/apps/ncdownloader/admin/save", - "ncd_yt_binary" => $this->settings->get("ncd_yt_binary"), - "ncd_aria2_binary" => $this->settings->get("ncd_aria2_binary"), - "ncd_rpctoken" => $this->settings->get("ncd_rpctoken"), - "ncd_aria2_rpc_host" => $this->settings->get("ncd_aria2_rpc_host"), - "ncd_aria2_rpc_port" => $this->settings->get("ncd_aria2_rpc_port"), - ] + 'settings' => $settings, ]; return new TemplateResponse('ncdownloader', 'settings/Admin', $parameters, ''); } diff --git a/lib/Settings/Personal.php b/lib/Settings/Personal.php index 68f663f..35c0160 100644 --- a/lib/Settings/Personal.php +++ b/lib/Settings/Personal.php @@ -45,6 +45,7 @@ class Personal implements ISettings 'ncd_seed_time_unit' => $this->settings->get("ncd_seed_time_unit"), 'ncd_seed_time' => $this->settings->get("ncd_seed_time"), "path" => '/apps/ncdownloader/personal/save', + "disallow_aria2_settings" => Helper::getAdminSettings("disallow_aria2_settings"), ] ]; diff --git a/lib/Tools/Helper.php b/lib/Tools/Helper.php index 39443fd..ae429ed 100644 --- a/lib/Tools/Helper.php +++ b/lib/Tools/Helper.php @@ -454,22 +454,28 @@ class Helper $torrentsDir = Helper::getRealTorrentsDir(); $appPath = self::getAppPath(); $dataDir = self::getDataDir(); - $aria2_dir = $dataDir . "/aria2"; + $aria2Dir = $dataDir . "/aria2"; $options['seed_time'] = $settings->get("ncd_seed_time"); $options['seed_ratio'] = $settings->get("ncd_seed_ratio"); if (is_array($customSettings = $settings->getAria2())) { $options = array_merge($customSettings, $options); } - $token = $settings->setType(Settings::TYPE['SYSTEM'])->get('ncd_rpctoken'); + $token = Helper::getAdminSettings("ncd_aria2_rpc_token"); + $rpcHost = Helper::getAdminSettings("ncd_aria2_rpc_host"); + $rpcPort = Helper::getAdminSettings("ncd_aria2_rpc_port"); + $binary = Helper::getAdminSettings("ncd_aria2_binary"); $config = [ 'dir' => $realDownloadDir, - 'torrents_dir' => $torrentsDir, - 'conf_dir' => $aria2_dir, - 'token' => $token, + 'torrentsDir' => $torrentsDir, + 'confDir' => $aria2Dir, + 'token' => $token ? $token : "ncdownloader123", 'settings' => $options, - 'binary' => $settings->setType(Settings::TYPE['SYSTEM'])->get('ncd_aria2_binary'), + 'rpcHost' => $rpcHost ? $rpcHost : "127.0.0.1", + 'rpcPort' => $rpcPort ? $rpcPort : "6800", + 'binary' => $binary, 'startHook' => $appPath . "/hooks/startHook.sh", 'completeHook' => $appPath . "/hooks/completeHook.sh", + 'aria2Conf' => Helper::getSettings("global_aria2_config", [], $settings::TYPE['SYSTEM']) ]; return $config; } @@ -522,4 +528,13 @@ class Helper { return self::isLegacyVersion() ? \OC::$server->getDatabaseConnection() : \OC::$server->get(\OCP\IDBConnection::class); } + public static function getAdminSettings($key): string + { + $settings = self::getAllAdminSettings(); + return $settings[$key] ?? ""; + } + public static function getAllAdminSettings(): array + { + return Helper::getSettings("ncd_admin_settings", [], Settings::TYPE["SYSTEM"]); + } } diff --git a/src/adminSettings.vue b/src/adminSettings.vue index 4d2f08a..cf52dbe 100644 --- a/src/adminSettings.vue +++ b/src/adminSettings.vue @@ -10,6 +10,15 @@ :path="option.path" /> +