diff --git a/appinfo/application.php b/appinfo/application.php
index 219d641..a6142c6 100644
--- a/appinfo/application.php
+++ b/appinfo/application.php
@@ -4,6 +4,7 @@ namespace OCA\NCDownloader\AppInfo;
use OCA\NCDownloader\Controller\Aria2Controller;
use OCA\NCDownloader\Controller\MainController;
+use OCA\NCDownloader\Controller\YoutubeController;
use OCA\NCDownloader\Tools\Aria2;
use OCA\NCDownloader\Tools\Helper;
use OCA\NCDownloader\Tools\Settings;
@@ -60,6 +61,16 @@ class Application extends App
$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()
diff --git a/appinfo/routes.php b/appinfo/routes.php
index e2d0819..af218f1 100644
--- a/appinfo/routes.php
+++ b/appinfo/routes.php
@@ -1,28 +1,23 @@
OCA\NCDownloader\Controller\Aria2Controller->index()
- *
- * The controller class has to be registered in the application.php file since
- * it's instantiated in there
- */
+
return [
'routes' => [
- ['name' => 'Main#Index', 'url' => '/', 'verb' => 'GET'],
- ['name' => 'main#newDownload', 'url' => '/new', 'verb' => 'POST'],
- ['name' => 'Aria2#Action', 'url' => '/aria2/{path}', 'verb' => 'POST'],
- ['name' => 'Aria2#getStatus', 'url' => '/status/{path}', 'verb' => 'POST'],
- ['name' => 'Aria2#Update', 'url' => '/update', 'verb' => 'GET'],
- //['name' => 'main#checkStatus', 'url' => '/checkstatus', 'verb' => 'POST'],
- // AdminSettings
- ['name' => 'Settings#Admin', 'url' => '/admin/save', 'verb' => 'POST'],
- // PersonalSettings
- ['name' => 'Settings#Personal', 'url' => '/personal/save', 'verb' => 'POST'],
- ['name' => 'Settings#aria2Get', 'url' => '/personal/aria2/get', 'verb' => 'POST'],
- ['name' => 'Settings#aria2Save', 'url' => '/personal/aria2/save', 'verb' => 'POST'],
- ['name' => 'Settings#aria2Delete', 'url' => '/personal/aria2/delete', 'verb' => 'POST'],
+ ['name' => 'Main#Index', 'url' => '/', 'verb' => 'GET'],
+ ['name' => 'main#Download', 'url' => '/new', 'verb' => 'POST'],
+ ['name' => 'Aria2#Action', 'url' => '/aria2/{path}', 'verb' => 'POST'],
+ ['name' => 'Aria2#getStatus', 'url' => '/status/{path}', 'verb' => 'POST'],
+ ['name' => 'Aria2#Update', 'url' => '/update', 'verb' => 'GET'],
+ ['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
+ ['name' => 'Settings#Admin', 'url' => '/admin/save', 'verb' => 'POST'],
+ // PersonalSettings
+ ['name' => 'Settings#Personal', 'url' => '/personal/save', 'verb' => 'POST'],
+ ['name' => 'Settings#aria2Get', 'url' => '/personal/aria2/get', 'verb' => 'POST'],
+ ['name' => 'Settings#aria2Save', 'url' => '/personal/aria2/save', 'verb' => 'POST'],
+ ['name' => 'Settings#aria2Delete', 'url' => '/personal/aria2/delete', 'verb' => 'POST'],
- ]
+ ],
];
-
diff --git a/lib/Command/Aria2Command.php b/lib/Command/Aria2Command.php
index bcb14b9..3234a5c 100644
--- a/lib/Command/Aria2Command.php
+++ b/lib/Command/Aria2Command.php
@@ -3,9 +3,8 @@
namespace OCA\NCDownloader\Command;
use OCA\NCDownloader\Tools\Aria2;
+use OCA\NCDownloader\Tools\Youtube;
use OCA\NCDownloader\Tools\DBConn;
-use OCA\NCDownloader\Tools\File;
-use OCA\NCDownloader\Tools\Helper;
use OC\Core\Command\Base;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
@@ -22,8 +21,7 @@ class Aria2Command extends base
}
protected function configure()
{
- $this
- ->setName('aria2')
+ $this->setName('aria2')
->setDescription('Aria2 hooks')
->addArgument(
'action',
@@ -38,7 +36,7 @@ class Aria2Command extends base
'path',
'p',
InputOption::VALUE_OPTIONAL,
- 'Downloaded file path',
+ 'Downloaded file path'
)->addOption(
'number',
'N',
@@ -64,7 +62,7 @@ class Aria2Command extends base
if ($parent_gid) {
$tablename = $this->conn->queryBuilder->getTableName("ncdownloader_info");
$sql = sprintf("UPDATE %s set followedby = ? WHERE gid = ?", $tablename);
- // $data = serialize(['followedby' => "82140bd962946ae0"]);
+ // $data = serialize(['followedby' => "82140bd962946ae0"]);
$this->conn->execute($sql, [$gid, $parent_gid]);
}
@@ -73,4 +71,5 @@ class Aria2Command extends base
$output->writeln(print_r($result, true));
return 0;
}
+
}
diff --git a/lib/Controller/Aria2Controller.php b/lib/Controller/Aria2Controller.php
index 6c2a556..471f633 100644
--- a/lib/Controller/Aria2Controller.php
+++ b/lib/Controller/Aria2Controller.php
@@ -3,7 +3,7 @@ namespace OCA\NCDownloader\Controller;
use OCA\NCDownloader\Tools\Aria2;
use OCA\NCDownloader\Tools\DBConn;
-use OCA\NCDownloader\Tools\File;
+use OCA\NCDownloader\Tools\folderScan;
use OCA\NCDownloader\Tools\Helper;
use OCA\NCDownloader\Tools\Settings;
use OCP\AppFramework\Controller;
@@ -16,11 +16,10 @@ use \OC\Files\Filesystem;
class Aria2Controller extends Controller
{
- private $userId;
+ private $uid;
private $settings = null;
//@config OC\AppConfig
private $config;
- private $aria2Opts;
private $l10n;
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)
{
$path = strtolower(trim($path));
+ $resp = [];
if (!in_array($path, ['start', 'check']) && !($gid = $this->request->getParam('gid'))) {
return new JSONResponse(['error' => "no gid value is received!"]);
@@ -55,22 +55,43 @@ class Aria2Controller extends Controller
$resp = $this->Start();
break;
case "pause":
- $resp = $this->aria2->pause($gid);
+ $resp = $this->doAction('pause', $gid);
break;
case "remove":
- $resp = $this->aria2->remove($gid);
+ $resp = $this->doAction('remove', $gid);
break;
case "unpause":
- $resp = $this->aria2->unpause($gid);
+ $resp = $this->doAction('unpause', $gid);
break;
case "get":
- $resp = $this->aria2->tellStatus($gid);
+ $resp = $this->doAction('tellStatus', $gid);
break;
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);
}
+
+ 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()
{
if ($this->aria2->isRunning()) {
@@ -82,8 +103,8 @@ class Aria2Controller extends Controller
}
public function Update()
{
- $resp = File::syncFolder();
- //return new JSONResponse($resp);
+ $resp = folderScan::create()->scan();
+ return new JSONResponse($resp);
}
private function createActionItem($name, $path)
@@ -97,7 +118,7 @@ class Aria2Controller extends Controller
{
//$path = $this->request->getRequestUri();
$counter = $this->aria2->getCounters();
- $this->Update();
+ folderScan::sync();
switch (strtolower($path)) {
case "active":
$resp = $this->aria2->tellActive();
@@ -179,11 +200,12 @@ class Aria2Controller extends Controller
$value['progress'] = array(sprintf("%s(%.2f%%)", $completed, $percentage), $extraInfo);
$timestamp = $timestamp ?? 0;
//$prefix = $value['files'][0]['path'];
- $filename = sprintf('%s', $folderLink, $filename);
- $fileInfo = sprintf("%s | %s", $total, date("Y-m-d H:i:s", $timestamp));
-
$tmp = [];
$actions = [];
+ $filename = sprintf('%s', $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") {
$actions[] = $this->createActionItem('purge', 'purge');
} else {
@@ -192,7 +214,6 @@ class Aria2Controller extends Controller
if ($this->aria2->methodName === "tellWaiting") {
$actions[] = $this->createActionItem('unpause', 'unpause');
}
- $tmp['filename'] = array($filename, $fileInfo);
if ($this->aria2->methodName === "tellActive") {
$speed = [Helper::formatBytes($value['downloadSpeed']), $left . " left"];
$tmp['speed'] = $speed;
diff --git a/lib/Controller/MainController.php b/lib/Controller/MainController.php
index e86a275..b901e30 100644
--- a/lib/Controller/MainController.php
+++ b/lib/Controller/MainController.php
@@ -2,10 +2,8 @@
namespace OCA\NCDownloader\Controller;
-use OCA\NCDownloader\Search\torrentSearch;
use OCA\NCDownloader\Tools\Aria2;
use OCA\NCDownloader\Tools\DBConn;
-use OCA\NCDownloader\Tools\File;
use OCA\NCDownloader\Tools\Helper;
use OCA\NCDownloader\Tools\Youtube;
use OCP\AppFramework\Controller;
@@ -40,8 +38,8 @@ class MainController extends Controller
$this->aria2->init();
$this->youtube = $youtube;
$this->dbconn = new DBConn();
+ $this->tablename = $this->dbconn->queryBuilder->getTableName("ncdownloader_info");
}
-
/**
* @NoAdminRequired
* @NoCSRFRequired
@@ -69,62 +67,39 @@ class MainController extends Controller
return $response;
}
- public function newDownload()
+ public function Download()
{
- $params = array();
- $inputValue = trim($this->request->getParam('form_input_text'));
- $type = trim($this->request->getParam('type'));
- 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);
- }
-
- $filename = Helper::getFileName($inputValue);
- $resp = $this->Save($inputValue, $filename);
+ $url = trim($this->request->getParam('form_input_text'));
+ //$type = trim($this->request->getParam('type'));
+ $resp = $this->_download($url);
return new JSONResponse($resp);
}
- private function Save($url, $filename = null)
+ private function _download($url)
{
- if (isset($filename)) {
+ $filename = Helper::getFileName($url);
+ if ($filename) {
$this->aria2->setFileName($filename);
}
- //$this->aria2->setDownloadDir("/tmp/downloads");
- $result = $this->aria2->addUri([$url]);
- $gid = $result['result'];
- if (!is_string($gid)) {
- return ['error' => 'Failed to add download task! ' . $result['error']];
- } else {
- $data = [
- 'uid' => $this->uid,
- 'gid' => $gid,
- 'type' => 1,
- 'filename' => $filename ?? 'unknown',
- 'timestamp' => time(),
- 'data' => serialize(['link' => $url]),
- ];
- $this->dbconn->save($data);
+ $result = $this->aria2->download($url);
+ if (!$result) {
+ return ['error' => 'failed to download the file for some reason!'];
}
- return ['gid' => $gid, 'file' => $filename, 'result' => $gid];
+ if (isset($result['error'])) {
+ return $result;
+ }
+
+ $data = [
+ 'uid' => $this->uid,
+ 'gid' => $result,
+ 'type' => Helper::DOWNLOADTYPE['ARIA2'],
+ 'filename' => $filename ?? 'unknown',
+ 'timestamp' => time(),
+ 'data' => serialize(['link' => $url]),
+ ];
+ $this->dbconn->save($data);
+ $resp = ['gid' => $result, 'file' => $filename, 'result' => $result];
+ return $resp;
}
+
}
diff --git a/lib/Controller/SearchController.php b/lib/Controller/SearchController.php
new file mode 100644
index 0000000..98151ce
--- /dev/null
+++ b/lib/Controller/SearchController.php
@@ -0,0 +1,33 @@
+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);
+ }
+
+}
diff --git a/lib/Controller/YoutubeController.php b/lib/Controller/YoutubeController.php
new file mode 100644
index 0000000..2d74b95
--- /dev/null
+++ b/lib/Controller/YoutubeController.php
@@ -0,0 +1,152 @@
+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('%s', $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!")];
+ }
+
+}
diff --git a/lib/Search/torrentSearch.php b/lib/Search/torrentSearch.php
index c5cad74..9288023 100644
--- a/lib/Search/torrentSearch.php
+++ b/lib/Search/torrentSearch.php
@@ -4,6 +4,7 @@ namespace OCA\NCDownloader\Search;
require __DIR__ . "/../../vendor/autoload.php";
use OCA\NCDownloader\Search\Sites\TPB;
+use OCA\NCDownloader\Tools\Helper;
use Symfony\Component\DomCrawler\Crawler;
use Symfony\Component\HttpClient\HttpClient;
diff --git a/lib/Tools/Aria2.php b/lib/Tools/Aria2.php
index a22c1c1..26bfc75 100644
--- a/lib/Tools/Aria2.php
+++ b/lib/Tools/Aria2.php
@@ -162,8 +162,11 @@ class Aria2
{
$this->filterResponse = false;
$resp = $this->tellStopped($range);
+ if (!isset($resp['result'])) {
+ return [];
+ }
$result = $this->sortDownloadsResult($resp['result'], ['complete', 'removed']);
- $this->filterResponse = true;;
+ $this->filterResponse = true;
return $result;
}
public function getCounters()
@@ -268,6 +271,21 @@ class Aria2
$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()
{
return [
diff --git a/lib/Tools/DBConn.php b/lib/Tools/DBConn.php
index e17ade9..e89fe2e 100644
--- a/lib/Tools/DBConn.php
+++ b/lib/Tools/DBConn.php
@@ -18,7 +18,7 @@ class DBConn
//$this->conn = $this->connAdapter->getInner();
}
- public function create($insert)
+ public function insert($insert)
{
$inserted = (bool) $this->conn->insertIfNotExist('*PREFIX*' . $this->table, $insert, [
'gid',
@@ -46,6 +46,19 @@ class DBConn
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)
{
$queryBuilder = $this->queryBuilder
@@ -57,9 +70,9 @@ class DBConn
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)
@@ -74,14 +87,14 @@ class DBConn
}
public function execute($sql, $values)
{
- return $this->conn->executeStatement($sql, $values);
+ return $this->conn->executeUpdate($sql, $values);
// for some reason this doesn't work
$query = $this->queryBuilder;
$query->update('ncdownloader_info')
->set("data", $query->createNamedParameter($value))
->where($query->expr()->eq('gid', $query->createNamedParameter($gid)));
- // ->setParameter('gid', $gid);
+ // ->setParameter('gid', $gid);
// return $query->execute();
//return $query->getSQL();
return $this->queryBuilder->getSQL();
diff --git a/lib/Tools/File.php b/lib/Tools/File.php
deleted file mode 100644
index 4a8113b..0000000
--- a/lib/Tools/File.php
+++ /dev/null
@@ -1,42 +0,0 @@
-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"];
-
- }
-}
diff --git a/lib/Tools/Helper.php b/lib/Tools/Helper.php
index e81f322..f0f01fd 100644
--- a/lib/Tools/Helper.php
+++ b/lib/Tools/Helper.php
@@ -8,7 +8,7 @@ use OC\Files\Filesystem;
class Helper
{
public const DOWNLOADTYPE = ['ARIA2' => 1, 'YOUTUBE-DL' => 2, 'OTHERS' => 3];
- public const STATUS = ['ACTIVE' => 1, 'ERROR' => 2, 'COMPLETE' => 3];
+ public const STATUS = ['ACTIVE' => 1, 'PAUSED' => 2, 'COMPLETE' => 3, 'ERROR' => 4];
public static function isUrl($URL)
{
$URLPattern = '%^(?:(?:https?|ftp)://)(?:\S+(?::\S*)?@|\d{1,3}(?:\.\d{1,3}){3}|(?:(?:[a-z\d\x{00a1}-\x{ffff}'
diff --git a/lib/Tools/Youtube.php b/lib/Tools/Youtube.php
index 1a99670..c202081 100644
--- a/lib/Tools/Youtube.php
+++ b/lib/Tools/Youtube.php
@@ -2,6 +2,7 @@
namespace OCA\NCDownloader\Tools;
use OCA\NCDownloader\Tools\Helper;
+use OCA\NCDownloader\Tools\YoutubeHelper;
use Symfony\Component\Process\Exception\ProcessFailedException;
use Symfony\Component\Process\Process;
@@ -12,11 +13,22 @@ class Youtube
private $audioFormat, $videoFormat = 'mp4';
private $options = [];
private $downloadDir;
+ private $timeout = 60 * 60 * 15;
+ private $outTpl = "/%(id)s-%(title)s.%(ext)s";
+ private $defaultDir = "/tmp/downloads";
+
public function __construct($config)
{
$config += ['downloadDir' => '/tmp/downloads'];
$this->bin = Helper::findBinaryPath('youtube-dl');
+ $this->init();
$this->setDownloadDir($config['downloadDir']);
+ $this->helper = YoutubeHelper::create();
+ }
+
+ public function init()
+ {
+ $this->addOption("--no-mtime");
}
public function GetUrlOnly()
@@ -46,38 +58,80 @@ class Youtube
array_unshift($this->options, $option);
}
- public function download($url)
+ public function downloadSync($url)
{
- $this->downloadDir = $this->downloadDir ?? "/tmp/downloads";
- $this->prependOption($this->downloadDir . "/%(id)s-%(title)s.%(ext)s");
+ $this->downloadDir = $this->downloadDir ?? $this->defaultDir;
+ $this->prependOption($this->downloadDir . $this->outTpl);
$this->prependOption("-o");
$this->setUrl($url);
$this->prependOption($this->bin);
// $this->buildCMD();
$process = new Process($this->options);
//the maximum time required to download the file
- $process->setTimeout(60*60*15);
+ $process->setTimeout($this->timeout);
try {
$process->mustRun();
$output = $process->getOutput();
} catch (ProcessFailedException $exception) {
$output = $exception->getMessage();
}
+
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+(?.*\.(?(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)
{
$this->setUrl($url);
$this->GetUrlOnly();
- //$process = new Process($this->options);
$this->buildCMD();
exec($this->cmd, $output, $returnCode);
if (count($output) === 1) {
return ['url' => reset($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)
diff --git a/lib/Tools/YoutubeHelper.php b/lib/Tools/YoutubeHelper.php
new file mode 100644
index 0000000..6d4dc5f
--- /dev/null
+++ b/lib/Tools/YoutubeHelper.php
@@ -0,0 +1,92 @@
+\d+(?:\.\d+)?%)' . //progress
+ '\s+of\s+[~]?' .
+ '(?\d+(?:\.\d+)?(?:K|M|G)iB)' . //file size
+ '(?:\s+at\s+' .
+ '(?(\d+(?:\.\d+)?(?:K|M|G)iB/s)|Unknown speed))' . //speed
+ '(?:\s+ETA\s+(?([\d:]{2,8}|Unknown ETA)))?' . //estimated download time
+ '(\s+in\s+(?[\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+(?.*\.(?(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]);*/
+ }
+ }
+ }
+}
diff --git a/lib/Tools/folderScan.php b/lib/Tools/folderScan.php
new file mode 100644
index 0000000..b347855
--- /dev/null
+++ b/lib/Tools/folderScan.php
@@ -0,0 +1,93 @@
+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();
+ }
+}
diff --git a/src/buttonActions.js b/src/buttonActions.js
index 7b2e682..bb3da2b 100644
--- a/src/buttonActions.js
+++ b/src/buttonActions.js
@@ -25,7 +25,10 @@ const buttonHandler = (event, type) => {
return;
}
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)
row.remove();
diff --git a/src/helper.js b/src/helper.js
index 658bba9..3b348b9 100644
--- a/src/helper.js
+++ b/src/helper.js
@@ -47,10 +47,10 @@ const helper = {
return magnetURI.test(url.trim());
},
- message: function (message) {
+ message: function (message,duration = 5000) {
Toastify({
text: message,
- duration: 3000,
+ duration:duration,
newWindow: true,
close: true,
gravity: "top", // `top` or `bottom`
diff --git a/src/inputAction.js b/src/inputAction.js
index fff3c84..bf06600 100644
--- a/src/inputAction.js
+++ b/src/inputAction.js
@@ -20,46 +20,49 @@ const createInputBox = (event, type) => {
let height = $(window).scrollTop();
if (height > 50)
$("html, body").animate({ scrollTop: 0 }, "fast");
- let name;
+ let name, path;
switch (type) {
case "ytdl":
name = t("ncdownloader", 'YTDL Download');
+ path = basePath + "/youtube/new";
break;
case "search":
name = t("ncdownloader", 'Search');
+ path = basePath + "/search";
break;
default:
name = t("ncdownloader", 'New Download');
+ path = basePath + "/new";
}
let container;
if (type === 'search') {
- container = inputBox.getInstance(name, type).addSpinner().create();
+ container = inputBox.getInstance(name, type, path).create().addSpinner();
//container.appendChild(inputBox.createLoading());
} else {
- container = inputBox.getInstance(name, type).create();
+ container = inputBox.getInstance(name, type, path).create().getContainer();
}
$("#ncdownloader-form-wrapper").append(container);
}
-const toggleButton = element => {
- if (!element.previousSibling) {
+const toggleSpinner = element => {
+ let spinner = element.previousSibling || element.nextSibling
+
+ if (!spinner) {
return;
}
if (element.style.display === 'none') {
element.style.display = 'block'
- element.previousSibling.style.display = 'none';
+ spinner.style.display = 'none';
} else {
element.style.display = 'none'
- element.previousSibling.style.display = 'block';
+ spinner.style.display = 'block';
}
}
const inputHandler = (event) => {
event.preventDefault();
let element = event.target;
- // element.textContent = '';
- //$(element).append(inputBox.createLoading());
- toggleButton(element);
+ toggleSpinner(element);
let inputData = helper.getData('form-input-wrapper');
let inputValue = inputData.form_input_text;
if (inputData.type !== 'search' && !helper.isURL(inputValue) && !helper.isMagnetURI(inputValue)) {
@@ -67,10 +70,10 @@ const inputHandler = (event) => {
return;
}
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') {
- //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;
nctable.getInstance().loading();
}
@@ -79,7 +82,7 @@ const inputHandler = (event) => {
if (data !== null && data.hasOwnProperty("file")) {
helper.message(t("ncdownloader", "Downloading" + " " + data.file));
}
- toggleButton(element);
+ toggleSpinner(element);
if (data && data.title) {
const tableInst = nctable.getInstance(data.title, data.row);
tableInst.actionLink = false;
diff --git a/src/inputBox.js b/src/inputBox.js
index 45a127f..d72769d 100644
--- a/src/inputBox.js
+++ b/src/inputBox.js
@@ -3,23 +3,35 @@ import helper from './helper'
class inputBox {
- constructor(name, id) {
+ path;
+ constructor(name, id, path = null) {
this.name = name;
- this.container = this._createForm();
- this.textInput = this._createTextInput(id);
- this.controlsContainer = this._createControlsContainer();
+ this.id = id;
+ this.path = path;
}
- static getInstance(name, id) {
- return new inputBox(name, id);
+ static getInstance(name, id, path = null) {
+ return new inputBox(name, id, path);
}
create() {
+ this.container = this._createForm();
+ this.textInput = this._createTextInput(this.id);
+ this.controlsContainer = this._createControlsContainer();
this.container.appendChild(this.textInput);
this.controlsContainer.appendChild(this._createControls());
this.container.appendChild(this.controlsContainer);
+ return this;
+ }
+
+ getContainer() {
return this.container;
}
+ setPath(path) {
+ this.path = path;
+ return this;
+ }
_createControlsContainer() {
let div = document.createElement("div");
+
div.classList.add("controls-container");
return div;
}
@@ -36,6 +48,9 @@ class inputBox {
textInput.setAttribute('id', "form_input_text");
textInput.setAttribute('data-type', id);
textInput.setAttribute('value', '');
+ if (this.path) {
+ textInput.setAttribute('data-path', this.path);
+ }
textInput.classList.add('form-input-text');
return textInput;
}
@@ -55,7 +70,7 @@ class inputBox {
let element = doc.querySelector(".bs-spinner");
element.style.display = 'none';
this.controlsContainer.appendChild(element);
- return this;
+ return this.container;
}
}
diff --git a/src/ncTable.js b/src/ncTable.js
index df89dc6..c511861 100644
--- a/src/ncTable.js
+++ b/src/ncTable.js
@@ -89,6 +89,9 @@ class ncTable {
let container = document.createElement("div");
container.classList.add("button-container");
element[key].forEach(value => {
+ if (!value.name) {
+ return;
+ }
container.appendChild(this.createActionButton(value.name, value.path));
})
rowItem.appendChild(container);
diff --git a/src/updatePage.js b/src/updatePage.js
index 71fa5c4..d3df498 100644
--- a/src/updatePage.js
+++ b/src/updatePage.js
@@ -6,9 +6,12 @@ const tableContainer = ".table";
export default {
run: function () {
- const eventHandler = (event, type) => {
+ const clickHandler = (event, type) => {
event.preventDefault();
- const path = basePath + type;
+ let path = basePath + type;
+ if (type === "youtube-dl") {
+ path = "/apps/ncdownloader/youtube/get";
+ }
let name = type + "-downloads";
//avoid repeated click
if ($(tableContainer).attr("type") === name && helper.enabledPolling) {
@@ -18,19 +21,28 @@ export default {
$(tableContainer).removeClass().addClass("table " + name);
$(tableContainer).attr("type", name);
let delay = 15000;
- if (name === "active-downloads") {
+ if (['active', 'youtube-dl'].includes(type)) {
delay = 1500;
}
helper.loop(helper.refresh, delay, ...[path])
};
- $(".waiting-downloads").on("click", event => eventHandler(event, 'waiting'));
- $(".complete-downloads").on("click", event => eventHandler(event, 'complete'));
- $(".active-downloads").on("click", event => eventHandler(event, 'active'));
- $(".fail-downloads").on("click", event => eventHandler(event, 'fail'));
+ $(".waiting-downloads").on("click", event => clickHandler(event, 'waiting'));
+ $(".complete-downloads").on("click", event => clickHandler(event, 'complete'));
+ $(".active-downloads").on("click", event => clickHandler(event, 'active'));
+ $(".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 + "complete")
helper.refresh(basePath + "fail")
+ helper.refresh("/apps/ncdownloader/youtube/get")
helper.loop(helper.refresh, 1000, basePath + "active");
diff --git a/templates/Navigation.php b/templates/Navigation.php
index 3518ea6..7076052 100644
--- a/templates/Navigation.php
+++ b/templates/Navigation.php
@@ -91,5 +91,18 @@ $aria2_installed = $_['aria2_installed'];
+
+
+
+ t('Youtube-dl Downloads'));?>
+
+
+
\ No newline at end of file
diff --git a/templates/settings/Admin.php b/templates/settings/Admin.php
index bc827c8..6ffc842 100644
--- a/templates/settings/Admin.php
+++ b/templates/settings/Admin.php
@@ -3,7 +3,10 @@ script("ncdownloader", 'appSettings');
?>