fixed #9; tweaked aria2 settings(including disabling certificate check);added aria2 event hooks;other minor changes;

This commit is contained in:
huangjx
2021-10-04 17:29:12 +08:00
parent 2c59da7cbb
commit b8b4d34b38
13 changed files with 145 additions and 81 deletions

View File

@@ -25,6 +25,7 @@ class Application extends App
$this->uid = ($user) ? $user->getUID() : ''; $this->uid = ($user) ? $user->getUID() : '';
$this->settings = new Settings($this->uid); $this->settings = new Settings($this->uid);
$this->dataDir = \OC::$server->getSystemConfig()->getValue('datadirectory'); $this->dataDir = \OC::$server->getSystemConfig()->getValue('datadirectory');
$this->appPath = \OC::$server->getAppManager()->getAppPath('ncdownloader');
$this->userFolder = Helper::getUserFolder($this->uid); $this->userFolder = Helper::getUserFolder($this->uid);
$container = $this->getContainer(); $container = $this->getContainer();
$container->registerService('UserId', function (IContainer $container) { $container->registerService('UserId', function (IContainer $container) {
@@ -110,7 +111,6 @@ class Application extends App
$realDownloadDir = $this->getRealDownloadDir(); $realDownloadDir = $this->getRealDownloadDir();
$this->torrentsDir = $this->settings->get('torrents_dir'); $this->torrentsDir = $this->settings->get('torrents_dir');
$aria2_dir = $this->dataDir . "/aria2"; $aria2_dir = $this->dataDir . "/aria2";
//$this->appPath = \OC::$server->getAppManager()->getAppPath('ncdownloader');
$settings['seed_time'] = $this->settings->get("ncd_seed_time"); $settings['seed_time'] = $this->settings->get("ncd_seed_time");
$settings['seed_ratio'] = $this->settings->get("ncd_seed_ratio"); $settings['seed_ratio'] = $this->settings->get("ncd_seed_ratio");
if (is_array($customSettings = $this->settings->getAria2())) { if (is_array($customSettings = $this->settings->getAria2())) {
@@ -123,6 +123,8 @@ class Application extends App
'token' => $token, 'token' => $token,
'settings' => $settings, 'settings' => $settings,
'binary' => $this->settings->setType(Settings::TYPE['SYSTEM'])->get('ncd_aria2_binary'), '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; return $config;
} }

View File

@@ -5,7 +5,7 @@
<summary>Aria2 and youtube-dl web gui for nextcloud</summary> <summary>Aria2 and youtube-dl web gui for nextcloud</summary>
<description>built-in torrent search;Start and stop Aria2 process, manage Aria2 from the web; <description>built-in torrent search;Start and stop Aria2 process, manage Aria2 from the web;
Download videos from youtube, twitter and other sites;</description> Download videos from youtube, twitter and other sites;</description>
<version>0.1.4</version> <version>0.2.0</version>
<licence>agpl</licence> <licence>agpl</licence>
<author mail="freefallbenson@gmail.com" homepage="https://github.com/shiningw">jiaxinhuang</author> <author mail="freefallbenson@gmail.com" homepage="https://github.com/shiningw">jiaxinhuang</author>
<namespace>NCDownloader</namespace> <namespace>NCDownloader</namespace>

7
hooks/completeHook.sh Executable file
View File

@@ -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

7
hooks/errorHook.sh Executable file
View File

@@ -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

7
hooks/startHook.sh Executable file
View File

@@ -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

View File

@@ -2,21 +2,18 @@
namespace OCA\NCDownloader\Command; namespace OCA\NCDownloader\Command;
use OCA\NCDownloader\Search\torrentSearch;
use OCA\NCDownloader\Tools\Aria2;
use OCA\NCDownloader\Tools\DBConn; use OCA\NCDownloader\Tools\DBConn;
use OCA\NCDownloader\Tools\Helper;
use OC\Core\Command\Base; use OC\Core\Command\Base;
use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Output\OutputInterface;
class Aria2Command extends base class Aria2Command extends base
{ {
public function __construct() public function __construct()
{ {
$this->conn = new DBConn(); $this->dbconn = new DBConn();
$this->aria2 = new Aria2();
parent::__construct(); parent::__construct();
} }
protected function configure() protected function configure()
@@ -27,20 +24,17 @@ class Aria2Command extends base
'action', 'action',
InputArgument::OPTIONAL, InputArgument::OPTIONAL,
'Aria2 hook names: start,complete,error' 'Aria2 hook names: start,complete,error'
)->addOption( )->addArgument(
'gid', 'gid',
'g', InputArgument::OPTIONAL,
InputOption::VALUE_REQUIRED,
'Aria2 gid' 'Aria2 gid'
)->addOption( )->addArgument(
'path', 'path',
'p', InputArgument::OPTIONAL,
InputOption::VALUE_OPTIONAL,
'Downloaded file path' 'Downloaded file path'
)->addOption( )->addArgument(
'number', 'numFiles',
'N', InputArgument::OPTIONAL,
InputOption::VALUE_OPTIONAL,
'Number of Files', 'Number of Files',
1 1
); );
@@ -48,31 +42,23 @@ class Aria2Command extends base
protected function execute(InputInterface $input, OutputInterface $output): int protected function execute(InputInterface $input, OutputInterface $output): int
{ {
if (!$action = $input->getArgument('action')) { if (!$action = $input->getArgument('action')) {
$action = 'start'; $action = 'start';
} }
$search = new torrentSearch();
$search->setSite('bitSearch'); $gid = $input->getArgument('gid');
$data = $search->go('test'); if (!is_string($gid)) {
$gid = $input->getOption('gid'); return 0;
$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]);
} }
$result = $this->conn->getByGid($parent_gid); if (in_array($action, ['complete', 'error'])) {
//$data = unserialize($result['data']); $status = strtoupper($action);
$output->writeln(print_r($result, true)); $this->dbconn->updateStatus($gid, Helper::STATUS[$status]);
return 0; }
if ($action === 'start') {
//Helper::log("$gid started");
}
return 1;
} }
} }

