added options for tracking youtube-dl downloads;bugs fixing
This commit is contained in:
@@ -4,6 +4,7 @@ namespace OCA\NCDownloader\AppInfo;
|
|||||||
|
|
||||||
use OCA\NCDownloader\Controller\Aria2Controller;
|
use OCA\NCDownloader\Controller\Aria2Controller;
|
||||||
use OCA\NCDownloader\Controller\MainController;
|
use OCA\NCDownloader\Controller\MainController;
|
||||||
|
use OCA\NCDownloader\Controller\YoutubeController;
|
||||||
use OCA\NCDownloader\Tools\Aria2;
|
use OCA\NCDownloader\Tools\Aria2;
|
||||||
use OCA\NCDownloader\Tools\Helper;
|
use OCA\NCDownloader\Tools\Helper;
|
||||||
use OCA\NCDownloader\Tools\Settings;
|
use OCA\NCDownloader\Tools\Settings;
|
||||||
@@ -60,6 +61,16 @@ class Application extends App
|
|||||||
$container->query('Aria2')
|
$container->query('Aria2')
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
$container->registerService('YoutubeController', function (IContainer $container) {
|
||||||
|
return new YoutubeController(
|
||||||
|
$container->query('AppName'),
|
||||||
|
$container->query('Request'),
|
||||||
|
$container->query('UserId'),
|
||||||
|
\OC::$server->getL10N('ncdownloader'),
|
||||||
|
$container->query('Aria2'),
|
||||||
|
$container->query('Youtube')
|
||||||
|
);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getRealDownloadDir()
|
private function getRealDownloadDir()
|
||||||
|
|||||||
@@ -1,20 +1,16 @@
|
|||||||
<?php
|
<?php
|
||||||
/**
|
|
||||||
* Create your routes in here. The name is the lowercase name of the controller
|
|
||||||
* without the controller part, the stuff after the hash is the method.
|
|
||||||
* e.g. page#index -> OCA\NCDownloader\Controller\Aria2Controller->index()
|
|
||||||
*
|
|
||||||
* The controller class has to be registered in the application.php file since
|
|
||||||
* it's instantiated in there
|
|
||||||
*/
|
|
||||||
return [
|
return [
|
||||||
'routes' => [
|
'routes' => [
|
||||||
['name' => 'Main#Index', 'url' => '/', 'verb' => 'GET'],
|
['name' => 'Main#Index', 'url' => '/', 'verb' => 'GET'],
|
||||||
['name' => 'main#newDownload', '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'],
|
||||||
['name' => 'Aria2#Update', 'url' => '/update', 'verb' => 'GET'],
|
['name' => 'Aria2#Update', 'url' => '/update', 'verb' => 'GET'],
|
||||||
//['name' => 'main#checkStatus', 'url' => '/checkstatus', 'verb' => 'POST'],
|
['name' => 'Youtube#Index', 'url' => '/youtube/get', 'verb' => 'POST'],
|
||||||
|
['name' => 'Youtube#Download', 'url' => '/youtube/new', 'verb' => 'POST'],
|
||||||
|
['name' => 'Youtube#Delete', 'url' => '/youtube/delete', 'verb' => 'POST'],
|
||||||
|
['name' => 'Search#Execute', 'url' => '/search', 'verb' => 'POST'],
|
||||||
// AdminSettings
|
// AdminSettings
|
||||||
['name' => 'Settings#Admin', 'url' => '/admin/save', 'verb' => 'POST'],
|
['name' => 'Settings#Admin', 'url' => '/admin/save', 'verb' => 'POST'],
|
||||||
// PersonalSettings
|
// PersonalSettings
|
||||||
@@ -23,6 +19,5 @@ return [
|
|||||||
['name' => 'Settings#aria2Save', 'url' => '/personal/aria2/save', 'verb' => 'POST'],
|
['name' => 'Settings#aria2Save', 'url' => '/personal/aria2/save', 'verb' => 'POST'],
|
||||||
['name' => 'Settings#aria2Delete', 'url' => '/personal/aria2/delete', 'verb' => 'POST'],
|
['name' => 'Settings#aria2Delete', 'url' => '/personal/aria2/delete', 'verb' => 'POST'],
|
||||||
|
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@@ -3,9 +3,8 @@
|
|||||||
namespace OCA\NCDownloader\Command;
|
namespace OCA\NCDownloader\Command;
|
||||||
|
|
||||||
use OCA\NCDownloader\Tools\Aria2;
|
use OCA\NCDownloader\Tools\Aria2;
|
||||||
|
use OCA\NCDownloader\Tools\Youtube;
|
||||||
use OCA\NCDownloader\Tools\DBConn;
|
use OCA\NCDownloader\Tools\DBConn;
|
||||||
use OCA\NCDownloader\Tools\File;
|
|
||||||
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;
|
||||||
@@ -22,8 +21,7 @@ class Aria2Command extends base
|
|||||||
}
|
}
|
||||||
protected function configure()
|
protected function configure()
|
||||||
{
|
{
|
||||||
$this
|
$this->setName('aria2')
|
||||||
->setName('aria2')
|
|
||||||
->setDescription('Aria2 hooks')
|
->setDescription('Aria2 hooks')
|
||||||
->addArgument(
|
->addArgument(
|
||||||
'action',
|
'action',
|
||||||
@@ -38,7 +36,7 @@ class Aria2Command extends base
|
|||||||
'path',
|
'path',
|
||||||
'p',
|
'p',
|
||||||
InputOption::VALUE_OPTIONAL,
|
InputOption::VALUE_OPTIONAL,
|
||||||
'Downloaded file path',
|
'Downloaded file path'
|
||||||
)->addOption(
|
)->addOption(
|
||||||
'number',
|
'number',
|
||||||
'N',
|
'N',
|
||||||
@@ -73,4 +71,5 @@ class Aria2Command extends base
|
|||||||
$output->writeln(print_r($result, true));
|
$output->writeln(print_r($result, true));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +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\File;
|
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;
|
||||||
use OCP\AppFramework\Controller;
|
use OCP\AppFramework\Controller;
|
||||||
@@ -16,11 +16,10 @@ use \OC\Files\Filesystem;
|
|||||||
|
|
||||||
class Aria2Controller extends Controller
|
class Aria2Controller extends Controller
|
||||||
{
|
{
|
||||||
private $userId;
|
private $uid;
|
||||||
private $settings = null;
|
private $settings = null;
|
||||||
//@config OC\AppConfig
|
//@config OC\AppConfig
|
||||||
private $config;
|
private $config;
|
||||||
private $aria2Opts;
|
|
||||||
private $l10n;
|
private $l10n;
|
||||||
|
|
||||||
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)
|
||||||
@@ -43,6 +42,7 @@ class Aria2Controller extends Controller
|
|||||||
public function Action($path)
|
public function Action($path)
|
||||||
{
|
{
|
||||||
$path = strtolower(trim($path));
|
$path = strtolower(trim($path));
|
||||||
|
$resp = [];
|
||||||
|
|
||||||
if (!in_array($path, ['start', 'check']) && !($gid = $this->request->getParam('gid'))) {
|
if (!in_array($path, ['start', 'check']) && !($gid = $this->request->getParam('gid'))) {
|
||||||
return new JSONResponse(['error' => "no gid value is received!"]);
|
return new JSONResponse(['error' => "no gid value is received!"]);
|
||||||
@@ -55,22 +55,43 @@ class Aria2Controller extends Controller
|
|||||||
$resp = $this->Start();
|
$resp = $this->Start();
|
||||||
break;
|
break;
|
||||||
case "pause":
|
case "pause":
|
||||||
$resp = $this->aria2->pause($gid);
|
$resp = $this->doAction('pause', $gid);
|
||||||
break;
|
break;
|
||||||
case "remove":
|
case "remove":
|
||||||
$resp = $this->aria2->remove($gid);
|
$resp = $this->doAction('remove', $gid);
|
||||||
break;
|
break;
|
||||||
case "unpause":
|
case "unpause":
|
||||||
$resp = $this->aria2->unpause($gid);
|
$resp = $this->doAction('unpause', $gid);
|
||||||
break;
|
break;
|
||||||
case "get":
|
case "get":
|
||||||
$resp = $this->aria2->tellStatus($gid);
|
$resp = $this->doAction('tellStatus', $gid);
|
||||||
break;
|
break;
|
||||||
case 'purge':
|
case 'purge':
|
||||||
$resp = $this->aria2->removeDownloadResult($gid);
|
$resp = $this->doAction('removeDownloadResult', $gid);
|
||||||
|
if (isset($resp['status']) && $resp['status']) {
|
||||||
|
$this->dbconn->deleteByGid($gid);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return new JSONResponse($resp);
|
return new JSONResponse($resp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function doAction($action, $gid)
|
||||||
|
{
|
||||||
|
if (!$action || !$gid) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
$resp = $this->aria2->{$action}($gid);
|
||||||
|
|
||||||
|
if (in_array($action, ['removeDownloadResult', 'remove'])) {
|
||||||
|
if (isset($resp['result']) && strtolower($resp['result']) === 'ok') {
|
||||||
|
return ['message' => $this->l10n->t("DONE!"), 'status' => 1];
|
||||||
|
} else {
|
||||||
|
return ['error' => $this->l10n->t("FAILED!"), 'status' => 0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $resp;
|
||||||
|
|
||||||
|
}
|
||||||
private function Start()
|
private function Start()
|
||||||
{
|
{
|
||||||
if ($this->aria2->isRunning()) {
|
if ($this->aria2->isRunning()) {
|
||||||
@@ -82,8 +103,8 @@ class Aria2Controller extends Controller
|
|||||||
}
|
}
|
||||||
public function Update()
|
public function Update()
|
||||||
{
|
{
|
||||||
$resp = File::syncFolder();
|
$resp = folderScan::create()->scan();
|
||||||
//return new JSONResponse($resp);
|
return new JSONResponse($resp);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function createActionItem($name, $path)
|
private function createActionItem($name, $path)
|
||||||
@@ -97,7 +118,7 @@ class Aria2Controller extends Controller
|
|||||||
{
|
{
|
||||||
//$path = $this->request->getRequestUri();
|
//$path = $this->request->getRequestUri();
|
||||||
$counter = $this->aria2->getCounters();
|
$counter = $this->aria2->getCounters();
|
||||||
$this->Update();
|
folderScan::sync();
|
||||||
switch (strtolower($path)) {
|
switch (strtolower($path)) {
|
||||||
case "active":
|
case "active":
|
||||||
$resp = $this->aria2->tellActive();
|
$resp = $this->aria2->tellActive();
|
||||||
@@ -179,11 +200,12 @@ class Aria2Controller extends Controller
|
|||||||
$value['progress'] = array(sprintf("%s(%.2f%%)", $completed, $percentage), $extraInfo);
|
$value['progress'] = array(sprintf("%s(%.2f%%)", $completed, $percentage), $extraInfo);
|
||||||
$timestamp = $timestamp ?? 0;
|
$timestamp = $timestamp ?? 0;
|
||||||
//$prefix = $value['files'][0]['path'];
|
//$prefix = $value['files'][0]['path'];
|
||||||
$filename = sprintf('<a class="download-file-folder" href="%s">%s</a>', $folderLink, $filename);
|
|
||||||
$fileInfo = sprintf("%s | %s", $total, date("Y-m-d H:i:s", $timestamp));
|
|
||||||
|
|
||||||
$tmp = [];
|
$tmp = [];
|
||||||
$actions = [];
|
$actions = [];
|
||||||
|
$filename = sprintf('<a class="download-file-folder" href="%s">%s</a>', $folderLink, $filename);
|
||||||
|
$fileInfo = sprintf("%s | %s", $total, date("Y-m-d H:i:s", $timestamp));
|
||||||
|
$tmp['filename'] = array($filename, $fileInfo);
|
||||||
|
|
||||||
if ($this->aria2->methodName === "tellStopped") {
|
if ($this->aria2->methodName === "tellStopped") {
|
||||||
$actions[] = $this->createActionItem('purge', 'purge');
|
$actions[] = $this->createActionItem('purge', 'purge');
|
||||||
} else {
|
} else {
|
||||||
@@ -192,7 +214,6 @@ class Aria2Controller extends Controller
|
|||||||
if ($this->aria2->methodName === "tellWaiting") {
|
if ($this->aria2->methodName === "tellWaiting") {
|
||||||
$actions[] = $this->createActionItem('unpause', 'unpause');
|
$actions[] = $this->createActionItem('unpause', 'unpause');
|
||||||
}
|
}
|
||||||
$tmp['filename'] = array($filename, $fileInfo);
|
|
||||||
if ($this->aria2->methodName === "tellActive") {
|
if ($this->aria2->methodName === "tellActive") {
|
||||||
$speed = [Helper::formatBytes($value['downloadSpeed']), $left . " left"];
|
$speed = [Helper::formatBytes($value['downloadSpeed']), $left . " left"];
|
||||||
$tmp['speed'] = $speed;
|
$tmp['speed'] = $speed;
|
||||||
|
|||||||
@@ -2,10 +2,8 @@
|
|||||||
|
|
||||||
namespace OCA\NCDownloader\Controller;
|
namespace OCA\NCDownloader\Controller;
|
||||||
|
|
||||||
use OCA\NCDownloader\Search\torrentSearch;
|
|
||||||
use OCA\NCDownloader\Tools\Aria2;
|
use OCA\NCDownloader\Tools\Aria2;
|
||||||
use OCA\NCDownloader\Tools\DBConn;
|
use OCA\NCDownloader\Tools\DBConn;
|
||||||
use OCA\NCDownloader\Tools\File;
|
|
||||||
use OCA\NCDownloader\Tools\Helper;
|
use OCA\NCDownloader\Tools\Helper;
|
||||||
use OCA\NCDownloader\Tools\Youtube;
|
use OCA\NCDownloader\Tools\Youtube;
|
||||||
use OCP\AppFramework\Controller;
|
use OCP\AppFramework\Controller;
|
||||||
@@ -40,8 +38,8 @@ class MainController extends Controller
|
|||||||
$this->aria2->init();
|
$this->aria2->init();
|
||||||
$this->youtube = $youtube;
|
$this->youtube = $youtube;
|
||||||
$this->dbconn = new DBConn();
|
$this->dbconn = new DBConn();
|
||||||
|
$this->tablename = $this->dbconn->queryBuilder->getTableName("ncdownloader_info");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @NoAdminRequired
|
* @NoAdminRequired
|
||||||
* @NoCSRFRequired
|
* @NoCSRFRequired
|
||||||
@@ -69,62 +67,39 @@ class MainController extends Controller
|
|||||||
return $response;
|
return $response;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function newDownload()
|
public function Download()
|
||||||
{
|
{
|
||||||
$params = array();
|
$url = trim($this->request->getParam('form_input_text'));
|
||||||
$inputValue = trim($this->request->getParam('form_input_text'));
|
//$type = trim($this->request->getParam('type'));
|
||||||
$type = trim($this->request->getParam('type'));
|
$resp = $this->_download($url);
|
||||||
if ($type == 'ytdl') {
|
|
||||||
$yt = $this->youtube;
|
|
||||||
if (!$yt->isInstalled()) {
|
|
||||||
try {
|
|
||||||
$filename = Helper::getFileName($yt->installUrl());
|
|
||||||
$this->aria2->setDownloadDir($this->dataDir . "/bin");
|
|
||||||
$resp = $this->Save($yt->installUrl(), $filename);
|
|
||||||
return new JSONResponse($resp);
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
return new JSONResponse(['error' => $e->getMessage()]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new JSONResponse(['error' => $this->l10n->t("Youtube-dl NOT installed!")]);
|
|
||||||
}
|
|
||||||
$resp = $yt->forceIPV4()->download($inputValue);
|
|
||||||
File::syncFolder();
|
|
||||||
return new JSONResponse(['yt' => $resp]);
|
|
||||||
|
|
||||||
} else if ($type === 'search') {
|
|
||||||
$data = torrentSearch::go($inputValue);
|
|
||||||
$resp['title'] = ['title', 'seeders', 'info', 'actions'];
|
|
||||||
$resp['row'] = $data;
|
|
||||||
return new JSONResponse($resp);
|
return new JSONResponse($resp);
|
||||||
}
|
}
|
||||||
|
|
||||||
$filename = Helper::getFileName($inputValue);
|
private function _download($url)
|
||||||
$resp = $this->Save($inputValue, $filename);
|
|
||||||
return new JSONResponse($resp);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function Save($url, $filename = null)
|
|
||||||
{
|
{
|
||||||
if (isset($filename)) {
|
$filename = Helper::getFileName($url);
|
||||||
|
if ($filename) {
|
||||||
$this->aria2->setFileName($filename);
|
$this->aria2->setFileName($filename);
|
||||||
}
|
}
|
||||||
//$this->aria2->setDownloadDir("/tmp/downloads");
|
$result = $this->aria2->download($url);
|
||||||
$result = $this->aria2->addUri([$url]);
|
if (!$result) {
|
||||||
$gid = $result['result'];
|
return ['error' => 'failed to download the file for some reason!'];
|
||||||
if (!is_string($gid)) {
|
}
|
||||||
return ['error' => 'Failed to add download task! ' . $result['error']];
|
if (isset($result['error'])) {
|
||||||
} else {
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
$data = [
|
$data = [
|
||||||
'uid' => $this->uid,
|
'uid' => $this->uid,
|
||||||
'gid' => $gid,
|
'gid' => $result,
|
||||||
'type' => 1,
|
'type' => Helper::DOWNLOADTYPE['ARIA2'],
|
||||||
'filename' => $filename ?? 'unknown',
|
'filename' => $filename ?? 'unknown',
|
||||||
'timestamp' => time(),
|
'timestamp' => time(),
|
||||||
'data' => serialize(['link' => $url]),
|
'data' => serialize(['link' => $url]),
|
||||||
];
|
];
|
||||||
$this->dbconn->save($data);
|
$this->dbconn->save($data);
|
||||||
|
$resp = ['gid' => $result, 'file' => $filename, 'result' => $result];
|
||||||
|
return $resp;
|
||||||
}
|
}
|
||||||
return ['gid' => $gid, 'file' => $filename, 'result' => $gid];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
33
lib/Controller/SearchController.php
Normal file
33
lib/Controller/SearchController.php
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
<?php
|
||||||
|
namespace OCA\NCDownloader\Controller;
|
||||||
|
|
||||||
|
use OCA\NCDownloader\Search\torrentSearch;
|
||||||
|
use OCP\AppFramework\Controller;
|
||||||
|
use OCP\AppFramework\Http\JSONResponse;
|
||||||
|
use OCP\IRequest;
|
||||||
|
|
||||||
|
class SearchController extends Controller
|
||||||
|
{
|
||||||
|
private $userId;
|
||||||
|
private $settings = null;
|
||||||
|
//@config OC\AppConfig
|
||||||
|
private $l10n;
|
||||||
|
|
||||||
|
public function __construct($appName, IRequest $request, $UserId)
|
||||||
|
{
|
||||||
|
parent::__construct($appName, $request);
|
||||||
|
$this->appName = $appName;
|
||||||
|
$this->uid = $UserId;
|
||||||
|
$this->urlGenerator = \OC::$server->getURLGenerator();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function execute()
|
||||||
|
{
|
||||||
|
$keyword = trim($this->request->getParam('form_input_text'));
|
||||||
|
$data = torrentSearch::go($keyword);
|
||||||
|
$resp['title'] = ['title', 'seeders', 'info', 'actions'];
|
||||||
|
$resp['row'] = $data;
|
||||||
|
return new JSONResponse($resp);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
152
lib/Controller/YoutubeController.php
Normal file
152
lib/Controller/YoutubeController.php
Normal file
@@ -0,0 +1,152 @@
|
|||||||
|
<?php
|
||||||
|
namespace OCA\NCDownloader\Controller;
|
||||||
|
|
||||||
|
use OCA\NCDownloader\Tools\Aria2;
|
||||||
|
use OCA\NCDownloader\Tools\DBConn;
|
||||||
|
use OCA\NCDownloader\Tools\folderScan;
|
||||||
|
use OCA\NCDownloader\Tools\Helper;
|
||||||
|
use OCA\NCDownloader\Tools\Settings;
|
||||||
|
use OCA\NCDownloader\Tools\Youtube;
|
||||||
|
use OCP\AppFramework\Controller;
|
||||||
|
use OCP\AppFramework\Http\JSONResponse;
|
||||||
|
use OCP\IL10N;
|
||||||
|
use OCP\IRequest;
|
||||||
|
|
||||||
|
class YoutubeController extends Controller
|
||||||
|
{
|
||||||
|
private $userId;
|
||||||
|
private $settings = null;
|
||||||
|
//@config OC\AppConfig
|
||||||
|
private $l10n;
|
||||||
|
|
||||||
|
public function __construct($appName, IRequest $request, $UserId, IL10N $IL10N, Aria2 $aria2, Youtube $youtube)
|
||||||
|
{
|
||||||
|
parent::__construct($appName, $request);
|
||||||
|
$this->appName = $appName;
|
||||||
|
$this->uid = $UserId;
|
||||||
|
$this->urlGenerator = \OC::$server->getURLGenerator();
|
||||||
|
$this->l10n = $IL10N;
|
||||||
|
$this->settings = new Settings($UserId);
|
||||||
|
$this->downloadDir = $this->settings->get('ncd_downloader_dir') ?? "/Downloads";
|
||||||
|
$this->dbconn = new DBConn();
|
||||||
|
$this->youtube = $youtube;
|
||||||
|
$this->aria2 = $aria2;
|
||||||
|
$this->aria2->init();
|
||||||
|
$this->tablename = $this->dbconn->queryBuilder->getTableName("ncdownloader_info");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function Index()
|
||||||
|
{
|
||||||
|
$data = $this->dbconn->getYoutubeByUid($this->uid);
|
||||||
|
if (is_array($data) && count($data) < 1) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
$resp['title'] = [];
|
||||||
|
$resp['row'] = [];
|
||||||
|
$params = ['dir' => $this->downloadDir];
|
||||||
|
$folderLink = $this->urlGenerator->linkToRoute('files.view.index', $params);
|
||||||
|
foreach ($data as $value) {
|
||||||
|
$tmp = [];
|
||||||
|
$filename = sprintf('<a class="download-file-folder" href="%s">%s</a>', $folderLink, $value['filename']);
|
||||||
|
$fileInfo = sprintf("%s | %s", $value['filesize'], date("Y-m-d H:i:s", $value['timestamp']));
|
||||||
|
$tmp['filename'] = array($filename, $fileInfo);
|
||||||
|
$tmp['speed'] = $value['speed'];
|
||||||
|
$tmp['progress'] = $value['progress'];
|
||||||
|
if ((int) $value['status'] == Helper::STATUS['COMPLETE']) {
|
||||||
|
$path = $this->urlGenerator->linkToRoute('ncdownloader.Youtube.Delete');
|
||||||
|
$tmp['actions'][] = ['name' => 'delete', 'path' => $path];
|
||||||
|
} else {
|
||||||
|
$tmp['actions'][] = ['name' => 'disabled', 'path' => '#'];
|
||||||
|
}
|
||||||
|
$tmp['data_gid'] = $value['gid'] ?? 0;
|
||||||
|
array_push($resp['row'], $tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
$resp['title'] = ['filename', 'speed', 'progress', 'actions'];
|
||||||
|
$resp['counter'] = ['youtube-dl' => count($data)];
|
||||||
|
return new JSONResponse($resp);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function Download()
|
||||||
|
{
|
||||||
|
$params = array();
|
||||||
|
$url = trim($this->request->getParam('form_input_text'));
|
||||||
|
$yt = $this->youtube;
|
||||||
|
if (!$yt->isInstalled()) {
|
||||||
|
return new JSONResponse($this->installYTD());
|
||||||
|
}
|
||||||
|
if (Helper::isGetUrlSite($url)) {
|
||||||
|
return new JSONResponse($this->downloadUrlSite($url));
|
||||||
|
}
|
||||||
|
|
||||||
|
$resp = $yt->forceIPV4()->download($url);
|
||||||
|
folderScan::sync();
|
||||||
|
return new JSONResponse(['data' => $resp]);
|
||||||
|
|
||||||
|
}
|
||||||
|
private function downloadUrlSite($url)
|
||||||
|
{
|
||||||
|
$yt = $this->youtube;
|
||||||
|
if ($data = $yt->forceIPV4()->getDownloadUrl($url)) {
|
||||||
|
return $this->_download($data['url'], $data['filename']);
|
||||||
|
} else {
|
||||||
|
return ['error' => $this->l10n->t("failed to get any url!")];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function Delete()
|
||||||
|
{
|
||||||
|
$gid = $this->request->getParam('gid');
|
||||||
|
if (!$gid) {
|
||||||
|
return new JSONResponse(['error' => "no gid value is received!"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->dbconn->deleteByGid($gid)) {
|
||||||
|
return new JSONResponse(['message' => $gid . " deleted!"]);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function _download($url, $filename = null)
|
||||||
|
{
|
||||||
|
if (!$filename) {
|
||||||
|
$filename = Helper::getFileName($url);
|
||||||
|
}
|
||||||
|
$this->aria2->setFileName($filename);
|
||||||
|
|
||||||
|
$result = $this->aria2->download($url);
|
||||||
|
if (!$result) {
|
||||||
|
return ['error' => 'failed to download the file for some reason!'];
|
||||||
|
}
|
||||||
|
if (isset($result['error'])) {
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = [
|
||||||
|
'uid' => $this->uid,
|
||||||
|
'gid' => $result,
|
||||||
|
'type' => 1,
|
||||||
|
'filename' => $filename ?? 'unknown',
|
||||||
|
'timestamp' => time(),
|
||||||
|
'data' => serialize(['link' => $url]),
|
||||||
|
];
|
||||||
|
$this->dbconn->save($data);
|
||||||
|
$resp = ['gid' => $result, 'file' => $filename, 'result' => $result];
|
||||||
|
return $resp;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function installYTD()
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$filename = Helper::getFileName($yt->installUrl());
|
||||||
|
$yt->setDownloadDir($this->dataDir . "/bin");
|
||||||
|
$resp = $this->Save($yt->installUrl(), $filename);
|
||||||
|
return $resp;
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
return ['error' => $e->getMessage()];
|
||||||
|
}
|
||||||
|
|
||||||
|
return ['error' => $this->l10n->t("Youtube-dl NOT installed!")];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -4,6 +4,7 @@ namespace OCA\NCDownloader\Search;
|
|||||||
|
|
||||||
require __DIR__ . "/../../vendor/autoload.php";
|
require __DIR__ . "/../../vendor/autoload.php";
|
||||||
use OCA\NCDownloader\Search\Sites\TPB;
|
use OCA\NCDownloader\Search\Sites\TPB;
|
||||||
|
use OCA\NCDownloader\Tools\Helper;
|
||||||
use Symfony\Component\DomCrawler\Crawler;
|
use Symfony\Component\DomCrawler\Crawler;
|
||||||
use Symfony\Component\HttpClient\HttpClient;
|
use Symfony\Component\HttpClient\HttpClient;
|
||||||
|
|
||||||
|
|||||||
@@ -162,8 +162,11 @@ class Aria2
|
|||||||
{
|
{
|
||||||
$this->filterResponse = false;
|
$this->filterResponse = false;
|
||||||
$resp = $this->tellStopped($range);
|
$resp = $this->tellStopped($range);
|
||||||
|
if (!isset($resp['result'])) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
$result = $this->sortDownloadsResult($resp['result'], ['complete', 'removed']);
|
$result = $this->sortDownloadsResult($resp['result'], ['complete', 'removed']);
|
||||||
$this->filterResponse = true;;
|
$this->filterResponse = true;
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
public function getCounters()
|
public function getCounters()
|
||||||
@@ -268,6 +271,21 @@ class Aria2
|
|||||||
$this->start();
|
$this->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function download(String $url)
|
||||||
|
{
|
||||||
|
$resp = $this->addUri([$url]);
|
||||||
|
|
||||||
|
if (isset($resp['error'])) {
|
||||||
|
return $resp;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($resp['result']) && is_string($gid = $resp['result'])) {
|
||||||
|
return $gid;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
public function getDefaults()
|
public function getDefaults()
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ class DBConn
|
|||||||
//$this->conn = $this->connAdapter->getInner();
|
//$this->conn = $this->connAdapter->getInner();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function create($insert)
|
public function insert($insert)
|
||||||
{
|
{
|
||||||
$inserted = (bool) $this->conn->insertIfNotExist('*PREFIX*' . $this->table, $insert, [
|
$inserted = (bool) $this->conn->insertIfNotExist('*PREFIX*' . $this->table, $insert, [
|
||||||
'gid',
|
'gid',
|
||||||
@@ -46,6 +46,19 @@ class DBConn
|
|||||||
return $queryBuilder->fetchAll();
|
return $queryBuilder->fetchAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getYoutubeByUid($uid)
|
||||||
|
{
|
||||||
|
$queryBuilder = $this->queryBuilder
|
||||||
|
->select('*')
|
||||||
|
->from($this->table)
|
||||||
|
->where('uid = :uid')
|
||||||
|
->where('type = :type')
|
||||||
|
->setParameter('uid', $uid)
|
||||||
|
->setParameter('type', 2)
|
||||||
|
->execute();
|
||||||
|
return $queryBuilder->fetchAll();
|
||||||
|
}
|
||||||
|
|
||||||
public function getByGid($gid)
|
public function getByGid($gid)
|
||||||
{
|
{
|
||||||
$queryBuilder = $this->queryBuilder
|
$queryBuilder = $this->queryBuilder
|
||||||
@@ -57,9 +70,9 @@ class DBConn
|
|||||||
return $queryBuilder->fetch();
|
return $queryBuilder->fetch();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function save(array $keys, $values = array())
|
public function save(array $keys, $values = array(),$conditions = array())
|
||||||
{
|
{
|
||||||
return $this->conn->setValues($this->table, $keys, $values);
|
return $this->conn->setValues($this->table, $keys, $values,$conditions);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function deleteByGid($gid)
|
public function deleteByGid($gid)
|
||||||
@@ -74,7 +87,7 @@ class DBConn
|
|||||||
}
|
}
|
||||||
public function execute($sql, $values)
|
public function execute($sql, $values)
|
||||||
{
|
{
|
||||||
return $this->conn->executeStatement($sql, $values);
|
return $this->conn->executeUpdate($sql, $values);
|
||||||
|
|
||||||
// for some reason this doesn't work
|
// for some reason this doesn't work
|
||||||
$query = $this->queryBuilder;
|
$query = $this->queryBuilder;
|
||||||
|
|||||||
@@ -1,42 +0,0 @@
|
|||||||
<?php
|
|
||||||
namespace OCA\NCDownloader\Tools;
|
|
||||||
|
|
||||||
use OCA\NCDownloader\Tools\Helper;
|
|
||||||
use OCA\NCDownloader\Tools\Settings;
|
|
||||||
use OC\Files\Utils\Scanner;
|
|
||||||
use \OCP\EventDispatcher\IEventDispatcher;
|
|
||||||
|
|
||||||
class File
|
|
||||||
{
|
|
||||||
public static function syncFolder($dir = null)
|
|
||||||
{
|
|
||||||
$user = \OC::$server->getUserSession()->getUser()->getUID();
|
|
||||||
if (!isset($dir)) {
|
|
||||||
$settings = new Settings($user);
|
|
||||||
$downloadDir = $settings->get('ncd_downloader_dir') ?? "/Downloads";
|
|
||||||
$rootFolder = Helper::getUserFolder($user);
|
|
||||||
$path = $rootFolder . "/" . ltrim($downloadDir, '/\\');
|
|
||||||
} else {
|
|
||||||
$path = $dir;
|
|
||||||
}
|
|
||||||
|
|
||||||
$realDir =\OC::$server->getSystemConfig()->getValue('datadirectory') . "/" . $path;
|
|
||||||
if (!(Helper::folderUpdated($realDir))) {
|
|
||||||
return ['message' => "no change"];
|
|
||||||
}
|
|
||||||
$logger = \OC::$server->getLogger();
|
|
||||||
$scanner = new Scanner($user, \OC::$server->getDatabaseConnection(), \OC::$server->query(IEventDispatcher::class), $logger);
|
|
||||||
try {
|
|
||||||
$scanner->scan($path);
|
|
||||||
// Helper::debug($logger->getLogPath());
|
|
||||||
//$logger->warning($logger->getLogPath(),['app' =>'Ncdownloader']);
|
|
||||||
} catch (ForbiddenException $e) {
|
|
||||||
$logger->warning("Make sure you're running the scan command only as the user the web server runs as");
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
|
|
||||||
$logger->warning("Exception during scan: " . $e->getMessage() . $e->getTraceAsString());
|
|
||||||
}
|
|
||||||
return ['message' => "changed"];
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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, 'ERROR' => 2, 'COMPLETE' => 3];
|
public const STATUS = ['ACTIVE' => 1, 'PAUSED' => 2, 'COMPLETE' => 3, 'ERROR' => 4];
|
||||||
public static function isUrl($URL)
|
public static function isUrl($URL)
|
||||||
{
|
{
|
||||||
$URLPattern = '%^(?:(?:https?|ftp)://)(?:\S+(?::\S*)?@|\d{1,3}(?:\.\d{1,3}){3}|(?:(?:[a-z\d\x{00a1}-\x{ffff}'
|
$URLPattern = '%^(?:(?:https?|ftp)://)(?:\S+(?::\S*)?@|\d{1,3}(?:\.\d{1,3}){3}|(?:(?:[a-z\d\x{00a1}-\x{ffff}'
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
namespace OCA\NCDownloader\Tools;
|
namespace OCA\NCDownloader\Tools;
|
||||||
|
|
||||||
use OCA\NCDownloader\Tools\Helper;
|
use OCA\NCDownloader\Tools\Helper;
|
||||||
|
use OCA\NCDownloader\Tools\YoutubeHelper;
|
||||||
use Symfony\Component\Process\Exception\ProcessFailedException;
|
use Symfony\Component\Process\Exception\ProcessFailedException;
|
||||||
use Symfony\Component\Process\Process;
|
use Symfony\Component\Process\Process;
|
||||||
|
|
||||||
@@ -12,11 +13,22 @@ class Youtube
|
|||||||
private $audioFormat, $videoFormat = 'mp4';
|
private $audioFormat, $videoFormat = 'mp4';
|
||||||
private $options = [];
|
private $options = [];
|
||||||
private $downloadDir;
|
private $downloadDir;
|
||||||
|
private $timeout = 60 * 60 * 15;
|
||||||
|
private $outTpl = "/%(id)s-%(title)s.%(ext)s";
|
||||||
|
private $defaultDir = "/tmp/downloads";
|
||||||
|
|
||||||
public function __construct($config)
|
public function __construct($config)
|
||||||
{
|
{
|
||||||
$config += ['downloadDir' => '/tmp/downloads'];
|
$config += ['downloadDir' => '/tmp/downloads'];
|
||||||
$this->bin = Helper::findBinaryPath('youtube-dl');
|
$this->bin = Helper::findBinaryPath('youtube-dl');
|
||||||
|
$this->init();
|
||||||
$this->setDownloadDir($config['downloadDir']);
|
$this->setDownloadDir($config['downloadDir']);
|
||||||
|
$this->helper = YoutubeHelper::create();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function init()
|
||||||
|
{
|
||||||
|
$this->addOption("--no-mtime");
|
||||||
}
|
}
|
||||||
|
|
||||||
public function GetUrlOnly()
|
public function GetUrlOnly()
|
||||||
@@ -46,38 +58,80 @@ class Youtube
|
|||||||
array_unshift($this->options, $option);
|
array_unshift($this->options, $option);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function download($url)
|
public function downloadSync($url)
|
||||||
{
|
{
|
||||||
$this->downloadDir = $this->downloadDir ?? "/tmp/downloads";
|
$this->downloadDir = $this->downloadDir ?? $this->defaultDir;
|
||||||
$this->prependOption($this->downloadDir . "/%(id)s-%(title)s.%(ext)s");
|
$this->prependOption($this->downloadDir . $this->outTpl);
|
||||||
$this->prependOption("-o");
|
$this->prependOption("-o");
|
||||||
$this->setUrl($url);
|
$this->setUrl($url);
|
||||||
$this->prependOption($this->bin);
|
$this->prependOption($this->bin);
|
||||||
// $this->buildCMD();
|
// $this->buildCMD();
|
||||||
$process = new Process($this->options);
|
$process = new Process($this->options);
|
||||||
//the maximum time required to download the file
|
//the maximum time required to download the file
|
||||||
$process->setTimeout(60*60*15);
|
$process->setTimeout($this->timeout);
|
||||||
try {
|
try {
|
||||||
$process->mustRun();
|
$process->mustRun();
|
||||||
$output = $process->getOutput();
|
$output = $process->getOutput();
|
||||||
} catch (ProcessFailedException $exception) {
|
} catch (ProcessFailedException $exception) {
|
||||||
$output = $exception->getMessage();
|
$output = $exception->getMessage();
|
||||||
}
|
}
|
||||||
|
|
||||||
return $output;
|
return $output;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function download($url)
|
||||||
|
{
|
||||||
|
$this->downloadDir = $this->downloadDir ?? $this->defaultDir;
|
||||||
|
$this->prependOption($this->downloadDir . $this->outTpl);
|
||||||
|
$this->prependOption("-o");
|
||||||
|
$this->setUrl($url);
|
||||||
|
$this->prependOption($this->bin);
|
||||||
|
$process = new Process($this->options);
|
||||||
|
$process->setTimeout($this->timeout);
|
||||||
|
$process->run(function ($type, $buffer) use ($url) {
|
||||||
|
if (Process::ERR === $type) {
|
||||||
|
$this->onError($buffer);
|
||||||
|
} else {
|
||||||
|
$this->onOutput($buffer, $url);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if ($process->isSuccessful()) {
|
||||||
|
$this->helper->updateStatus(Helper::STATUS['COMPLETE']);
|
||||||
|
return ['message' => $this->helper->file ?? $process->getErrorOutput()];
|
||||||
|
}
|
||||||
|
return $process->getErrorOutput();
|
||||||
|
|
||||||
|
}
|
||||||
|
public function getFilePath($output)
|
||||||
|
{
|
||||||
|
$rules = '#\[download\]\s+Destination:\s+(?<filename>.*\.(?<ext>(mp4|mp3|aac)))$#i';
|
||||||
|
|
||||||
|
preg_match($rules, $output, $matches);
|
||||||
|
|
||||||
|
return $matches['filename'] ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function onError($buffer)
|
||||||
|
{
|
||||||
|
$this->helper->log($buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function onOutput($buffer, $url)
|
||||||
|
{
|
||||||
|
$this->helper->run($buffer, $url);
|
||||||
|
}
|
||||||
public function getDownloadUrl($url)
|
public function getDownloadUrl($url)
|
||||||
{
|
{
|
||||||
$this->setUrl($url);
|
$this->setUrl($url);
|
||||||
$this->GetUrlOnly();
|
$this->GetUrlOnly();
|
||||||
//$process = new Process($this->options);
|
|
||||||
$this->buildCMD();
|
$this->buildCMD();
|
||||||
exec($this->cmd, $output, $returnCode);
|
exec($this->cmd, $output, $returnCode);
|
||||||
if (count($output) === 1) {
|
if (count($output) === 1) {
|
||||||
return ['url' => reset($output)];
|
return ['url' => reset($output)];
|
||||||
}
|
}
|
||||||
list($url, $filename) = $output;
|
list($url, $filename) = $output;
|
||||||
return ['url' => $url, 'filename' => Helper::cleanString($filename)];
|
$filename = Helper::cleanString($filename);
|
||||||
|
return ['url' => $url, 'filename' => Helper::clipFilename($filename)];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setUrl($url)
|
public function setUrl($url)
|
||||||
|
|||||||
92
lib/Tools/YoutubeHelper.php
Normal file
92
lib/Tools/YoutubeHelper.php
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
<?php
|
||||||
|
namespace OCA\NCDownloader\Tools;
|
||||||
|
|
||||||
|
use OCA\NCDownloader\Tools\DBConn;
|
||||||
|
use OCA\NCDownloader\Tools\Helper;
|
||||||
|
|
||||||
|
class YoutubeHelper
|
||||||
|
{
|
||||||
|
public const PROGRESS_PATTERN = '#\[download\]\s+' .
|
||||||
|
'(?<percentage>\d+(?:\.\d+)?%)' . //progress
|
||||||
|
'\s+of\s+[~]?' .
|
||||||
|
'(?<size>\d+(?:\.\d+)?(?:K|M|G)iB)' . //file size
|
||||||
|
'(?:\s+at\s+' .
|
||||||
|
'(?<speed>(\d+(?:\.\d+)?(?:K|M|G)iB/s)|Unknown speed))' . //speed
|
||||||
|
'(?:\s+ETA\s+(?<eta>([\d:]{2,8}|Unknown ETA)))?' . //estimated download time
|
||||||
|
'(\s+in\s+(?<totalTime>[\d:]{2,8}))?#i';
|
||||||
|
public $file = null;
|
||||||
|
public $filesize = null;
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->dbconn = new DBConn();
|
||||||
|
$this->tablename = $this->dbconn->queryBuilder->getTableName("ncdownloader_info");
|
||||||
|
$this->user = \OC::$server->getUserSession()->getUser()->getUID();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function create()
|
||||||
|
{
|
||||||
|
return new static();
|
||||||
|
}
|
||||||
|
public function getFilePath($output)
|
||||||
|
{
|
||||||
|
$rules = '#\[download\]\s+Destination:\s+(?<filename>.*\.(?<ext>(mp4|mp3|aac)))$#i';
|
||||||
|
|
||||||
|
preg_match($rules, $output, $matches);
|
||||||
|
|
||||||
|
return $matches['filename'] ?? null;
|
||||||
|
}
|
||||||
|
public function log($message)
|
||||||
|
{
|
||||||
|
Helper::debug($message);
|
||||||
|
}
|
||||||
|
public function updateStatus($status = null)
|
||||||
|
{
|
||||||
|
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]);
|
||||||
|
}
|
||||||
|
public function run($buffer, $url)
|
||||||
|
{
|
||||||
|
$this->gid = Helper::generateGID($url);
|
||||||
|
$file = $this->getFilePath($buffer);
|
||||||
|
if ($file) {
|
||||||
|
$data = [
|
||||||
|
'uid' => $this->user,
|
||||||
|
'gid' => $this->gid,
|
||||||
|
'type' => Helper::DOWNLOADTYPE['YOUTUBE-DL'],
|
||||||
|
'filename' => basename($file),
|
||||||
|
'status' => Helper::STATUS['ACTIVE'],
|
||||||
|
'timestamp' => time(),
|
||||||
|
'data' => serialize(['link' => $url]),
|
||||||
|
];
|
||||||
|
//save the filename as this runs only once
|
||||||
|
$this->file = $file;
|
||||||
|
$this->dbconn->insert($data);
|
||||||
|
//$this->dbconn->save($data,[],['gid' => $this->gid]);
|
||||||
|
}
|
||||||
|
if (preg_match_all(self::PROGRESS_PATTERN, $buffer, $matches, PREG_SET_ORDER) !== false) {
|
||||||
|
if (count($matches) > 0) {
|
||||||
|
$match = reset($matches);
|
||||||
|
|
||||||
|
//save the filesize
|
||||||
|
if (!isset($this->filesize) && isset($match['size'])) {
|
||||||
|
$this->filesize = $match['size'];
|
||||||
|
}
|
||||||
|
$size = $match['size'];
|
||||||
|
$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]);
|
||||||
|
/* $data = [
|
||||||
|
'filesize' => $size,
|
||||||
|
'speed' => $speed,
|
||||||
|
'progress' => $percentage,
|
||||||
|
'gid' => $this->gid,
|
||||||
|
];
|
||||||
|
$this->dbconn->save([], $data, ['gid' => $this->gid]);*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
93
lib/Tools/folderScan.php
Normal file
93
lib/Tools/folderScan.php
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
<?php
|
||||||
|
namespace OCA\NCDownloader\Tools;
|
||||||
|
|
||||||
|
use OCA\NCDownloader\Tools\Helper;
|
||||||
|
use OCA\NCDownloader\Tools\Settings;
|
||||||
|
use OC\Files\Utils\Scanner;
|
||||||
|
use \OCP\EventDispatcher\IEventDispatcher;
|
||||||
|
|
||||||
|
class folderScan
|
||||||
|
{
|
||||||
|
private $user;
|
||||||
|
private $path;
|
||||||
|
public function __construct($path = null, $user = null)
|
||||||
|
{
|
||||||
|
$this->user = $user ?? \OC::$server->getUserSession()->getUser()->getUID();
|
||||||
|
$this->path = $path ?? $this->getDefaultPath();
|
||||||
|
$this->realDir = \OC::$server->getSystemConfig()->getValue('datadirectory') . "/" . $this->path;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDefaultPath()
|
||||||
|
{
|
||||||
|
$settings = new Settings($this->user);
|
||||||
|
$rootFolder = Helper::getUserFolder($this->user);
|
||||||
|
$downloadDir = $settings->get('ncd_downloader_dir') ?? "/Downloads";
|
||||||
|
return $rootFolder . "/" . ltrim($downloadDir, '/\\');
|
||||||
|
}
|
||||||
|
public static function create($path = null, $user = null)
|
||||||
|
{
|
||||||
|
return new static($path, $user);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setUser($user)
|
||||||
|
{
|
||||||
|
$this->user = $user;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
public function setPath($path)
|
||||||
|
{
|
||||||
|
$this->path = $path;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function update()
|
||||||
|
{
|
||||||
|
if (!(self::folderUpdated($this->realDir))) {
|
||||||
|
return ['message' => "no change"];
|
||||||
|
}
|
||||||
|
$this->scan();
|
||||||
|
return ['message' => "changed"];
|
||||||
|
}
|
||||||
|
//force update
|
||||||
|
public function scan()
|
||||||
|
{
|
||||||
|
$this->logger = \OC::$server->getLogger();
|
||||||
|
$this->scanner = new Scanner($this->user, \OC::$server->getDatabaseConnection(), \OC::$server->query(IEventDispatcher::class), $this->logger);
|
||||||
|
try {
|
||||||
|
$this->scanner->scan($this->path);
|
||||||
|
return ['status' => 'OK', 'path' => $this->path];
|
||||||
|
} catch (ForbiddenException $e) {
|
||||||
|
$this->logger->warning("Make sure you're running the scan command only as the user the web server runs as");
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
|
||||||
|
$this->logger->warning("Exception during scan: " . $e->getMessage() . $e->getTraceAsString());
|
||||||
|
}
|
||||||
|
return ['status' => $e->getMessage(), 'path' => $this->path];
|
||||||
|
|
||||||
|
}
|
||||||
|
public static function folderUpdated($dir)
|
||||||
|
{
|
||||||
|
if (!file_exists($dir)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$checkFile = $dir . "/.lastmodified";
|
||||||
|
if (!file_exists($checkFile)) {
|
||||||
|
$time = \filemtime($dir);
|
||||||
|
file_put_contents($checkFile, $time);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$lastModified = (int) file_get_contents($checkFile);
|
||||||
|
$time = \filemtime($dir);
|
||||||
|
if ($time > $lastModified) {
|
||||||
|
file_put_contents($checkFile, $time);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//update only folder is modified
|
||||||
|
public static function sync($path = null, $user = null)
|
||||||
|
{
|
||||||
|
return self::create($path, $user)->update();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -25,7 +25,10 @@ const buttonHandler = (event, type) => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (data.hasOwnProperty('result')) {
|
if (data.hasOwnProperty('result')) {
|
||||||
helper.message("Success for " + data['result']);
|
helper.message("Success " + data['result']);
|
||||||
|
}
|
||||||
|
if (data.hasOwnProperty('message')) {
|
||||||
|
helper.message(data.message);
|
||||||
}
|
}
|
||||||
if (row && removeRow)
|
if (row && removeRow)
|
||||||
row.remove();
|
row.remove();
|
||||||
|
|||||||
@@ -47,10 +47,10 @@ const helper = {
|
|||||||
|
|
||||||
return magnetURI.test(url.trim());
|
return magnetURI.test(url.trim());
|
||||||
},
|
},
|
||||||
message: function (message) {
|
message: function (message,duration = 5000) {
|
||||||
Toastify({
|
Toastify({
|
||||||
text: message,
|
text: message,
|
||||||
duration: 3000,
|
duration:duration,
|
||||||
newWindow: true,
|
newWindow: true,
|
||||||
close: true,
|
close: true,
|
||||||
gravity: "top", // `top` or `bottom`
|
gravity: "top", // `top` or `bottom`
|
||||||
|
|||||||
@@ -20,46 +20,49 @@ const createInputBox = (event, type) => {
|
|||||||
let height = $(window).scrollTop();
|
let height = $(window).scrollTop();
|
||||||
if (height > 50)
|
if (height > 50)
|
||||||
$("html, body").animate({ scrollTop: 0 }, "fast");
|
$("html, body").animate({ scrollTop: 0 }, "fast");
|
||||||
let name;
|
let name, path;
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case "ytdl":
|
case "ytdl":
|
||||||
name = t("ncdownloader", 'YTDL Download');
|
name = t("ncdownloader", 'YTDL Download');
|
||||||
|
path = basePath + "/youtube/new";
|
||||||
break;
|
break;
|
||||||
case "search":
|
case "search":
|
||||||
name = t("ncdownloader", 'Search');
|
name = t("ncdownloader", 'Search');
|
||||||
|
path = basePath + "/search";
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
name = t("ncdownloader", 'New Download');
|
name = t("ncdownloader", 'New Download');
|
||||||
|
path = basePath + "/new";
|
||||||
}
|
}
|
||||||
let container;
|
let container;
|
||||||
if (type === 'search') {
|
if (type === 'search') {
|
||||||
container = inputBox.getInstance(name, type).addSpinner().create();
|
container = inputBox.getInstance(name, type, path).create().addSpinner();
|
||||||
//container.appendChild(inputBox.createLoading());
|
//container.appendChild(inputBox.createLoading());
|
||||||
} else {
|
} else {
|
||||||
container = inputBox.getInstance(name, type).create();
|
container = inputBox.getInstance(name, type, path).create().getContainer();
|
||||||
}
|
}
|
||||||
$("#ncdownloader-form-wrapper").append(container);
|
$("#ncdownloader-form-wrapper").append(container);
|
||||||
}
|
}
|
||||||
|
|
||||||
const toggleButton = element => {
|
const toggleSpinner = element => {
|
||||||
if (!element.previousSibling) {
|
let spinner = element.previousSibling || element.nextSibling
|
||||||
|
|
||||||
|
if (!spinner) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (element.style.display === 'none') {
|
if (element.style.display === 'none') {
|
||||||
element.style.display = 'block'
|
element.style.display = 'block'
|
||||||
element.previousSibling.style.display = 'none';
|
spinner.style.display = 'none';
|
||||||
} else {
|
} else {
|
||||||
element.style.display = 'none'
|
element.style.display = 'none'
|
||||||
element.previousSibling.style.display = 'block';
|
spinner.style.display = 'block';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const inputHandler = (event) => {
|
const inputHandler = (event) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
let element = event.target;
|
let element = event.target;
|
||||||
// element.textContent = '';
|
toggleSpinner(element);
|
||||||
//$(element).append(inputBox.createLoading());
|
|
||||||
toggleButton(element);
|
|
||||||
let inputData = helper.getData('form-input-wrapper');
|
let inputData = helper.getData('form-input-wrapper');
|
||||||
let inputValue = inputData.form_input_text;
|
let inputValue = inputData.form_input_text;
|
||||||
if (inputData.type !== 'search' && !helper.isURL(inputValue) && !helper.isMagnetURI(inputValue)) {
|
if (inputData.type !== 'search' && !helper.isURL(inputValue) && !helper.isMagnetURI(inputValue)) {
|
||||||
@@ -67,10 +70,10 @@ const inputHandler = (event) => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (inputData.type === 'ytdl') {
|
if (inputData.type === 'ytdl') {
|
||||||
helper.message(t("ncdownloader", "YTDL Download initiated"));
|
helper.message(t("ncdownloader", "Please check your download folder for progress"), 5000);
|
||||||
}
|
}
|
||||||
if (inputData.type === 'search') {
|
if (inputData.type === 'search') {
|
||||||
//there is a scheduled 60s-interval update running in the background, this is to prevent it from running when searching
|
//a scheduled 60s-interval update is running in the background, this is to prevent it from interfering when searching
|
||||||
helper.enabledPolling = 0;
|
helper.enabledPolling = 0;
|
||||||
nctable.getInstance().loading();
|
nctable.getInstance().loading();
|
||||||
}
|
}
|
||||||
@@ -79,7 +82,7 @@ const inputHandler = (event) => {
|
|||||||
if (data !== null && data.hasOwnProperty("file")) {
|
if (data !== null && data.hasOwnProperty("file")) {
|
||||||
helper.message(t("ncdownloader", "Downloading" + " " + data.file));
|
helper.message(t("ncdownloader", "Downloading" + " " + data.file));
|
||||||
}
|
}
|
||||||
toggleButton(element);
|
toggleSpinner(element);
|
||||||
if (data && data.title) {
|
if (data && data.title) {
|
||||||
const tableInst = nctable.getInstance(data.title, data.row);
|
const tableInst = nctable.getInstance(data.title, data.row);
|
||||||
tableInst.actionLink = false;
|
tableInst.actionLink = false;
|
||||||
|
|||||||
@@ -3,23 +3,35 @@ import helper from './helper'
|
|||||||
|
|
||||||
|
|
||||||
class inputBox {
|
class inputBox {
|
||||||
constructor(name, id) {
|
path;
|
||||||
|
constructor(name, id, path = null) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.container = this._createForm();
|
this.id = id;
|
||||||
this.textInput = this._createTextInput(id);
|
this.path = path;
|
||||||
this.controlsContainer = this._createControlsContainer();
|
|
||||||
}
|
}
|
||||||
static getInstance(name, id) {
|
static getInstance(name, id, path = null) {
|
||||||
return new inputBox(name, id);
|
return new inputBox(name, id, path);
|
||||||
}
|
}
|
||||||
create() {
|
create() {
|
||||||
|
this.container = this._createForm();
|
||||||
|
this.textInput = this._createTextInput(this.id);
|
||||||
|
this.controlsContainer = this._createControlsContainer();
|
||||||
this.container.appendChild(this.textInput);
|
this.container.appendChild(this.textInput);
|
||||||
this.controlsContainer.appendChild(this._createControls());
|
this.controlsContainer.appendChild(this._createControls());
|
||||||
this.container.appendChild(this.controlsContainer);
|
this.container.appendChild(this.controlsContainer);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
getContainer() {
|
||||||
return this.container;
|
return this.container;
|
||||||
}
|
}
|
||||||
|
setPath(path) {
|
||||||
|
this.path = path;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
_createControlsContainer() {
|
_createControlsContainer() {
|
||||||
let div = document.createElement("div");
|
let div = document.createElement("div");
|
||||||
|
|
||||||
div.classList.add("controls-container");
|
div.classList.add("controls-container");
|
||||||
return div;
|
return div;
|
||||||
}
|
}
|
||||||
@@ -36,6 +48,9 @@ class inputBox {
|
|||||||
textInput.setAttribute('id', "form_input_text");
|
textInput.setAttribute('id', "form_input_text");
|
||||||
textInput.setAttribute('data-type', id);
|
textInput.setAttribute('data-type', id);
|
||||||
textInput.setAttribute('value', '');
|
textInput.setAttribute('value', '');
|
||||||
|
if (this.path) {
|
||||||
|
textInput.setAttribute('data-path', this.path);
|
||||||
|
}
|
||||||
textInput.classList.add('form-input-text');
|
textInput.classList.add('form-input-text');
|
||||||
return textInput;
|
return textInput;
|
||||||
}
|
}
|
||||||
@@ -55,7 +70,7 @@ class inputBox {
|
|||||||
let element = doc.querySelector(".bs-spinner");
|
let element = doc.querySelector(".bs-spinner");
|
||||||
element.style.display = 'none';
|
element.style.display = 'none';
|
||||||
this.controlsContainer.appendChild(element);
|
this.controlsContainer.appendChild(element);
|
||||||
return this;
|
return this.container;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -89,6 +89,9 @@ class ncTable {
|
|||||||
let container = document.createElement("div");
|
let container = document.createElement("div");
|
||||||
container.classList.add("button-container");
|
container.classList.add("button-container");
|
||||||
element[key].forEach(value => {
|
element[key].forEach(value => {
|
||||||
|
if (!value.name) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
container.appendChild(this.createActionButton(value.name, value.path));
|
container.appendChild(this.createActionButton(value.name, value.path));
|
||||||
})
|
})
|
||||||
rowItem.appendChild(container);
|
rowItem.appendChild(container);
|
||||||
|
|||||||
@@ -6,9 +6,12 @@ const tableContainer = ".table";
|
|||||||
export default {
|
export default {
|
||||||
run: function () {
|
run: function () {
|
||||||
|
|
||||||
const eventHandler = (event, type) => {
|
const clickHandler = (event, type) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
const path = basePath + type;
|
let path = basePath + type;
|
||||||
|
if (type === "youtube-dl") {
|
||||||
|
path = "/apps/ncdownloader/youtube/get";
|
||||||
|
}
|
||||||
let name = type + "-downloads";
|
let name = type + "-downloads";
|
||||||
//avoid repeated click
|
//avoid repeated click
|
||||||
if ($(tableContainer).attr("type") === name && helper.enabledPolling) {
|
if ($(tableContainer).attr("type") === name && helper.enabledPolling) {
|
||||||
@@ -18,19 +21,28 @@ export default {
|
|||||||
$(tableContainer).removeClass().addClass("table " + name);
|
$(tableContainer).removeClass().addClass("table " + name);
|
||||||
$(tableContainer).attr("type", name);
|
$(tableContainer).attr("type", name);
|
||||||
let delay = 15000;
|
let delay = 15000;
|
||||||
if (name === "active-downloads") {
|
if (['active', 'youtube-dl'].includes(type)) {
|
||||||
delay = 1500;
|
delay = 1500;
|
||||||
}
|
}
|
||||||
helper.loop(helper.refresh, delay, ...[path])
|
helper.loop(helper.refresh, delay, ...[path])
|
||||||
};
|
};
|
||||||
$(".waiting-downloads").on("click", event => eventHandler(event, 'waiting'));
|
$(".waiting-downloads").on("click", event => clickHandler(event, 'waiting'));
|
||||||
$(".complete-downloads").on("click", event => eventHandler(event, 'complete'));
|
$(".complete-downloads").on("click", event => clickHandler(event, 'complete'));
|
||||||
$(".active-downloads").on("click", event => eventHandler(event, 'active'));
|
$(".active-downloads").on("click", event => clickHandler(event, 'active'));
|
||||||
$(".fail-downloads").on("click", event => eventHandler(event, 'fail'));
|
$(".fail-downloads").on("click", event => clickHandler(event, 'fail'));
|
||||||
|
$(".youtube-dl-downloads").on("click", event => clickHandler(event, 'youtube-dl'));
|
||||||
|
|
||||||
|
$("#ncdownloader-table-wrapper").on("click", ".download-file-folder", function (event) {
|
||||||
|
event.stopPropagation();
|
||||||
|
const path = "/apps/ncdownloader/update";
|
||||||
|
let url = helper.generateUrl(path);
|
||||||
|
Http.getInstance(url).setMethod('GET').send();
|
||||||
|
});
|
||||||
|
|
||||||
helper.refresh(basePath + "waiting")
|
helper.refresh(basePath + "waiting")
|
||||||
helper.refresh(basePath + "complete")
|
helper.refresh(basePath + "complete")
|
||||||
helper.refresh(basePath + "fail")
|
helper.refresh(basePath + "fail")
|
||||||
|
helper.refresh("/apps/ncdownloader/youtube/get")
|
||||||
|
|
||||||
helper.loop(helper.refresh, 1000, basePath + "active");
|
helper.loop(helper.refresh, 1000, basePath + "active");
|
||||||
|
|
||||||
|
|||||||
@@ -91,5 +91,18 @@ $aria2_installed = $_['aria2_installed'];
|
|||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
|
<li class="youtube-dl-downloads">
|
||||||
|
<div class="app-navigation-entry-bullet"></div>
|
||||||
|
<a href="/apps/ncdownloader/youtube/get">
|
||||||
|
<?php print($l->t('Youtube-dl Downloads'));?>
|
||||||
|
</a>
|
||||||
|
<div class="app-navigation-entry-utils">
|
||||||
|
<ul>
|
||||||
|
<li class="app-navigation-entry-utils-counter" id="youtube-dl-downloads-counter">
|
||||||
|
<div class="number">0</div>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
@@ -3,7 +3,10 @@ script("ncdownloader", 'appSettings');
|
|||||||
?>
|
?>
|
||||||
<div class="ncdownloader-admin-settings">
|
<div class="ncdownloader-admin-settings">
|
||||||
<form id="ncdownloader" class="section">
|
<form id="ncdownloader" class="section">
|
||||||
<h2><?php print($l->t('NCDownloader Admin Settings'));?></h2>
|
<h2>ncDownloader admin Settings</h2>
|
||||||
|
<div>
|
||||||
|
<span id="ncdownloader-message"></span>
|
||||||
|
</div>
|
||||||
<div id="ncd_rpctoken_settings" path="<?php print $path;?>">
|
<div id="ncd_rpctoken_settings" path="<?php print $path;?>">
|
||||||
<label for="ncd_rpctoken">
|
<label for="ncd_rpctoken">
|
||||||
<?php print($l->t('Aria2 RPC Token'));?>
|
<?php print($l->t('Aria2 RPC Token'));?>
|
||||||
|
|||||||
Reference in New Issue
Block a user