Compare commits

..

12 commits

Author SHA1 Message Date
Roman Kelesidis
144aa0558d
chore: Removed deploy pipeline (#2047)
Some checks failed
Continuous Integration / Nightly builds 📦 (push) Has been cancelled
PHPMD / Run PHPMD scanning (push) Has been cancelled
2025-07-16 10:15:09 +03:00
Roman Kelesidis
6e7e3dd9ef
fix: handle Nette DateTime objects in birthday validation (#2032)
Some checks failed
Continuous Integration / Nightly builds 📦 (push) Has been cancelled
Continuous Integration / 🎉 Deploy (push) Has been cancelled
PHPMD / Run PHPMD scanning (push) Has been cancelled
* fix: handle Nette DateTime objects in birthday validation

* Update register.php

* Update User.php
2025-07-03 23:07:09 +02:00
Roman Kelesidis
423fb65dbf
release: v2.8.3
Some checks are pending
Continuous Integration / Nightly builds 📦 (push) Waiting to run
Continuous Integration / 🎉 Deploy (push) Waiting to run
PHPMD / Run PHPMD scanning (push) Waiting to run
2025-07-03 10:51:21 +03:00
Roman Kelesidis
51f2c70d81
feat(updater): Added exceptions logging (#2026)
* feat(updater): Added exceptions logging
* refactor(updater): Use `sha256` hash if available
2025-07-03 10:48:25 +03:00
Roman Kelesidis
fd46d3d04a
feat(lang): Added RTL languages support (#2031) 2025-07-03 10:43:02 +03:00
Roman Kelesidis
d4d82101dd
refactor(TorrentFileList): Reduce duplication in root directory unset logic (#2027) 2025-07-03 10:40:56 +03:00
Roman Kelesidis
9e3f3588f2
release: v2.8.2
Some checks failed
PHPMD / Run PHPMD scanning (push) Has been cancelled
Continuous Integration / Nightly builds 📦 (push) Has been cancelled
Continuous Integration / 🎉 Deploy (push) Has been cancelled
2025-06-30 10:49:42 +03:00
Roman Kelesidis
915e1d817c
fix(TorrentFileList): Avoid array_merge reindexing for numeric folder names (#2014)
Some checks are pending
Continuous Integration / Nightly builds 📦 (push) Waiting to run
Continuous Integration / 🎉 Deploy (push) Waiting to run
PHPMD / Run PHPMD scanning (push) Waiting to run
Co-authored-by: zxc <17812947+metalwarrior88@users.noreply.github.com>
2025-06-29 15:03:56 +03:00
Roman Kelesidis
7ac335974b
refactor: Use DEFAULT_CHARSET constant instead of hardcoded string (#2011)
Some checks failed
PHPMD / Run PHPMD scanning (push) Has been cancelled
Continuous Integration / Nightly builds 📦 (push) Has been cancelled
Continuous Integration / 🎉 Deploy (push) Has been cancelled
2025-06-26 13:32:45 +03:00
Roman Kelesidis
c2e3a13a04
release: v2.8.1 2025-06-24 13:00:37 +03:00
Roman Kelesidis
f1d6e74e5d
fix(ip-api): Add error handling and logging for freeipapi.com requests (#2006) 2025-06-24 12:55:41 +03:00
Roman Kelesidis
7f4cc9d3b9
fix(filelist): Undefined property: FileTree::$length when v2 torrent only (#2004) 2025-06-23 21:49:53 +03:00
20 changed files with 150 additions and 106 deletions

View file

@ -43,32 +43,3 @@ jobs:
with:
name: TorrentPier-master
path: ${{ steps.create-zip.outputs.ZIP_NAME }}
deploy:
name: 🎉 Deploy
runs-on: ubuntu-22.04
steps:
- name: 🚚 Get latest code
uses: actions/checkout@v4
- name: 🔩 Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.2'
- name: 🖇 Install Composer dependencies
run: composer install --no-dev --no-progress --prefer-dist --optimize-autoloader
- name: 📂 Sync files
uses: SamKirkland/FTP-Deploy-Action@v4.3.5
with:
server: ${{ secrets.FTP_SERVER }}
username: ${{ secrets.FTP_USERNAME }}
password: ${{ secrets.FTP_PASSWORD }}
server-dir: ${{ secrets.FTP_DIR }}
protocol: ${{ secrets.FTP_PROTOCOL }}
port: ${{ secrets.FTP_PORT }}
exclude: |
**/.git*
**/.git*/**
.env

View file

@ -2,6 +2,37 @@
# 📖 Change Log
## [v2.8.3](https://github.com/torrentpier/torrentpier/compare/v2.8.2..v2.8.3) (2025-07-03)
### 🚀 Features
- *(lang)* Added `RTL` languages support ([#2031](https://github.com/torrentpier/torrentpier/pull/2031)) - ([fd46d3d](https://github.com/torrentpier/torrentpier/commit/fd46d3d04ad3ab1453256b2ab620508e2ba33586))
- *(updater)* Added exceptions logging ([#2026](https://github.com/torrentpier/torrentpier/pull/2026)) - ([51f2c70](https://github.com/torrentpier/torrentpier/commit/51f2c70d81b910012cdecd111b5b92c1dfd0d6f6))
### 🚜 Refactor
- *(TorrentFileList)* Reduce duplication in root directory unset logic ([#2027](https://github.com/torrentpier/torrentpier/pull/2027)) - ([d4d8210](https://github.com/torrentpier/torrentpier/commit/d4d82101dd67c9f4cd86e0f6f909495696974354))
## [v2.8.2](https://github.com/torrentpier/torrentpier/compare/v2.8.1..v2.8.2) (2025-06-30)
### 🐛 Bug Fixes
- *(TorrentFileList)* Avoid `array_merge` reindexing for numeric folder names ([#2014](https://github.com/torrentpier/torrentpier/pull/2014)) - ([915e1d8](https://github.com/torrentpier/torrentpier/commit/915e1d817c61d2a4f0691b24ec1bc6577a9cd44b))
### 🚜 Refactor
- Use `DEFAULT_CHARSET` constant instead of hardcoded string ([#2011](https://github.com/torrentpier/torrentpier/pull/2011)) - ([7ac3359](https://github.com/torrentpier/torrentpier/commit/7ac335974baa44a8575bebb71ae2fbc0902d10e7))
## [v2.8.1](https://github.com/torrentpier/torrentpier/compare/v2.8.0..v2.8.1) (2025-06-24)
### 🐛 Bug Fixes
- *(filelist)* `Undefined property: FileTree::$length` when v2 torrent only ([#2004](https://github.com/torrentpier/torrentpier/pull/2004)) - ([7f4cc9d](https://github.com/torrentpier/torrentpier/commit/7f4cc9d3b9a5b87100f710cc60f636d6e7d5a34e))
- *(ip-api)* Add error handling and logging for freeipapi.com requests ([#2006](https://github.com/torrentpier/torrentpier/pull/2006)) - ([f1d6e74](https://github.com/torrentpier/torrentpier/commit/f1d6e74e5d4c74b6e12e9e742f60f62e71783d11))
## [v2.8.0](https://github.com/torrentpier/torrentpier/compare/v2.7.0..v2.8.0) (2025-06-21)
### 🐛 Bug Fixes

View file

@ -90,7 +90,7 @@ if (isset($_GET['pane']) && $_GET['pane'] == 'left') {
'NEW_VERSION_SIZE' => $update_data['latest_version_size'],
'NEW_VERSION_DL_LINK' => $update_data['latest_version_dl_link'],
'NEW_VERSION_LINK' => $update_data['latest_version_link'],
'NEW_VERSION_MD5' => $update_data['latest_version_checksum']
'NEW_VERSION_HASH' => $update_data['latest_version_checksum']
]);
}

View file

@ -115,7 +115,7 @@ $stopped = ($event === 'stopped');
// Check info_hash length
if (strlen($info_hash) !== 20) {
msg_die('Invalid info_hash: ' . (mb_check_encoding($info_hash, 'UTF8') ? $info_hash : $info_hash_hex));
msg_die('Invalid info_hash: ' . (mb_check_encoding($info_hash, DEFAULT_CHARSET) ? $info_hash : $info_hash_hex));
}
/**
@ -257,7 +257,7 @@ if ($lp_info) {
// Verify if torrent registered on tracker and user authorized
if (empty($row['topic_id'])) {
msg_die('Torrent not registered, info_hash = ' . (mb_check_encoding($info_hash, 'UTF8') ? $info_hash : $info_hash_hex));
msg_die('Torrent not registered, info_hash = ' . (mb_check_encoding($info_hash, DEFAULT_CHARSET) ? $info_hash : $info_hash_hex));
}
if (empty($row['user_id'])) {
msg_die('Please LOG IN and RE-DOWNLOAD this torrent (user not found)');

View file

@ -32,7 +32,7 @@ $info_hash_hex = bin2hex($info_hash);
// Check info_hash length
if (strlen($info_hash) !== 20) {
msg_die('Invalid info_hash: ' . (mb_check_encoding($info_hash, 'UTF8') ? $info_hash : $info_hash_hex));
msg_die('Invalid info_hash: ' . (mb_check_encoding($info_hash, DEFAULT_CHARSET) ? $info_hash : $info_hash_hex));
}
// Handle multiple hashes
@ -97,7 +97,7 @@ if (!empty($info_hash_count)) {
// Verify if torrent registered on tracker
if (empty($torrents)) {
msg_die('Torrent not registered, info_hash = ' . (mb_check_encoding($info_hash, 'UTF8') ? $info_hash : $info_hash_hex));
msg_die('Torrent not registered, info_hash = ' . (mb_check_encoding($info_hash, DEFAULT_CHARSET) ? $info_hash : $info_hash_hex));
}
die(\Arokettu\Bencode\Bencode::encode($torrents));

View file

@ -82,7 +82,7 @@ if (IS_GUEST && $torrent->isPrivate()) {
// Get torrent files
$files = $torrent->$t_version_field()->$t_files_field();
if ($meta_v1 && $meta_v2) {
if ($meta_v2) {
$files = new \RecursiveIteratorIterator($files); // Flatten the list
}
@ -102,19 +102,6 @@ foreach ($files as $file) {
$torrent_name = !empty($t_name = $torrent->getName()) ? str_short(htmlCHR($t_name), 200) : $lang['UNKNOWN'];
$torrent_size = humn_size($row['size'], 2);
// Get announcers list
$announcers_list = $torrent->getAnnounceList()->toArray();
$announcers_count = 0;
foreach ($announcers_list as $announcer) {
$announcers_count++;
$row_class = ($announcers_count % 2) ? 'row1' : 'row2';
$template->assign_block_vars('announcers', [
'ROW_NUMBER' => $announcers_count,
'ROW_CLASS' => $row_class,
'ANNOUNCER' => $announcer[0]
]);
}
// Output page
$template->assign_vars([
'PAGE_TITLE' => "$torrent_name (" . $torrent_size . ")",

View file

@ -475,6 +475,8 @@ if ($tor_reged && $tor_info) {
if ($infoByIP = infoByIP((!empty($peer['ipv6']) ? $peer['ipv6'] : $peer['ip']), $peer['port'])) {
if (!empty($infoByIP['countryCode'])) {
$peerCountry = render_flag($infoByIP['countryCode'], false);
} else {
$peerCountry = $lang['NOT_AVAILABLE'];
}
}
}

View file

@ -18,8 +18,8 @@ $reserved_port = env('TP_PORT', 80);
$bb_cfg = [];
// Version info
$bb_cfg['tp_version'] = 'v2.8.0';
$bb_cfg['tp_release_date'] = '21-06-2025';
$bb_cfg['tp_version'] = 'v2.8.3';
$bb_cfg['tp_release_date'] = '03-07-2025';
$bb_cfg['tp_release_codename'] = 'Cattle';
// Increase version number after changing JS or CSS
@ -204,6 +204,7 @@ $bb_cfg['lang'] = [
'ar' => [
'name' => 'Arabic',
'locale' => 'ar_SA.UTF-8',
'rtl' => true,
],
'hy' => [
'name' => 'Armenian',
@ -280,6 +281,7 @@ $bb_cfg['lang'] = [
'he' => [
'name' => 'Hebrew',
'locale' => 'he_IL.UTF-8',
'rtl' => true,
],
'hi' => [
'name' => 'Hindi',

View file

@ -16,9 +16,16 @@ if (!config()->get('tp_updater_settings.enabled')) {
}
$data = [];
$data[] = ['latest_check_timestamp' => TIMENOW];
$updaterDownloader = new \TorrentPier\Updater();
$updaterDownloader = $updaterDownloader->getLastVersion(config()->get('tp_updater_settings.allow_pre_releases'));
try {
$updaterDownloader = new \TorrentPier\Updater();
$updaterDownloader = $updaterDownloader->getLastVersion(config()->get('tp_updater_settings.allow_pre_releases'));
} catch (Exception $exception) {
bb_log('[Updater] Exception: ' . $exception->getMessage() . LOG_LF);
$this->store('check_updates', $data);
return;
}
$getVersion = \TorrentPier\Helpers\VersionHelper::removerPrefix($updaterDownloader['tag_name']);
$currentVersion = \TorrentPier\Helpers\VersionHelper::removerPrefix(config()->get('tp_version'));
@ -26,6 +33,7 @@ $currentVersion = \TorrentPier\Helpers\VersionHelper::removerPrefix(config()->ge
// Has update!
if (\z4kn4fein\SemVer\Version::greaterThan($getVersion, $currentVersion)) {
$latestBuildFileLink = $updaterDownloader['assets'][0]['browser_download_url'];
$SHAFileHash = $updaterDownloader['assets'][0]['digest'] ?? '';
// Check updater file
$updaterFile = readUpdaterFile();
@ -39,10 +47,12 @@ if (\z4kn4fein\SemVer\Version::greaterThan($getVersion, $currentVersion)) {
]), UPDATER_FILE, replace_content: true);
}
// Get MD5 checksum
// Get MD5 / sha256 checksum
$buildFileChecksum = '';
if (isset($latestBuildFileLink)) {
$buildFileChecksum = strtoupper(md5_file($latestBuildFileLink));
if (!empty($SHAFileHash)) {
$buildFileChecksum = $SHAFileHash;
} else {
$buildFileChecksum = 'MD5: ' . strtoupper(md5_file($latestBuildFileLink));
}
// Build data array
@ -56,5 +66,4 @@ if (\z4kn4fein\SemVer\Version::greaterThan($getVersion, $currentVersion)) {
];
}
$data[] = ['latest_check_timestamp' => TIMENOW];
$this->store('check_updates', $data);

View file

@ -2196,6 +2196,8 @@ function infoByIP(string $ipAddress, int $port = 0): array
}
$context = stream_context_create($contextOptions);
try {
$response = file_get_contents(config()->get('ip2country_settings.endpoint') . $ipAddress, context: $context);
if ($response !== false) {
@ -2209,6 +2211,11 @@ function infoByIP(string $ipAddress, int $port = 0): array
'continentCode' => $json['continentCode']
];
}
} else {
bb_log("[FreeIPAPI] Failed to get IP info for: $ipAddress" . LOG_LF);
}
} catch (Exception $e) {
bb_log("[FreeIPAPI] " . $e->getMessage() . LOG_LF);
}
if (empty($data)) {

View file

@ -117,6 +117,7 @@ $template->assign_vars([
'USER_HIDE_CAT' => (BB_SCRIPT == 'index'),
'USER_LANG' => $userdata['user_lang'],
'USER_LANG_DIRECTION' => (isset($bb_cfg['lang'][$userdata['user_lang']]['rtl']) && $bb_cfg['lang'][$userdata['user_lang']]['rtl'] === true) ? 'rtl' : 'ltr',
'INCLUDE_BBCODE_JS' => !empty($page_cfg['include_bbcode_js']),
'USER_OPTIONS_JS' => IS_GUEST ? '{}' : json_encode($user->opt_js, JSON_THROW_ON_ERROR),

View file

@ -142,6 +142,7 @@ switch ($mode) {
if (!$pr_data = DB()->fetch_row($sql)) {
bb_die($lang['PROFILE_NOT_FOUND']);
}
$pr_data['user_birthday'] = $pr_data['user_birthday']->format('Y-m-d');
if (IN_DEMO_MODE && isset($_COOKIE['user_lang'])) {
$pr_data['user_lang'] = $_COOKIE['user_lang'];
}

View file

@ -30,6 +30,8 @@ if (!$profiledata = get_userdata($_GET[POST_USERS_URL], profile_view: true)) {
bb_die($lang['NO_USER_ID_SPECIFIED']);
}
$profiledata['user_birthday'] = $profiledata['user_birthday']->format('Y-m-d');
if (!$ranks = $datastore->get('ranks')) {
$datastore->update('ranks');
$ranks = $datastore->get('ranks');

View file

@ -232,6 +232,7 @@ class User
}
}
$this->data['user_birthday'] = $this->data['user_birthday']->format('Y-m-d');
return $this->data;
}

View file

@ -53,8 +53,10 @@ class TorrentFileList
$this->build_filelist_array();
if ($this->multiple) {
if (isset($this->files_ary['/'])) {
if (!empty($this->files_ary['/'])) {
$this->files_ary = array_merge($this->files_ary, $this->files_ary['/']);
$this->files_ary = $this->files_ary + $this->files_ary['/'];
}
unset($this->files_ary['/']);
}
$filelist = $html->array2html($this->files_ary);

View file

@ -38,6 +38,13 @@ class Updater
*/
public string $savePath;
/**
* LTS version pattern (v2.8.*)
*
* @var string
*/
private const LTS_VERSION_PATTERN = '/^v2\.8\.\d+$/';
/**
* Stream context
*
@ -130,23 +137,67 @@ class Updater
}
/**
* Returns information of latest TorrentPier version available
* Returns information of latest TorrentPier LTS version (v2.8.*) available
*
* @param bool $allowPreReleases
* @return array
* @throws Exception
*/
public function getLastVersion(bool $allowPreReleases = true): array
{
// Filter releases to get only LTS versions (v2.8.*)
$ltsVersions = array_filter($this->jsonResponse, function ($release) {
return preg_match(self::LTS_VERSION_PATTERN, $release['tag_name']);
});
if (empty($ltsVersions)) {
throw new Exception('No LTS versions (v2.8.*) found');
}
// Sort LTS versions by version number (descending)
usort($ltsVersions, function ($a, $b) {
return version_compare($b['tag_name'], $a['tag_name']);
});
if (!$allowPreReleases) {
foreach ($ltsVersions as $release) {
if (isset($release['prerelease']) && $release['prerelease']) {
continue;
}
return $release;
}
// If no stable LTS versions found
throw new Exception('No stable LTS versions (v2.8.*) found');
}
return $ltsVersions[0];
}
/**
* Get all available LTS versions (v2.8.*)
*
* @param bool $allowPreReleases
* @return array
*/
public function getLastVersion(bool $allowPreReleases = true): array
public function getAllLTSVersions(bool $allowPreReleases = true): array
{
if (!$allowPreReleases) {
foreach ($this->jsonResponse as $index) {
if (isset($index['prerelease']) && $index['prerelease']) {
continue;
// Filter releases to get only LTS versions (v2.8.*)
$ltsVersions = array_filter($this->jsonResponse, function ($release) use ($allowPreReleases) {
$isLTSVersion = preg_match(self::LTS_VERSION_PATTERN, $release['tag_name']);
if (!$allowPreReleases && isset($release['prerelease']) && $release['prerelease']) {
return false;
}
return $index;
}
}
return $isLTSVersion;
});
return $this->jsonResponse[0];
// Sort LTS versions by version number (descending)
usort($ltsVersions, function ($a, $b) {
return version_compare($b['tag_name'], $a['tag_name']);
});
return array_values($ltsVersions);
}
}

View file

@ -1,7 +1,7 @@
<!-- IF TPL_ADMIN_FRAMESET -->
<!--========================================================================-->
<!DOCTYPE html>
<html lang="{$bb_cfg['default_lang']}">
<html dir="{USER_LANG_DIRECTION}" lang="{USER_LANG}">
<head>
<meta charset="{CONTENT_ENCODING}">
<link rel="shortcut icon" href="{SITE_URL}favicon.png" type="image/x-icon">
@ -160,7 +160,7 @@
<!-- IF updater.UPDATE_AVAILABLE -->
<tr>
<td class="row1" nowrap="nowrap" width="25%"><b>{L_UPDATE_AVAILABLE}:</b></td>
<td class="row2"><b>{updater.NEW_VERSION_NUMBER}</b><!-- IF updater.NEW_VERSION_SIZE -->&nbsp;({L_SIZE}:&nbsp;{updater.NEW_VERSION_SIZE})<!-- ENDIF -->&nbsp;&middot;&nbsp;<a target="_blank" href="{updater.NEW_VERSION_DL_LINK}">{L_DOWNLOAD}</a>&nbsp;&middot;&nbsp;<a target="_blank" href="{updater.NEW_VERSION_LINK}">{L_CHANGELOG}</a><!-- IF updater.NEW_VERSION_MD5 -->&nbsp;&middot;&nbsp;<span class="copyElement" data-clipboard-text="{updater.NEW_VERSION_MD5}" title="{L_COPY_TO_CLIPBOARD}">MD5:&nbsp;{updater.NEW_VERSION_MD5}</span><!-- ENDIF --></td>
<td class="row2"><b>{updater.NEW_VERSION_NUMBER}</b><!-- IF updater.NEW_VERSION_SIZE -->&nbsp;({L_SIZE}:&nbsp;{updater.NEW_VERSION_SIZE})<!-- ENDIF -->&nbsp;&middot;&nbsp;<a target="_blank" href="{updater.NEW_VERSION_DL_LINK}">{L_DOWNLOAD}</a>&nbsp;&middot;&nbsp;<a target="_blank" href="{updater.NEW_VERSION_LINK}">{L_CHANGELOG}</a><!-- IF updater.NEW_VERSION_HASH -->&nbsp;&middot;&nbsp;<span class="copyElement" data-clipboard-text="{updater.NEW_VERSION_HASH}" title="{L_COPY_TO_CLIPBOARD}">{updater.NEW_VERSION_HASH}</span><!-- ENDIF --></td>
</tr>
<!-- ENDIF -->
<!-- END updater -->

View file

@ -6,30 +6,6 @@
</ul>
<br/>
<h1 class="pagetitle">{L_BT_FLIST_ANNOUNCERS_LIST}</h1>
<table class="forumline">
<thead>
<tr>
<th>#</th>
<th>{L_BT_FLIST_ANNOUNCERS}</th>
</tr>
</thead>
<!-- BEGIN announcers -->
<tbody>
<tr class="{announcers.ROW_CLASS} tCenter">
<td>{announcers.ROW_NUMBER}</td>
<td>{announcers.ANNOUNCER}</td>
</tr>
</tbody>
<!-- END announcers -->
<tfoot>
<tr>
<td class="catBottom warnColor1" colspan="2">{L_BT_FLIST_ANNOUNCERS_NOTICE}</td>
</tr>
</tfoot>
</table>
<br/>
<h1 class="pagetitle">{L_BT_FLIST}</h1>
<table class="forumline">
<thead>

View file

@ -1,5 +1,5 @@
<!DOCTYPE html>
<html lang="{$bb_cfg['default_lang']}">
<html dir="{USER_LANG_DIRECTION}" lang="{USER_LANG}">
<head>
<meta charset="{CONTENT_ENCODING}">
<meta http-equiv="X-UA-Compatible" content="IE=Edge">

View file

@ -565,6 +565,7 @@ for ($i = 0; $i < $total_posts; $i++) {
$poster_from = ($postrow[$i]['user_from'] && !$poster_guest) ? $postrow[$i]['user_from'] : '';
$poster_joined = !$poster_guest ? $lang['JOINED'] . ': ' . bb_date($postrow[$i]['user_regdate'], 'Y-m-d H:i') : '';
$poster_longevity = !$poster_guest ? delta_time($postrow[$i]['user_regdate']) : '';
$poster_birthday = $postrow[$i]['user_birthday']->format('Y-m-d');
$post_id = $postrow[$i]['post_id'];
$mc_type = (int)$postrow[$i]['mc_type'];
$mc_comment = $postrow[$i]['mc_comment'];
@ -715,7 +716,7 @@ for ($i = 0; $i < $total_posts; $i++) {
'DELETE' => $delpost_btn,
'IP' => $ip_btn,
'POSTER_BIRTHDAY' => user_birthday_icon($postrow[$i]['user_birthday'], $postrow[$i]['user_id']),
'POSTER_BIRTHDAY' => user_birthday_icon($poster_birthday, $postrow[$i]['user_id']),
'MC_COMMENT' => $mc_type ? bbcode2html($mc_comment) : '',
'MC_BBCODE' => $mc_type ? $mc_comment : '',