View File

@@ -21,6 +21,7 @@ class Aria2Controller extends Controller
//@config OC\AppConfig //@config OC\AppConfig
private $config; private $config;
private $l10n; private $l10n;
private $minmax = [0, 999];
public function __construct($appName, IRequest $request, $UserId, IL10N $IL10N, IRootFolder $rootFolder, Aria2 $aria2) 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->aria2->init();
$this->dbconn = new DBConn(); $this->dbconn = new DBConn();
} }
/** /**
* @NoAdminRequired * @NoAdminRequired
* @NoCSRFRequired * @NoCSRFRequired
*/ */
@@ -80,7 +81,16 @@ class Aria2Controller extends Controller
return []; return [];
} }
$resp = $this->aria2->{$action}($gid); $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 (in_array($action, ['removeDownloadResult', 'remove'])) {
if (isset($resp['result']) && strtolower($resp['result']) === 'ok') { if (isset($resp['result']) && strtolower($resp['result']) === 'ok') {
return ['message' => $this->l10n->t("DONE!"), 'status' => 1]; return ['message' => $this->l10n->t("DONE!"), 'status' => 1];
@@ -100,7 +110,7 @@ class Aria2Controller extends Controller
$data = $this->aria2->start(); $data = $this->aria2->start();
return $data; return $data;
} }
/** /**
* @NoAdminRequired * @NoAdminRequired
* @NoCSRFRequired * @NoCSRFRequired
*/ */
@@ -117,27 +127,27 @@ class Aria2Controller extends Controller
'path' => $this->urlGenerator->linkToRoute('ncdownloader.Aria2.Action', ['path' => $path]), 'path' => $this->urlGenerator->linkToRoute('ncdownloader.Aria2.Action', ['path' => $path]),
); );
} }
/** /**
* @NoAdminRequired * @NoAdminRequired
* @NoCSRFRequired * @NoCSRFRequired
*/ */
public function getStatus($path) public function getStatus($path)
{ {
//$path = $this->request->getRequestUri(); //$path = $this->request->getRequestUri();
$counter = $this->aria2->getCounters(); $counter = $this->getCounters();
folderScan::sync(); folderScan::sync();
switch (strtolower($path)) { switch (strtolower($path)) {
case "active": case "active":
$resp = $this->aria2->tellActive(); $resp = $this->aria2->tellActive();
break; break;
case "waiting": case "waiting":
$resp = $this->aria2->tellWaiting([0, 999]); $resp = $this->aria2->tellWaiting($this->minmax);
break; break;
case "complete": case "complete":
$resp = $this->aria2->tellStopped([0, 999]); $resp = $this->aria2->tellStopped($this->minmax);
break; break;
case "fail": case "fail":
$resp = $this->aria2->tellFail([0, 999]); $resp = $this->aria2->tellFail($this->minmax);
break; break;
default: default:
$resp = $this->aria2->tellActive(); $resp = $this->aria2->tellActive();
@@ -157,7 +167,7 @@ class Aria2Controller extends Controller
return $data; return $data;
} }
$data['row'] = []; $data['row'] = [];
$resp = $this->filterData($resp);
foreach ($resp as $value) { foreach ($resp as $value) {
$gid = $value['following'] ?? $value['gid']; $gid = $value['following'] ?? $value['gid'];
@@ -246,4 +256,41 @@ class Aria2Controller extends Controller
} }
return $data; 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));
}
} }

