Compare commits

...

46 commits

Author SHA1 Message Date
Roman Kelesidis
07e35c0205
release: v2.4.11 🦚
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
2025-08-06 10:23:47 +03:00
Roman Kelesidis
5ff296f83b
chore: Some minor improvements (#2076) 2025-08-06 10:19:23 +03:00
Roman Kelesidis
abb2b242b7
fix(Attach.php): Trying to access array offset on value of type null (#2075) 2025-08-06 10:16:48 +03:00
Roman Kelesidis
d690447cdb
fix(ACP): A non-numeric value encountered for stats (#2073)
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
2025-08-03 20:01:55 +03:00
Roman Kelesidis
7c6ab0eed4
feat: Add clear button for file upload input in posting_attach.tpl (#2072) 2025-08-03 18:48:17 +03:00
Roman Kelesidis
eecfe1a951
feat: Prevent robots indexing for private topics (#2071)
Some checks are pending
PHPMD / Run PHPMD scanning (push) Waiting to run
Continuous Integration / Nightly builds 📦 (push) Waiting to run
Continuous Integration / 🎉 Deploy (push) Waiting to run
2025-08-03 14:51:18 +03:00
Roman Kelesidis
3eba11f26b
fix: Prevent showing meta description if defined HAS_DIED (#2070)
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-08-03 04:47:31 +03:00
Roman Kelesidis
d12e6ba922
deps: Replace belomaxorka/captcha with gregwar/captcha (#2069)
Some checks failed
Continuous Integration / 🎉 Deploy (push) Has been cancelled
PHPMD / Run PHPMD scanning (push) Has been cancelled
Continuous Integration / Nightly builds 📦 (push) Has been cancelled
2025-07-31 11:02:34 +03:00
Roman Kelesidis
e3eb22e2d8
chore: Some minor improvements (#2068) 2025-07-31 10:48:01 +03:00
Roman Kelesidis
7e38c5b63c
feat(view_torrent.php): Added checking auth to download (#2067)
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
* feat(view_torrent.php): Added checking auth to download

* Update view_torrent.php
2025-07-30 19:41:50 +03:00
Roman Kelesidis
efd85eef4a
fix: Make Ajax::$action property nullable to handle missing POST parameter (#2066)
## Problem
When calling ajax.php without passing the 'action' parameter, PHP throws a TypeError:
`Cannot assign null to property TorrentPier\Ajax::$action of type string`

## Solution
Changed the `$action` property type from `string` to `?string` to allow null values when the POST parameter is not provided.

## Changes
- Changed `public string $action;` to `public ?string $action;`
2025-07-30 18:59:02 +03:00
Roman Kelesidis
57a9f3f7c6
feat: Added check for frozen torrent in playback_m3u.php (#2065)
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-30 12:06:58 +03:00
Roman Kelesidis
07399fc00d
feat: Add option to use original torrent filenames for downloads (#2064)
* feat: Add option to use original torrent filenames for downloads

* Update displaying_torrent.php
2025-07-30 10:14:00 +03:00
Roman Kelesidis
e1337ef5bc
feat(vote topic): Improved functionality & implemented caching (#2063)
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
* feat(vote topic): Improved functionality & implemented caching

* Update thanks.php

* Update thanks.php

* Update thanks.php

* Update thanks.php

* Update thanks.php

* Update thanks.php

* Update thanks.php

* Update thanks.php

* Update thanks.php
2025-07-29 22:16:46 +03:00
Roman Kelesidis
f80cad0c6f
feat(log action): Show torrent delete action (#2061)
* feat(log action): Show `torrent delete` action

* Update Torrent.php

* Update admin_log.php
2025-07-28 20:15:14 +03:00
Roman Kelesidis
66c01a591f
feat(log action): Show torrent register action (#2060)
* feat(log action): Show torrent register action

* Update main.php

* Update admin_log.php
2025-07-28 19:40:42 +03:00
Roman Kelesidis
a863a61941
chore: Added pull request template & updated workflow (#2052) 2025-07-20 22:06:38 +03:00
Roman Kelesidis
bb992fd81b
refactor(admin): Remove redundant dir and lang attributes from html tag (#2051) 2025-07-18 18:04:18 +03:00
Roman Kelesidis
dd64236da1
feat: Added check for demo-mode in admin_robots.php and admin_sitemap.php (#2046)
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
* feat: Added check for demo-mode in `admin_robots.php` and `admin_sitemap.php`

* Update ci.yml
2025-07-16 10:10:39 +03:00
Roman Kelesidis
c27d4373d6
release: v2.4.10
Some checks failed
Continuous Integration / Nightly builds 📦 (push) Has been cancelled
PHPMD / Run PHPMD scanning (push) Has been cancelled
2025-07-03 10:53:59 +03:00
Roman Kelesidis
9024640d59
feat(lang): Added RTL languages support (#2031) 2025-07-03 10:35:30 +03:00
Roman Kelesidis
e6976721dc
revert: "refactor: Moved Select class into Legacy\Common (#1846)"
This reverts commit bd0ef063fa.
2025-07-03 10:10:48 +03:00
Roman Kelesidis
695864ef69
feat: Restore some deprecated code for backward compatibility (#2028)
Some checks are pending
Continuous Integration / Nightly builds 📦 (push) Waiting to run
PHPMD / Run PHPMD scanning (push) Waiting to run
* feat: Restore some deprecated code for backward compatibility

* feat: Restore some constants

* feat: Restore `commify()` function

* feat: Restored functions: `bb_ltrim`, `bb_rtrim`, `get_db_stat`

* feat: Restore `bb_realpath`

* Update functions.php

* feat: Restore `AJAX_HTML_DIR` constant

* Update defines.php

* Update attach_maintenance.php

* Update viewtopic.php
2025-07-02 12:46:27 +03:00
Roman Kelesidis
90121aa21d
release: v2.4.9 2025-07-02 10:34:18 +03:00
Roman Kelesidis
68403760c1
refactor(TorrentFileList): Reduce duplication in root directory unset logic (#2027) 2025-07-02 10:31:07 +03:00
Roman Kelesidis
57d0d59b53
feat(updater): Added exceptions logging (#2026)
* feat(updater): Added exceptions logging

* refactor(updater): Use `sha256` hash if available
2025-07-02 10:16:54 +03:00
Roman Kelesidis
76b191ff41
release: v2.4.8
Some checks failed
Continuous Integration / Nightly builds 📦 (push) Has been cancelled
PHPMD / Run PHPMD scanning (push) Has been cancelled
2025-06-30 10:48:29 +03:00
Roman Kelesidis
a5fbc2ffc7
fix(TorrentFileList): Avoid array_merge reindexing for numeric folder names (#2014)
Some checks are pending
Continuous Integration / Nightly builds 📦 (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:01:20 +03:00
Roman Kelesidis
c2cbc77b14
refactor: Use DEFAULT_CHARSET constant instead of hardcoded string (#2011)
Some checks failed
Continuous Integration / Nightly builds 📦 (push) Has been cancelled
PHPMD / Run PHPMD scanning (push) Has been cancelled
2025-06-26 13:31:41 +03:00
Roman Kelesidis
134b3dfa5c
fix(redirect): add no-cache headers to prevent browser caching of redirects (#2010) 2025-06-26 13:07:42 +03:00
Roman Kelesidis
986d198aaf
release: v2.4.7 2025-06-24 13:23:52 +03:00
Roman Kelesidis
12ce6e783e
fix(ip-api): Add error handling and logging for freeipapi.com requests (#2006) 2025-06-24 13:18:35 +03:00
Roman Kelesidis
8c161ceae0
fix(filelist): Undefined property: FileTree::$length when v2 torrent only (#2004) 2025-06-24 13:16:04 +03:00
belomaxorka
896cf6c3d6 changelog: Update CHANGELOG.md 📖
Some checks failed
Continuous Integration / Nightly builds 📦 (push) Has been cancelled
PHPMD / Run PHPMD scanning (push) Has been cancelled
2025-06-20 06:12:19 +00:00
Roman Kelesidis
dc64426574
docs: Changed nightly.link url in README.md (#1977)
Some checks are pending
Continuous Integration / Nightly builds 📦 (push) Waiting to run
PHPMD / Run PHPMD scanning (push) Waiting to run
2025-06-19 18:34:15 +03:00
Roman Kelesidis
b7bc7f9166
docs: Updated Requirements sections in README.md (#1975) 2025-06-19 14:52:07 +03:00
Roman Kelesidis
403fcf2aca
docs: Fixed some typos in README.md (#1974) 2025-06-19 14:47:06 +03:00
Roman Kelesidis
de9f5e2cb1
release: v2.4.6 🦜 2025-06-19 11:19:30 +03:00
Roman Kelesidis
6a1d682385
fix: Duplicate column SQL query issues in viewtopic.php (#1973)
Co-authored-by: Yury Pikhtarev <exileum@icloud.com>
2025-06-19 11:16:17 +03:00
Roman Kelesidis
faf3d79192
fix(sql): Resolve only_full_group_by compatibility issues in tracker cleanup
- Replace non-aggregated 'seeder' column with MAX(seeder) in GROUP BY query
- Remove ORDER BY clause incompatible with GROUP BY in seeder update query

Fixes MySQL 5.7+ strict SQL mode errors in tr_cleanup_and_dlstat cron job.

Co-Authored-By: Yury Pikhtarev <exileum@icloud.com>
2025-06-19 11:11:35 +03:00
Roman Kelesidis
7dc69ba699
chore: Changed active branch name in _release.php (#1972)
* chore: Changed active branch name in `_release.php`

* Update _release.php
2025-06-19 11:08:58 +03:00
Roman Kelesidis
2a8b6daecf
fix: SQL queries in online_userlist.php to use MAX() for session data and adjusted GROUP BY clause for better accuracy (#1971)
Co-authored-by: Yury Pikhtarev <exileum@icloud.com>
2025-06-19 11:05:23 +03:00
Roman Kelesidis
7d9594eeda
chore(cliff): Add conventional commit prefix to changelog message (#1970) 2025-06-19 11:01:52 +03:00
Roman Kelesidis
15f9948403
fix(installer): Strip protocol from TP_HOST to keep only hostname (#1969) 2025-06-19 10:59:18 +03:00
belomaxorka
ce1f35c2b5 Update CHANGELOG.md 📖 2025-06-19 07:52:50 +00:00
Roman Kelesidis
a8e252f64f
chore: Changed branch name from master to v2.4 (#1968) 2025-06-19 10:50:26 +03:00
59 changed files with 724 additions and 303 deletions

49
.github/PULL_REQUEST_TEMPLATE.md vendored Normal file
View file

@ -0,0 +1,49 @@
## 🚀 Whats this Pull Request?
Please describe the purpose and context of this PR. Is it a bugfix, a feature, a refactor, or maintenance?
- Type:
- [ ] Bugfix
- [ ] Feature
- [ ] Refactor
- [ ] Chore
- [ ] Other
- Related Issue(s): Closes #XXXX, Implements #XXXX
## ✅ Whats Changed?
Briefly summarize the changes youve made.
- ...
- ...
- ...
## 🔬 How to Test
Describe how a maintainer or reviewer can manually verify your changes.
1. ...
2. ...
3. ...
## 🧪 Tests
- [ ] Unit tests added or updated
- [ ] No tests needed
- [ ] Not applicable
## 📚 Documentation
- [ ] Updated relevant docs
- [ ] No docs needed
- [ ] Not applicable
## 💡 Additional Notes
- Compatibility concerns? (e.g., PHP version, tracker behavior, database migrations)
- Any known limitations?
- Anything reviewers should pay special attention to?
## 📸 UI / Frontend Changes (if applicable)
_Add screenshots, videos, or gif demos if you made UI changes._

View file

@ -3,7 +3,7 @@ name: Continuous Integration
on:
push:
branches:
- master
- v2.4
jobs:
nightly:
@ -44,17 +44,17 @@ jobs:
- name: Upload Archive 📤
uses: actions/upload-artifact@v4
with:
name: TorrentPier-master
name: TorrentPier-v2.4
path: ${{ steps.create-zip.outputs.ZIP_NAME }}
deploy:
name: 🎉 Deploy
runs-on: ubuntu-22.04
steps:
- name: 🚚 Get latest code
- name: Checkout code 🗳
uses: actions/checkout@v4
- name: 🔩 Setup PHP
- name: Setup PHP 🔩
uses: shivammathur/setup-php@v2
with:
php-version: '8.1'
@ -62,10 +62,10 @@ jobs:
- name: Update composer.lock file
run: composer update --no-install
- name: 🖇 Install Composer dependencies
- name: Install Composer dependencies 🪚
run: composer install --no-progress --prefer-dist --optimize-autoloader
- name: 📂 Sync files
- name: Sync files 📂
uses: SamKirkland/FTP-Deploy-Action@v4.3.5
with:
server: ${{ secrets.FTP_SERVER }}

View file

@ -17,10 +17,10 @@ name: PHPMD
on:
push:
branches: [ "master" ]
branches: [ "v2.4" ]
pull_request:
# The branches below must be a subset of the branches above
branches: [ "master" ]
branches: [ "v2.4" ]
schedule:
- cron: '40 0 * * 3'

View file

@ -14,7 +14,7 @@ jobs:
uses: actions/checkout@v4
with:
fetch-depth: 0
ref: master
ref: v2.4
token: ${{ secrets.REPO_TOKEN }}
- name: Generate a changelog
@ -32,10 +32,10 @@ jobs:
- name: Commit changelog
run: |
git checkout master
git checkout v2.4
git config --local user.name 'belomaxorka'
git config --local user.email 'roman25052006.kelesh@gmail.com'
set +e
git add CHANGELOG.md
git commit -m "Update CHANGELOG.md 📖"
git push https://${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}.git master
git commit -m "changelog: Update CHANGELOG.md 📖"
git push https://${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}.git v2.4

View file

@ -2,7 +2,99 @@
# 📖 Change Log
## [nightly](https://nightly.link/torrentpier/torrentpier/workflows/ci/master/TorrentPier-master)
## [v2.4.11](https://github.com/torrentpier/torrentpier/compare/v2.4.10..v2.4.11) (2025-08-06)
### 🚀 Features
- *(log action)* Show `torrent delete` action ([#2061](https://github.com/torrentpier/torrentpier/pull/2061)) - ([f80cad0](https://github.com/torrentpier/torrentpier/commit/f80cad0c6f8606ae3314e6dc4962f027f12798a3))
- *(log action)* Show torrent register action ([#2060](https://github.com/torrentpier/torrentpier/pull/2060)) - ([66c01a5](https://github.com/torrentpier/torrentpier/commit/66c01a591f8618e911fd042cc23bf36902de8a38))
- *(view_torrent.php)* Added checking auth to download ([#2067](https://github.com/torrentpier/torrentpier/pull/2067)) - ([7e38c5b](https://github.com/torrentpier/torrentpier/commit/7e38c5b63cacaec4c974a423fd1a6c0352529fd6))
- *(vote topic)* Improved functionality & implemented caching ([#2063](https://github.com/torrentpier/torrentpier/pull/2063)) - ([e1337ef](https://github.com/torrentpier/torrentpier/commit/e1337ef5bc9cd7741d40cd645059019b5b5b576a))
- Add clear button for file upload input in `posting_attach.tpl` ([#2072](https://github.com/torrentpier/torrentpier/pull/2072)) - ([7c6ab0e](https://github.com/torrentpier/torrentpier/commit/7c6ab0eed4691fa0f1bd29f9e19f956fdb16b43e))
- Prevent robots indexing for private topics ([#2071](https://github.com/torrentpier/torrentpier/pull/2071)) - ([eecfe1a](https://github.com/torrentpier/torrentpier/commit/eecfe1a9515034d263a49f84210d3d32430253be))
- Added check for frozen torrent in `playback_m3u.php` ([#2065](https://github.com/torrentpier/torrentpier/pull/2065)) - ([57a9f3f](https://github.com/torrentpier/torrentpier/commit/57a9f3f7c67ca5c8db2218269a465bfc2d4644b4))
- Add option to use original torrent filenames for downloads ([#2064](https://github.com/torrentpier/torrentpier/pull/2064)) - ([07399fc](https://github.com/torrentpier/torrentpier/commit/07399fc00df214d1ad863e8a893495ace26ff7fa))
- Added check for demo-mode in `admin_robots.php` and `admin_sitemap.php` ([#2046](https://github.com/torrentpier/torrentpier/pull/2046)) - ([dd64236](https://github.com/torrentpier/torrentpier/commit/dd64236da12f7d76e0b548601c86f38164a71725))
### 🐛 Bug Fixes
- *(ACP)* A non-numeric value encountered for stats ([#2073](https://github.com/torrentpier/torrentpier/pull/2073)) - ([d690447](https://github.com/torrentpier/torrentpier/commit/d690447cdbdf7f07de9a539ef752dab69a205390))
- *(Attach.php)* Trying to access array offset on value of type null ([#2075](https://github.com/torrentpier/torrentpier/pull/2075)) - ([abb2b24](https://github.com/torrentpier/torrentpier/commit/abb2b242b75d1acc41e2d901f8b558e90a3b35d7))
- Prevent showing meta description if defined `HAS_DIED` ([#2070](https://github.com/torrentpier/torrentpier/pull/2070)) - ([3eba11f](https://github.com/torrentpier/torrentpier/commit/3eba11f26b3432ef7446de5bc938cbcbfa4932f5))
- Make `Ajax::$action` property nullable to handle missing POST parameter ([#2066](https://github.com/torrentpier/torrentpier/pull/2066)) - ([efd85ee](https://github.com/torrentpier/torrentpier/commit/efd85eef4ad69e5b53be3f3d0ea75d267d0b664c))
### 📦 Dependencies
- Replace `belomaxorka/captcha` with `gregwar/captcha` ([#2069](https://github.com/torrentpier/torrentpier/pull/2069)) - ([d12e6ba](https://github.com/torrentpier/torrentpier/commit/d12e6ba922d38c5c24380c58c037d405af5c38c9))
### 🚜 Refactor
- *(admin)* Remove redundant `dir` and `lang` attributes from html tag ([#2051](https://github.com/torrentpier/torrentpier/pull/2051)) - ([bb992fd](https://github.com/torrentpier/torrentpier/commit/bb992fd81b0fede511ab566fdc7bf4d25b924ae2))
### ⚙️ Miscellaneous
- Some minor improvements ([#2076](https://github.com/torrentpier/torrentpier/pull/2076)) - ([5ff296f](https://github.com/torrentpier/torrentpier/commit/5ff296f83be87a0cc5607fd352d62321819b0e03))
- Some minor improvements ([#2068](https://github.com/torrentpier/torrentpier/pull/2068)) - ([e3eb22e](https://github.com/torrentpier/torrentpier/commit/e3eb22e2d8d7b3bd2413cfcb1badfbd81ee9dc54))
- Added pull request template & updated workflow ([#2052](https://github.com/torrentpier/torrentpier/pull/2052)) - ([a863a61](https://github.com/torrentpier/torrentpier/commit/a863a619419881e831a6556fa5e77dae746ff031))
## [v2.4.10](https://github.com/torrentpier/torrentpier/compare/v2.4.9..v2.4.10) (2025-07-03)
### 🚀 Features
- *(lang)* Added `RTL` languages support ([#2031](https://github.com/torrentpier/torrentpier/pull/2031)) - ([9024640](https://github.com/torrentpier/torrentpier/commit/9024640d59428cc164fc6b10246ee40e333ec8e9))
- Restore some deprecated code for backward compatibility ([#2028](https://github.com/torrentpier/torrentpier/pull/2028)) - ([695864e](https://github.com/torrentpier/torrentpier/commit/695864ef6995a3c7b16ade822036c23908fc3aaf))
### ◀️ Revert
- "refactor: Moved `Select` class into `Legacy\Common` ([#1846](https://github.com/torrentpier/torrentpier/pull/1846))" - ([e697672](https://github.com/torrentpier/torrentpier/commit/e6976721dc2f6cde6a09b6a55e2f37e5f43f5932))
## [v2.4.9](https://github.com/torrentpier/torrentpier/compare/v2.4.8..v2.4.9) (2025-07-02)
### 🚀 Features
- *(updater)* Added exceptions logging ([#2026](https://github.com/torrentpier/torrentpier/pull/2026)) - ([57d0d59](https://github.com/torrentpier/torrentpier/commit/57d0d59b5379600f63cf7d5f774e3ec000e39473))
### 🚜 Refactor
- *(TorrentFileList)* Reduce duplication in root directory unset logic ([#2027](https://github.com/torrentpier/torrentpier/pull/2027)) - ([6840376](https://github.com/torrentpier/torrentpier/commit/68403760c1e9e01133536bb5021b08d9101d323e))
## [v2.4.8](https://github.com/torrentpier/torrentpier/compare/v2.4.7..v2.4.8) (2025-06-30)
### 🐛 Bug Fixes
- *(TorrentFileList)* Avoid `array_merge` reindexing for numeric folder names ([#2014](https://github.com/torrentpier/torrentpier/pull/2014)) - ([a5fbc2f](https://github.com/torrentpier/torrentpier/commit/a5fbc2ffc7389c30ffbb98d253ff8e936528fec1))
- *(redirect)* Add no-cache headers to prevent browser caching of redirects ([#2010](https://github.com/torrentpier/torrentpier/pull/2010)) - ([134b3df](https://github.com/torrentpier/torrentpier/commit/134b3dfa5cd8e8e5ce3f10912b58afecc4f118e0))
### 🚜 Refactor
- Use `DEFAULT_CHARSET` constant instead of hardcoded string ([#2011](https://github.com/torrentpier/torrentpier/pull/2011)) - ([c2cbc77](https://github.com/torrentpier/torrentpier/commit/c2cbc77b144057d3d37cd58b635eabc6280fe137))
## [v2.4.7](https://github.com/torrentpier/torrentpier/compare/v2.4.6..v2.4.7) (2025-06-24)
### 🐛 Bug Fixes
- *(filelist)* `Undefined property: FileTree::$length` when v2 torrent only ([#2004](https://github.com/torrentpier/torrentpier/pull/2004)) - ([8c161ce](https://github.com/torrentpier/torrentpier/commit/8c161ceae0f80a3ffe57da06dbadd1f9a53272f3))
- *(ip-api)* Add error handling and logging for freeipapi.com requests ([#2006](https://github.com/torrentpier/torrentpier/pull/2006)) - ([12ce6e7](https://github.com/torrentpier/torrentpier/commit/12ce6e783ec97a6c3df0e11273944a3e6cfe466d))
### 📚 Documentation
- Changed nightly.link url in `README.md` ([#1977](https://github.com/torrentpier/torrentpier/pull/1977)) - ([dc64426](https://github.com/torrentpier/torrentpier/commit/dc64426574087e69bc7e056a89ff367438e37344))
- Updated `Requirements` sections in README.md ([#1975](https://github.com/torrentpier/torrentpier/pull/1975)) - ([b7bc7f9](https://github.com/torrentpier/torrentpier/commit/b7bc7f91662b050082843d18b03376dc67efa3e0))
- Fixed some typos in `README.md` ([#1974](https://github.com/torrentpier/torrentpier/pull/1974)) - ([403fcf2](https://github.com/torrentpier/torrentpier/commit/403fcf2aca4b2d70bfca194107f4b4f5c5ba7f03))
## [v2.4.6](https://github.com/torrentpier/torrentpier/compare/v2.4.6-alpha.4..v2.4.6) (2025-06-19)
### 🐛 Bug Fixes
- *(installer)* Strip protocol from TP_HOST to keep only hostname ([#1969](https://github.com/torrentpier/torrentpier/pull/1969)) - ([15f9948](https://github.com/torrentpier/torrentpier/commit/15f994840331b135cd64c0cd61de95fecfc29db8))
- *(sql)* Resolve `only_full_group_by` compatibility issues in tracker cleanup - ([faf3d79](https://github.com/torrentpier/torrentpier/commit/faf3d7919249d869d8ca8d41617dd4356dc0ac48))
- Duplicate column SQL query issues in `viewtopic.php` ([#1973](https://github.com/torrentpier/torrentpier/pull/1973)) - ([6a1d682](https://github.com/torrentpier/torrentpier/commit/6a1d6823856dd7c3cef45bea2681828526d1b9f8))
- SQL queries in online_userlist.php to use MAX() for session data and adjusted GROUP BY clause for better accuracy ([#1971](https://github.com/torrentpier/torrentpier/pull/1971)) - ([2a8b6da](https://github.com/torrentpier/torrentpier/commit/2a8b6daecf63752b8a852c950e9a7fd08e17f57c))
### 📦 Dependencies
@ -11,7 +103,14 @@
### ⚙️ Miscellaneous
- *(_release.php)* Finally! Removed some useless params ([#1947](https://github.com/torrentpier/torrentpier/pull/1947)) - ([9c7d270](https://github.com/torrentpier/torrentpier/commit/9c7d270598c0153fb82f4b7ad96f5b59399b2159))
- *(cliff)* Add conventional commit prefix to changelog message ([#1970](https://github.com/torrentpier/torrentpier/pull/1970)) - ([7d9594e](https://github.com/torrentpier/torrentpier/commit/7d9594eedab1b2c81d888dfba68ded1b8a142282))
- Changed active branch name in `_release.php` ([#1972](https://github.com/torrentpier/torrentpier/pull/1972)) - ([7dc69ba](https://github.com/torrentpier/torrentpier/commit/7dc69ba699c75d87c709a799291c4b544b3e92aa))
- Changed branch name from `master` to `v2.4` ([#1968](https://github.com/torrentpier/torrentpier/pull/1968)) - ([a8e252f](https://github.com/torrentpier/torrentpier/commit/a8e252f64f7205b7bb24739ab637144c6fb022d6))
## New Contributors ❤️
* @belomaxorka made their first contribution
* @dependabot[bot] made their first contribution in [#1948](https://github.com/torrentpier/torrentpier/pull/1948)
## [v2.4.6-alpha.4](https://github.com/torrentpier/torrentpier/compare/v2.4.6-alpha.3..v2.4.6-alpha.4) (2025-06-13)

View file

@ -9,25 +9,25 @@
<a href="https://github.com/torrentpier/torrentpier/blob/master/LICENSE"><img src="https://img.shields.io/github/license/torrentpier/torrentpier" alt="License"></a>
<a href="https://packagist.org/packages/torrentpier/torrentpier"><img src="https://img.shields.io/packagist/stars/torrentpier/torrentpier" alt="Stars Packagist"></a>
<a href="https://crowdin.com/project/torrentpier"><img src="https://badges.crowdin.net/torrentpier/localized.svg" alt="Crowdin"></a>
<a href="https://nightly.link/torrentpier/torrentpier/workflows/ci/master/TorrentPier-master"><img src="https://img.shields.io/badge/Nightly%20release-gray?logo=hackthebox&logoColor=fff" alt="TorrentPier nightly"></a>
<a href="https://nightly.link/torrentpier/torrentpier/workflows/ci/v2.4/TorrentPier-v2.4"><img src="https://img.shields.io/badge/Nightly%20release-gray?logo=hackthebox&logoColor=fff" alt="TorrentPier nightly"></a>
<a href="https://packagist.org/packages/torrentpier/torrentpier"><img src="https://img.shields.io/packagist/dt/torrentpier/torrentpier" alt="Downloads"></a>
<a href="https://packagist.org/packages/torrentpier/torrentpier"><img src="https://img.shields.io/packagist/v/torrentpier/torrentpier" alt="Version"></a>
<a href="https://github.com/torrentpier/torrentpier/releases"><img src="https://img.shields.io/github/release-date/torrentpier/torrentpier" alt="Last release"></a>
<img src="https://img.shields.io/github/repo-size/torrentpier/torrentpier" alt="Size">
<a href="https://github.com/SamKirkland/FTP-Deploy-Action"><img src="https://img.shields.io/badge/Deployed to TorrentPier Demo with-FTP DEPLOY ACTION-%3CCOLOR%3E?color=2b9348" alt="Deployed to TorrentPier Demo with FTP Deploy Action"></a>
<a href="https://github.com/SamKirkland/FTP-Deploy-Action"><img src="https://img.shields.io/badge/Deployed%20with-FTP%20DEPLOY%20ACTION-2b9348" alt="Deployed with FTP Deploy Action"></a>
</p>
## 🐂 About TorrentPier
TorrentPier — bull-powered BitTorrent Public/Private tracker engine, written in PHP. High speed, simple modifications, load-balanced
architecture. In addition, we have a very helpful
TorrentPier — bull-powered BitTorrent Public/Private tracker engine, written in PHP. High speed, simple modifications, load-balanced
architecture. In addition, we have a very helpful
[official support forum](https://torrentpier.com), where it's possible to get support and download modifications for the engine.
## 🌈 Current status
TorrentPier is currently in active development. The goal is to remove all legacy code and rewrite the existing code to
modern specifications. If you want delve deep into the code, check our [issues](https://github.com/torrentpier/torrentpier/issues)
and go from there. The documentation will be translated to english in the near future, currently russian is the main language of it.
TorrentPier is currently in active development. The goal is to remove all legacy code and rewrite the existing code to
modern specifications. If you want to delve deep into the code, check our [issues](https://github.com/torrentpier/torrentpier/issues)
and go from there. The documentation will be translated to English in the near future; currently Russian is the main language.
## ✨ Features
* Rich forum with browsing/moderation tools
@ -40,7 +40,7 @@ and go from there. The documentation will be translated to english in the near f
* Bonus points
* Polling system
* PM/DM system
* Multilingual support (Russian and English is currently fully supported, with others in the future)
* Multilingual support (Russian and English are currently fully supported, with others in the future)
* Atom/RSS feeds
* ... and so MUCH MORE!
@ -56,7 +56,7 @@ and go from there. The documentation will be translated to english in the near f
## 🔧 Requirements
* Apache / nginx ([example config](install/nginx.conf)) / caddy ([example config](install/Caddyfile))
* MySQL 5.5.3 or above / MariaDB 10.0 or above / Percona
* MySQL 5.5.3 or above (including MySQL 8.0+) / MariaDB 10.0 or above / Percona
* PHP: 8.1 / 8.2 / 8.3 / 8.4
* PHP Extensions: mbstring, gd, bcmath, intl, tidy (optional), xml, xmlwriter
* Crontab (Recommended)
@ -103,9 +103,9 @@ Check out our [autoinstall](https://github.com/torrentpier/autoinstall) reposito
5. Create a database and import the dump located at `install/sql/mysql.sql`
6. Edit database configuration settings in the environment (`.env.example`), after, rename to `.env`
7. Provide write permissions to the specified folders:
* `data/avatars`, `data/uploads`, `data/uploads/thumbs`
* `internal_data/atom`, `internal_data/cache`, `internal_data/log`, `internal_data/triggers`
* `sitemap`
* `data/avatars`, `data/uploads`, `data/uploads/thumbs`
* `internal_data/atom`, `internal_data/cache`, `internal_data/log`, `internal_data/triggers`
* `sitemap`
8. Voila! ✨
> [!IMPORTANT]
@ -114,8 +114,8 @@ Check out our [autoinstall](https://github.com/torrentpier/autoinstall) reposito
### Additional steps 👣
1. Edit these files:
* `favicon.png` (change to your own)
* `robots.txt` (change the addresses in lines `Host` and `Sitemap` to your own)
* `favicon.png` (change to your own)
* `robots.txt` (change the addresses in lines `Host` and `Sitemap` to your own)
2. Log in to the forum using the **admin/admin** login/password, and finish setting up via admin panel. Don't forget to change your password!
## 🔐 Security vulnerabilities
@ -124,13 +124,13 @@ If you discover a security vulnerability within TorrentPier, please follow our [
## 📌 Our recommendations
* *It's recommended to run `cron.php`.* - For significant tracker speed increase it ay be required to replace the built-in cron.php in operating system daemon.
* *It's recommended to run `cron.php`.* - For significant tracker speed increase it may be required to replace the built-in cron.php with an operating system daemon.
* *Local configuration copy.* - You can override the settings using the local configuration file `library/config.local.php`.
## 💚 Contributing / Contributors
Please read our [contributing policy](CONTRIBUTING.md) and [code of conduct](CODE_OF_CONDUCT.md) for details, and the process for
submitting pull requests to us. But we are always ready to renew your pull-request for compliance with
Please read our [contributing policy](CONTRIBUTING.md) and [code of conduct](CODE_OF_CONDUCT.md) for details, and the process for
submitting pull requests to us. But we are always ready to review your pull-request for compliance with
these requirements. Just send it!
<a href="https://github.com/torrentpier/torrentpier/graphs/contributors">
@ -141,7 +141,7 @@ Made with [contrib.rocks](https://contrib.rocks).
## 💞 Sponsoring
Support this project by becoming a sponsor or a backer.
Support this project by becoming a sponsor or a backer.
[![OpenCollective sponsors](https://opencollective.com/torrentpier/sponsors/badge.svg)](https://opencollective.com/torrentpier)
[![OpenCollective backers](https://opencollective.com/torrentpier/backers/badge.svg)](https://opencollective.com/torrentpier)
@ -164,7 +164,7 @@ Support this project by becoming a sponsor or a backer.
## 📦 Versioning
We use [SemVer](http://semver.org/) for versioning. For the versions available, see the [tags on this repository](https://github.com/torrentpier/torrentpier/tags).
We use [SemVer](http://semver.org/) for versioning. For the versions available, see the [tags on this repository](https://github.com/torrentpier/torrentpier/tags).
## 📖 License

View file

@ -124,7 +124,8 @@ runProcess("git tag -a \"$version\" -m \"Release $version\"");
runProcess("git tag -v \"$version\"");
// Git push
runProcess("git push origin master");
runProcess("git checkout v2.4");
runProcess("git push origin v2.4");
runProcess("git push origin $version");
out("\n- Release $version has been successfully prepared, committed and pushed!", 'success');

View file

@ -136,8 +136,8 @@ switch ($mode) {
'POSTS_PER_PAGE' => $new['posts_per_page'],
'HOT_TOPIC' => $new['hot_threshold'],
'DEFAULT_DATEFORMAT' => $new['default_dateformat'],
'LANG_SELECT' => \TorrentPier\Legacy\Common\Select::language($new['default_lang'], 'default_lang'),
'TIMEZONE_SELECT' => \TorrentPier\Legacy\Common\Select::timezone($new['board_timezone'], 'board_timezone'),
'LANG_SELECT' => \TorrentPier\Legacy\Select::language($new['default_lang'], 'default_lang'),
'TIMEZONE_SELECT' => \TorrentPier\Legacy\Select::timezone($new['board_timezone'], 'board_timezone'),
'MAX_LOGIN_ATTEMPTS' => $new['max_login_attempts'],
'LOGIN_RESET_TIME' => $new['login_reset_time'],
'PRUNE_ENABLE' => (bool)$new['prune_enable'],

View file

@ -228,6 +228,8 @@ if ($log_rowset) {
case $log_type['mod_topic_change_tor_status']:
case $log_type['mod_topic_change_tor_type']:
case $log_type['mod_topic_tor_unregister']:
case $log_type['mod_topic_tor_register']:
case $log_type['mod_topic_tor_delete']:
case $log_type['mod_topic_renamed']:
case $log_type['mod_post_delete']:
case $log_type['mod_post_pin']:

View file

@ -16,8 +16,12 @@ require __DIR__ . '/pagestart.php';
$robots_file = BB_ROOT . 'robots.txt';
// Обработка сохранения
if (isset($_POST['save'])) {
// Check for demo mode
if (IN_DEMO_MODE) {
bb_die($lang['CANT_EDIT_IN_DEMO_MODE']);
}
$robots_txt = $_POST['robots_txt'] ?? '';
if (!is_writable($robots_file) && is_file($robots_file)) {

View file

@ -33,6 +33,10 @@ if (!$result = DB()->sql_query($sql)) {
}
if (isset($_POST['submit'])) {
// Check for demo mode
if (IN_DEMO_MODE) {
bb_die($lang['CANT_EDIT_IN_DEMO_MODE']);
}
if (!empty($new_params)) {
bb_update_config($new_params);
}

View file

@ -52,8 +52,8 @@ if (!isset($_REQUEST['dosearch'])) {
}
}
$language_list = \TorrentPier\Legacy\Common\Select::language('', 'language_type');
$timezone_list = \TorrentPier\Legacy\Common\Select::timezone('', 'timezone_type');
$language_list = \TorrentPier\Legacy\Select::language('', 'language_type');
$timezone_list = \TorrentPier\Legacy\Select::timezone('', 'timezone_type');
$sql = 'SELECT f.forum_id, f.forum_name, f.forum_parent, c.cat_id, c.cat_title
FROM ( ' . BB_FORUMS . ' AS f INNER JOIN ' . BB_CATEGORIES . ' AS c ON c.cat_id = f.cat_id )

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']
]);
}
@ -128,14 +128,14 @@ if (isset($_GET['pane']) && $_GET['pane'] == 'left') {
$topics_per_day = $total_topics;
}
if ($users_per_day > $total_users) {
if ((int)$users_per_day > $total_users) {
$users_per_day = $total_users;
}
$template->assign_vars([
'NUMBER_OF_POSTS' => $total_posts,
'NUMBER_OF_TOPICS' => $total_topics,
'NUMBER_OF_USERS' => $total_users,
'NUMBER_OF_POSTS' => commify($total_posts),
'NUMBER_OF_TOPICS' => commify($total_topics),
'NUMBER_OF_USERS' => commify($total_users),
'START_DATE' => $start_date,
'POSTS_PER_DAY' => $posts_per_day,
'TOPICS_PER_DAY' => $topics_per_day,

View file

@ -117,7 +117,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));
}
/**
@ -259,7 +259,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

@ -34,7 +34,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
@ -99,7 +99,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

@ -23,7 +23,7 @@ body = """
{%- endmacro -%}
{%- macro nightly_url() -%}
https://nightly.link/{{ remote.github.owner }}/{{ remote.github.repo }}/workflows/ci/master/TorrentPier-master
https://nightly.link/{{ remote.github.owner }}/{{ remote.github.repo }}/workflows/ci/v2.4/TorrentPier-v2.4
{%- endmacro -%}
{% macro print_commit(commit) -%}
@ -105,12 +105,12 @@ commit_parsers = [
{ message = "^refactor", group = "<!-- 2 -->🚜 Refactor" },
{ message = "^style", group = "<!-- 5 -->🎨 Styling" },
{ message = "^test", group = "<!-- 6 -->🧪 Testing" },
{ message = "^ignore|^release", skip = true },
{ message = "^ignore|^release|^changelog", skip = true },
{ message = "^chore|^ci|^misc", group = "<!-- 7 -->⚙️ Miscellaneous" },
{ body = ".*security", group = "<!-- 8 -->🛡️ Security" },
{ message = "^revert", group = "<!-- 9 -->◀️ Revert" },
{ message = "^crowdin|^crodwin", group = "<!-- 10 -->🈳 New translations" }, # crowdin pulls supporting
{ message = "^Composer", group = "<!-- 11 -->📦 Dependencies" }, # dependabot pulls supporting
{ message = "^Composer|^deps", group = "<!-- 11 -->📦 Dependencies" }, # dependabot pulls supporting
{ message = "^rem|^drop|^removed", group = "<!-- 12 -->🗑️ Removed" },
{ message = ".*", group = "<!-- 13 -->💼 Other" },
]

View file

@ -53,7 +53,7 @@
"arokettu/torrent-file": "^5.2.1",
"bugsnag/bugsnag": "^v3.29.1",
"claviska/simpleimage": "^4.0",
"belomaxorka/captcha": "1.*",
"gregwar/captcha": "1.*",
"egulias/email-validator": "^4.0.1",
"filp/whoops": "^2.15",
"z4kn4fein/php-semver": "^v3.0.0",

222
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": "2acad3dafd9fd57bc8c26303df22dd15",
"content-hash": "4a8e483526e6241286bf04937e1f4913",
"packages": [
{
"name": "arokettu/bencode",
@ -286,16 +286,16 @@
},
{
"name": "arokettu/torrent-file",
"version": "5.3.1",
"version": "5.3.2",
"source": {
"type": "git",
"url": "https://github.com/arokettu/torrent-file.git",
"reference": "650ed7109bcd01dd6c4f47d129f120eb1f82ca07"
"reference": "0fba9ed15b8f60beb33a590a36db9b97d28ce171"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/arokettu/torrent-file/zipball/650ed7109bcd01dd6c4f47d129f120eb1f82ca07",
"reference": "650ed7109bcd01dd6c4f47d129f120eb1f82ca07",
"url": "https://api.github.com/repos/arokettu/torrent-file/zipball/0fba9ed15b8f60beb33a590a36db9b97d28ce171",
"reference": "0fba9ed15b8f60beb33a590a36db9b97d28ce171",
"shasum": ""
},
"require": {
@ -313,9 +313,9 @@
"league/event": "^3.0",
"phpunit/phpunit": "^10.5.3",
"psy/psysh": "*",
"sandfox.dev/code-standard": "^1.2024.07.05",
"sandfox.dev/code-standard": "^1.2025.05.07",
"squizlabs/php_codesniffer": "*",
"vimeo/psalm": "^5.2"
"vimeo/psalm": "^5.2 | ^6"
},
"suggest": {
"ext-openssl": "for signature logic"
@ -351,7 +351,7 @@
"issues": "https://gitlab.com/sandfox/torrent-file/-/issues",
"source": "https://gitlab.com/sandfox/torrent-file"
},
"time": "2024-07-28T21:43:34+00:00"
"time": "2025-06-28T21:41:10+00:00"
},
{
"name": "arokettu/unsigned",
@ -411,88 +411,18 @@
},
"time": "2025-03-31T23:49:37+00:00"
},
{
"name": "belomaxorka/captcha",
"version": "v1.2.4",
"source": {
"type": "git",
"url": "https://github.com/belomaxorka/Captcha.git",
"reference": "db51723a9539b57ac3faff0211c117b4c55dbe23"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/belomaxorka/Captcha/zipball/db51723a9539b57ac3faff0211c117b4c55dbe23",
"reference": "db51723a9539b57ac3faff0211c117b4c55dbe23",
"shasum": ""
},
"require": {
"ext-fileinfo": "*",
"ext-gd": "*",
"ext-mbstring": "*",
"php": ">=5.3.0",
"symfony/finder": "*"
},
"require-dev": {
"phpunit/phpunit": "^4.8.35 || ^5.7.21 || ^6.4 || ^7.0 || ^8.0 || ^9.0"
},
"type": "library",
"autoload": {
"psr-4": {
"Gregwar\\": "src/Gregwar"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Grégoire Passault",
"email": "g.passault@gmail.com",
"homepage": "https://www.gregwar.com/",
"role": "Developer"
},
{
"name": "Jeremy Livingston",
"email": "jeremy.j.livingston@gmail.com"
},
{
"name": "belomaxorka",
"email": "roman25052006.kelesh@gmail.com",
"homepage": "https://belomaxorka.github.io/",
"role": "Developer"
}
],
"description": "Captcha generator",
"homepage": "https://github.com/belomaxorka/Captcha",
"keywords": [
"anti-bot",
"anti-spam",
"bot-protection",
"captcha",
"no-bot",
"obfuscation",
"security",
"spam",
"spam-protection"
],
"support": {
"source": "https://github.com/belomaxorka/Captcha/tree/v1.2.4"
},
"time": "2025-03-10T13:15:53+00:00"
},
{
"name": "bugsnag/bugsnag",
"version": "v3.29.3",
"version": "v3.30.0",
"source": {
"type": "git",
"url": "https://github.com/bugsnag/bugsnag-php.git",
"reference": "9d9aa665f5e9d24f45aad5114dbd2d861119febb"
"reference": "ea174966d8a09424d7963e1e0fe9d570b63ff98c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/bugsnag/bugsnag-php/zipball/9d9aa665f5e9d24f45aad5114dbd2d861119febb",
"reference": "9d9aa665f5e9d24f45aad5114dbd2d861119febb",
"url": "https://api.github.com/repos/bugsnag/bugsnag-php/zipball/ea174966d8a09424d7963e1e0fe9d570b63ff98c",
"reference": "ea174966d8a09424d7963e1e0fe9d570b63ff98c",
"shasum": ""
},
"require": {
@ -540,9 +470,9 @@
],
"support": {
"issues": "https://github.com/bugsnag/bugsnag-php/issues",
"source": "https://github.com/bugsnag/bugsnag-php/tree/v3.29.3"
"source": "https://github.com/bugsnag/bugsnag-php/tree/v3.30.0"
},
"time": "2025-03-06T12:03:07+00:00"
"time": "2025-07-08T15:15:58+00:00"
},
{
"name": "claviska/simpleimage",
@ -995,16 +925,16 @@
},
{
"name": "google/recaptcha",
"version": "1.3.0",
"version": "1.3.1",
"source": {
"type": "git",
"url": "https://github.com/google/recaptcha.git",
"reference": "d59a801e98a4e9174814a6d71bbc268dff1202df"
"reference": "56522c261d2e8c58ba416c90f81a4cd9f2ed89b9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/google/recaptcha/zipball/d59a801e98a4e9174814a6d71bbc268dff1202df",
"reference": "d59a801e98a4e9174814a6d71bbc268dff1202df",
"url": "https://api.github.com/repos/google/recaptcha/zipball/56522c261d2e8c58ba416c90f81a4cd9f2ed89b9",
"reference": "56522c261d2e8c58ba416c90f81a4cd9f2ed89b9",
"shasum": ""
},
"require": {
@ -1043,7 +973,7 @@
"issues": "https://github.com/google/recaptcha/issues",
"source": "https://github.com/google/recaptcha"
},
"time": "2023-02-18T17:41:46+00:00"
"time": "2025-06-26T22:21:57+00:00"
},
{
"name": "graham-campbell/result-type",
@ -1107,6 +1037,64 @@
],
"time": "2024-07-20T21:45:45+00:00"
},
{
"name": "gregwar/captcha",
"version": "v1.3.0",
"source": {
"type": "git",
"url": "https://github.com/Gregwar/Captcha.git",
"reference": "4edbcd09fde4353b94ce550f43460eba73baf2cc"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Gregwar/Captcha/zipball/4edbcd09fde4353b94ce550f43460eba73baf2cc",
"reference": "4edbcd09fde4353b94ce550f43460eba73baf2cc",
"shasum": ""
},
"require": {
"ext-fileinfo": "*",
"ext-gd": "*",
"ext-mbstring": "*",
"php": ">=5.3.0",
"symfony/finder": "*"
},
"require-dev": {
"phpunit/phpunit": "^4.8.35 || ^5.7.21 || ^6.4 || ^7.0 || ^8.0 || ^9.0"
},
"type": "library",
"autoload": {
"psr-4": {
"Gregwar\\": "src/Gregwar"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Grégoire Passault",
"email": "g.passault@gmail.com",
"homepage": "http://www.gregwar.com/"
},
{
"name": "Jeremy Livingston",
"email": "jeremy.j.livingston@gmail.com"
}
],
"description": "Captcha generator",
"homepage": "https://github.com/Gregwar/Captcha",
"keywords": [
"bot",
"captcha",
"spam"
],
"support": {
"issues": "https://github.com/Gregwar/Captcha/issues",
"source": "https://github.com/Gregwar/Captcha/tree/v1.3.0"
},
"time": "2025-06-23T12:25:54+00:00"
},
{
"name": "guzzlehttp/guzzle",
"version": "7.9.3",
@ -1620,16 +1608,16 @@
},
{
"name": "league/flysystem",
"version": "3.29.1",
"version": "3.30.0",
"source": {
"type": "git",
"url": "https://github.com/thephpleague/flysystem.git",
"reference": "edc1bb7c86fab0776c3287dbd19b5fa278347319"
"reference": "2203e3151755d874bb2943649dae1eb8533ac93e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/thephpleague/flysystem/zipball/edc1bb7c86fab0776c3287dbd19b5fa278347319",
"reference": "edc1bb7c86fab0776c3287dbd19b5fa278347319",
"url": "https://api.github.com/repos/thephpleague/flysystem/zipball/2203e3151755d874bb2943649dae1eb8533ac93e",
"reference": "2203e3151755d874bb2943649dae1eb8533ac93e",
"shasum": ""
},
"require": {
@ -1653,13 +1641,13 @@
"composer/semver": "^3.0",
"ext-fileinfo": "*",
"ext-ftp": "*",
"ext-mongodb": "^1.3",
"ext-mongodb": "^1.3|^2",
"ext-zip": "*",
"friendsofphp/php-cs-fixer": "^3.5",
"google/cloud-storage": "^1.23",
"guzzlehttp/psr7": "^2.6",
"microsoft/azure-storage-blob": "^1.1",
"mongodb/mongodb": "^1.2",
"mongodb/mongodb": "^1.2|^2",
"phpseclib/phpseclib": "^3.0.36",
"phpstan/phpstan": "^1.10",
"phpunit/phpunit": "^9.5.11|^10.0",
@ -1697,22 +1685,22 @@
],
"support": {
"issues": "https://github.com/thephpleague/flysystem/issues",
"source": "https://github.com/thephpleague/flysystem/tree/3.29.1"
"source": "https://github.com/thephpleague/flysystem/tree/3.30.0"
},
"time": "2024-10-08T08:58:34+00:00"
"time": "2025-06-25T13:29:59+00:00"
},
{
"name": "league/flysystem-local",
"version": "3.29.0",
"version": "3.30.0",
"source": {
"type": "git",
"url": "https://github.com/thephpleague/flysystem-local.git",
"reference": "e0e8d52ce4b2ed154148453d321e97c8e931bd27"
"reference": "6691915f77c7fb69adfb87dcd550052dc184ee10"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/thephpleague/flysystem-local/zipball/e0e8d52ce4b2ed154148453d321e97c8e931bd27",
"reference": "e0e8d52ce4b2ed154148453d321e97c8e931bd27",
"url": "https://api.github.com/repos/thephpleague/flysystem-local/zipball/6691915f77c7fb69adfb87dcd550052dc184ee10",
"reference": "6691915f77c7fb69adfb87dcd550052dc184ee10",
"shasum": ""
},
"require": {
@ -1746,9 +1734,9 @@
"local"
],
"support": {
"source": "https://github.com/thephpleague/flysystem-local/tree/3.29.0"
"source": "https://github.com/thephpleague/flysystem-local/tree/3.30.0"
},
"time": "2024-08-09T21:24:39+00:00"
"time": "2025-05-21T10:34:19+00:00"
},
{
"name": "league/mime-type-detection",
@ -3146,16 +3134,16 @@
},
{
"name": "symfony/mailer",
"version": "v6.4.21",
"version": "v6.4.23",
"source": {
"type": "git",
"url": "https://github.com/symfony/mailer.git",
"reference": "ada2809ccd4ec27aba9fc344e3efdaec624c6438"
"reference": "a480322ddf8e54de262c9bca31fdcbe26b553de5"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/mailer/zipball/ada2809ccd4ec27aba9fc344e3efdaec624c6438",
"reference": "ada2809ccd4ec27aba9fc344e3efdaec624c6438",
"url": "https://api.github.com/repos/symfony/mailer/zipball/a480322ddf8e54de262c9bca31fdcbe26b553de5",
"reference": "a480322ddf8e54de262c9bca31fdcbe26b553de5",
"shasum": ""
},
"require": {
@ -3206,7 +3194,7 @@
"description": "Helps sending emails",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/mailer/tree/v6.4.21"
"source": "https://github.com/symfony/mailer/tree/v6.4.23"
},
"funding": [
{
@ -3222,7 +3210,7 @@
"type": "tidelift"
}
],
"time": "2025-04-26T23:47:35+00:00"
"time": "2025-06-26T21:24:02+00:00"
},
{
"name": "symfony/mime",
@ -3651,16 +3639,16 @@
"packages-dev": [
{
"name": "symfony/var-dumper",
"version": "v6.4.21",
"version": "v6.4.23",
"source": {
"type": "git",
"url": "https://github.com/symfony/var-dumper.git",
"reference": "22560f80c0c5cd58cc0bcaf73455ffd81eb380d5"
"reference": "d55b1834cdbfcc31bc2cd7e095ba5ed9a88f6600"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/var-dumper/zipball/22560f80c0c5cd58cc0bcaf73455ffd81eb380d5",
"reference": "22560f80c0c5cd58cc0bcaf73455ffd81eb380d5",
"url": "https://api.github.com/repos/symfony/var-dumper/zipball/d55b1834cdbfcc31bc2cd7e095ba5ed9a88f6600",
"reference": "d55b1834cdbfcc31bc2cd7e095ba5ed9a88f6600",
"shasum": ""
},
"require": {
@ -3716,7 +3704,7 @@
"dump"
],
"support": {
"source": "https://github.com/symfony/var-dumper/tree/v6.4.21"
"source": "https://github.com/symfony/var-dumper/tree/v6.4.23"
},
"funding": [
{
@ -3732,7 +3720,7 @@
"type": "tidelift"
}
],
"time": "2025-04-09T07:34:50+00:00"
"time": "2025-06-27T15:05:27+00:00"
}
],
"aliases": [],
@ -3746,6 +3734,6 @@
"platform": {
"php": ">=8.1"
},
"platform-dev": [],
"plugin-api-version": "2.3.0"
"platform-dev": {},
"plugin-api-version": "2.6.0"
}

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

@ -272,9 +272,9 @@ $template->assign_vars([
'PAGE_TITLE' => $viewcat ? $cat_title_html[$viewcat] : $lang['HOME'],
'NO_FORUMS_MSG' => $only_new ? $lang['NO_NEW_POSTS'] : $lang['NO_FORUMS'],
'TOTAL_TOPICS' => sprintf($lang['POSTED_TOPICS_TOTAL'], $stats['topiccount']),
'TOTAL_POSTS' => sprintf($lang['POSTED_ARTICLES_TOTAL'], $stats['postcount']),
'TOTAL_USERS' => sprintf($lang['REGISTERED_USERS_TOTAL'], $stats['usercount']),
'TOTAL_TOPICS' => sprintf($lang['POSTED_TOPICS_TOTAL'], commify($stats['topiccount'])),
'TOTAL_POSTS' => sprintf($lang['POSTED_ARTICLES_TOTAL'], commify($stats['postcount'])),
'TOTAL_USERS' => sprintf($lang['REGISTERED_USERS_TOTAL'], commify($stats['usercount'])),
'TOTAL_GENDER' => $bb_cfg['gender'] ? sprintf(
$lang['USERS_TOTAL_GENDER'],
$stats['male'],

View file

@ -206,6 +206,12 @@ if (is_file(BB_ROOT . '.env')) {
$newValue = trim(readline());
if (!empty($newValue) || $key === 'DB_PASSWORD') {
if ($key === 'TP_HOST') {
if (!preg_match('/^https?:\/\//', $newValue)) {
$newValue = 'https://' . $newValue;
}
$newValue = parse_url($newValue, PHP_URL_HOST);
}
$line = "$key=$newValue";
$$key = $newValue;
} else {

View file

@ -68,11 +68,23 @@ switch ($type) {
case 'reg':
\TorrentPier\Legacy\Torrent::tracker_register($attach_id);
// Log action
$log_action->mod('mod_topic_tor_register', [
'forum_id' => $torrent['forum_id'],
'topic_id' => $torrent['topic_id'],
'topic_title' => $torrent['topic_title'],
]);
$url = (TOPIC_URL . $torrent['topic_id']);
break;
case 'unreg':
\TorrentPier\Legacy\Torrent::tracker_unregister($attach_id);
// Log action
$log_action->mod('mod_topic_tor_unregister', [
'forum_id' => $torrent['forum_id'],
'topic_id' => $torrent['topic_id'],
'topic_title' => $torrent['topic_title'],
]);
$url = (TOPIC_URL . $torrent['topic_id']);
break;

View file

@ -27,7 +27,7 @@ $post = DB()->fetch_row("
WHERE p.post_id = $post_id
");
if (!$post) {
$this->ajax_die('not post');
$this->ajax_die($lang['TOPIC_POST_NOT_EXIST']);
}
$data = [

View file

@ -26,7 +26,7 @@ if (isset($this->request['post_id'])) {
AND p.post_id = pt.post_id
LIMIT 1");
if (!$post) {
$this->ajax_die('not post');
$this->ajax_die($lang['TOPIC_POST_NOT_EXIST']);
}
$is_auth = auth(AUTH_ALL, $post['forum_id'], $userdata, $post);

View file

@ -29,6 +29,40 @@ if (!$poster_id = (int)$this->request['poster_id']) {
$this->ajax_die($lang['NO_USER_ID_SPECIFIED']);
}
$cache_lifetime = 3600;
$thanks_cache_key = 'topic_thanks_' . $topic_id;
/**
* Get thanks by topic id
*
* @param $topic_id
* @param string $thanks_cache_key
* @param int $cache_lifetime
* @return array
*/
function get_thanks_list($topic_id, string $thanks_cache_key, int $cache_lifetime)
{
if (!$cached_thanks = CACHE('bb_cache')->get($thanks_cache_key)) {
$cached_thanks = [];
$sql = DB()->fetch_rowset('SELECT u.username, u.user_rank, u.user_id, thx.* FROM ' . BB_THX . ' thx, ' . BB_USERS . " u WHERE thx.topic_id = $topic_id AND thx.user_id = u.user_id");
foreach ($sql as $row) {
$cached_thanks[$row['user_id']] = [
'user_id' => $row['user_id'],
'username' => $row['username'],
'user_rank' => $row['user_rank'],
'time' => $row['time']
];
}
if (!empty($cached_thanks)) {
CACHE('bb_cache')->set($thanks_cache_key, $cached_thanks, $cache_lifetime);
}
}
return $cached_thanks;
}
switch ($mode) {
case 'add':
if (IS_GUEST) {
@ -39,7 +73,8 @@ switch ($mode) {
$this->ajax_die($lang['LIKE_OWN_POST']);
}
if (DB()->fetch_row('SELECT topic_id FROM ' . BB_THX . " WHERE topic_id = $topic_id AND user_id = " . $userdata['user_id'])) {
$cached_thanks = get_thanks_list($topic_id, $thanks_cache_key, $cache_lifetime);
if (isset($cached_thanks[$userdata['user_id']])) {
$this->ajax_die($lang['LIKE_ALREADY']);
}
@ -47,10 +82,34 @@ switch ($mode) {
$values = "$topic_id, {$userdata['user_id']}, " . TIMENOW;
DB()->query('INSERT IGNORE INTO ' . BB_THX . " ($columns) VALUES ($values)");
$cached_thanks[$userdata['user_id']] = [
'user_id' => $userdata['user_id'],
'username' => $userdata['username'],
'user_rank' => $userdata['user_rank'],
'time' => TIMENOW
];
// Limit voters per topic
$thanks_count = DB()->fetch_row('SELECT COUNT(*) as thx FROM ' . BB_THX . " WHERE topic_id = $topic_id")['thx'];
if ($thanks_count > (int)$bb_cfg['tor_thank_limit_per_topic']) {
DB()->query('DELETE FROM ' . BB_THX . " WHERE topic_id = $topic_id ORDER BY time ASC LIMIT 1");
$tor_thank_limit_per_topic = (int)$bb_cfg['tor_thank_limit_per_topic'];
if ($tor_thank_limit_per_topic > 0) {
$thanks_count = count($cached_thanks);
if ($thanks_count > $tor_thank_limit_per_topic) {
$oldest_user_id = null;
foreach ($cached_thanks as $user_id => $thanks_data) {
// First value
$oldest_user_id = $thanks_data['user_id'];
break;
}
if ($oldest_user_id) {
DB()->query('DELETE FROM ' . BB_THX . " WHERE topic_id = $topic_id AND user_id = $oldest_user_id LIMIT 1");
unset($cached_thanks[$oldest_user_id]);
}
}
}
if (!empty($cached_thanks)) {
CACHE('bb_cache')->set($thanks_cache_key, $cached_thanks, $cache_lifetime);
}
break;
case 'get':
@ -58,9 +117,9 @@ switch ($mode) {
$this->ajax_die($lang['NEED_TO_LOGIN_FIRST']);
}
$cached_thanks = get_thanks_list($topic_id, $thanks_cache_key, $cache_lifetime);
$user_list = [];
$sql = DB()->fetch_rowset('SELECT u.username, u.user_rank, u.user_id, t.* FROM ' . BB_THX . ' t, ' . BB_USERS . " u WHERE t.topic_id = $topic_id AND t.user_id = u.user_id");
foreach ($sql as $row) {
foreach ($cached_thanks as $row) {
$user_list[] = '<b>' . profile_url($row) . ' <i>(' . bb_date($row['time']) . ')</i></b>';
}

View file

@ -11,18 +11,30 @@ if (!defined('IN_AJAX')) {
die(basename(__FILE__));
}
global $lang;
global $lang, $userdata;
if (!isset($this->request['attach_id'])) {
$this->ajax_die($lang['EMPTY_ATTACH_ID']);
}
$attach_id = (int)$this->request['attach_id'];
$torrent = DB()->fetch_row("SELECT attach_id, physical_filename FROM " . BB_ATTACHMENTS_DESC . " WHERE attach_id = $attach_id LIMIT 1");
$torrent = DB()->fetch_row("
SELECT
ad.attach_id, ad.physical_filename,
tor.forum_id
FROM " . BB_ATTACHMENTS_DESC . " ad
INNER JOIN " . BB_BT_TORRENTS . " tor ON (ad.attach_id = tor.attach_id)
WHERE ad.attach_id = $attach_id LIMIT 1");
if (!$torrent) {
$this->ajax_die($lang['ERROR_BUILD']);
}
// Check rights
$is_auth = auth(AUTH_ALL, $torrent['forum_id'], $userdata);
if (!$is_auth['auth_view']) {
$this->ajax_die($lang['SORRY_AUTH_VIEW_ATTACH']);
}
$file_contents = null;
$filename = get_attachments_dir() . '/' . $torrent['physical_filename'];
if (!is_file($filename) || !$file_contents = file_get_contents($filename)) {
@ -37,7 +49,6 @@ try {
}
$torrent = new TorrentPier\Legacy\TorrentFileList($tor);
$tor_filelist = $torrent->get_filelist();
$this->response['html'] = $tor_filelist;

View file

@ -66,6 +66,7 @@ $tracker_status = $attachments['_' . $post_id][$i]['tracker_status'];
$download_count = declension((int)$attachments['_' . $post_id][$i]['download_count'], 'times');
$tor_file_size = humn_size($attachments['_' . $post_id][$i]['filesize']);
$tor_file_time = bb_date($attachments['_' . $post_id][$i]['filetime']);
$real_filename = clean_filename(basename($attachments['_' . $post_id][$i]['real_filename']));
$tor_reged = (bool)$tracker_status;
$show_peers = (bool)$bb_cfg['bt_show_peers'];
@ -88,10 +89,14 @@ if ($tor_auth_reg || $tor_auth_del) {
$tracker_link = ($tor_reged) ? $unreg_tor_url : $reg_tor_url;
}
if ($bb_cfg['tracker']['use_old_torrent_name_format']) {
$display_name = '[' . $bb_cfg['server_name'] . '].t' . $bt_topic_id . '.' . TORRENT_EXT;
if ($bb_cfg['tracker']['use_real_filename']) {
$display_name = $real_filename;
} else {
$display_name = $t_data['topic_title'] . ' [' . $bb_cfg['server_name'] . '-' . $bt_topic_id . ']' . '.' . TORRENT_EXT;
if ($bb_cfg['tracker']['use_old_torrent_name_format']) {
$display_name = '[' . $bb_cfg['server_name'] . '].t' . $bt_topic_id . '.' . TORRENT_EXT;
} else {
$display_name = $t_data['topic_title'] . ' [' . $bb_cfg['server_name'] . '-' . $bt_topic_id . ']' . '.' . TORRENT_EXT;
}
}
if (!$tor_reged) {
@ -475,6 +480,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.4.6-alpha.4';
$bb_cfg['tp_release_date'] = '13-06-2025';
$bb_cfg['tp_version'] = 'v2.4.11';
$bb_cfg['tp_release_date'] = '06-08-2025';
$bb_cfg['tp_release_codename'] = 'Cattle';
// Increase version number after changing JS or CSS
@ -209,6 +209,7 @@ $bb_cfg['lang'] = [
'ar' => [
'name' => 'Arabic',
'locale' => 'ar_SA.UTF-8',
'rtl' => true,
],
'hy' => [
'name' => 'Armenian',
@ -285,6 +286,7 @@ $bb_cfg['lang'] = [
'he' => [
'name' => 'Hebrew',
'locale' => 'he_IL.UTF-8',
'rtl' => true,
],
'hi' => [
'name' => 'Hindi',
@ -567,7 +569,7 @@ $bb_cfg['limit_max_search_results'] = false; // Limit for number of search resul
// Posting
$bb_cfg['prevent_multiposting'] = true; // TODO: replace "reply" with "edit last msg" if user (not admin or mod) is last topic poster
$bb_cfg['max_smilies'] = 25; //Max number of smilies in a post (0 - unlimited)
$bb_cfg['max_smilies'] = 25; // Max number of smilies in a post (0 - unlimited)
$bb_cfg['max_symbols_post'] = 5000; // TODO: Max number of symbols in a post (0 - unlimited)
// PM
@ -591,7 +593,7 @@ $bb_cfg['user_not_active_days_keep'] = 180; // After how many days should I dele
// Vote for torrents
$bb_cfg['tor_thank'] = true;
$bb_cfg['tor_thanks_list_guests'] = true; // Show voters to guests
$bb_cfg['tor_thank_limit_per_topic'] = 50;
$bb_cfg['tor_thank_limit_per_topic'] = 50; // Set "0" to disable limit
// Groups
$bb_cfg['group_members_per_page'] = 50; // How many groups will be displayed in a page
@ -724,6 +726,8 @@ $bb_cfg['tracker'] = [
'update_dlstat' => true,
'expire_factor' => 2.5,
'compact_mode' => true,
'upd_user_up_down_stat' => true, // unused
'browser_redirect_url' => '', // unused
'scrape' => true,
'limit_active_tor' => true,
'limit_seed_count' => 0,
@ -743,7 +747,8 @@ $bb_cfg['tracker'] = [
'hybrid_stat_protocol' => 1, // For hybrid torrents there are two identical requests sent by clients, for counting stats we gotta choose one, you can change this to '2' in future, when v1 protocol is outdated
'disabled_v1_torrents' => false, // disallow registration of v1-only torrents, for future implementations where client will use v2 only and there won't be need for v1, thus relieving tracker
'disabled_v2_torrents' => false, // disallow registration of v2-only torrents
'use_old_torrent_name_format' => false, // when enabled, the names of torrent files will have the classic format: [yoursite.com].txxx.torrent
'use_real_filename' => false, // Use original torrent filename for downloads. If disabled, filename will be generated automatically
'use_old_torrent_name_format' => false, // Use classic filename format '[yoursite.com].txxx.torrent'. Only works when use_real_filename is disabled
];
// Ratio settings

View file

@ -15,11 +15,13 @@ if (!defined('BB_ROOT')) {
define('ADMIN_DIR', BB_PATH . '/admin');
define('DATA_DIR', BB_PATH . '/data');
define('INT_DATA_DIR', BB_PATH . '/internal_data');
define('AJAX_HTML_DIR', BB_ROOT . '/internal_data/ajax_html/');
define('CACHE_DIR', BB_PATH . '/internal_data/cache');
define('LOG_DIR', BB_PATH . '/internal_data/log');
define('TRIGGERS_DIR', BB_PATH . '/internal_data/triggers');
define('AJAX_DIR', BB_PATH . '/library/ajax');
define('ATTACH_DIR', BB_PATH . '/library/attach_mod');
define('CFG_DIR', BB_PATH . '/library/config');
define('INC_DIR', BB_PATH . '/library/includes');
define('UCP_DIR', BB_PATH . '/library/includes/ucp');
define('LANG_ROOT_DIR', BB_PATH . '/library/language');

View file

@ -26,9 +26,9 @@ $posts_without_attach = $topics_without_attach = [];
DB()->query("
CREATE TEMPORARY TABLE $tmp_attach_tbl (
physical_filename VARCHAR(255) NOT NULL default '',
physical_filename VARCHAR(255) NOT NULL default '' COLLATE utf8mb4_unicode_ci,
KEY physical_filename (physical_filename(20))
) ENGINE = MyISAM DEFAULT CHARSET = utf8
) ENGINE = MyISAM DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci
");
DB()->add_shutdown_query("DROP TEMPORARY TABLE IF EXISTS $tmp_attach_tbl");

View file

@ -39,7 +39,7 @@ if ($bb_cfg['tracker']['update_dlstat']) {
INSERT INTO " . NEW_BB_BT_LAST_TORSTAT . "
(topic_id, user_id, dl_status, up_add, down_add, release_add, speed_up, speed_down)
SELECT
topic_id, user_id, IF(releaser, $releaser, seeder), SUM(up_add), SUM(down_add), IF(releaser, SUM(up_add), 0), SUM(speed_up), SUM(speed_down)
topic_id, user_id, IF(MAX(releaser), $releaser, MAX(seeder)), SUM(up_add), SUM(down_add), IF(MAX(releaser), SUM(up_add), 0), SUM(speed_up), SUM(speed_down)
FROM " . BB_BT_TRACKER . "
WHERE (up_add != 0 OR down_add != 0)
GROUP BY topic_id, user_id
@ -61,7 +61,6 @@ DB()->query("
FROM " . BB_BT_TRACKER . "
WHERE seeder = 1
GROUP BY topic_id, user_id
ORDER BY update_time DESC
");
// Clean peers table

View file

@ -18,9 +18,16 @@ if (!$bb_cfg['tp_updater_settings']['enabled']) {
}
$data = [];
$data[] = ['latest_check_timestamp' => TIMENOW];
$updaterDownloader = new \TorrentPier\Updater();
$updaterDownloader = $updaterDownloader->getLastVersion($bb_cfg['tp_updater_settings']['allow_pre_releases']);
try {
$updaterDownloader = new \TorrentPier\Updater();
$updaterDownloader = $updaterDownloader->getLastVersion($bb_cfg['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($bb_cfg['tp_version']);
@ -28,6 +35,7 @@ $currentVersion = \TorrentPier\Helpers\VersionHelper::removerPrefix($bb_cfg['tp_
// 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();
@ -41,10 +49,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
@ -58,5 +68,4 @@ if (\z4kn4fein\SemVer\Version::greaterThan($getVersion, $currentVersion)) {
];
}
$data[] = ['latest_check_timestamp' => TIMENOW];
$this->store('check_updates', $data);

View file

@ -17,7 +17,7 @@ $data = [];
// usercount
$row = DB()->fetch_row("SELECT COUNT(*) AS usercount FROM " . BB_USERS . " WHERE user_id NOT IN(" . EXCLUDED_USERS . ")");
$data['usercount'] = commify($row['usercount']);
$data['usercount'] = (int)$row['usercount'];
// newestuser
$row = DB()->fetch_row("SELECT user_id, username, user_rank FROM " . BB_USERS . " WHERE user_active = 1 AND user_id NOT IN(" . EXCLUDED_USERS . ") ORDER BY user_id DESC LIMIT 1");
@ -25,8 +25,8 @@ $data['newestuser'] = $row;
// post/topic count
$row = DB()->fetch_row("SELECT SUM(forum_topics) AS topiccount, SUM(forum_posts) AS postcount FROM " . BB_FORUMS);
$data['postcount'] = commify($row['postcount']);
$data['topiccount'] = commify($row['topiccount']);
$data['postcount'] = (int)$row['postcount'];
$data['topiccount'] = (int)$row['topiccount'];
// Tracker stats
if ($bb_cfg['tor_stats']) {

View file

@ -800,6 +800,11 @@ function str_short($text, $max_length, $space = ' ')
return $text ?? '';
}
function wbr($text, $max_word_length = HTML_WBR_LENGTH)
{
return preg_replace("/([\w\->;:.,~!?(){}@#$%^*\/\\\\]{" . $max_word_length . "})/ui", '$1<wbr>', $text);
}
function generate_user_info($row, bool $have_auth = IS_ADMIN): array
{
global $userdata, $lang, $images, $bb_cfg;
@ -940,6 +945,47 @@ function bb_update_config($params, $table = BB_CONFIG)
bb_get_config($table, true, true);
}
function get_db_stat($mode)
{
switch ($mode) {
case 'usercount':
$sql = "SELECT COUNT(user_id) AS total FROM " . BB_USERS;
break;
case 'newestuser':
$sql = "SELECT user_id, username FROM " . BB_USERS . " WHERE user_id <> " . GUEST_UID . " ORDER BY user_id DESC LIMIT 1";
break;
case 'postcount':
case 'topiccount':
$sql = "SELECT SUM(forum_topics) AS topic_total, SUM(forum_posts) AS post_total FROM " . BB_FORUMS;
break;
}
if (!($result = DB()->sql_query($sql))) {
return false;
}
$row = DB()->sql_fetchrow($result);
switch ($mode) {
case 'usercount':
return $row['total'];
break;
case 'newestuser':
return $row;
break;
case 'postcount':
return $row['post_total'];
break;
case 'topiccount':
return $row['topic_total'];
break;
}
return false;
}
function clean_username($username)
{
$username = mb_substr(htmlspecialchars(str_replace("\'", "'", trim($username))), 0, 25, DEFAULT_CHARSET);
@ -949,6 +995,28 @@ function clean_username($username)
return $username;
}
function bb_ltrim($str, $charlist = false)
{
if ($charlist === false) {
return ltrim($str);
}
$str = ltrim($str, $charlist);
return $str;
}
function bb_rtrim($str, $charlist = false)
{
if ($charlist === false) {
return rtrim($str);
}
$str = rtrim($str, $charlist);
return $str;
}
/**
* Get Userdata
*
@ -1094,6 +1162,7 @@ function setup_style()
$css_dir = 'styles/' . basename(TEMPLATES_DIR) . '/' . $tpl_dir_name . '/css/';
$template->assign_vars([
'BB_ROOT' => BB_ROOT,
'SPACER' => make_url('styles/images/spacer.gif'),
'STYLESHEET' => make_url($css_dir . $stylesheet),
'EXT_LINK_NEW_WIN' => $bb_cfg['ext_link_new_win'],
@ -1412,6 +1481,11 @@ function bb_simple_die($txt, $status_code = null)
die($txt);
}
function bb_realpath($path)
{
return realpath($path);
}
function login_redirect($url = '')
{
redirect(LOGIN_URL . '?redirect=' . (($url) ?: ($_SERVER['REQUEST_URI'] ?? '/')));
@ -1450,6 +1524,9 @@ function redirect($url)
$redirect_url = $server_protocol . $server_name . $server_port . $script_name . preg_replace('#^\/?(.*?)\/?$#', '/\1', $url);
// Send no-cache headers to prevent browsers from caching redirects
send_no_cache_headers();
// Behave as per HTTP/1.1 spec for others
header('Location: ' . $redirect_url, response_code: 301);
exit;
@ -2210,19 +2287,26 @@ function infoByIP(string $ipAddress, int $port = 0): array
}
$context = stream_context_create($contextOptions);
$response = file_get_contents($bb_cfg['ip2country_settings']['endpoint'] . $ipAddress, context: $context);
if ($response !== false) {
$json = json_decode($response, true);
try {
$response = file_get_contents($bb_cfg['ip2country_settings']['endpoint'] . $ipAddress, context: $context);
if (is_array($json) && !empty($json)) {
$data = [
'ipVersion' => $json['ipVersion'],
'countryCode' => $json['countryCode'],
'continent' => $json['continent'],
'continentCode' => $json['continentCode']
];
if ($response !== false) {
$json = json_decode($response, true);
if (is_array($json) && !empty($json)) {
$data = [
'ipVersion' => $json['ipVersion'],
'countryCode' => $json['countryCode'],
'continent' => $json['continent'],
'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

@ -293,6 +293,7 @@ define('USER_AGENT', strtolower($_SERVER['HTTP_USER_AGENT']));
define('HTML_SELECT_MAX_LENGTH', 60);
define('HTML_SF_SPACER', '&nbsp;|-&nbsp;');
define('HTML_WBR_LENGTH', 12);
define('HTML_CHECKED', ' checked ');
define('HTML_DISABLED', ' disabled ');

View file

@ -36,11 +36,11 @@ $online = $online_short = ['userlist' => ''];
$sql = "
SELECT
u.username, u.user_id, u.user_opt, u.user_rank, u.user_level,
s.session_logged_in, s.session_ip, (s.session_time - s.session_start) AS ses_len, COUNT(s.session_id) AS sessions, COUNT(DISTINCT s.session_ip) AS ips
MAX(s.session_logged_in) AS session_logged_in, MAX(s.session_ip) AS session_ip, MAX(s.session_time - s.session_start) AS ses_len, COUNT(s.session_id) AS sessions, COUNT(DISTINCT s.session_ip) AS ips
FROM " . BB_SESSIONS . " s, " . BB_USERS . " u
WHERE s.session_time > $time_online
AND u.user_id = s.session_user_id
GROUP BY s.session_user_id
GROUP BY s.session_user_id, u.username, u.user_id, u.user_opt, u.user_rank, u.user_level
ORDER BY u.username
";

View file

@ -117,13 +117,14 @@ $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),
'USE_TABLESORTER' => !empty($page_cfg['use_tablesorter']),
'ALLOW_ROBOTS' => !$bb_cfg['board_disable'] && (!isset($page_cfg['allow_robots']) || $page_cfg['allow_robots'] === true),
'META_DESCRIPTION' => !empty($page_cfg['meta_description']) ? trim(htmlCHR($page_cfg['meta_description'])) : '',
'META_DESCRIPTION' => (!defined('HAS_DIED') && !empty($page_cfg['meta_description'])) ? trim(htmlCHR($page_cfg['meta_description'])) : '',
'SITENAME' => $bb_cfg['sitename'],
'U_INDEX' => BB_ROOT . 'index.php',
@ -194,8 +195,14 @@ $template->assign_vars([
'BONUS_URL' => BB_ROOT . BONUS_URL,
'TOPIC_URL' => BB_ROOT . TOPIC_URL,
'AJAX_HTML_DIR' => AJAX_HTML_DIR,
'ONLY_NEW_POSTS' => ONLY_NEW_POSTS,
'ONLY_NEW_TOPICS' => ONLY_NEW_TOPICS,
// Misc
'BOT_UID' => BOT_UID,
'COOKIE_MARK' => COOKIE_MARK,
'SID' => $userdata['session_id'],
'SID_HIDDEN' => '<input type="hidden" name="sid" value="' . $userdata['session_id'] . '" />',

View file

@ -568,7 +568,7 @@ foreach ($profile_fields as $field => $can_edit) {
}
}
}
$tp_data['TEMPLATES_SELECT'] = \TorrentPier\Legacy\Common\Select::template($pr_data['tpl_name'], 'tpl_name');
$tp_data['TEMPLATES_SELECT'] = \TorrentPier\Legacy\Select::template($pr_data['tpl_name'], 'tpl_name');
break;
/**
@ -725,8 +725,8 @@ $template->assign_vars([
'INVITE_CODE' => !empty($_GET['invite']) ? htmlCHR($_GET['invite']) : '',
'CAPTCHA_HTML' => ($need_captcha) ? bb_captcha('get') : '',
'LANGUAGE_SELECT' => \TorrentPier\Legacy\Common\Select::language($pr_data['user_lang'], 'user_lang'),
'TIMEZONE_SELECT' => \TorrentPier\Legacy\Common\Select::timezone($pr_data['user_timezone'], 'user_timezone'),
'LANGUAGE_SELECT' => \TorrentPier\Legacy\Select::language($pr_data['user_lang'], 'user_lang'),
'TIMEZONE_SELECT' => \TorrentPier\Legacy\Select::timezone($pr_data['user_timezone'], 'user_timezone'),
'AVATAR_EXPLAIN' => sprintf($lang['AVATAR_EXPLAIN'], $bb_cfg['avatars']['max_width'], $bb_cfg['avatars']['max_height'], humn_size($bb_cfg['avatars']['max_size'])),
'AVATAR_DISALLOWED' => bf($pr_data['user_opt'], 'user_opt', 'dis_avatar'),

View file

@ -2823,6 +2823,8 @@ $lang['LOG_ACTION']['LOG_TYPE'] = [
'mod_topic_change_tor_status' => 'Topic:<br /> <b>changed torrent status</b>',
'mod_topic_change_tor_type' => 'Topic:<br /> <b>changed torrent type</b>',
'mod_topic_tor_unregister' => 'Topic:<br /> <b>torrent unregistered</b>',
'mod_topic_tor_register' => 'Topic:<br /> <b>torrent registered</b>',
'mod_topic_tor_delete' => 'Topic:<br /> <b>torrent deleted</b>',
'mod_topic_renamed' => 'Topic:<br /> <b>renamed</b>',
'mod_post_delete' => 'Post:<br /> <b>deleted</b>',
'mod_post_pin' => 'Post:<br /> <b>pinned</b>',

View file

@ -34,7 +34,7 @@ if (!$topic_id) {
}
// Getting torrent info from database
$sql = 'SELECT attach_id, forum_id, info_hash, info_hash_v2
$sql = 'SELECT attach_id, forum_id, info_hash, info_hash_v2, tor_status, poster_id
FROM ' . BB_BT_TORRENTS . '
WHERE topic_id = ' . $topic_id . '
LIMIT 1';
@ -58,6 +58,13 @@ if (!$is_auth['auth_download']) {
bb_die($lang['SORRY_AUTH_VIEW_ATTACH']);
}
// Check for frozen torrent
$releaser = $userdata['user_id'] == $row['poster_id'];
$tor_status = $row['tor_status'];
if (!IS_AM && isset($bb_cfg['tor_frozen'][$tor_status]) && !(isset($bb_cfg['tor_frozen_author_download'][$tor_status]) && $releaser)) {
bb_die($lang['TOR_STATUS_FORBIDDEN'] . $lang['TOR_STATUS_NAME'][$tor_status]);
}
// Parse M3U file
$m3uParser = new M3uParser\M3uParser();
$m3uParser->addDefaultTags();

View file

@ -253,7 +253,11 @@ if (!empty($bb_cfg['tor_cannot_edit']) && $post_info['allow_reg_tracker'] && $po
$robots_indexing = $post_info['topic_allow_robots'] ?? true;
if ($submit || $refresh) {
if (IS_AM) {
$robots_indexing = !empty($_POST['robots']);
if ($post_info['auth_read'] == AUTH_ALL) {
$robots_indexing = !empty($_POST['robots']);
} else {
$robots_indexing = true;
}
}
$notify_user = (int)!empty($_POST['notify']);
} else {
@ -504,7 +508,7 @@ if (!IS_GUEST) {
$topic_type_toggle = '';
if ($mode == 'newtopic' || ($mode == 'editpost' && $post_data['first_post'])) {
// Allow robots indexing
if (IS_AM) {
if (IS_AM && $post_info['auth_read'] == AUTH_ALL) {
$template->assign_var('SHOW_ROBOTS_CHECKBOX');
}
@ -625,6 +629,8 @@ $template->assign_vars([
'POSTER_RGROUPS' => !empty($poster_rgroups) ? $poster_rgroups : '',
'ATTACH_RG_SIG' => $switch_rg_sig ?: false,
'U_VIEWTOPIC' => ($mode == 'reply') ? TOPIC_URL . "$topic_id&amp;postorder=desc" : '',
'S_NOTIFY_CHECKED' => $notify_user ? 'checked' : '',
'S_ROBOTS_CHECKED' => $robots_indexing ? 'checked' : '',
'S_TYPE_TOGGLE' => $topic_type_toggle,

View file

@ -50,7 +50,7 @@ class Ajax
'index_data' => ['guest'],
];
public string $action;
public ?string $action;
/**
* Constructor

View file

@ -479,6 +479,8 @@ class Attach
unlink_attach($row['physical_filename'], MODE_THUMBNAIL);
}
// todo: log action - torrent updated
//bt
if ($this->attachment_extension_list[$actual_element] === TORRENT_EXT && $attachments[$actual_element]['tracker_status']) {
Torrent::tracker_unregister($attachment_id);
@ -786,9 +788,10 @@ class Attach
}
DB()->sql_freeresult($result);
$allowed_filesize = $row['max_filesize'] ?: $attach_config['max_filesize'];
$cat_id = (int)$row['cat_id'];
$auth_cache = trim($row['forum_permissions']);
$allowed_filesize = $row['max_filesize'] ?? $attach_config['max_filesize'];
$cat_id = isset($row['cat_id']) ? (int)$row['cat_id'] : 0;
$auth_cache = isset($row['forum_permissions']) ? trim($row['forum_permissions']) : '';
$row['allow_group'] = $row['allow_group'] ?? 0;
// check Filename
if (preg_match("#[\\/:*?\"<>|]#i", $this->filename)) {

View file

@ -33,6 +33,8 @@ class LogAction
'mod_topic_change_tor_status' => 15,
'mod_topic_change_tor_type' => 16,
'mod_topic_tor_unregister' => 17,
'mod_topic_tor_register' => 18,
'mod_topic_tor_delete' => 19,
];
public $log_type_select = [];
public $log_disabled = false;

View file

@ -7,11 +7,11 @@
* @license https://github.com/torrentpier/torrentpier/blob/master/LICENSE MIT License
*/
namespace TorrentPier\Legacy\Common;
namespace TorrentPier\Legacy;
/**
* Class Select
* @package TorrentPier\Legacy\Common
* @package TorrentPier\Legacy
*/
class Select
{

View file

@ -97,7 +97,7 @@ class Torrent
*/
public static function tracker_unregister($attach_id, $mode = '')
{
global $lang, $bb_cfg, $log_action;
global $lang, $bb_cfg;
$attach_id = (int)$attach_id;
$post_id = $topic_id = $topic_title = $forum_id = null;
@ -153,13 +153,6 @@ class Torrent
$torrServer->removeM3U($attach_id);
}
// Log action
$log_action->mod('mod_topic_tor_unregister', [
'forum_id' => $forum_id,
'topic_id' => $topic_id,
'topic_title' => $topic_title,
]);
// Delete torrent
$sql = "DELETE FROM " . BB_BT_TORRENTS . " WHERE attach_id = $attach_id";
@ -188,7 +181,7 @@ class Torrent
*/
public static function delete_torrent($attach_id, $mode = '')
{
global $lang, $reg_mode, $topic_id;
global $lang, $reg_mode, $topic_id, $log_action;
$attach_id = (int)$attach_id;
$reg_mode = $mode;
@ -208,6 +201,13 @@ class Torrent
self::torrent_auth_check($forum_id, $poster_id);
self::tracker_unregister($attach_id);
delete_attachment(0, $attach_id);
// Log action
$log_action->mod('mod_topic_tor_delete', [
'forum_id' => $torrent['forum_id'],
'topic_id' => $torrent['topic_id'],
'topic_title' => $torrent['topic_title'],
]);
}
/**
@ -644,10 +644,15 @@ class Torrent
// Send torrent
$output = Bencode::encode($tor);
if ($bb_cfg['tracker']['use_old_torrent_name_format']) {
$dl_fname = '[' . $bb_cfg['server_name'] . '].t' . $topic_id . '.' . TORRENT_EXT;
$real_filename = clean_filename(basename($attachment['real_filename']));
if ($bb_cfg['tracker']['use_real_filename']) {
$dl_fname = $real_filename;
} else {
$dl_fname = html_ent_decode($topic_title) . ' [' . $bb_cfg['server_name'] . '-' . $topic_id . ']' . '.' . TORRENT_EXT;
if ($bb_cfg['tracker']['use_old_torrent_name_format']) {
$dl_fname = '[' . $bb_cfg['server_name'] . '].t' . $topic_id . '.' . TORRENT_EXT;
} else {
$dl_fname = html_ent_decode($topic_title) . ' [' . $bb_cfg['server_name'] . '-' . $topic_id . ']' . '.' . TORRENT_EXT;
}
}
if (!empty($_COOKIE['explain'])) {

View file

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

View file

@ -54,7 +54,7 @@ class TorrServerAPI
{
global $bb_cfg;
$this->url = $bb_cfg['torr_server']['url'] . '/';
$this->url = rtrim(trim($bb_cfg['torr_server']['url']), '/') . '/';
}
/**

View file

@ -38,6 +38,13 @@ class Updater
*/
public string $savePath;
/**
* LTS version pattern (v2.4.*)
*
* @var string
*/
private const LTS_VERSION_PATTERN = '/^v2\.4\.\d+$/';
/**
* Stream context
*
@ -130,23 +137,67 @@ class Updater
}
/**
* Returns information of latest TorrentPier version available
* Returns information of latest TorrentPier LTS version (v2.4.*) available
*
* @param bool $allowPreReleases
* @return array
* @throws Exception
*/
public function getLastVersion(bool $allowPreReleases = true): array
{
// Filter releases to get only LTS versions (v2.4.*)
$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.4.*) 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.4.*) found');
}
return $ltsVersions[0];
}
/**
* Get all available LTS versions (v2.4.*)
*
* @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.4.*)
$ltsVersions = array_filter($this->jsonResponse, function ($release) use ($allowPreReleases) {
$isLTSVersion = preg_match(self::LTS_VERSION_PATTERN, $release['tag_name']);
return $index;
if (!$allowPreReleases && isset($release['prerelease']) && $release['prerelease']) {
return false;
}
}
return $this->jsonResponse[0];
return $isLTSVersion;
});
// 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>
<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>

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

View file

@ -0,0 +1,2 @@
Color: #3c618b
Font: Arial (Regular) 11pt

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

@ -1,6 +1,8 @@
<!-- IF TPL_ADD_ATTACHMENT -->
<!--========================================================================-->
<style>#clear_file_upload { display: none; }</style>
<tr>
<th colspan="2" class="thHead">{L_ADD_ATTACHMENT_TITLE}</th>
</tr>
@ -10,6 +12,7 @@
<table class="borderless" cellspacing="0">
<tr>
<td class="pad_4">
<input type="button" id="clear_file_upload" value="{L_CLEAR}" />
<input type="file" name="fileupload" size="45" maxlength="{FILESIZE}" />
<p class="small nowrap">{L_ADD_ATTACHMENT_EXPLAIN}</p>
</td>
@ -26,6 +29,24 @@
</td>
</tr>
<script type="text/javascript">
$(document).ready(function () {
$('input[name="fileupload"]').on('change', function () {
if (this.files && this.files.length > 0) {
$('input[type=button]#clear_file_upload').show();
} else {
$('input[type=button]#clear_file_upload').hide();
}
});
$('input[type=button]#clear_file_upload').on('click', function () {
$('input[name="filecomment"]').val('');
$('input[name="fileupload"]').val('');
$('input[type=button]#clear_file_upload').hide();
});
});
</script>
<!--========================================================================-->
<!-- ENDIF / TPL_ADD_ATTACHMENT -->

View file

@ -173,12 +173,14 @@
<!-- 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_BT_FLIST}" /></p>
<!-- IF not postrow.attach.tor_reged.TOR_FROZEN -->
<!-- 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 alt="{L_PLAYBACK_M3U}" src="{postrow.attach.tor_reged.tor_server.TORR_SERVER_M3U_ICON}" width="21" height="21" border="0"></p>{L_PLAYBACK_M3U}</a>
<!-- ENDIF -->
<!-- END tor_server -->
<!-- ENDIF -->
</td>
</tr>
<tr class="row1">

View file

@ -85,17 +85,17 @@ if ($topic_id && isset($_GET['view']) && ($_GET['view'] == 'next' || $_GET['view
// Get forum/topic data
if ($topic_id) {
$sql = "SELECT t.*, f.*, tw.notify_status
$sql = "SELECT t.*, f.cat_id, f.forum_name, f.forum_desc, f.forum_status, f.forum_order, f.forum_posts, f.forum_topics, f.forum_last_post_id, f.forum_tpl_id, f.prune_days, f.auth_view, f.auth_read, f.auth_post, f.auth_reply, f.auth_edit, f.auth_delete, f.auth_sticky, f.auth_announce, f.auth_vote, f.auth_pollcreate, f.auth_attachments, f.auth_download, f.allow_reg_tracker, f.allow_porno_topic, f.self_moderated, f.forum_parent, f.show_on_index, f.forum_display_sort, f.forum_display_order, tw.notify_status
FROM " . BB_TOPICS . " t
LEFT JOIN " . BB_FORUMS . " f USING(forum_id)
LEFT JOIN " . BB_FORUMS . " f ON t.forum_id = f.forum_id
LEFT JOIN " . BB_TOPICS_WATCH . " tw ON(tw.topic_id = t.topic_id AND tw.user_id = {$userdata['user_id']})
WHERE t.topic_id = $topic_id
";
} elseif ($post_id) {
$sql = "SELECT t.*, f.*, p.post_time, tw.notify_status
$sql = "SELECT t.*, f.cat_id, f.forum_name, f.forum_desc, f.forum_status, f.forum_order, f.forum_posts, f.forum_topics, f.forum_last_post_id, f.forum_tpl_id, f.prune_days, f.auth_view, f.auth_read, f.auth_post, f.auth_reply, f.auth_edit, f.auth_delete, f.auth_sticky, f.auth_announce, f.auth_vote, f.auth_pollcreate, f.auth_attachments, f.auth_download, f.allow_reg_tracker, f.allow_porno_topic, f.self_moderated, f.forum_parent, f.show_on_index, f.forum_display_sort, f.forum_display_order, p.post_time, tw.notify_status
FROM " . BB_TOPICS . " t
LEFT JOIN " . BB_FORUMS . " f USING(forum_id)
LEFT JOIN " . BB_POSTS . " p USING(topic_id)
LEFT JOIN " . BB_FORUMS . " f ON t.forum_id = f.forum_id
LEFT JOIN " . BB_POSTS . " p ON t.topic_id = p.topic_id
LEFT JOIN " . BB_TOPICS_WATCH . " tw ON(tw.topic_id = t.topic_id AND tw.user_id = {$userdata['user_id']})
WHERE p.post_id = $post_id
";
@ -113,9 +113,6 @@ $topic_id = $t_data['topic_id'];
$forum_id = $t_data['forum_id'];
$topic_attachment = isset($t_data['topic_attachment']) ? (int)$t_data['topic_attachment'] : null;
// Allow robots indexing
$page_cfg['allow_robots'] = (bool)$t_data['topic_allow_robots'];
if ($t_data['allow_porno_topic'] && bf($userdata['user_opt'], 'user_opt', 'user_porn_forums')) {
bb_die($lang['ERROR_PORNO_FORUM']);
}
@ -229,6 +226,13 @@ $datastore->rm('cat_forums');
// Make jumpbox
make_jumpbox();
// Allow robots indexing
if ($is_auth['auth_read']) {
$page_cfg['allow_robots'] = (bool)$t_data['topic_allow_robots'];
} else {
$page_cfg['allow_robots'] = false;
}
if ($post_id && !empty($t_data['prev_posts'])) {
$start = floor(($t_data['prev_posts'] - 1) / $posts_per_page) * $posts_per_page;
}
@ -759,7 +763,9 @@ if (defined('SPLIT_FORM_START')) {
$template->assign_vars([
'SPLIT_FORM' => true,
'START' => $start,
'S_SPLIT_ACTION' => 'modcp.php'
'S_SPLIT_ACTION' => 'modcp.php',
'POST_FORUM_URL' => POST_FORUM_URL,
'POST_TOPIC_URL' => POST_TOPIC_URL,
]);
}