diff --git a/appinfo/info.xml b/appinfo/info.xml
index bd818e3..c41572a 100644
--- a/appinfo/info.xml
+++ b/appinfo/info.xml
@@ -8,7 +8,7 @@ Search for torrents within the app from mutiple BT sites;
Control Aria2 and manage download tasks from the web;
download videos from 700+ video sites(youtube,youku,vimo,dailymotion,twitter,facebook and the likes
- 0.6.1
+ 0.6.5
agpl
jiaxinhuang
NCDownloader
diff --git a/img/clippy.svg b/img/clippy.svg
new file mode 100644
index 0000000..6e30e1a
--- /dev/null
+++ b/img/clippy.svg
@@ -0,0 +1 @@
+
diff --git a/lib/Controller/YoutubeController.php b/lib/Controller/YoutubeController.php
index 4a57375..c691ef6 100644
--- a/lib/Controller/YoutubeController.php
+++ b/lib/Controller/YoutubeController.php
@@ -50,18 +50,18 @@ class YoutubeController extends Controller
$folderLink = $this->urlGenerator->linkToRoute('files.view.index', $params);
foreach ($data as $value) {
$tmp = [];
+ $extra = unserialize($value['data']);
$filename = sprintf('%s', $folderLink, $value['filename']);
- $fileInfo = sprintf("%s | %s", $value['filesize'], date("Y-m-d H:i:s", $value['timestamp']));
+ $fileInfo = sprintf('
%s | % s
', $extra['link'], $value['filesize'], date("Y-m-d H:i:s", $value['timestamp']));
$tmp['filename'] = array($filename, $fileInfo);
$tmp['speed'] = explode("|", $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 {
- $path = $this->urlGenerator->linkToRoute('ncdownloader.Youtube.Redownload');
- $tmp['actions'][] = ['name' => 'refresh', 'path' => $path];
- }
+
+ $path = $this->urlGenerator->linkToRoute('ncdownloader.Youtube.Delete');
+ $tmp['actions'][] = ['name' => 'delete', 'path' => $path];
+ $path = $this->urlGenerator->linkToRoute('ncdownloader.Youtube.Redownload');
+ $tmp['actions'][] = ['name' => 'refresh', 'path' => $path];
+
$tmp['data_gid'] = $value['gid'] ?? 0;
array_push($resp['row'], $tmp);
}
@@ -111,10 +111,30 @@ class YoutubeController extends Controller
return new JSONResponse(['error' => "no gid value is received!"]);
}
- if ($this->dbconn->deleteByGid($gid)) {
- return new JSONResponse(['message' => $gid . " Deleted!"]);
-
+ $row = $this->dbconn->getByGid($gid);
+ $data = unserialize($row['data']);
+ if (!isset($data['pid'])) {
+ if ($this->dbconn->deleteByGid($gid)) {
+ $msg = sprintf("%s is deleted from database!", $gid);
+ }
+ return new JSONResponse(['message' => $msg]);
}
+ $pid = $data['pid'];
+ if (!Helper::isRunning($pid)) {
+ if ($this->dbconn->deleteByGid($gid)) {
+ $msg = sprintf("%s is deleted from database!", $gid);
+ } else {
+ $msg = sprintf("process %d is not running!", $pid);
+ }
+ } else {
+ if (Helper::stop($pid)) {
+ $msg = sprintf("process %d has been terminated!", $pid);
+ } else {
+ $msg = sprintf("failed to terminate process %d!", $pid);
+ }
+ $this->dbconn->deleteByGid($gid);
+ }
+ return new JSONResponse(['message' => $msg]);
}
/**
* @NoAdminRequired
@@ -129,6 +149,7 @@ class YoutubeController extends Controller
$row = $this->dbconn->getByGid($gid);
$data = unserialize($row['data']);
if (!empty($data['link'])) {
+ //$this->dbconn->deleteByGid($gid);
$resp = $this->youtube->forceIPV4()->download($data['link']);
folderScan::sync();
return new JSONResponse($resp);
diff --git a/lib/Search/torrentSearch.php b/lib/Search/torrentSearch.php
index 6a7499b..426f74e 100644
--- a/lib/Search/torrentSearch.php
+++ b/lib/Search/torrentSearch.php
@@ -46,7 +46,7 @@ class torrentSearch
if (!$value) {
continue;
}
- $value['actions'][] = array("name" => 'download', 'path' => '/index.php/apps/ncdownloader/new');
+ $value['actions'] = [["name" => 'download', 'path' => '/index.php/apps/ncdownloader/new'], ['name' => 'clipboard']];
}
}
diff --git a/lib/Tools/Helper.php b/lib/Tools/Helper.php
index 8405cbf..0c48dfc 100644
--- a/lib/Tools/Helper.php
+++ b/lib/Tools/Helper.php
@@ -43,6 +43,7 @@ class Helper
{
$host = parse_url($url, PHP_URL_HOST);
//$sites = ['twitter.com', 'www.twitter.com'];
+ $sites = [];
return (bool) (in_array($host, $sites));
}
public static function parseUrl($url)
@@ -134,7 +135,7 @@ class Helper
public static function debug($msg)
{
$logger = \OC::$server->getLogger();
- $logger->debug($msg, ['app' => 'ncdownloader']);
+ $logger->error($msg, ['app' => 'ncdownloader']);
}
public static function log($msg, $file = "/tmp/nc.log")
@@ -298,4 +299,28 @@ class Helper
return filter_var($string, FILTER_SANITIZE_STRING);
}
+ public static function doSignal($pid, $signal): bool
+ {
+ if (\function_exists('posix_kill')) {
+ $ok = @posix_kill($pid, $signal);
+ } elseif ($ok = proc_open(sprintf('kill -%d %d', $signal, $pid), [2 => ['pipe', 'w']], $pipes)) {
+ $ok = false === fgets($pipes[2]);
+ }
+
+ if (!$ok) {
+ return false;
+ }
+ return true;
+ }
+
+ public static function isRunning($pid)
+ {
+ return self::doSignal($pid, 0);
+ }
+
+ public static function stop($pid)
+ {
+ return self::doSignal($pid, 9);
+ }
+
}
diff --git a/lib/Tools/Youtube.php b/lib/Tools/Youtube.php
index b75a32f..40698a5 100644
--- a/lib/Tools/Youtube.php
+++ b/lib/Tools/Youtube.php
@@ -154,11 +154,13 @@ class Youtube
//\OC::$server->getLogger()->error($process->getCommandLine(), ['app' => 'PHP']);
$process = new Process($this->options, null, $this->env);
$process->setTimeout($this->timeout);
- $process->run(function ($type, $buffer) use ($url) {
+ $data = ['link' => $url];
+ $process->run(function ($type, $buffer) use ($data, $process) {
if (Process::ERR === $type) {
- $this->onError($buffer);
+ // $this->onError($buffer);
} else {
- $this->onOutput($buffer, $url);
+ $data['pid'] = $process->getPid();
+ $this->onOutput($buffer, $data);
}
});
if ($process->isSuccessful()) {
@@ -173,9 +175,9 @@ class Youtube
$this->helper->log($buffer);
}
- public function onOutput($buffer, $url)
+ public function onOutput($buffer, $extra)
{
- $this->helper->run($buffer, $url);
+ $this->helper->run($buffer, $extra);
}
public function getDownloadUrl($url)
{
diff --git a/lib/Tools/YoutubeHelper.php b/lib/Tools/YoutubeHelper.php
index 4e963e7..5d03d7e 100644
--- a/lib/Tools/YoutubeHelper.php
+++ b/lib/Tools/YoutubeHelper.php
@@ -16,6 +16,7 @@ class YoutubeHelper
'(\s+in\s+(?[\d:]{2,8}))?#i';
public $file = null;
public $filesize = null;
+ protected $pid = 0;
public function __construct()
{
$this->dbconn = new DbHelper();
@@ -47,9 +48,13 @@ class YoutubeHelper
//$sql = sprintf("UPDATE %s set status = ? WHERE gid = ?", $this->tablename);
$this->dbconn->updateStatus($this->gid, $this->status);
}
- public function run($buffer, $url)
+ public function setPid($pid)
{
- $this->gid = Helper::generateGID($url);
+ $this->pid = $pid;
+ }
+ public function run($buffer, $extra)
+ {
+ $this->gid = Helper::generateGID($extra['link']);
$file = $this->getFilePath($buffer);
if ($file) {
$data = [
@@ -59,7 +64,7 @@ class YoutubeHelper
'filename' => basename($file),
'status' => Helper::STATUS['ACTIVE'],
'timestamp' => time(),
- 'data' => serialize(['link' => $url]),
+ 'data' => serialize($extra),
];
//save the filename as this runs only once
$this->file = $file;
diff --git a/src/actions/buttonActions.js b/src/actions/buttonActions.js
index 28425d3..fe97bf4 100644
--- a/src/actions/buttonActions.js
+++ b/src/actions/buttonActions.js
@@ -1,6 +1,9 @@
import Http from '../lib/http'
import helper from '../utils/helper'
import eventHandler from '../lib/eventHandler'
+import Clipboard from '../utils/clipboard'
+import '../css/clipboard.scss';
+
const buttonHandler = (event, type) => {
let element = event.target;
event.stopPropagation();
@@ -9,6 +12,11 @@ const buttonHandler = (event, type) => {
let row, data = {};
let removeRow = true;
if (row = element.closest('.table-row-search')) {
+ if (element.className == 'icon-clipboard') {
+ const clippy = new Clipboard(element, row.dataset.link);
+ clippy.Copy();
+ return;
+ }
data['text-input-value'] = row.dataset.link;
} else {
row = element.closest('.table-row')
@@ -38,5 +46,10 @@ const buttonHandler = (event, type) => {
export default {
run: function () {
eventHandler.add("click", "#ncdownloader-table-wrapper", ".table-cell-action-item .button-container button", e => buttonHandler(e, ''));
+ eventHandler.add("click", "#ncdownloader-table-wrapper", ".table-row button.icon-clipboard", function (e) {
+ let element = e.target;
+ const clippy = new Clipboard(element);
+ clippy.Copy();
+ });
}
}
\ No newline at end of file
diff --git a/src/css/clipboard.scss b/src/css/clipboard.scss
new file mode 100644
index 0000000..e819b7a
--- /dev/null
+++ b/src/css/clipboard.scss
@@ -0,0 +1,5 @@
+#ncdownloader-tooltip {
+ color : #5d6395;
+ font-size : medium;
+ font-weight: bold;
+}
\ No newline at end of file
diff --git a/src/css/style.scss b/src/css/style.scss
index f64282e..186d16f 100644
--- a/src/css/style.scss
+++ b/src/css/style.scss
@@ -41,7 +41,9 @@
.icon-add {
background-image: url('../../img/add.svg');
}
-
+ .icon-clipboard {
+ background-image: url('../../img/clippy.svg');
+ }
#ncdownloader-form-wrapper {
margin-left: 2px;
diff --git a/src/lib/tooltip.js b/src/lib/tooltip.js
new file mode 100644
index 0000000..b73a7f5
--- /dev/null
+++ b/src/lib/tooltip.js
@@ -0,0 +1,50 @@
+import $ from 'jquery'
+
+class Tooltip {
+ id = "ncdownloader-tooltip";
+ messageNode;
+ style = {};
+ text;
+ constructor(element, text) {
+ if (typeof element !== 'string' && !(element instanceof HTMLElement))
+ throw ("invalid element!");
+ this.element = typeof element == 'object' ? element : document.querySelector(element);
+ this.style = {
+ position: 'fixed',
+ display: 'block',
+ }
+ this.text = text || element.getAttribute("data-text");
+ }
+ create(id) {
+ this.messageNode = document.createElement("div");
+ this.messageNode.classList.add(this.id);
+ this.messageNode.setAttribute("id", this.id);
+ this.messageNode.style.display = this.style.display;
+ this.messageNode.style.position = this.style.position;
+ this.messageNode.style.zIndex = 10000;
+ let div = document.createElement('div');
+ div.setAttribute("id", id);
+ let text = document.createTextNode(this.text);
+ div.appendChild(text);
+ this.messageNode.appendChild(div);
+ this.setPosition();
+ return this;
+ }
+ render() {
+ document.body.appendChild(this.messageNode);
+ }
+ html() {
+ return this.messageNode;
+ }
+ setPosition(bottomMargin, leftMargin) {
+ bottomMargin = bottomMargin || 20;
+ leftMargin = leftMargin || 0;
+ let rect = this.element.getBoundingClientRect();
+ let top = (rect['top'] + bottomMargin) + "px";
+ let left = (rect['left'] - leftMargin) + "px";
+ this.messageNode.style.top = top;
+ this.messageNode.style.left = left
+ }
+}
+
+export default Tooltip;
\ No newline at end of file
diff --git a/src/utils/clipboard.js b/src/utils/clipboard.js
new file mode 100644
index 0000000..4d1c646
--- /dev/null
+++ b/src/utils/clipboard.js
@@ -0,0 +1,66 @@
+import Tooltip from "../lib/tooltip";
+
+class Clipboard {
+ element;
+ text;
+
+ constructor(element, text) {
+ if (typeof element !== 'string' && !(element instanceof HTMLElement))
+ throw ("invalid element!");
+ this.element = typeof element == 'object' ? element : document.querySelector(element);
+ this.text = text || element.getAttribute("data-text");
+ }
+
+ _copy(text) {
+ let textArea = document.createElement("textarea");
+ textArea.value = text;
+
+ textArea.style.top = "0";
+ textArea.style.left = "0";
+ textArea.style.position = "fixed";
+
+ document.body.appendChild(textArea);
+ textArea.focus();
+ textArea.select();
+ let result;
+ try {
+ result = document.execCommand('copy');
+ //console.log('copied using exceCommand');
+
+ } catch (err) {
+ console.error('failed to copy', err);
+ result = false;
+ } finally {
+ document.body.removeChild(textArea);
+ }
+ if (result) {
+ this.ShowMsg("Copied!");
+ }
+ }
+
+ ShowMsg(msg) {
+ let tip = new Tooltip(this.element, msg);
+ let html = tip.create('copy-alert').html();
+ document.body.appendChild(html);
+ const callback = (element) => {
+ element.remove()
+ }
+ setTimeout(() => {
+ callback(html)
+ }, 1000);
+ }
+
+ Copy() {
+ if (!navigator.clipboard) {
+ return this._copy(this.text);
+ }
+ return navigator.clipboard.writeText(this.text).then(() => {
+ this.ShowMsg("Copied!");
+ }, function (err) {
+ console.error('failed to copy text: ', err);
+ });
+ }
+
+}
+
+export default Clipboard;
\ No newline at end of file
diff --git a/src/utils/helper.js b/src/utils/helper.js
index 7f41624..cc67889 100644
--- a/src/utils/helper.js
+++ b/src/utils/helper.js
@@ -172,6 +172,12 @@ const helper = {
>Loading...`;
return html;
+ },
+ getCssVar(prop) {
+ return window.getComputedStyle(document.documentElement).getPropertyValue(prop);
+ },
+ getScrollTop() {
+ return window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0;
}
}