diff --git a/appinfo/application.php b/appinfo/application.php index 8b20479..d6fc2aa 100644 --- a/appinfo/application.php +++ b/appinfo/application.php @@ -25,6 +25,7 @@ class Application extends App $this->uid = ($user) ? $user->getUID() : ''; $this->settings = new Settings($this->uid); $this->dataDir = \OC::$server->getSystemConfig()->getValue('datadirectory'); + $this->appPath = \OC::$server->getAppManager()->getAppPath('ncdownloader'); $this->userFolder = Helper::getUserFolder($this->uid); $container = $this->getContainer(); $container->registerService('UserId', function (IContainer $container) { @@ -110,7 +111,6 @@ class Application extends App $realDownloadDir = $this->getRealDownloadDir(); $this->torrentsDir = $this->settings->get('torrents_dir'); $aria2_dir = $this->dataDir . "/aria2"; - //$this->appPath = \OC::$server->getAppManager()->getAppPath('ncdownloader'); $settings['seed_time'] = $this->settings->get("ncd_seed_time"); $settings['seed_ratio'] = $this->settings->get("ncd_seed_ratio"); if (is_array($customSettings = $this->settings->getAria2())) { @@ -123,6 +123,8 @@ class Application extends App 'token' => $token, 'settings' => $settings, 'binary' => $this->settings->setType(Settings::TYPE['SYSTEM'])->get('ncd_aria2_binary'), + 'startHook' => $this->appPath . "/hooks/startHook.sh", + 'completeHook' => $this->appPath . "/hooks/completeHook.sh", ]; return $config; } diff --git a/appinfo/info.xml b/appinfo/info.xml index 48c43e0..4faa636 100644 --- a/appinfo/info.xml +++ b/appinfo/info.xml @@ -5,7 +5,7 @@ Aria2 and youtube-dl web gui for nextcloud built-in torrent search;Start and stop Aria2 process, manage Aria2 from the web; Download videos from youtube, twitter and other sites; - 0.1.4 + 0.2.0 agpl jiaxinhuang NCDownloader diff --git a/hooks/completeHook.sh b/hooks/completeHook.sh new file mode 100755 index 0000000..5219834 --- /dev/null +++ b/hooks/completeHook.sh @@ -0,0 +1,7 @@ +#!/bin/sh +php=$(which php) +dir=$(dirname "$0") +script="${dir}/../../../occ" + +#$php "${dir}/run.php" aria2 start $1 $2 $3 +$php $script aria2 complete $1 $2 $3 \ No newline at end of file diff --git a/hooks/errorHook.sh b/hooks/errorHook.sh new file mode 100755 index 0000000..8b389c1 --- /dev/null +++ b/hooks/errorHook.sh @@ -0,0 +1,7 @@ +#!/bin/sh +php=$(which php) +dir=$(dirname "$0") +script="${dir}/../../../occ" + +#$php "${dir}/run.php" aria2 start $1 $2 $3 +$php $script aria2 error $1 $2 $3 \ No newline at end of file diff --git a/hooks/startHook.sh b/hooks/startHook.sh new file mode 100755 index 0000000..a66bcc4 --- /dev/null +++ b/hooks/startHook.sh @@ -0,0 +1,7 @@ +#!/bin/sh +php=$(which php) +dir=$(dirname "$0") +script="${dir}/../../../occ" + +#$php "${dir}/run.php" aria2 start $1 $2 $3 +$php $script aria2 start $1 $2 $3 \ No newline at end of file diff --git a/lib/Command/Aria2Command.php b/lib/Command/Aria2Command.php index 1425082..8cecfec 100644 --- a/lib/Command/Aria2Command.php +++ b/lib/Command/Aria2Command.php @@ -2,21 +2,18 @@ namespace OCA\NCDownloader\Command; -use OCA\NCDownloader\Search\torrentSearch; -use OCA\NCDownloader\Tools\Aria2; use OCA\NCDownloader\Tools\DBConn; +use OCA\NCDownloader\Tools\Helper; use OC\Core\Command\Base; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; -use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; class Aria2Command extends base { public function __construct() { - $this->conn = new DBConn(); - $this->aria2 = new Aria2(); + $this->dbconn = new DBConn(); parent::__construct(); } protected function configure() @@ -27,20 +24,17 @@ class Aria2Command extends base 'action', InputArgument::OPTIONAL, 'Aria2 hook names: start,complete,error' - )->addOption( + )->addArgument( 'gid', - 'g', - InputOption::VALUE_REQUIRED, + InputArgument::OPTIONAL, 'Aria2 gid' - )->addOption( + )->addArgument( 'path', - 'p', - InputOption::VALUE_OPTIONAL, + InputArgument::OPTIONAL, 'Downloaded file path' - )->addOption( - 'number', - 'N', - InputOption::VALUE_OPTIONAL, + )->addArgument( + 'numFiles', + InputArgument::OPTIONAL, 'Number of Files', 1 ); @@ -48,31 +42,23 @@ class Aria2Command extends base protected function execute(InputInterface $input, OutputInterface $output): int { - if (!$action = $input->getArgument('action')) { $action = 'start'; } - $search = new torrentSearch(); - $search->setSite('bitSearch'); - $data = $search->go('test'); - $gid = $input->getOption('gid'); - $path = $input->getOption('path'); - $numFile = $input->getOption('number'); - if (!$gid) { - return 1; - } - $parent_gid = $this->aria2->getFollowingGid($gid); // $this->conn->getAll(); - if ($parent_gid) { - $tablename = $this->conn->queryBuilder->getTableName("ncdownloader_info"); - $sql = sprintf("UPDATE %s set followedby = ? WHERE gid = ?", $tablename); - // $data = serialize(['followedby' => "82140bd962946ae0"]); - $this->conn->execute($sql, [$gid, $parent_gid]); + + $gid = $input->getArgument('gid'); + if (!is_string($gid)) { + return 0; } - $result = $this->conn->getByGid($parent_gid); - //$data = unserialize($result['data']); - $output->writeln(print_r($result, true)); - return 0; + if (in_array($action, ['complete', 'error'])) { + $status = strtoupper($action); + $this->dbconn->updateStatus($gid, Helper::STATUS[$status]); + } + if ($action === 'start') { + //Helper::log("$gid started"); + } + return 1; } } diff --git a/lib/Controller/Aria2Controller.php b/lib/Controller/Aria2Controller.php index 2a092a6..cabd6b2 100644 --- a/lib/Controller/Aria2Controller.php +++ b/lib/Controller/Aria2Controller.php @@ -21,6 +21,7 @@ class Aria2Controller extends Controller //@config OC\AppConfig private $config; private $l10n; + private $minmax = [0, 999]; public function __construct($appName, IRequest $request, $UserId, IL10N $IL10N, IRootFolder $rootFolder, Aria2 $aria2) { @@ -38,7 +39,7 @@ class Aria2Controller extends Controller $this->aria2->init(); $this->dbconn = new DBConn(); } - /** + /** * @NoAdminRequired * @NoCSRFRequired */ @@ -80,7 +81,16 @@ class Aria2Controller extends Controller return []; } $resp = $this->aria2->{$action}($gid); - + if (isset($resp['result'])) { + switch ($action) { + case "pause": + $this->dbconn->updateStatus($gid, Helper::STATUS['PAUSED']); + break; + case "unpause": + $this->dbconn->updateStatus($gid); + break; + } + } if (in_array($action, ['removeDownloadResult', 'remove'])) { if (isset($resp['result']) && strtolower($resp['result']) === 'ok') { return ['message' => $this->l10n->t("DONE!"), 'status' => 1]; @@ -100,7 +110,7 @@ class Aria2Controller extends Controller $data = $this->aria2->start(); return $data; } - /** + /** * @NoAdminRequired * @NoCSRFRequired */ @@ -117,27 +127,27 @@ class Aria2Controller extends Controller 'path' => $this->urlGenerator->linkToRoute('ncdownloader.Aria2.Action', ['path' => $path]), ); } - /** + /** * @NoAdminRequired * @NoCSRFRequired */ public function getStatus($path) { //$path = $this->request->getRequestUri(); - $counter = $this->aria2->getCounters(); + $counter = $this->getCounters(); folderScan::sync(); switch (strtolower($path)) { case "active": $resp = $this->aria2->tellActive(); break; case "waiting": - $resp = $this->aria2->tellWaiting([0, 999]); + $resp = $this->aria2->tellWaiting($this->minmax); break; case "complete": - $resp = $this->aria2->tellStopped([0, 999]); + $resp = $this->aria2->tellStopped($this->minmax); break; case "fail": - $resp = $this->aria2->tellFail([0, 999]); + $resp = $this->aria2->tellFail($this->minmax); break; default: $resp = $this->aria2->tellActive(); @@ -157,7 +167,7 @@ class Aria2Controller extends Controller return $data; } $data['row'] = []; - + $resp = $this->filterData($resp); foreach ($resp as $value) { $gid = $value['following'] ?? $value['gid']; @@ -246,4 +256,41 @@ class Aria2Controller extends Controller } return $data; } + private function filterData($resp) + { + + $data = []; + if (empty($resp)) { + return $data; + } + + $data = array_filter($resp, function ($value) { + $gid = $value['gid']; + return (bool) ($this->dbconn->getUidByGid($gid) === $this->uid); + }); + + return $data; + } + private function getCounters() + { + return [ + 'active' => $this->getCounter(), + 'waiting' => $this->getCounter('tellWaiting'), + 'complete' => $this->getCounter('tellStopped'), + 'fail' => $this->getCounter('tellFail'), + ]; + } + private function getCounter($action = 'tellActive') + { + if ($action === 'tellActive') { + $data = $this->aria2->{$action}([]); + } else { + $data = $this->aria2->{$action}($this->minmax); + } + + if (!is_array($data)) { + return 0; + } + return count($this->filterData($data)); + } } diff --git a/lib/Controller/YoutubeController.php b/lib/Controller/YoutubeController.php index b6a0ddf..a9f6db2 100644 --- a/lib/Controller/YoutubeController.php +++ b/lib/Controller/YoutubeController.php @@ -88,8 +88,7 @@ class YoutubeController extends Controller $resp = $yt->forceIPV4()->download($url); folderScan::sync(); - return new JSONResponse(['data' => $resp]); - + return new JSONResponse($resp); } private function downloadUrlSite($url) { diff --git a/lib/Tools/Aria2.php b/lib/Tools/Aria2.php index ebaccbc..24d2ae2 100644 --- a/lib/Tools/Aria2.php +++ b/lib/Tools/Aria2.php @@ -32,6 +32,7 @@ class Aria2 'dir' => '/tmp/Downloads', 'token' => null, 'conf_dir' => '/tmp/aria2', + 'completeHook' => $_SERVER['DOCUMENT_ROOT'] . "/apps/ncdownloader/hooks/completeHook.sh", 'settings' => [], ); //turn keys in $options into variables @@ -43,6 +44,8 @@ class Aria2 } } $this->bin = Helper::findBinaryPath('aria2c'); + $this->php = Helper::findBinaryPath('php'); + $this->completeHook = $completeHook; $this->rpcUrl = sprintf("http://%s:%s/jsonrpc", $host, $port); $this->tokenString = $token ?? 'ncdownloader123'; $this->setToken($this->tokenString); @@ -169,14 +172,6 @@ class Aria2 $this->filterResponse = true; return $result; } - public function getCounters() - { - $active = is_array($data = $this->tellActive([])) ? count($data) : 0; - $waiting = is_array($data = $this->tellWaiting([0, 999])) ? count($data) : 0; - $stopped = is_array($data = $this->tellStopped([0, 999])) ? count($data) : 0; - $fail = is_array($data = $this->tellFail([0, 999])) ? count($data) : 0; - return ['active' => $active, 'waiting' => $waiting, 'complete' => $stopped, 'fail' => $fail]; - } public function tellAll() { $this->filterResponse = false; @@ -303,13 +298,15 @@ class Aria2 '--enable-peer-exchange=true', '--peer-id-prefix=-TR2770-', '--user-agent=Transmission/2.77', - '--log-level=info', + '--log-level=notice', '--seed-ratio=1.0', '--bt-seed-unverified=true', '--max-overall-upload-limit=1M', '--max-overall-download-limit=0', '--max-connection-per-server=4', - '--max-concurrent-downloads=5', + '--max-concurrent-downloads=10', + '--check-certificate=false', + '--on-download-complete=' . $this->completeHook, ]; } public function start($bin = null) diff --git a/lib/Tools/DBConn.php b/lib/Tools/DBConn.php index e89fe2e..5114703 100644 --- a/lib/Tools/DBConn.php +++ b/lib/Tools/DBConn.php @@ -11,6 +11,7 @@ class DBConn { $this->conn = \OC::$server->getDatabaseConnection(); $this->queryBuilder = $this->conn->getQueryBuilder(); + $this->prefixedTable = $this->queryBuilder->getTableName($this->table); //$container = \OC::$server->query(\OCP\IServerContainer::class); //Helper::debug(get_class($container->query(\OCP\RichObjectStrings\IValidator::class))); //$this->conn = \OC::$server->query(Connection::class);//working only with 22 @@ -46,17 +47,28 @@ class DBConn return $queryBuilder->fetchAll(); } - public function getYoutubeByUid($uid) + public function getUidByGid($gid) { $queryBuilder = $this->queryBuilder + ->select('uid') + ->from($this->table) + ->where('gid = :gid') + ->setParameter('gid', $gid) + ->execute(); + return $queryBuilder->fetchColumn(); + } + + public function getYoutubeByUid($uid) + { + $qb = $this->queryBuilder ->select('*') ->from($this->table) ->where('uid = :uid') - ->where('type = :type') + ->andWhere('type = :type') ->setParameter('uid', $uid) - ->setParameter('type', 2) + ->setParameter('type', Helper::DOWNLOADTYPE['YOUTUBE-DL']) ->execute(); - return $queryBuilder->fetchAll(); + return $qb->fetchAll(); } public function getByGid($gid) @@ -70,34 +82,34 @@ class DBConn return $queryBuilder->fetch(); } - public function save(array $keys, $values = array(),$conditions = array()) + public function save(array $keys, $values = array(), $conditions = array()) { - return $this->conn->setValues($this->table, $keys, $values,$conditions); + return $this->conn->setValues($this->table, $keys, $values, $conditions); } public function deleteByGid($gid) { - // $sql = sprintf("DELETE FROM %s WHERE gid = ?",'*PREFIX*'.$this->table); - // return $this->conn->executeStatement($sql,array($gid)); $qb = $this->queryBuilder ->delete($this->table) ->where('gid = :gid') ->setParameter('gid', $gid); return $qb->execute(); } - public function execute($sql, $values) + public function executeUpdate($sql, $values) { return $this->conn->executeUpdate($sql, $values); + } - // for some reason this doesn't work + public function updateStatus($gid, $status = 1) + { $query = $this->queryBuilder; $query->update('ncdownloader_info') - ->set("data", $query->createNamedParameter($value)) - ->where($query->expr()->eq('gid', $query->createNamedParameter($gid))); - // ->setParameter('gid', $gid); - // return $query->execute(); - //return $query->getSQL(); - return $this->queryBuilder->getSQL(); + ->set("status", $query->createNamedParameter($status)) + ->where('gid = :gid') + ->setParameter('gid', $gid); + return $query->execute(); + //$sql = sprintf("UPDATE %s set status = ? WHERE gid = ?", $this->prefixedTable); + //$this->execute($sql, [$status, $gid]); } } diff --git a/lib/Tools/Helper.php b/lib/Tools/Helper.php index 5d68b41..210dc34 100644 --- a/lib/Tools/Helper.php +++ b/lib/Tools/Helper.php @@ -8,7 +8,7 @@ use OC\Files\Filesystem; class Helper { public const DOWNLOADTYPE = ['ARIA2' => 1, 'YOUTUBE-DL' => 2, 'OTHERS' => 3]; - public const STATUS = ['ACTIVE' => 1, 'PAUSED' => 2, 'COMPLETE' => 3, 'ERROR' => 4]; + public const STATUS = ['ACTIVE' => 1, 'PAUSED' => 2, 'COMPLETE' => 3, 'WAITING' => 4,'ERROR' => 5]; public static function isUrl($URL) { @@ -193,7 +193,7 @@ class Helper return true; } - public static function findBinaryPath($program) + public static function findBinaryPath($program,$default = null) { $memcache = \OC::$server->getMemCacheFactory()->createDistributed('findBinaryPath'); if ($memcache->hasKey($program)) { @@ -204,7 +204,7 @@ class Helper $result = null; $exeSniffer = new ExecutableFinder(); // Returns null if nothing is found - $result = $exeSniffer->find($program, null, $paths); + $result = $exeSniffer->find($program, $default, $paths); // store the value for 5 minutes $memcache->set($program, $result, 300); return $result; diff --git a/lib/Tools/Youtube.php b/lib/Tools/Youtube.php index b0270f1..dc8f484 100644 --- a/lib/Tools/Youtube.php +++ b/lib/Tools/Youtube.php @@ -14,7 +14,7 @@ class Youtube private $format = 'bestvideo[ext=mp4]+bestaudio[ext=m4a]/best[ext=mp4]/best'; private $options = []; private $downloadDir; - private $timeout = 60 * 60 * 15; + private $timeout = 60 * 60 * 3;//3 hours private $outTpl = "/%(id)s-%(title)s.%(ext)s"; private $defaultDir = "/tmp/downloads"; private $env = []; diff --git a/lib/Tools/YoutubeHelper.php b/lib/Tools/YoutubeHelper.php index 768b0e6..4fe88c1 100644 --- a/lib/Tools/YoutubeHelper.php +++ b/lib/Tools/YoutubeHelper.php @@ -44,8 +44,8 @@ class YoutubeHelper if (isset($status)) { $this->status = trim($status); } - $sql = sprintf("UPDATE %s set status = ? WHERE gid = ?", $this->tablename); - $this->dbconn->execute($sql, [$this->status, $this->gid]); + //$sql = sprintf("UPDATE %s set status = ? WHERE gid = ?", $this->tablename); + $this->dbconn->updateStatus($this->gid, $this->status); } public function run($buffer, $url) { @@ -78,7 +78,7 @@ class YoutubeHelper $percentage = $match['percentage']; $speed = $match['speed'] . "|" . $match['eta']; $sql = sprintf("UPDATE %s set filesize = ?,speed = ?,progress = ? WHERE gid = ?", $this->tablename); - $this->dbconn->execute($sql, [$this->filesize, $speed, $percentage, $this->gid]); + $this->dbconn->executeUpdate($sql, [$this->filesize, $speed, $percentage, $this->gid]); /* $data = [ 'filesize' => $size, 'speed' => $speed,