fixed #15;added support for downloading via bittorrent files;added new class for getting download statistics

This commit is contained in:
huangjx
2021-10-21 18:18:41 +08:00
parent c2ce945aad
commit 5037180a40
12 changed files with 190 additions and 36 deletions

View File

@@ -104,12 +104,17 @@ class Application extends App
$dir = $this->settings->get('ncd_downloader_dir') ?? "/Downloads"; $dir = $this->settings->get('ncd_downloader_dir') ?? "/Downloads";
return $this->dataDir . $this->userFolder . $dir; return $this->dataDir . $this->userFolder . $dir;
} }
private function getRealTorrentsDir()
{
$dir = $this->settings->get('ncd_torrents_dir') ?? "/Torrents";
return $this->dataDir . $this->userFolder . $dir;
}
private function getConfig() private function getConfig()
{ {
//$this->config = \OC::$server->getAppConfig(); //$this->config = \OC::$server->getAppConfig();
$realDownloadDir = $this->getRealDownloadDir(); $realDownloadDir = $this->getRealDownloadDir();
$this->torrentsDir = $this->settings->get('torrents_dir'); $torrentsDir = $this->getRealTorrentsDir();
$aria2_dir = $this->dataDir . "/aria2"; $aria2_dir = $this->dataDir . "/aria2";
$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");
@@ -119,6 +124,7 @@ class Application extends App
$token = $this->settings->setType(Settings::TYPE['SYSTEM'])->get('ncd_rpctoken'); $token = $this->settings->setType(Settings::TYPE['SYSTEM'])->get('ncd_rpctoken');
$config = [ $config = [
'dir' => $realDownloadDir, 'dir' => $realDownloadDir,
'torrents_dir' => $torrentsDir,
'conf_dir' => $aria2_dir, 'conf_dir' => $aria2_dir,
'token' => $token, 'token' => $token,
'settings' => $settings, 'settings' => $settings,

View File

@@ -3,6 +3,7 @@
return [ return [
'routes' => [ 'routes' => [
['name' => 'Main#Index', 'url' => '/', 'verb' => 'GET'], ['name' => 'Main#Index', 'url' => '/', 'verb' => 'GET'],
['name' => 'Main#Upload', 'url' => '/upload', 'verb' => 'POST'],
['name' => 'main#Download', 'url' => '/new', 'verb' => 'POST'], ['name' => 'main#Download', 'url' => '/new', 'verb' => 'POST'],
['name' => 'Aria2#Action', 'url' => '/aria2/{path}', 'verb' => 'POST'], ['name' => 'Aria2#Action', 'url' => '/aria2/{path}', 'verb' => 'POST'],
['name' => 'Aria2#getStatus', 'url' => '/status/{path}', 'verb' => 'POST'], ['name' => 'Aria2#getStatus', 'url' => '/status/{path}', 'verb' => 'POST'],

1
img/upload.svg Normal file
View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewbox="0 0 16 16" width="16" height="16"><path d="M8 1L2 7h4v4h4V7h4zM2 13v2h12v-2z" fill="#000"/></svg>

After

Width:  |  Height:  |  Size: 161 B

View File

@@ -3,6 +3,7 @@ namespace OCA\NCDownloader\Controller;
use OCA\NCDownloader\Tools\Aria2; use OCA\NCDownloader\Tools\Aria2;
use OCA\NCDownloader\Tools\DBConn; use OCA\NCDownloader\Tools\DBConn;
use OCA\NCDownloader\Tools\Counters;
use OCA\NCDownloader\Tools\folderScan; use OCA\NCDownloader\Tools\folderScan;
use OCA\NCDownloader\Tools\Helper; use OCA\NCDownloader\Tools\Helper;
use OCA\NCDownloader\Tools\Settings; use OCA\NCDownloader\Tools\Settings;
@@ -38,6 +39,8 @@ class Aria2Controller extends Controller
$this->aria2 = $aria2; $this->aria2 = $aria2;
$this->aria2->init(); $this->aria2->init();
$this->dbconn = new DBConn(); $this->dbconn = new DBConn();
$this->counters = new Counters($aria2, $this->dbconn,$UserId);
} }
/** /**
* @NoAdminRequired * @NoAdminRequired
@@ -98,7 +101,7 @@ class Aria2Controller extends Controller
return ['message' => $this->l10n->t("DONE!"), 'status' => 1]; return ['message' => $this->l10n->t("DONE!"), 'status' => 1];
} }
if (is_string($result)) { if (is_string($result)) {
return ['message' => $this->l10n->t($result), 'status' => 1]; return ['message' => $this->l10n->t("DONE!"), 'status' => 1];
} }
} else { } else {
return ['error' => $this->l10n->t("FAILED!"), 'status' => 0]; return ['error' => $this->l10n->t("FAILED!"), 'status' => 0];
@@ -140,7 +143,7 @@ class Aria2Controller extends Controller
public function getStatus($path) public function getStatus($path)
{ {
//$path = $this->request->getRequestUri(); //$path = $this->request->getRequestUri();
$counter = $this->getCounters(); $counter = $this->counters->getCounters();
folderScan::sync(); folderScan::sync();
switch (strtolower($path)) { switch (strtolower($path)) {
case "active": case "active":
@@ -269,6 +272,9 @@ class Aria2Controller extends Controller
if (empty($resp)) { if (empty($resp)) {
return $data; return $data;
} }
if (isset($resp['error'])) {
return $resp;
}
$data = array_filter($resp, function ($value) { $data = array_filter($resp, function ($value) {
$gid = $value['following'] ?? $value['gid']; $gid = $value['following'] ?? $value['gid'];
@@ -277,26 +283,4 @@ class Aria2Controller extends Controller
return $data; 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

@@ -3,6 +3,7 @@
namespace OCA\NCDownloader\Controller; namespace OCA\NCDownloader\Controller;
use OCA\NCDownloader\Tools\Aria2; use OCA\NCDownloader\Tools\Aria2;
use OCA\NCDownloader\Tools\Counters;
use OCA\NCDownloader\Tools\DBConn; use OCA\NCDownloader\Tools\DBConn;
use OCA\NCDownloader\Tools\Helper; use OCA\NCDownloader\Tools\Helper;
use OCP\AppFramework\Controller; use OCP\AppFramework\Controller;
@@ -33,6 +34,7 @@ class MainController extends Controller
$this->aria2 = $aria2; $this->aria2 = $aria2;
$this->aria2->init(); $this->aria2->init();
$this->dbconn = new DBConn(); $this->dbconn = new DBConn();
$this->counters = new Counters($aria2, $this->dbconn, $UserId);
} }
/** /**
* @NoAdminRequired * @NoAdminRequired
@@ -43,12 +45,12 @@ class MainController extends Controller
// $str = \OC::$server->getDatabaseConnection()->getInner()->getPrefix(); // $str = \OC::$server->getDatabaseConnection()->getInner()->getPrefix();
//$config = \OC::$server->getAppConfig(); //$config = \OC::$server->getAppConfig();
OC_Util::addScript($this->appName, 'app'); OC_Util::addScript($this->appName, 'app');
// OC_Util::addStyle($this->appName, 'style');
// OC_Util::addStyle($this->appName, 'table'); // OC_Util::addStyle($this->appName, 'table');
$params = array(); $params = array();
$params['aria2_running'] = $this->aria2->isRunning(); $params['aria2_running'] = $this->aria2->isRunning();
$params['aria2_installed'] = $this->aria2->isInstalled(); $params['aria2_installed'] = $this->aria2->isInstalled();
$params['youtube_installed'] = (bool) Helper::findBinaryPath('youtube-dl'); $params['youtube_installed'] = (bool) Helper::findBinaryPath('youtube-dl');
$params['counter'] = $this->counters->getCounters();
$response = new TemplateResponse($this->appName, 'Index', $params); $response = new TemplateResponse($this->appName, 'Index', $params);
@@ -60,7 +62,7 @@ class MainController extends Controller
*/ */
public function Download() public function Download()
{ {
$url = trim($this->request->getParam('form_input_text')); $url = trim($this->request->getParam('text-input-value'));
//$type = trim($this->request->getParam('type')); //$type = trim($this->request->getParam('type'));
$resp = $this->_download($url); $resp = $this->_download($url);
return new JSONResponse($resp); return new JSONResponse($resp);
@@ -89,8 +91,39 @@ class MainController extends Controller
'data' => serialize(['link' => $url]), 'data' => serialize(['link' => $url]),
]; ];
$this->dbconn->save($data); $this->dbconn->save($data);
$resp = ['message' => $filename, 'result' => $result,'file' => $filename]; $resp = ['message' => $filename, 'result' => $result, 'file' => $filename];
return $resp; return $resp;
} }
/**
* @NoAdminRequired
* @NoCSRFRequired
*/
public function Upload()
{
if (is_uploaded_file($file = $_FILES['torrentfile']['tmp_name'])) {
$file = $this->aria2->getTorrentsDir() . '/' . Helper::cleanString($_FILES['torrentfile']['name']);
move_uploaded_file($_FILES['torrentfile']['tmp_name'], $file);
$result = $this->aria2->btDownload($file);
if (!$result) {
return ['error' => 'failed to download the file for some reason!'];
}
if (isset($result['error'])) {
return $result;
}
$data = [
'uid' => $this->uid,
'gid' => $result['gid'],
'type' => Helper::DOWNLOADTYPE['ARIA2'],
'filename' => $result['filename'] ?? 'unknown',
'timestamp' => time(),
];
$this->dbconn->save($data);
$resp = ['message' => $result['filename'], 'result' => $result['gid'], 'file' => $result['filename']];
}
return new JSONResponse($resp);
}
} }

View File

@@ -27,7 +27,7 @@ class SearchController extends Controller
*/ */
public function execute() public function execute()
{ {
$keyword = trim($this->request->getParam('form_input_text')); $keyword = trim($this->request->getParam('text-input-value'));
$site = trim($this->request->getParam('select-value-search')); $site = trim($this->request->getParam('select-value-search'));
$this->search->setSite($site); $this->search->setSite($site);
$data = $this->search->go($keyword); $data = $this->search->go($keyword);

View File

@@ -77,9 +77,9 @@ class YoutubeController extends Controller
public function Download() public function Download()
{ {
$params = array(); $params = array();
$url = trim($this->request->getParam('form_input_text')); $url = trim($this->request->getParam('text-input-value'));
$yt = $this->youtube; $yt = $this->youtube;
$yt->audioOnly = (bool) $this->request->getParam('audioOnly'); $yt->audioOnly = (bool) $this->request->getParam('audio-only');
if (!$yt->isInstalled()) { if (!$yt->isInstalled()) {
return new JSONResponse($this->installYTD()); return new JSONResponse($this->installYTD());
} }

View File

@@ -3,12 +3,15 @@
namespace OCA\NCDownloader\Search; namespace OCA\NCDownloader\Search;
require __DIR__ . "/../../vendor/autoload.php"; require __DIR__ . "/../../vendor/autoload.php";
use OCP\AppFramework\QueryException;
use OCP\IServerContainer; use OCP\IServerContainer;
use Symfony\Component\HttpClient\Exception\ClientException;
class torrentSearch class torrentSearch
{ {
public $container; public $container;
private $site = null; private $site = null;
private $defaultSite = __NAMESPACE__ . '\Sites\TPB';
public function __construct() public function __construct()
{ {
$this->container = \OC::$server->query(IServerContainer::class); $this->container = \OC::$server->query(IServerContainer::class);
@@ -16,7 +19,13 @@ class torrentSearch
} }
public function go($keyword) public function go($keyword)
{ {
try {
$siteInst = $this->container->query($this->site); $siteInst = $this->container->query($this->site);
} catch (QueryException $e) {
$siteInst = $this->container->query($this->defaultSite);
} catch (ClientException $e) {
return ['message', $e->getMessage()];
}
$data = $siteInst->search($keyword); $data = $siteInst->search($keyword);
$this->addAction($data); $this->addAction($data);
return $data; return $data;

View File

@@ -30,6 +30,7 @@ class Aria2
'host' => '127.0.0.1', 'host' => '127.0.0.1',
'port' => 6800, 'port' => 6800,
'dir' => '/tmp/Downloads', 'dir' => '/tmp/Downloads',
'torrents_dir' => '/tmp/Torrents',
'token' => null, 'token' => null,
'conf_dir' => '/tmp/aria2', 'conf_dir' => '/tmp/aria2',
'completeHook' => $_SERVER['DOCUMENT_ROOT'] . "/apps/ncdownloader/hooks/completeHook.sh", 'completeHook' => $_SERVER['DOCUMENT_ROOT'] . "/apps/ncdownloader/hooks/completeHook.sh",
@@ -43,6 +44,7 @@ class Aria2
$this->bin = Helper::findBinaryPath('aria2c'); $this->bin = Helper::findBinaryPath('aria2c');
} }
$this->setDownloadDir($dir); $this->setDownloadDir($dir);
$this->setTorrentsDir($torrents_dir);
if (!empty($settings)) { if (!empty($settings)) {
foreach ($settings as $key => $value) { foreach ($settings as $key => $value) {
$this->setOption($key, $value); $this->setOption($key, $value);
@@ -114,6 +116,18 @@ class Aria2
{ {
return $this->options; return $this->options;
} }
public function setTorrentsDir($dir)
{
$this->torrentsDir = $dir;
if (!is_dir($dir)) {
mkdir($dir, 0755, true);
}
return $this;
}
public function getTorrentsDir()
{
return $this->torrentsDir;
}
public function setDownloadDir($dir) public function setDownloadDir($dir)
{ {
$this->setOption('dir', $dir); $this->setOption('dir', $dir);
@@ -185,12 +199,14 @@ class Aria2
public function __call($name, $args) public function __call($name, $args)
{ {
$this->methodName = $name; $this->methodName = $name;
$data = array(); $data = array();
if (isset($args[0]) && is_array($args[0]) && count($args) == 1 && strtolower($name) !== "adduri") { if (isset($args[0]) && is_array($args[0]) && count($args) == 1 && strtolower($name) !== "adduri") {
$args = reset($args); $args = reset($args);
} }
switch ($name) { switch ($name) {
case "addUri": case "addUri":
case "addTorrent":
array_push($args, $this->options); array_push($args, $this->options);
break; break;
case "tellActive": case "tellActive":
@@ -286,6 +302,26 @@ class Aria2
return false; return false;
} }
public function btDownload($file)
{
if ($data = file_get_contents($file)) {
$filename = Helper::getBasicFilename($file);
$torrent = base64_encode($data);
$resp = $this->addTorrent($torrent, []);
}else{
return ['error' => "no valid torrents file!"];
}
if (isset($resp['error'])) {
return $resp;
}
if (isset($resp['result']) && is_string($gid = $resp['result'])) {
return ['gid' => $gid, 'filename' => $filename];
}
return false;
}
public function getDefaults() public function getDefaults()
{ {
return [ return [

65
lib/Tools/Counters.php Normal file
View File

@@ -0,0 +1,65 @@
<?php
namespace OCA\NCDownloader\Tools;
use OCA\NCDownloader\Tools\Aria2;
use OCA\NCDownloader\Tools\DBConn;
class Counters
{
private $minmax = [0, 999];
public function __construct(Aria2 $aria2, DBConn $dbconn, $uid)
{
$this->aria2 = $aria2;
$this->dbconn = $dbconn;
$this->uid = $uid;
}
public function getCounters()
{
return [
'active' => $this->getCounter(),
'waiting' => $this->getCounter('tellWaiting'),
'complete' => $this->getCounter('tellStopped'),
'fail' => $this->getCounter('tellFail'),
'youtube-dl' => $this->getCounter('youtube-dl'),
];
}
private function getCounter($action = 'tellActive')
{
if ($action === 'youtube-dl') {
$data = $this->dbconn->getYoutubeByUid($this->uid);
} else if ($action === 'tellActive') {
$data = $this->aria2->{$action}([]);
} else {
$data = $this->aria2->{$action}($this->minmax);
}
if (!is_array($data) && count($data) < 1) {
return 0;
}
if ($action !== 'youtube-dl') {
$data = $this->filterData($data);
}
return count($data);
}
private function filterData($resp)
{
$data = [];
if (empty($resp)) {
return $data;
}
if (isset($resp['error'])) {
return $resp;
}
$data = array_filter($resp, function ($value) {
$gid = $value['following'] ?? $value['gid'];
return (bool) ($this->dbconn->getUidByGid($gid) === $this->uid);
});
return $data;
}
}

View File

@@ -124,7 +124,7 @@ class Helper
'/[]/u' => '', // Literally a single quote '/[]/u' => '', // Literally a single quote
'/[“”«»„]/u' => '', // Double quote '/[“”«»„]/u' => '', // Double quote
'/ /' => '_', // nonbreaking space(equiv. to 0x160) '/ /' => '_', // nonbreaking space(equiv. to 0x160)
'/[^a-z0-9_\s.-]/i' => '_', // '/[^a-z0-9_\s.-]/i' => '_',
); );
return preg_replace(array_keys($replace), array_values($replace), $string); return preg_replace(array_keys($replace), array_values($replace), $string);
} }
@@ -286,5 +286,9 @@ class Helper
{ {
return (bool) self::findBinaryPath('ffmpeg'); return (bool) self::findBinaryPath('ffmpeg');
} }
// filename without extension
public static function getBasicFilename($path){
return pathinfo($path, PATHINFO_FILENAME);
}
} }

View File

@@ -14,11 +14,15 @@ const Http = class {
this.data = data this.data = data
return this return this
} }
setDataType($value) {
this.dataType = $value;
}
send() { send() {
let token = this.getToken(); let token = this.getToken();
this.xhr.open(this.method, this.url); this.xhr.open(this.method, this.url);
this.xhr.setRequestHeader('requesttoken', token) this.xhr.setRequestHeader('requesttoken', token)
this.xhr.setRequestHeader('OCS-APIREQUEST', 'true') this.xhr.setRequestHeader('OCS-APIREQUEST', 'true')
if (this.dataType)
this.xhr.setRequestHeader('Content-Type', this.dataType); this.xhr.setRequestHeader('Content-Type', this.dataType);
let callback = this.handler; let callback = this.handler;
this.xhr.onload = () => { this.xhr.onload = () => {
@@ -47,6 +51,17 @@ const Http = class {
this.errorHandler = handler this.errorHandler = handler
return this; return this;
} }
upload(file) {
const fd = new FormData();
this.xhr.open(this.method, this.url, true);
let callback = this.handler;
this.xhr.onload = () => {
if (typeof callback === 'function')
callback(JSON.parse(this.xhr.response));
}
fd.append('torrentfile', file);
return this.xhr.send(fd);
}
} }
export default Http export default Http