View File

@@ -88,8 +88,7 @@ class YoutubeController extends Controller
$resp = $yt->forceIPV4()->download($url); $resp = $yt->forceIPV4()->download($url);
folderScan::sync(); folderScan::sync();
return new JSONResponse(['data' => $resp]); return new JSONResponse($resp);
} }
private function downloadUrlSite($url) private function downloadUrlSite($url)
{ {

View File

@@ -32,6 +32,7 @@ class Aria2
'dir' => '/tmp/Downloads', 'dir' => '/tmp/Downloads',
'token' => null, 'token' => null,
'conf_dir' => '/tmp/aria2', 'conf_dir' => '/tmp/aria2',
'completeHook' => $_SERVER['DOCUMENT_ROOT'] . "/apps/ncdownloader/hooks/completeHook.sh",
'settings' => [], 'settings' => [],
); );
//turn keys in $options into variables //turn keys in $options into variables
@@ -43,6 +44,8 @@ class Aria2
} }
} }
$this->bin = Helper::findBinaryPath('aria2c'); $this->bin = Helper::findBinaryPath('aria2c');
$this->php = Helper::findBinaryPath('php');
$this->completeHook = $completeHook;
$this->rpcUrl = sprintf("http://%s:%s/jsonrpc", $host, $port); $this->rpcUrl = sprintf("http://%s:%s/jsonrpc", $host, $port);
$this->tokenString = $token ?? 'ncdownloader123'; $this->tokenString = $token ?? 'ncdownloader123';
$this->setToken($this->tokenString); $this->setToken($this->tokenString);
@@ -169,14 +172,6 @@ class Aria2
$this->filterResponse = true; $this->filterResponse = true;
return $result; 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() public function tellAll()
{ {
$this->filterResponse = false; $this->filterResponse = false;
@@ -303,13 +298,15 @@ class Aria2
'--enable-peer-exchange=true', '--enable-peer-exchange=true',
'--peer-id-prefix=-TR2770-', '--peer-id-prefix=-TR2770-',
'--user-agent=Transmission/2.77', '--user-agent=Transmission/2.77',
'--log-level=info', '--log-level=notice',
'--seed-ratio=1.0', '--seed-ratio=1.0',
'--bt-seed-unverified=true', '--bt-seed-unverified=true',
'--max-overall-upload-limit=1M', '--max-overall-upload-limit=1M',
'--max-overall-download-limit=0', '--max-overall-download-limit=0',
'--max-connection-per-server=4', '--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) public function start($bin = null)

View File

@@ -11,6 +11,7 @@ class DBConn
{ {
$this->conn = \OC::$server->getDatabaseConnection(); $this->conn = \OC::$server->getDatabaseConnection();
$this->queryBuilder = $this->conn->getQueryBuilder(); $this->queryBuilder = $this->conn->getQueryBuilder();
$this->prefixedTable = $this->queryBuilder->getTableName($this->table);
//$container = \OC::$server->query(\OCP\IServerContainer::class); //$container = \OC::$server->query(\OCP\IServerContainer::class);
//Helper::debug(get_class($container->query(\OCP\RichObjectStrings\IValidator::class))); //Helper::debug(get_class($container->query(\OCP\RichObjectStrings\IValidator::class)));
//$this->conn = \OC::$server->query(Connection::class);//working only with 22 //$this->conn = \OC::$server->query(Connection::class);//working only with 22
@@ -46,17 +47,28 @@ class DBConn
return $queryBuilder->fetchAll(); return $queryBuilder->fetchAll();
} }
public function getYoutubeByUid($uid) public function getUidByGid($gid)
{ {
$queryBuilder = $this->queryBuilder $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('*') ->select('*')
->from($this->table) ->from($this->table)
->where('uid = :uid') ->where('uid = :uid')
->where('type = :type') ->andWhere('type = :type')
->setParameter('uid', $uid) ->setParameter('uid', $uid)
->setParameter('type', 2) ->setParameter('type', Helper::DOWNLOADTYPE['YOUTUBE-DL'])
->execute(); ->execute();
return $queryBuilder->fetchAll(); return $qb->fetchAll();
} }
public function getByGid($gid) public function getByGid($gid)
@@ -70,34 +82,34 @@ class DBConn
return $queryBuilder->fetch(); 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) public function deleteByGid($gid)
{ {
// $sql = sprintf("DELETE FROM %s WHERE gid = ?",'*PREFIX*'.$this->table);
// return $this->conn->executeStatement($sql,array($gid));
$qb = $this->queryBuilder $qb = $this->queryBuilder
->delete($this->table) ->delete($this->table)
->where('gid = :gid') ->where('gid = :gid')
->setParameter('gid', $gid); ->setParameter('gid', $gid);
return $qb->execute(); return $qb->execute();
} }
public function execute($sql, $values) public function executeUpdate($sql, $values)
{ {
return $this->conn->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 = $this->queryBuilder;
$query->update('ncdownloader_info') $query->update('ncdownloader_info')
->set("data", $query->createNamedParameter($value)) ->set("status", $query->createNamedParameter($status))
->where($query->expr()->eq('gid', $query->createNamedParameter($gid))); ->where('gid = :gid')
// ->setParameter('gid', $gid); ->setParameter('gid', $gid);
// return $query->execute(); return $query->execute();
//return $query->getSQL(); //$sql = sprintf("UPDATE %s set status = ? WHERE gid = ?", $this->prefixedTable);
return $this->queryBuilder->getSQL(); //$this->execute($sql, [$status, $gid]);
} }
} }

