added one more bt site;added the option for choosing a site to search torrents

This commit is contained in:
huangjx
2021-09-17 14:32:22 +08:00
parent 7427f395f5
commit de2afbb0ef
10 changed files with 200 additions and 47 deletions

View File

@@ -5,12 +5,16 @@ 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\Controller\YoutubeController;
use OCA\NCDownloader\Search\Sites\bitSearch;
use OCA\NCDownloader\Search\Sites\TPB;
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;
use OCA\NCDownloader\Tools\Youtube; use OCA\NCDownloader\Tools\Youtube;
use OCP\AppFramework\App; use OCP\AppFramework\App;
use OCP\IContainer; use OCP\IContainer;
use Symfony\Component\DomCrawler\Crawler;
use Symfony\Component\HttpClient\HttpClient;
class Application extends App class Application extends App
{ {
@@ -71,6 +75,22 @@ class Application extends App
$container->query('Youtube') $container->query('Youtube')
); );
}); });
$container->registerService('crawler', function () {
return new Crawler();
});
$container->registerService('httpClient', function () {
return HttpClient::create();
});
$container->registerService(TPB::class, function (IContainer $container) {
$crawler = $container->query('crawler');
$client = $container->query('httpClient');
return new TPB($crawler, $client);
});
$container->registerService(bitSearch::class, function (IContainer $container) {
$crawler = $container->query('crawler');
$client = $container->query('httpClient');
return new bitSearch($crawler, $client);
});
} }
private function getRealDownloadDir() private function getRealDownloadDir()

View File

@@ -7,6 +7,15 @@ a {
text-decoration: none; text-decoration: none;
} }
#ncdownloader-form-wrapper .form-input-wrapper {
display : flex;
flex-flow: row nowrap;
}
#ncdownloader-form-wrapper .form-input-wrapper select,
#ncdownloader-form-wrapper .form-input-wrapper input {
justify-content: left;
}
a:hover, a:hover,
a:focus { a:focus {
color : #23527c; color : #23527c;
@@ -17,11 +26,6 @@ a:focus {
outline : 5px auto -webkit-focus-ring-color; outline : 5px auto -webkit-focus-ring-color;
outline-offset: -2px; outline-offset: -2px;
} }
#ncdownloader-form-wrapper input {
display: block;
}
div .number { div .number {
background : none repeat scroll 0 0 #5f5853; background : none repeat scroll 0 0 #5f5853;
border-radius: 999px; border-radius: 999px;
@@ -37,7 +41,7 @@ div .number {
#ncdownloader-form-wrapper input[type=text] { #ncdownloader-form-wrapper input[type=text] {
padding: 0px 5px; padding: 0px 5px;
width : 100%; flex:auto;
} }
#ncdownloader-table-data .table-cell { #ncdownloader-table-data .table-cell {
@@ -51,9 +55,11 @@ div .number {
.icon-purge { .icon-purge {
background-image: url('../img/trash.svg'); background-image: url('../img/trash.svg');
} }
.icon-unpause { .icon-unpause {
background-image: url('../img/play.svg'); background-image: url('../img/play.svg');
} }
#ncdownloader-action-links-container { #ncdownloader-action-links-container {
position: relative; position: relative;
} }

View File

