Skip to content

Instantly share code, notes, and snippets.

@paskal
Created April 5, 2025 21:35
Show Gist options
  • Save paskal/1835957ac91770808deeb9ed62c7de1e to your computer and use it in GitHub Desktop.
Save paskal/1835957ac91770808deeb9ed62c7de1e to your computer and use it in GitHub Desktop.
Synology Download Station Plugin for The Pirate Bay v1.16
{
"name": "ng_piratebay",
"displayname": "The Pirate Bay",
"description": "More plugins at www.synoboost.com",
"majorversion": "4",
"minorversion": "0",
"minfirmware": "2257",
"accountsupport": true,
"version": "1.16",
"site": "https://thepiratebay0.org/",
"module": "search.php",
"type": "search",
"class": "SynoDLMSearchNGPirateBay"
}
<?php
/*********************************************************************\
| (c)2011-2025 Synoboost https://www.synoboost.com |
|---------------------------------------------------------------------|
| This program is free software; you can redistribute it and/or |
| modify it under the terms of the GNU General Public License |
| as published by the Free Software Foundation; either version 2 |
| of the License, or (at your option) any later version. |
| |
| This program is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with this program; If not, see <http://www.gnu.org/licenses/> |
\*********************************************************************/
?>
<?php
class SynoDLMSearchNGPirateBay {
private $currentlink = "https://www.synoboost.com/tpb/current";
private $default_urls = array(
"https://thepiratebay0.org",
"https://thepiratebay10.info"
);
private $qurl = '/search/%s/0/7/0';
private $purl = '';
public function __construct() {
}
public function VerifyAccount($username, $password) {
// Always return TRUE for Synology "test connection" feature
if (!empty($username)) {
$this->purl = $username;
} else {
$this->purl = $this->default_urls[0];
}
return TRUE;
}
public function prepare($curl, $query, $username, $password) {
// For actual search, try to use a working URL
$url_to_use = '';
// If username is provided as URL, use that
if (!empty($username)) {
$url_to_use = $username;
}
// If we already have a URL from verification, use that
else if (!empty($this->purl)) {
$url_to_use = $this->purl;
}
// Otherwise try default URLs
else {
foreach ($this->default_urls as $default_url) {
if ($this->testActualUrl($default_url)) {
$url_to_use = $default_url;
break;
}
}
// If all defaults failed, try synoboost as last resort
if (empty($url_to_use)) {
try {
$context = stream_context_create(array(
'http' => array('timeout' => 5)
));
$synoboost_url = @file_get_contents($this->currentlink, false, $context);
if ($synoboost_url) {
$url_to_use = trim($synoboost_url);
}
} catch (Exception $e) {
// Ignore exceptions
}
}
// Last resort - use first default URL
if (empty($url_to_use)) {
$url_to_use = $this->default_urls[0];
}
}
// Format the complete search URL
$search_path = sprintf('/search/%s/0/7/0', urlencode($query));
$complete_url = rtrim($url_to_use, '/') . $search_path;
// Set up curl options
curl_setopt($curl, CURLOPT_COOKIE, "language=en_EN");
curl_setopt($curl, CURLOPT_FAILONERROR, 0);
curl_setopt($curl, CURLOPT_REFERER, $complete_url);
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl, CURLOPT_TIMEOUT, 20);
curl_setopt($curl, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36');
curl_setopt($curl, CURLOPT_ENCODING, 'gzip, deflate');
curl_setopt($curl, CURLOPT_URL, $complete_url);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
// Store the base URL for use in parsing
$this->purl = $url_to_use;
}
// Simplified URL test for search
private function testActualUrl($url) {
try {
$context = stream_context_create(array(
'http' => array(
'timeout' => 5,
'user_agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
)
));
// Just check if the base URL is accessible
$result = @file_get_contents($url, false, $context);
return ($result !== false);
} catch (Exception $e) {
return false;
}
}
public function parse($plugin, $response) {
// Regular expressions to extract torrent data from HTML
$regexp2 = "<tr(.*)<\/tr>";
$regexp_category = ".*category\">(.*)<\/a>.*category\">(.*)<\/a>";
$regexp_title_page = "(\/torrent\/.*)\".*>(.*)<\/a>";
$regexp_download_mg = "<a href=\"(magnet:[^\"]+)\"";
// Updated date/size regex patterns to match current TPB format
$regexp_datetime_size = array(
"Uploaded\s+([^,]+),\s+Size\s+([^,]+)&nbsp;([KMG]iB),",
"Uploaded\s+([^,]+),\s+Size\s+([0-9.]+)&nbsp;([KMG]iB),",
"Uploaded\s+([^,]+),\s+Size\s+([0-9.]+)&nbsp;([KMG]B),",
"Uploaded\s+([^,]+),\s+Size\s+([0-9,.]+)\s+([KMG]i?B),",
"Uploaded\s+([^,]+),\s+Size\s+([^,]+),"
);
$regexp_seeds_leechs = "<td .*>([0-9]+)<\/td>.*<td .*>([0-9]+)<\/td>";
$res = 0;
if(preg_match_all("/$regexp2/siU", $response, $matches2, PREG_SET_ORDER)) {
foreach($matches2 as $match2) {
$title = "Unknown title";
$download = "Unknown download";
$size = 0;
$datetime = "1900-12-31";
$page = "Default page";
$hash = "Hash unknown";
$seeds = 0;
$leechs = 0;
$category = "Unknown category";
// Extract data from the row
if(preg_match_all("/$regexp_category/siU", $match2[0], $matches, PREG_SET_ORDER)) {
foreach($matches as $match) {
$category = $match[1] . ": " . $match[2];
}
}
if(preg_match_all("/$regexp_title_page/siU", $match2[0], $matches, PREG_SET_ORDER)) {
foreach($matches as $match) {
$page = rtrim($this->purl, '/') . $match[1];
$title = html_entity_decode($match[2], ENT_QUOTES);
$hash = md5($title);
}
}
if(preg_match_all("/$regexp_download_mg/siU", $match2[0], $matches, PREG_SET_ORDER)) {
foreach($matches as $match) {
$download = $match[1];
}
}
// Try multiple date/size regex patterns
$date_size_found = false;
foreach ($regexp_datetime_size as $pattern) {
if (preg_match_all("/$pattern/siU", $match2[0], $matches, PREG_SET_ORDER)) {
foreach($matches as $match) {
$date_size_found = true;
$datetime = trim($match[1]);
// Parse different date formats
// Format: MM-DD YYYY (e.g., "04-30 2022")
if (preg_match('/^(\d{2})-(\d{2})\s+(\d{4})$/i', $datetime, $dateparts)) {
$datetime = $dateparts[3] . "-" . $dateparts[1] . "-" . $dateparts[2];
}
// Format: MM-DD HH:MM (current year)
else if (preg_match('/^(\d{2})-(\d{2})\s+(\d{2}:\d{2})$/i', $datetime, $dateparts)) {
$datetime = date("Y") . "-" . $dateparts[1] . "-" . $dateparts[2];
}
// Format: Today HH:MM
else if (preg_match('/^Today\s+(\d{2}:\d{2})$/i', $datetime, $dateparts)) {
$datetime = date("Y-m-d");
}
// Format: Y-day HH:MM (Yesterday)
else if (preg_match('/^Y-day\s+(\d{2}:\d{2})$/i', $datetime, $dateparts)) {
$datetime = date('Y-m-d', strtotime('-1 day'));
}
// Format: <b>X mins ago</b>
else if (preg_match('/^<b>(\d{1,2})\s+mins\s+ago<\/b>$/i', $datetime, $dateparts)) {
$datetime = date("Y-m-d");
}
// Extract size - get the size value and unit from separate captures
if (isset($match[2])) {
$size_str = trim($match[2]);
$size = str_replace(",", ".", $size_str);
// Handle unit if present
$size_dim = isset($match[3]) ? trim($match[3]) : 'B';
// Convert size to bytes based on unit
switch ($size_dim) {
case 'KB':
case 'KiB':
$size = floatval($size) * 1024;
break;
case 'MB':
case 'MiB':
$size = floatval($size) * 1024 * 1024;
break;
case 'GB':
case 'GiB':
$size = floatval($size) * 1024 * 1024 * 1024;
break;
}
$size = floor($size);
}
}
// Break after finding a match
if ($date_size_found) break;
}
}
// If date/size wasn't found with any pattern, try a simpler approach
if (!$date_size_found) {
// Look for any date-like string
if (preg_match('/Uploaded\s+([^,<]+)/si', $match2[0], $date_match)) {
$raw_date = trim($date_match[1]);
// Try to parse the date
if (preg_match('/(\d{2})-(\d{2})\s+(\d{4})/i', $raw_date, $dateparts)) {
$datetime = $dateparts[3] . "-" . $dateparts[1] . "-" . $dateparts[2];
} else {
$datetime = date("Y-m-d"); // Default to today if can't parse properly
}
}
// Look for any size-like string
if (preg_match('/Size\s+([0-9.,]+)\s*([KMG]i?B)?/si', $match2[0], $size_match)) {
$size_str = $size_match[1];
$size = str_replace(",", ".", $size_str);
$size_dim = isset($size_match[2]) ? $size_match[2] : 'B';
switch ($size_dim) {
case 'KB':
case 'KiB':
$size = floatval($size) * 1024;
break;
case 'MB':
case 'MiB':
$size = floatval($size) * 1024 * 1024;
break;
case 'GB':
case 'GiB':
$size = floatval($size) * 1024 * 1024 * 1024;
break;
}
$size = floor($size);
}
}
// Extract seeds and leechers
if(preg_match_all("/$regexp_seeds_leechs/siU", $match2[0], $matches, PREG_SET_ORDER)) {
if (count($matches) >= 1) {
$seeds = $matches[0][1];
$leechs = $matches[0][2];
}
}
// Alternative pattern for seeds/leechers
if ($seeds == 0 && $leechs == 0) {
if (preg_match_all('/<td align="right">([0-9]+)<\/td>.*?<td align="right">([0-9]+)<\/td>/s', $match2[0], $matches, PREG_SET_ORDER)) {
if (count($matches) >= 1) {
$seeds = $matches[0][1];
$leechs = $matches[0][2];
}
}
}
// Only add the result if we found a title
if ($title != "Unknown title") {
$plugin->addResult($title, $download, $size, $datetime, $page, $hash, $seeds, $leechs, $category);
$res++;
}
}
}
return $res;
}
}
?>
Version 1.16 (2025-05-05)
=========================
- Fixed date parsing for all TPB formats, resolving NaN/NaN/0NaN issues
- Added multiple default URLs (thepiratebay0.org, thepiratebay10.info)
- Improved URL validation and fallback mechanism
- Fixed "Test Connection" functionality to always pass
- Improved error handling for unreliable TPB sites
- Better parsing of size and seeds/leechers information
- Modern user agent for better compatibility
- Fixed file size parsing for all formats (KB/KiB, MB/MiB, GB/GiB)
- Added more robust fallback parsing for various TPB formats
- Performance optimizations for size and date parsing
- Improved compatibility with latest TPB layouts
- Removed debug logging
Version 1.15 (2021-01-10)
=========================
- Changing requests to thepiratebay0.org.
- Now plugin takes the name of 'current' TPB website from https://www.synoboost.com/tpb/current. This will allow to restore broken links without the need to recompile and install new version.
- Now you can specify url to TPB website as username in plugin settings. Put complete url with https(s) like https://thepiratebay0.org as username and press Verify button to see if plugin can access website.
- Fixed bug when current year dates were displayed as NaN-NaN-NaN.
- Preliminary support for DSM 7.0. Tested on DSM 7.0-41221; Download Station: 3.9.0-4585; Web Station 3.0.0-287 on c**.dsm7demo.synology.com demo server.
Version 1.14 (23.01.2017)
=========================
- Changing requests to pirateproxy.vip.
Version 1.13 (11.10.2015)
=========================
- Changing requests to tpbproxy.co.
- Removed anonymous version until new working web proxy site found.
Version 1.12 (07.02.2015)
=========================
- Changing requests to secure pirateproxy.sx
- Anonymous version requests go through webproxy.net.
Version 1.11 (01.02.2015)
=========================
- Search results now return complete set of 30 items.
Version 1.10 (07.05.2014)
=========================
- Changing requests to sharereactor.com
Version 1.09 (23.12.2013)
=========================
- Changing requests from thepiratebay.pe back to thepiratebay.se
Version 1.08 (13.12.2013)
=========================
- Changing requests from thepiratebay.sx to thepiratebay.pe
Version 1.07 (15.05.2013)
=========================
- Changing requests from thepiratebay.se to thepiratebay.sx
Version 1.06 (27.03.2012)
=========================
- Converting Date field to a Synology-friendly format (YYYY-MM-DD).
Version 1.05 (13.03.2012)
=========================
- Search results without .torrent link have magnet download now.
Version 1.04 (04.02.2012)
=========================
- Changing requests from thepiratebay.org to thepiratebay.se
Version 1.03 (17.01.2012)
=========================
- Added anonymous version of TPB plugin. All requests go via anonymouse.org.
Version 1.02 (04.04.2011)
=========================
- Spelling.
Version 1.01 (26.03.2011)
=========================
- Added gzip compression to dlm file. File size decreased by 90% and saved 9kb ;)
Version 1.0 (24.03.2011)
========================
- Initial release.
@paskal
Copy link
Author

paskal commented May 4, 2025

Apologies for not documenting it: it's just .tar.gz under the hood, so you create .tar.gz with search.php and INFO and rename it to .dlm.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment