From c6b46727342ffd8709ce8a0188e1864e3d837523 Mon Sep 17 00:00:00 2001 From: Roman Kelesidis Date: Tue, 20 Aug 2024 22:16:49 +0700 Subject: [PATCH] =?UTF-8?q?Added=20TorrServer=20instance=20support!=20?= =?UTF-8?q?=F0=9F=8E=9E=20(#1603)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 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> --- CHANGELOG.md | 1 + README.md | 1 + composer.json | 1 + composer.lock | 82 ++++++- library/attach_mod/displaying_torrent.php | 9 + .../attach_mod/includes/functions_delete.php | 9 +- library/config.php | 8 + .../includes/cron/jobs/attach_maintenance.php | 7 + src/Legacy/Torrent.php | 19 +- src/TorrServerAPI.php | 200 ++++++++++++++++++ styles/images/tor_m3u_format.png | Bin 0 -> 2034 bytes styles/templates/default/tpl_config.php | 2 + styles/templates/default/viewtopic_attach.tpl | 10 +- 13 files changed, 344 insertions(+), 5 deletions(-) create mode 100644 src/TorrServerAPI.php create mode 100644 styles/images/tor_m3u_format.png diff --git a/CHANGELOG.md b/CHANGELOG.md index 439fc7596..85fee3987 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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)) diff --git a/README.md b/README.md index 9dfa3c1f6..f9e6acb29 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/composer.json b/composer.json index 436d07190..8c0644213 100644 --- a/composer.json +++ b/composer.json @@ -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", diff --git a/composer.lock b/composer.lock index f01854dad..7cb28a4d0 100644 --- a/composer.lock +++ b/composer.lock @@ -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", diff --git a/library/attach_mod/displaying_torrent.php b/library/attach_mod/displaying_torrent.php index 28e57e11f..8ccaeb2fa 100644 --- a/library/attach_mod/displaying_torrent.php +++ b/library/attach_mod/displaying_torrent.php @@ -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]); } diff --git a/library/attach_mod/includes/functions_delete.php b/library/attach_mod/includes/functions_delete.php index 04a5f586f..3ed0f1c5a 100644 --- a/library/attach_mod/includes/functions_delete.php +++ b/library/attach_mod/includes/functions_delete.php @@ -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]; diff --git a/library/config.php b/library/config.php index d46bfd283..0fd52f4b2 100644 --- a/library/config.php +++ b/library/config.php @@ -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, diff --git a/library/includes/cron/jobs/attach_maintenance.php b/library/includes/cron/jobs/attach_maintenance.php index 151708eaf..179cfadf6 100644 --- a/library/includes/cron/jobs/attach_maintenance.php +++ b/library/includes/cron/jobs/attach_maintenance.php @@ -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)"); diff --git a/src/Legacy/Torrent.php b/src/Legacy/Torrent.php index 851ff21d1..8a832a2be 100644 --- a/src/Legacy/Torrent.php +++ b/src/Legacy/Torrent.php @@ -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]); diff --git a/src/TorrServerAPI.php b/src/TorrServerAPI.php new file mode 100644 index 000000000..eb2ae1e16 --- /dev/null +++ b/src/TorrServerAPI.php @@ -0,0 +1,200 @@ + '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; + } +} diff --git a/styles/images/tor_m3u_format.png b/styles/images/tor_m3u_format.png new file mode 100644 index 0000000000000000000000000000000000000000..963efff45d576c19de7ead0b285f7a88c0653828 GIT binary patch literal 2034 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 E7ueCSV*mgE literal 0 HcmV?d00001 diff --git a/styles/templates/default/tpl_config.php b/styles/templates/default/tpl_config.php index a0901bee0..d82079523 100644 --- a/styles/templates/default/tpl_config.php +++ b/styles/templates/default/tpl_config.php @@ -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'; diff --git a/styles/templates/default/viewtopic_attach.tpl b/styles/templates/default/viewtopic_attach.tpl index ef6781bc3..1ff876fa0 100644 --- a/styles/templates/default/viewtopic_attach.tpl +++ b/styles/templates/default/viewtopic_attach.tpl @@ -146,8 +146,8 @@ + +  {postrow.attach.tor_reged.MAGNET} @@ -173,6 +173,12 @@

{postrow.attach.tor_reged.FILESIZE}

+ + +
+

Download .m3u
+ +
{postrow.attach.tor_reged.DOWNLOAD_NAME} - -  {postrow.attach.tor_reged.MAGNET}