View File

@@ -8,7 +8,7 @@ use OC\Files\Filesystem;
class Helper class Helper
{ {
public const DOWNLOADTYPE = ['ARIA2' => 1, 'YOUTUBE-DL' => 2, 'OTHERS' => 3]; 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) public static function isUrl($URL)
{ {
@@ -193,7 +193,7 @@ class Helper
return true; return true;
} }
public static function findBinaryPath($program) public static function findBinaryPath($program,$default = null)
{ {
$memcache = \OC::$server->getMemCacheFactory()->createDistributed('findBinaryPath'); $memcache = \OC::$server->getMemCacheFactory()->createDistributed('findBinaryPath');
if ($memcache->hasKey($program)) { if ($memcache->hasKey($program)) {
@@ -204,7 +204,7 @@ class Helper
$result = null; $result = null;
$exeSniffer = new ExecutableFinder(); $exeSniffer = new ExecutableFinder();
// Returns null if nothing is found // Returns null if nothing is found
$result = $exeSniffer->find($program, null, $paths); $result = $exeSniffer->find($program, $default, $paths);
// store the value for 5 minutes // store the value for 5 minutes
$memcache->set($program, $result, 300); $memcache->set($program, $result, 300);
return $result; return $result;

View File

@@ -14,7 +14,7 @@ class Youtube
private $format = 'bestvideo[ext=mp4]+bestaudio[ext=m4a]/best[ext=mp4]/best'; private $format = 'bestvideo[ext=mp4]+bestaudio[ext=m4a]/best[ext=mp4]/best';
private $options = []; private $options = [];
private $downloadDir; private $downloadDir;
private $timeout = 60 * 60 * 15; private $timeout = 60 * 60 * 3;//3 hours
private $outTpl = "/%(id)s-%(title)s.%(ext)s"; private $outTpl = "/%(id)s-%(title)s.%(ext)s";
private $defaultDir = "/tmp/downloads"; private $defaultDir = "/tmp/downloads";
private $env = []; private $env = [];

View File

@@ -44,8 +44,8 @@ class YoutubeHelper
if (isset($status)) { if (isset($status)) {
$this->status = trim($status); $this->status = trim($status);
} }
$sql = sprintf("UPDATE %s set status = ? WHERE gid = ?", $this->tablename); //$sql = sprintf("UPDATE %s set status = ? WHERE gid = ?", $this->tablename);
$this->dbconn->execute($sql, [$this->status, $this->gid]); $this->dbconn->updateStatus($this->gid, $this->status);
} }
public function run($buffer, $url) public function run($buffer, $url)
{ {
@@ -78,7 +78,7 @@ class YoutubeHelper
$percentage = $match['percentage']; $percentage = $match['percentage'];
$speed = $match['speed'] . "|" . $match['eta']; $speed = $match['speed'] . "|" . $match['eta'];
$sql = sprintf("UPDATE %s set filesize = ?,speed = ?,progress = ? WHERE gid = ?", $this->tablename); $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 = [ /* $data = [
'filesize' => $size, 'filesize' => $size,
'speed' => $speed, 'speed' => $speed,