Added TorrServer instance support! 🎞 (#1603)

* Added integration with TorrServe 🎞

* Updated

* Updated

* Update functions.php

* Updated

* Update functions.php

* Update functions.php

* Updated

* Update TorrServerAPI.php

* Updated

* Updated

* Updated

* Updated

* Updated

* Updated

* Update TorrServerAPI.php

* Update TorrServerAPI.php

* Update TorrServerAPI.php

* Updated

* Updated

* Update config.php

* Update Attach.php

* Update Torrent.php

* Update CHANGELOG.md

* Update TorrServerAPI.php

* Update TorrServerAPI.php

* Update displaying_torrent.php

* Update Torrent.php

* Update TorrServerAPI.php

* Update TorrServerAPI.php

* Update TorrServerAPI.php

* Update TorrServerAPI.php

* Update TorrServerAPI.php

* Updated

* Update viewtopic_attach.tpl

* Updated

* Update tor_m3u_format.svg

* Updated

* Updated

* Update tor_m3u_format.png

* Update TorrServerAPI.php

* Update TorrServerAPI.php

* Updated

* Update Torrent.php

* Update functions_delete.php

* Updated

* Update TorrServerAPI.php

* Updated

* Updated

* Updated

* Update TorrServerAPI.php

* Update TorrServerAPI.php

* Update displaying_torrent.php

* Update TorrServerAPI.php

* Update CHANGELOG.md

Co-Authored-By: YouROK <4067300+yourok@users.noreply.github.com>

---------

Co-authored-by: YouROK <4067300+yourok@users.noreply.github.com>
This commit is contained in:
Roman Kelesidis 2024-08-20 22:16:49 +07:00 committed by GitHub
commit c6b4672734
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 344 additions and 5 deletions

View file

@ -9,6 +9,7 @@
- [CLI] TorrentPier installer ☕️ [\#1576](https://github.com/torrentpier/torrentpier/pull/1576), [\#1582](https://github.com/torrentpier/torrentpier/pull/1582), [\#1585](https://github.com/torrentpier/torrentpier/pull/1585), [\#1591](https://github.com/torrentpier/torrentpier/pull/1591) ([belomaxorka](https://github.com/belomaxorka))
- Added some new HTML meta-tags [\#1562](https://github.com/torrentpier/torrentpier/pull/1562) ([belomaxorka](https://github.com/belomaxorka))
- Added robots meta-tag support 🤖 [\#1587](https://github.com/torrentpier/torrentpier/pull/1587) ([belomaxorka](https://github.com/belomaxorka))
- Added [TorrServer](https://github.com/YouROK/TorrServer) instance support! 🎞 [\#1603](https://github.com/torrentpier/torrentpier/pull/1603) ([belomaxorka](https://github.com/belomaxorka))
- Newtopic: Added configuring robots indexing [\#1599](https://github.com/torrentpier/torrentpier/pull/1599) ([belomaxorka](https://github.com/belomaxorka))
- Added showing releaser stats in profile [\#1568](https://github.com/torrentpier/torrentpier/pull/1568) ([belomaxorka](https://github.com/belomaxorka))
- Improved `filelist.php` [\#1586](https://github.com/torrentpier/torrentpier/pull/1586) ([belomaxorka](https://github.com/belomaxorka))

View file

@ -32,6 +32,7 @@ and go from there. The documentation will be translated into english in the near
* Rich forum browsing/moderation tools
* High-load capable, heavily configurable announcer
* Scrape support
* [TorrServer integration](https://github.com/YouROK/TorrServer)
* FreeLeech
* BitTorrent v2 support
* Event-based invite system

View file

@ -59,6 +59,7 @@
"google/recaptcha": "^1.3",
"jacklul/monolog-telegram": "^3.1",
"josantonius/cookie": "^2.0",
"php-curl-class/php-curl-class": "^9.19.2",
"league/flysystem": "^3.28",
"longman/ip-tools": "1.2.1",
"matthiasmullie/scrapbook": "^1.5",

82
composer.lock generated
View file

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "c0d21cdb591458dce2d6cebef725cf75",
"content-hash": "7c5b99b513b26c61075e197a519464fa",
"packages": [
{
"name": "arokettu/bencode",
@ -1986,6 +1986,86 @@
},
"time": "2024-03-19T20:45:05+00:00"
},
{
"name": "php-curl-class/php-curl-class",
"version": "9.19.2",
"source": {
"type": "git",
"url": "https://github.com/php-curl-class/php-curl-class.git",
"reference": "c41efeb4ea2dc3cf8f90f8f967b0fcf45a41e294"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-curl-class/php-curl-class/zipball/c41efeb4ea2dc3cf8f90f8f967b0fcf45a41e294",
"reference": "c41efeb4ea2dc3cf8f90f8f967b0fcf45a41e294",
"shasum": ""
},
"require": {
"ext-curl": "*",
"php": ">=7.0"
},
"require-dev": {
"dealerdirect/phpcodesniffer-composer-installer": "*",
"ext-gd": "*",
"friendsofphp/php-cs-fixer": "*",
"phpcompatibility/php-compatibility": "dev-develop",
"phpcsstandards/phpcsutils": "@alpha",
"phpunit/phpunit": "*",
"squizlabs/php_codesniffer": "*",
"vimeo/psalm": ">=0.3.63"
},
"suggest": {
"ext-mbstring": "*"
},
"type": "library",
"autoload": {
"psr-4": {
"Curl\\": "src/Curl/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"Unlicense"
],
"authors": [
{
"name": "Zach Borboa"
},
{
"name": "Contributors",
"homepage": "https://github.com/php-curl-class/php-curl-class/graphs/contributors"
}
],
"description": "PHP Curl Class makes it easy to send HTTP requests and integrate with web APIs.",
"homepage": "https://github.com/php-curl-class/php-curl-class",
"keywords": [
"API-Client",
"api",
"class",
"client",
"curl",
"framework",
"http",
"http-client",
"http-proxy",
"json",
"php",
"php-curl",
"php-curl-library",
"proxy",
"requests",
"restful",
"web-scraper",
"web-scraping ",
"web-service",
"xml"
],
"support": {
"issues": "https://github.com/php-curl-class/php-curl-class/issues",
"source": "https://github.com/php-curl-class/php-curl-class/tree/9.19.2"
},
"time": "2024-04-09T18:03:13+00:00"
},
{
"name": "php-http/discovery",
"version": "1.19.4",

View file

@ -214,6 +214,7 @@ if ($tor_reged && $tor_info) {
'MAGNET' => $tor_magnet,
'HASH' => !empty($tor_info['info_hash']) ? strtoupper(bin2hex($tor_info['info_hash'])) : false,
'HASH_V2' => !empty($tor_info['info_hash_v2']) ? strtoupper(bin2hex($tor_info['info_hash_v2'])) : false,
'FILELIST_ICON' => $images['icon_tor_filelist'],
'FILELIST_LINK' => FILELIST_URL . $tor_info['topic_id'],
'REGED_TIME' => bb_date($tor_info['reg_time']),
'REGED_DELTA' => delta_time($tor_info['reg_time']),
@ -222,6 +223,14 @@ if ($tor_reged && $tor_info) {
'COMPLETED' => $tor_completed_count,
]);
// TorrServer integration
if ($bb_cfg['torr_server']['enabled']) {
$template->assign_block_vars('postrow.attach.tor_reged.tor_server', [
'TORR_SERVER_M3U_LINK' => (new \TorrentPier\TorrServerAPI())->getM3UPath($attach_id),
'TORR_SERVER_M3U_ICON' => $images['icon_tor_m3u_icon'],
]);
}
if ($comment) {
$template->assign_block_vars('postrow.attach.tor_reged.comment', ['COMMENT' => $comment]);
}

View file

@ -16,7 +16,8 @@
*/
function delete_attachment($post_id_array = 0, $attach_id_array = 0, $page = 0, $user_id = 0)
{
$lang = [];
global $lang, $bb_cfg;
// Generate Array, if it's not an array
if ($post_id_array === 0 && $attach_id_array === 0 && $page === 0) {
return;
@ -185,6 +186,12 @@ function delete_attachment($post_id_array = 0, $attach_id_array = 0, $page = 0,
DB()->sql_freeresult($result);
if ($num_rows == 0) {
// TorrServer integration
if ($bb_cfg['torr_server']['enabled']) {
$torrServer = new \TorrentPier\TorrServerAPI();
$torrServer->removeM3U($attach_id_array[$i]);
}
$sql = 'SELECT attach_id, physical_filename, thumbnail
FROM ' . BB_ATTACHMENTS_DESC . '
WHERE attach_id = ' . (int)$attach_id_array[$i];

View file

@ -109,6 +109,14 @@ $bb_cfg['client_ban'] = [
]
];
// TorrServer integration
$bb_cfg['torr_server'] = [
// Read more: https://github.com/YouROK/TorrServer
'enabled' => true,
'url' => "http://$domain_name:8090",
'timeout' => 5
];
// Ocelot
$bb_cfg['ocelot'] = [
'enabled' => false,

View file

@ -144,6 +144,13 @@ if ($check_attachments) {
$orphan_db_attach[] = $row['attach_id'];
}
// Delete all orphan attachments
if ($bb_cfg['torr_server']['enabled']) {
foreach ($orphan_db_attach as $attach_id) {
// TorrServer integration
$torrServer = new \TorrentPier\TorrServerAPI();
$torrServer->removeM3U($attach_id);
}
}
if ($orphans_sql = implode(',', $orphan_db_attach)) {
if ($fix_errors) {
DB()->query("DELETE FROM " . BB_ATTACHMENTS_DESC . " WHERE attach_id IN($orphans_sql)");

View file

@ -9,8 +9,11 @@
namespace TorrentPier\Legacy;
use TorrentPier\TorrServerAPI;
use Arokettu\Bencode\Bencode;
use Arokettu\Bencode\Bencode\Collection;
use Exception;
/**
@ -34,7 +37,7 @@ class Torrent
$sql = "
SELECT
a.post_id, d.physical_filename, d.extension, d.tracker_status,
a.post_id, d.physical_filename, d.extension, d.tracker_status, d.mimetype,
t.topic_first_post_id,
p.poster_id, p.topic_id, p.forum_id,
f.allow_reg_tracker
@ -143,6 +146,12 @@ class Torrent
bb_die('Could not delete peers');
}
// TorrServer integration
if ($bb_cfg['torr_server']['enabled']) {
$torrServer = new TorrServerAPI();
$torrServer->removeM3U($attach_id);
}
// Ocelot
if ($bb_cfg['ocelot']['enabled']) {
if ($row = DB()->fetch_row("SELECT info_hash FROM " . BB_BT_TORRENTS . " WHERE attach_id = $attach_id LIMIT 1")) {
@ -387,6 +396,14 @@ class Torrent
$info_hash_where = "WHERE info_hash_v2 = '$info_hash_v2_sql'";
}
// TorrServer integration
if ($bb_cfg['torr_server']['enabled']) {
$torrServer = new TorrServerAPI();
if ($torrServer->uploadTorrent($filename, $torrent['mimetype'])) {
$torrServer->saveM3U($attach_id, bin2hex($info_hash ?? $info_hash_v2));
}
}
// Ocelot
if ($bb_cfg['ocelot']['enabled']) {
self::ocelot_update_tracker('add_torrent', ['info_hash' => rawurlencode($info_hash ?? hex2bin(substr($v2_hash, 0, 40))), 'id' => $topic_id, 'freetorrent' => 0]);

200
src/TorrServerAPI.php Normal file
View file

@ -0,0 +1,200 @@
<?php
/**
* TorrentPier Bull-powered BitTorrent tracker engine
*
* @copyright Copyright (c) 2005-2024 TorrentPier (https://torrentpier.com)
* @link https://github.com/torrentpier/torrentpier for the canonical source repository
* @license https://github.com/torrentpier/torrentpier/blob/master/LICENSE MIT License
*/
namespace TorrentPier;
use Curl\Curl;
use CURLFile;
/**
* Class TorrServerAPI
* @package TorrentPier
*/
class TorrServerAPI
{
/**
* URL to TorrServer instance
*
* @var string
*/
private string $url;
/**
* Endpoints list
*
* @var array|string[]
*/
private array $endpoints = [
'playlist' => 'playlist',
'upload' => 'torrent/upload',
'stream' => 'stream'
];
/**
* M3U file params
*/
const M3U = [
'prefix' => 'm3u_',
'extension' => '.m3u'
];
/**
* Log filename
*
* @var string
*/
private string $logFile = 'torr_server';
/**
* TorrServer constructor
*/
public function __construct()
{
global $bb_cfg;
$this->url = $bb_cfg['torr_server']['url'] . '/';
}
/**
* Upload torrent-file to TorrServer instance
*
* @param string $path
* @param string $mimetype
* @return bool
*/
public function uploadTorrent(string $path, string $mimetype): bool
{
global $bb_cfg;
// Check mimetype
if ($mimetype !== 'application/x-bittorrent') {
return false;
}
$curl = new Curl();
$curl->setTimeout($bb_cfg['torr_server']['timeout']);
$curl->setHeaders([
'Accept' => 'application/json',
'Content-Type' => 'multipart/form-data'
]);
$curl->post($this->url . $this->endpoints['upload'], [
'file' => new CURLFile($path, $mimetype)
]);
$isSuccess = $curl->httpStatusCode === 200;
if (!$isSuccess) {
bb_log("TorrServer (ERROR) [$this->url]: Response code: {$curl->httpStatusCode} | Content: {$curl->response}\n", $this->logFile);
}
$curl->close();
return $isSuccess;
}
/**
* Saves M3U file (local)
*
* @param string|int $attach_id
* @param string $hash
* @return string
*/
public function saveM3U(string|int $attach_id, string $hash): string
{
global $bb_cfg;
$m3uFile = get_attachments_dir() . '/' . self::M3U['prefix'] . $attach_id . self::M3U['extension'];
// Make stream call to store torrent in memory
if (!$this->getStream($hash)) {
return false;
}
$curl = new Curl();
$curl->setTimeout($bb_cfg['torr_server']['timeout']);
$curl->setHeader('Accept', 'audio/x-mpegurl');
$curl->get($this->url . $this->endpoints['playlist'], ['hash' => $hash]);
if ($curl->httpStatusCode === 200 && !empty($curl->response)) {
// Validate response
$validResponse = false;
$responseLines = explode("\n", $curl->response);
foreach ($responseLines as $line) {
if (str_contains($line, '#EXTINF')) {
$validResponse = true;
break;
}
}
// Store M3U file
if ($validResponse && !is_file($m3uFile)) {
file_put_contents($m3uFile, $curl->response);
}
} else {
bb_log("TorrServer (ERROR) [$this->url]: Response code: {$curl->httpStatusCode} | Content: {$curl->response}\n", $this->logFile);
}
$curl->close();
return is_file($m3uFile) && (int)filesize($m3uFile) > 0;
}
/**
* Returns full path to M3U file
*
* @param int|string $attach_id
* @return string
*/
public function getM3UPath(int|string $attach_id): string
{
$m3uFile = get_attachments_dir() . '/' . self::M3U['prefix'] . $attach_id . self::M3U['extension'];
if (is_file($m3uFile)) {
return $m3uFile;
}
return false;
}
/**
* Removed M3U file (local)
*
* @param string|int $attach_id
* @return bool
*/
public function removeM3U(string|int $attach_id): bool
{
$m3uFile = get_attachments_dir() . '/' . self::M3U['prefix'] . $attach_id . self::M3U['extension'];
if (is_file($m3uFile)) {
return unlink($m3uFile);
}
return false;
}
/**
* Up stream
*
* @param string $hash
* @return bool
*/
private function getStream(string $hash): bool
{
global $bb_cfg;
$curl = new Curl();
$curl->setTimeout($bb_cfg['torr_server']['timeout']);
$curl->setHeader('Accept', 'application/octet-stream');
$curl->get($this->url . $this->endpoints['stream'], ['link' => $hash]);
$isSuccess = $curl->httpStatusCode === 200;
if (!$isSuccess) {
bb_log("TorrServer (ERROR) [$this->url]: Response code: {$curl->httpStatusCode} | Content: {$curl->response}\n", $this->logFile);
}
$curl->close();
return $isSuccess;
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2 KiB

View file

@ -38,6 +38,8 @@ $images['icon_male'] = $_main . 'icon_male.gif';
$images['icon_female'] = $_main . 'icon_female.gif';
$images['icon_nogender'] = $_main . 'icon_nogender.gif';
$images['icon_tor_m3u_icon'] = $_img . 'tor_m3u_format.png';
$images['icon_tor_filelist'] = $_img . 't_info.png';
$images['icon_tor_gold'] = $_img . 'tor_gold.gif';
$images['icon_tor_silver'] = $_img . 'tor_silver.gif';

View file

@ -146,8 +146,8 @@
<table class="attach bordered med">
<tr class="row3">
<th colspan="3" class="{postrow.attach.tor_reged.DL_LINK_CLASS}">{postrow.attach.tor_reged.DOWNLOAD_NAME}
<a href="{postrow.attach.tor_reged.FILELIST_LINK}" title="File hashes | .torrent meta-info" target="_blank"><img src="./styles/images/t_info.png" width="12" height="12" border="0"></a>
<!-- IF MAGNET_LINKS and not postrow.attach.tor_reged.TOR_FROZEN -->&nbsp;{postrow.attach.tor_reged.MAGNET}<!-- ENDIF --></th>
<a href="{postrow.attach.tor_reged.FILELIST_LINK}" title="File hashes | .torrent meta-info" target="_blank"><img src="{postrow.attach.tor_reged.FILELIST_ICON}" width="12" height="12" border="0"></a>
<!-- IF MAGNET_LINKS and not postrow.attach.tor_reged.TOR_FROZEN -->&nbsp;{postrow.attach.tor_reged.MAGNET}<!-- ENDIF --></th>
</tr>
<!-- IF postrow.attach.tor_reged.TOR_TYPE -->
<tr class="row4">
@ -173,6 +173,12 @@
<!-- ENDIF -->
<p class="small">{postrow.attach.tor_reged.FILESIZE}</p>
<p style="padding-top: 6px;"><input id="tor-filelist-btn" type="button" class="lite" value="{L_FILELIST}" /></p>
<!-- BEGIN tor_server -->
<!-- IF postrow.attach.tor_reged.tor_server.TORR_SERVER_M3U_LINK -->
<hr>
<a href="{postrow.attach.tor_reged.tor_server.TORR_SERVER_M3U_LINK}" target="_blank"><p><img src="{postrow.attach.tor_reged.tor_server.TORR_SERVER_M3U_ICON}" width="21" height="21" border="0"></p>Download .m3u</a>
<!-- ENDIF -->
<!-- END tor_server -->
</td>
</tr>
<tr class="row1">