@@ -134,11 +134,11 @@ class Aria2Controller extends Controller
if (isset($resp['error'])) { if (isset($resp['error'])) {
return new JSONResponse($resp); return new JSONResponse($resp);
} }
$data = $this->prepareResp($resp); $data = $this->transformResp($resp);
$data['counter'] = $counter; $data['counter'] = $counter;
return new JSONResponse($data); return new JSONResponse($data);
} }
private function prepareResp($resp) private function transformResp($resp)
{ {
$data = []; $data = [];
@@ -191,7 +191,9 @@ class Aria2Controller extends Controller
$left = Helper::formatInterval($remaining); $left = Helper::formatInterval($remaining);
$numSeeders = $value['numSeeders'] ?? 0; $numSeeders = $value['numSeeders'] ?? 0;
$extraInfo = "Seeders: $numSeeders"; $upload = $value['uploadLength'] ?? 0;
$upload = Helper::formatBytes($upload);
$extraInfo = "Seeders: $numSeeders|Up:$upload";
// $numPeers = isset($peers['result']) ? count($peers['result']) : 0; // $numPeers = isset($peers['result']) ? count($peers['result']) : 0;
$value['progress'] = array(sprintf("%s(%.2f%%)", $completed, $percentage), $extraInfo); $value['progress'] = array(sprintf("%s(%.2f%%)", $completed, $percentage), $extraInfo);
$timestamp = $timestamp ?? 0; $timestamp = $timestamp ?? 0;

View File

@@ -19,12 +19,15 @@ class SearchController extends Controller
$this->appName = $appName; $this->appName = $appName;
$this->uid = $UserId; $this->uid = $UserId;
$this->urlGenerator = \OC::$server->getURLGenerator(); $this->urlGenerator = \OC::$server->getURLGenerator();
$this->search = new torrentSearch();
} }
public function execute() public function execute()
{ {
$keyword = trim($this->request->getParam('form_input_text')); $keyword = trim($this->request->getParam('form_input_text'));
$data = torrentSearch::go($keyword); $site = trim($this->request->getParam('select-value-search'));
$this->search->setSite($site);
$data = $this->search->go($keyword);
$resp['title'] = ['title', 'seeders', 'info', 'actions']; $resp['title'] = ['title', 'seeders', 'info', 'actions'];
$resp['row'] = $data; $resp['row'] = $data;
return new JSONResponse($resp); return new JSONResponse($resp);

View File

@@ -3,7 +3,7 @@
namespace OCA\NCDownloader\Search\Sites; namespace OCA\NCDownloader\Search\Sites;
//The Piratebay //The Piratebay
class TPB class TPB implements searchBase
{ {
//html content //html content
private $content = null; private $content = null;

View File

@@ -0,0 +1,65 @@
<?php
namespace OCA\NCDownloader\Search\Sites;
//bitsearch.to
class bitSearch implements searchBase
{
//html content
private $content = null;
public $baseUrl = "https://bitsearch.to/search";
private $query = null;
public function __construct($crawler, $client)
{
$this->client = $client;
$this->crawler = $crawler;
}
public function search($keyword)
{
$this->query = ['q' => trim($keyword), 'sort' => 'seeders'];
$this->searchUrl = $this->baseUrl;
//$this->setContent(file_get_contents(__DIR__ . "/BitSearch.html"));
$this->crawler->add($this->getContent());
return $this->parse();
}
public function setContent($content)
{
$this->content = $content;
}
public function getContent()
{
if ($this->content) {
return $this->content;
}
$response = $this->client->request('GET', $this->searchUrl, ['query' => $this->query]);
return $response->getContent();
}
public function parse()
{
$data = $this->crawler->filter(".w3-col.s12.mt-4 .search-result")->each(function ($node, $i) {
if ($node->getNode(0)) {
try {
$title = $node->filter(".info h5.title")->text();
$infoNode = $node->filter(".info .stats div");
$count = $infoNode->count();
$info = [];
for ($i = 0; $i < $count; $i++) {
$name = strtolower($infoNode->filter("img")->eq($i)->attr("alt"));
$info[$name] = trim($infoNode->eq($i)->text());
}
$seeders = $info['seeder'];
$info = sprintf("%s on %s", $info['size'], $info['date']);
$magnetLink = $node->filter(".links.center-flex a:nth-child(2)")->attr("href");
return ['title' => $title, 'data-link' => $magnetLink, 'seeders' => $seeders, 'info' => $info];
} catch (\Exception $e) {
//echo $e->getMessage();
}
}
});
return $data;
}
}

View File

@@ -0,0 +1,10 @@
<?php
namespace OCA\NCDownloader\Search\Sites;
interface searchBase
{
public function search($keyword);
public function parse();
}

View File

@@ -3,25 +3,35 @@
namespace OCA\NCDownloader\Search; namespace OCA\NCDownloader\Search;
require __DIR__ . "/../../vendor/autoload.php"; require __DIR__ . "/../../vendor/autoload.php";
use OCA\NCDownloader\Search\Sites\TPB; use OCP\IServerContainer;
use OCA\NCDownloader\Tools\Helper;
use Symfony\Component\DomCrawler\Crawler;
use Symfony\Component\HttpClient\HttpClient;
class torrentSearch class torrentSearch
{ {
public $container;
public static function go($keyword) private $site = null;
public function __construct()
{ {
$client = HttpClient::create(); $this->container = \OC::$server->query(IServerContainer::class);
$crawler = new Crawler(); $this->site = __NAMESPACE__ . '\Sites\TPB';
$tpb = new TPB($crawler, $client); }
$data = $tpb->search($keyword); public function go($keyword)
self::addAction($data); {
$siteInst = $this->container->query($this->site);
$data = $siteInst->search($keyword);
$this->addAction($data);
return $data; return $data;
} }
private static function addAction(&$data) public function setSite($site)
{
if (strpos($site, '\\') !== false) {
$this->site = $site;
} else {
$this->site = __NAMESPACE__ . '\Sites\\' . $site;
}
}
private function addAction(&$data)
{ {
foreach ($data as $key => &$value) { foreach ($data as $key => &$value) {
if (!$value) { if (!$value) {

View File

@@ -36,7 +36,10 @@ const createInputBox = (event, type) => {
} }
let container; let container;
if (type === 'search') { if (type === 'search') {
container = inputBox.getInstance(name, type, path).create().addSpinner(); let selectOptions = [];
selectOptions.push({name:'bitSearch',label:'BITSEARCH',default:0});
selectOptions.push({name:'TPB',label:'THEPIRATEBAY',selected:1});
container = inputBox.getInstance(name, type, path).createOptions(selectOptions).create().addSpinner();
//container.appendChild(inputBox.createLoading()); //container.appendChild(inputBox.createLoading());
} else { } else {
container = inputBox.getInstance(name, type, path).create().getContainer(); container = inputBox.getInstance(name, type, path).create().getContainer();
@@ -63,6 +66,8 @@ const inputHandler = (event) => {
event.preventDefault(); event.preventDefault();
let element = event.target; let element = event.target;
toggleSpinner(element); toggleSpinner(element);
let formWrapper = element.closest('form');
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)) {
@@ -82,7 +87,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));
} }
toggleSpinner(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;
@@ -90,7 +95,7 @@ const inputHandler = (event) => {
tableInst.create(); tableInst.create();
} }
} }
const path = inputData.path || basePath + "/new"; const path = formWrapper.dataset.path || basePath + "/new";
let url = helper.generateUrl(path); let url = helper.generateUrl(path);
Http.getInstance(url).setData(inputData).setHandler(function (data) { Http.getInstance(url).setData(inputData).setHandler(function (data) {
successCallback(data, element); successCallback(data, element);

View File

@@ -4,43 +4,78 @@ import helper from './helper'
class inputBox { class inputBox {
path; path;
constructor(name, id, path = null) { selectOptions = [];
this.name = name; constructor(btnName, id, path = null) {
this.btnName = btnName;
this.id = id; this.id = id;
this.path = path; this.path = path;
} }
static getInstance(name, id, path = null) { static getInstance(btnName, id, path = null) {
return new inputBox(name, id, path); return new inputBox(btnName, id, path);
} }
create() { create() {
this.container = this._createForm(); this.formContainer = this._createForm();
this.textInput = this._createTextInput(this.id); this.textInput = this._createTextInput(this.id);
this.controlsContainer = this._createControlsContainer(); this.buttonContainer = this._createButtonContainer();
this.container.appendChild(this.textInput); this.formContainer.appendChild(this.textInput);
this.controlsContainer.appendChild(this._createControls()); if (this.selectOptions.length !== 0) {
this.container.appendChild(this.controlsContainer); this.formContainer.appendChild(this._createSelect());
}
this.buttonContainer.appendChild(this._createButton());
this.formContainer.appendChild(this.buttonContainer);
return this; return this;
} }
getContainer() { getContainer() {
return this.container; return this.formContainer;
} }
setPath(path) { setPath(path) {
this.path = path; this.path = path;
return this; return this;
} }
_createControlsContainer() { _createButtonContainer() {
let div = document.createElement("div"); let div = document.createElement("div");
div.classList.add("controls-container"); div.classList.add("button-container");
return div; return div;
} }
_createForm() { _createForm() {
let container = document.createElement("form"); let container = document.createElement("form");
container.classList.add("form-input-wrapper"); container.classList.add("form-input-wrapper");
container.setAttribute('id', 'form-input-wrapper'); container.setAttribute('id', 'form-input-wrapper');
if (this.path) {
container.setAttribute('data-path', this.path);
}
return container; return container;
} }
_createSelect(id) {
id = id || this.id;
let select = document.createElement('select');
select.setAttribute('id', "select-value-" + id);
select.setAttribute('value', '');
select.classList.add('form-select');
this.selectOptions.forEach(element => {
select.appendChild(element);
});
return select;
}
createOptions(data) {
if (!data) {
return;
}
data.forEach(element => {
let option = document.createElement('option');
option.setAttribute('value', element.name);
let text = document.createTextNode(element.label);
option.appendChild(text);
if (element.selected) {
option.setAttribute("selected", "selected");
}
this.selectOptions.push(option);
});
return this;
}
_createTextInput(id) { _createTextInput(id) {
id = id || 'general'; id = id || 'general';
let textInput = document.createElement('input'); let textInput = document.createElement('input');
@@ -48,18 +83,15 @@ 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;
} }
_createControls() { _createButton() {
let button = document.createElement('button'); let button = document.createElement('button');
button.setAttribute('type', this.name); button.setAttribute('type', this.btnName);
button.setAttribute('id', 'form-input-button'); button.setAttribute('id', 'form-input-button');
//buttonInput.setAttribute('value', t('ncdownloader', helper.ucfirst(name))); //buttonInput.setAttribute('value', t('ncdownloader', helper.ucfirst(btnName)));
let text = document.createTextNode(t('ncdownloader', helper.ucfirst(this.name))); let text = document.createTextNode(t('ncdownloader', helper.ucfirst(this.btnName)));
button.appendChild(text); button.appendChild(text);
return button; return button;
} }
@@ -69,8 +101,8 @@ class inputBox {
let doc = parser.parseFromString(htmlString, "text/html") let doc = parser.parseFromString(htmlString, "text/html")
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.buttonContainer.appendChild(element);
return this.container; return this.formContainer;
} }
} }