BitTorrent v2 support enhancements 🥳 (#876)

* BitTorrent v2 support enchancements

* Added torrent name sanitizing

* Using faster language construct instead of function call for name sanitizing

* Minor improvements

- Fixed deformed avatars => get_avatar() function
- Removed outdated dc links support

* Code comments

* Changed function name

* Added table generation function with file list

For search engines to index

* Used humn_size function for size formatting in table generation

* Fixed typo

* Removed useless language variables

* Fixed code formatting

* Fixed broken displaying magnet link

* Torrent fields sanitization in table

* Fixed info hash issue

* Support for v2 only torrents

* Code re-formatting

* Typo

* Update Torrent.php

* Update functions.php

* Updated

* Updated

* Update Torrent.php

* Update TorrentFileList.php

* Update Torrent.php

* Update Torrent.php

* Update Torrent.php

* Update Torrent.php

* Error msg

* Update Torrent.php

* Update Torrent.php

* Updated

* Update Torrent.php

* Update Torrent.php

* Update config.php

* Update mysql.sql

* Update mysql.sql

* Update mysql.sql

* Update mysql.sql

* Update mysql.sql

* String fixes

* Update TorrentFileList.php

---------

Co-authored-by: Roman Kelesidis <roman25052006.kelesh@gmail.com>
This commit is contained in:
Constantine Kovalensky 2023-09-02 21:55:21 +04:00 committed by GitHub
commit 50926639cf
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 139 additions and 85 deletions

View file

@ -188,7 +188,11 @@ if ($lp_info) {
} else { } else {
// Verify if torrent registered on tracker and user authorized // Verify if torrent registered on tracker and user authorized
$info_hash_sql = rtrim(DB()->escape($info_hash), ' '); $info_hash_sql = rtrim(DB()->escape($info_hash), ' ');
$info_hash_where = $is_bt_v2 ? "WHERE tor.info_hash_v2 = '$info_hash_sql'" : "WHERE tor.info_hash = '$info_hash_sql'"; /**
* Поскольку торрент-клиенты в настоящее время обрезают инфо-хэш до 20 символов (независимо от его типа, как известно v1 = 20 символов, а v2 = 32 символа),
* то результатов $is_bt_v2 (исходя из длины строки определяем тип инфо-хэша) проверки нам будет мало, именно поэтому происходит поиск v2 хэша, если торрент является v1 (по длине) и если в tor.info_hash столбце нету v1 хэша.
*/
$info_hash_where = $is_bt_v2 ? "WHERE tor.info_hash_v2 = '$info_hash_sql'" : "WHERE tor.info_hash = '$info_hash_sql' OR tor.info_hash_v2 LIKE '$info_hash_sql%'";
$passkey_sql = DB()->escape($passkey); $passkey_sql = DB()->escape($passkey);
$sql = " $sql = "

View file

@ -53,7 +53,11 @@ function msg_die($msg)
require __DIR__ . '/includes/init_tr.php'; require __DIR__ . '/includes/init_tr.php';
$info_hash_sql = rtrim(DB()->escape($info_hash), ' '); $info_hash_sql = rtrim(DB()->escape($info_hash), ' ');
$info_hash_where = $is_bt_v2 ? "WHERE tor.info_hash_v2 = '$info_hash_sql'" : "WHERE tor.info_hash = '$info_hash_sql'"; /**
* Поскольку торрент-клиенты в настоящее время обрезают инфо-хэш до 20 символов (независимо от его типа, как известно v1 = 20 символов, а v2 = 32 символа),
* то результатов $is_bt_v2 (исходя из длины строки определяем тип инфо-хэша) проверки нам будет мало, именно поэтому происходит поиск v2 хэша, если торрент является v1 (по длинне) и если в tor.info_hash столбце нету v1 хэша.
*/
$info_hash_where = $is_bt_v2 ? "WHERE tor.info_hash_v2 = '$info_hash_sql'" : "WHERE tor.info_hash = '$info_hash_sql' OR tor.info_hash_v2 LIKE '$info_hash_sql%'";
$row = DB()->fetch_row(" $row = DB()->fetch_row("
SELECT tor.complete_count, snap.seeders, snap.leechers SELECT tor.complete_count, snap.seeders, snap.leechers

View file

@ -291,7 +291,7 @@ CREATE TABLE IF NOT EXISTS `bb_bt_torrents`
`tor_type` TINYINT(1) NOT NULL DEFAULT '0', `tor_type` TINYINT(1) NOT NULL DEFAULT '0',
`speed_up` INT(11) NOT NULL DEFAULT '0', `speed_up` INT(11) NOT NULL DEFAULT '0',
`speed_down` INT(11) NOT NULL DEFAULT '0', `speed_down` INT(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`info_hash`), PRIMARY KEY (`topic_id`),
UNIQUE KEY `post_id` (`post_id`), UNIQUE KEY `post_id` (`post_id`),
UNIQUE KEY `topic_id` (`topic_id`), UNIQUE KEY `topic_id` (`topic_id`),
UNIQUE KEY `attach_id` (`attach_id`), UNIQUE KEY `attach_id` (`attach_id`),

View file

@ -37,6 +37,9 @@ if (!$tor = \SandFox\Bencode\Bencode::decode($file_contents)) {
} }
$torrent = new TorrentPier\Legacy\TorrentFileList($tor); $torrent = new TorrentPier\Legacy\TorrentFileList($tor);
$tor_filelist = $torrent->get_filelist(); if (($tor['info']['meta version'] ?? null) == 2 && is_array($tor['info']['file tree'] ?? null)) {
$tor_filelist = $torrent->fileTreeList($tor['info']['file tree'], $tor['info']['name'] ?? ''); // v2
} else {
$tor_filelist = $torrent->get_filelist(); // v1
}
$this->response['html'] = $tor_filelist; $this->response['html'] = $tor_filelist;

View file

@ -211,7 +211,7 @@ if ($tor_reged && $tor_info) {
'DL_TITLE_CLASS' => (isset($bt_userdata['user_status'])) ? $dl_status_css[$bt_userdata['user_status']] : 'gen', 'DL_TITLE_CLASS' => (isset($bt_userdata['user_status'])) ? $dl_status_css[$bt_userdata['user_status']] : 'gen',
'FILESIZE' => $tor_file_size, 'FILESIZE' => $tor_file_size,
'MAGNET' => $tor_magnet, 'MAGNET' => $tor_magnet,
'HASH' => strtoupper(bin2hex($tor_info['info_hash'])), 'HASH' => !empty($tor_info['info_hash']) ? strtoupper(bin2hex($tor_info['info_hash'])) : false,
'HASH_V2' => !empty($tor_info['info_hash_v2']) ? strtoupper(bin2hex($tor_info['info_hash_v2'])) : false, 'HASH_V2' => !empty($tor_info['info_hash_v2']) ? strtoupper(bin2hex($tor_info['info_hash_v2'])) : false,
'DOWNLOAD_COUNT' => declension((int)$download_count, 'times'), 'DOWNLOAD_COUNT' => declension((int)$download_count, 'times'),
'REGED_TIME' => bb_date($tor_info['reg_time']), 'REGED_TIME' => bb_date($tor_info['reg_time']),

View file

@ -647,8 +647,9 @@ $bb_cfg['tracker'] = [
'retracker_host' => 'http://retracker.local/announce', 'retracker_host' => 'http://retracker.local/announce',
'guest_tracker' => true, 'guest_tracker' => true,
'search_by_tor_status' => true, 'search_by_tor_status' => true,
'freeleech' => false, // freelech mode (If enabled, then disable "gold_silver_enabled") 'freeleech' => false, // freeleech mode (If enabled, then disable "gold_silver_enabled")
'gold_silver_enabled' => true // golden / silver days mode (If enabled, then disable "freeleech") 'gold_silver_enabled' => true, // golden / silver days mode (If enabled, then disable "freeleech")
'disabled_v2_torrents' => false // allow registration of v2-only torrents
]; ];
// Ratio settings // Ratio settings

View file

@ -1787,7 +1787,20 @@ function create_magnet(string $infohash, string $infohash_v2, string $auth_key):
return false; return false;
} }
return '<a href="magnet:?xt=urn:btih:' . bin2hex($infohash) . (!empty($infohash_v2) ? '&xt=urn:btmh:1220' . bin2hex($infohash_v2) : '') . '&tr=' . urlencode($bb_cfg['bt_announce_url'] . "?{$bb_cfg['passkey_key']}=$auth_key") . '"><img src="' . $images['icon_magnet'] . '" width="12" height="12" border="0" /></a>'; $magnet = 'magnet:?';
if (!empty($infohash)) {
$magnet .= 'xt=urn:btih:' . bin2hex($infohash);
}
if (!empty($infohash_v2)) {
if (!empty($infohash)) {
$magnet .= '&';
}
$magnet .= 'xt=urn:btmh:1220' . bin2hex($infohash_v2);
}
return '<a href="' . $magnet . '&tr=' . urlencode($bb_cfg['bt_announce_url'] . "?{$bb_cfg['passkey_key']}=$auth_key") . '"><img src="' . $images['icon_magnet'] . '" width="12" height="12" border="0" /></a>';
} }
function set_die_append_msg($forum_id = null, $topic_id = null, $group_id = null) function set_die_append_msg($forum_id = null, $topic_id = null, $group_id = null)
@ -1876,20 +1889,17 @@ function profile_url($data)
return $profile; return $profile;
} }
function get_avatar($user_id, $ext_id, $allow_avatar = true, $height = 100, $width = 100) function get_avatar($user_id, $ext_id, $allow_avatar = true)
{ {
global $bb_cfg; global $bb_cfg;
$height = $height ? 'height="' . $height . '"' : ''; $user_avatar = '<img src="' . make_url($bb_cfg['avatars']['display_path'] . $bb_cfg['avatars']['no_avatar']) . '" alt="' . $user_id . '" />';
$width = $width ? 'width="' . $width . '"' : '';
$user_avatar = '<img src="' . make_url($bb_cfg['avatars']['display_path'] . $bb_cfg['avatars']['no_avatar']) . '" alt="' . $user_id . '" ' . $height . ' ' . $width . ' />';
if ($user_id == BOT_UID && $bb_cfg['avatars']['bot_avatar']) { if ($user_id == BOT_UID && $bb_cfg['avatars']['bot_avatar']) {
$user_avatar = '<img src="' . make_url($bb_cfg['avatars']['display_path'] . $bb_cfg['avatars']['bot_avatar']) . '" alt="' . $user_id . '" ' . $height . ' ' . $width . ' />'; $user_avatar = '<img src="' . make_url($bb_cfg['avatars']['display_path'] . $bb_cfg['avatars']['bot_avatar']) . '" alt="' . $user_id . '" />';
} elseif ($allow_avatar && $ext_id) { } elseif ($allow_avatar && $ext_id) {
if (file_exists(get_avatar_path($user_id, $ext_id))) { if (file_exists(get_avatar_path($user_id, $ext_id))) {
$user_avatar = '<img src="' . make_url(get_avatar_path($user_id, $ext_id, $bb_cfg['avatars']['display_path'])) . '" alt="' . $user_id . '" ' . $height . ' ' . $width . ' />'; $user_avatar = '<img src="' . make_url(get_avatar_path($user_id, $ext_id, $bb_cfg['avatars']['display_path'])) . '" alt="' . $user_id . '" />';
} }
} }

View file

@ -1082,8 +1082,6 @@ $lang['SEEDING'] = 'Seed';
$lang['LEECHING'] = 'Leech'; $lang['LEECHING'] = 'Leech';
$lang['IS_REGISTERED'] = 'Registered'; $lang['IS_REGISTERED'] = 'Registered';
$lang['MAGNET'] = 'Magnet'; $lang['MAGNET'] = 'Magnet';
$lang['DC_MAGNET'] = 'Search in DC++ by filename';
$lang['DC_MAGNET_EXT'] = 'Search in DC++ by extension';
//torrent status mod //torrent status mod
$lang['TOR_STATUS'] = 'Status'; $lang['TOR_STATUS'] = 'Status';

View file

@ -287,8 +287,10 @@ class Torrent
$topic_id = $torrent['topic_id']; $topic_id = $torrent['topic_id'];
$forum_id = $torrent['forum_id']; $forum_id = $torrent['forum_id'];
$poster_id = $torrent['poster_id']; $poster_id = $torrent['poster_id'];
$info_hash = $info_hash_v2 = null; $info_hash = $info_hash_v2 = null;
$info_hash_sql = $info_hash_v2_sql = null; $info_hash_sql = $info_hash_v2_sql = $info_hash_where = null;
$v2_hash = null;
if ($torrent['extension'] !== TORRENT_EXT) { if ($torrent['extension'] !== TORRENT_EXT) {
return self::torrent_error_exit($lang['NOT_TORRENT']); return self::torrent_error_exit($lang['NOT_TORRENT']);
@ -331,7 +333,7 @@ class Torrent
if ($bb_cfg['bt_check_announce_url']) { if ($bb_cfg['bt_check_announce_url']) {
include INC_DIR . '/torrent_announce_urls.php'; include INC_DIR . '/torrent_announce_urls.php';
$ann = (@$tor['announce']) ? $tor['announce'] : ''; $ann = isset($tor['announce']) ? $tor['announce'] : '';
$announce_urls['main_url'] = $bb_cfg['bt_announce_url']; $announce_urls['main_url'] = $bb_cfg['bt_announce_url'];
if (!$ann || !\in_array($ann, $announce_urls)) { if (!$ann || !\in_array($ann, $announce_urls)) {
@ -340,35 +342,45 @@ class Torrent
} }
} }
$info = (@$tor['info']) ? $tor['info'] : []; $info = isset($tor['info']) ? $tor['info'] : [];
if (!isset($info['name'], $info['piece length'], $info['pieces']) || \strlen($info['pieces']) % 20 != 0) { if (!isset($info['name'], $info['piece length'])) {
return self::torrent_error_exit($lang['TORFILE_INVALID']); return self::torrent_error_exit($lang['TORFILE_INVALID']);
} }
// Check if torrent contains info_hash v2 // Check if torrent contains info_hash v2 or v1
$bt_v2 = false; $bt_v1 = $bt_v2 = false;
if (($info['meta version'] ?? null) == 2 && is_array($info['file tree'] ?? null)) { if (($info['meta version'] ?? null) == 2 && is_array($info['file tree'] ?? null)) {
$bt_v2 = true; $bt_v2 = true;
} }
if (isset($info['pieces'])) {
$bt_v1 = true;
}
if ($bb_cfg['tracker']['disabled_v2_torrents'] && $bt_v2 && !$bt_v1) {
return self::torrent_error_exit('v2-only torrents were disabled, allowed: v1 and hybrids');
}
// Getting info_hash v1 // Getting info_hash v1
$info_hash = pack('H*', sha1(\SandFox\Bencode\Bencode::encode($info))); if ($bt_v1) {
$info_hash_sql = rtrim(DB()->escape($info_hash), ' '); $info_hash = pack('H*', sha1(\SandFox\Bencode\Bencode::encode($info)));
$info_hash_md5 = md5($info_hash); $info_hash_sql = rtrim(DB()->escape($info_hash), ' ');
$info_hash_where = "WHERE info_hash = '$info_hash_sql'";
}
// Getting info_hash v2 // Getting info_hash v2
if ($bt_v2) { if ($bt_v2) {
$info_hash_v2 = pack('H*', hash('sha256', \SandFox\Bencode\Bencode::encode($info))); $v2_hash = hash('sha256', \SandFox\Bencode\Bencode::encode($info));
$info_hash_v2 = pack('H*', $v2_hash);
$info_hash_v2_sql = rtrim(DB()->escape($info_hash_v2), ' '); $info_hash_v2_sql = rtrim(DB()->escape($info_hash_v2), ' ');
$info_hash_where = "WHERE info_hash_v2 = '$info_hash_v2_sql'";
} }
// Ocelot // Ocelot
if ($bb_cfg['ocelot']['enabled']) { if ($bb_cfg['ocelot']['enabled']) {
self::ocelot_update_tracker('add_torrent', ['info_hash' => rawurlencode($info_hash), 'id' => $topic_id, 'freetorrent' => 0]); self::ocelot_update_tracker('add_torrent', ['info_hash' => rawurlencode($info_hash ?? hex2bin(substr($v2_hash, 0, 40))), 'id' => $topic_id, 'freetorrent' => 0]);
} }
if ($row = DB()->fetch_row("SELECT topic_id FROM " . BB_BT_TORRENTS . " WHERE info_hash = '$info_hash_sql' LIMIT 1")) { if ($row = DB()->fetch_row("SELECT topic_id FROM " . BB_BT_TORRENTS . " $info_hash_where LIMIT 1")) {
$msg = sprintf($lang['BT_REG_FAIL_SAME_HASH'], TOPIC_URL . $row['topic_id']); $msg = sprintf($lang['BT_REG_FAIL_SAME_HASH'], TOPIC_URL . $row['topic_id']);
bb_die($msg); bb_die($msg);
set_die_append_msg($forum_id, $topic_id); set_die_append_msg($forum_id, $topic_id);
@ -378,13 +390,29 @@ class Torrent
if (isset($info['length'])) { if (isset($info['length'])) {
$totallen = (float)$info['length']; $totallen = (float)$info['length'];
} elseif (isset($info['files']) && \is_array($info['files'])) { } elseif ($bt_v1 && isset($info['files']) && \is_array($info['files'])) {
foreach ($info['files'] as $fn => $f) { foreach ($info['files'] as $fn => $f) {
// Exclude padding files // Exclude padding files
if (($f['attr'] ?? null) !== 'p') { if (($f['attr'] ?? null) !== 'p') {
$totallen += (float)$f['length']; $totallen += (float)$f['length'];
} }
} }
} elseif ($bt_v2) {
$fileTreeSize = function (array $array, string $name = '') use (&$fileTreeSize) {
$size = 0;
foreach ($array as $key => $value) {
if (!isset($value[''])) {
$size += $fileTreeSize($value);
} else {
$size += (int)$value['']['length'];
}
}
return $size;
};
$totallen = (float)$fileTreeSize($info['file tree']);
} else { } else {
return self::torrent_error_exit($lang['TORFILE_INVALID']); return self::torrent_error_exit($lang['TORFILE_INVALID']);
} }

View file

@ -43,45 +43,18 @@ class TorrentFileList
{ {
global $html; global $html;
if (($this->tor_decoded['info']['meta version'] ?? null) == 2 && is_array($this->tor_decoded['info']['file tree'] ?? null)) { $this->build_filelist_array();
// v2
function fileTree($array, $name = '')
{
$folders = [];
$rootFiles = [];
foreach ($array as $key => $value) { if ($this->multiple) {
if (is_array($value) && !isset($value[''])) { if ($this->files_ary['/'] !== '') {
$html_v2 = fileTree($value); $this->files_ary = array_merge($this->files_ary, $this->files_ary['/']);
$folders[] = "<li><span class=\"b\">$key</span><ul>$html_v2</ul></li>"; unset($this->files_ary['/']);
} else {
$length = $value['']['length'];
$root = bin2hex($value['']['pieces root'] ?? '');
$rootFiles[] = "<li><span>$key<i>$length</i> <h style='color:gray;'>$root</h></span></li>";
}
}
$allItems = array_merge($folders, $rootFiles);
return '<div class="tor-root-dir">' . (empty($folders) ? '' : $name) . '</div><ul class="tree-root">' . implode('', $allItems) . '</ul>';
} }
$filelist = $html->array2html($this->files_ary);
return fileTree($this->tor_decoded['info']['file tree'], $this->tor_decoded['info']['name']); return "<div class=\"tor-root-dir\">{$this->root_dir}</div>$filelist";
} else {
// v1
$this->build_filelist_array();
if ($this->multiple) {
if ($this->files_ary['/'] !== '') {
$this->files_ary = array_merge($this->files_ary, $this->files_ary['/']);
unset($this->files_ary['/']);
}
$filelist = $html->array2html($this->files_ary);
return "<div class=\"tor-root-dir\">{$this->root_dir}</div>$filelist";
}
return implode('', $this->files_ary['/']);
} }
return implode('', $this->files_ary['/']);
} }
/** /**
@ -134,42 +107,76 @@ class TorrentFileList
$GLOBALS['bnc_error'] = 1; $GLOBALS['bnc_error'] = 1;
break; break;
} }
$cur_files_ary[] = $this->build_file_item($name, $length); $cur_files_ary[] = "$name <i>$length</i>";
} }
} }
asort($cur_files_ary); asort($cur_files_ary);
} else { } else {
$name = $f['path'][0]; $name = $f['path'][0];
$this->files_ary['/'][] = $this->build_file_item($name, $length); $this->files_ary['/'][] = "$name <i>$length</i>";
natsort($this->files_ary['/']); natsort($this->files_ary['/']);
} }
} }
} else { } else {
$name = clean_tor_dirname($info['name']); $name = clean_tor_dirname($info['name']);
$length = (float)$info['length']; $length = (float)$info['length'];
$this->files_ary['/'][] = $this->build_file_item($name, $length); $this->files_ary['/'][] = "$name <i>$length</i>";
natsort($this->files_ary['/']); natsort($this->files_ary['/']);
} }
} }
/** /**
* Формирование файла * File list generation for v2 supported torrents
* *
* @param $name * @param array $array
* @param $length * @param string $name
* @return string * @return string
*/ */
private function build_file_item($name, $length): string public function fileTreeList(array $array, string $name = ''): string
{ {
global $bb_cfg, $images, $lang; $folders = [];
$rootFiles = [];
$magnet_name = $magnet_ext = ''; foreach ($array as $key => $value) {
$key = htmlCHR($key);
if ($bb_cfg['magnet_links_enabled']) { if (!isset($value[''])) {
$magnet_name = '<a title="' . $lang['DC_MAGNET'] . '" href="dchub:magnet:?kt=' . $name . '&xl=' . $length . '"><img src="' . $images['icon_dc_magnet'] . '" width="10" height="10" border="0" /></a>'; $html_v2 = $this->fileTreeList($value);
$magnet_ext = '<a title="' . $lang['DC_MAGNET_EXT'] . '" href="dchub:magnet:?kt=.' . substr(strrchr($name, '.'), 1) . '&xl=' . $length . '"><img src="' . $images['icon_dc_magnet_ext'] . '" width="10" height="10" border="0" /></a>'; $folders[] = "<li><span class=\"b\">$key</span><ul>$html_v2</ul></li>";
} else {
$length = (int)$value['']['length'];
$root = bin2hex($value['']['pieces root'] ?? '');
$rootFiles[] = "<li><span>$key<i>$length</i><p>$root</p></span></li>";
}
} }
return "$name <i>$length</i> $magnet_name $magnet_ext"; $allFiles = implode('', [...$folders, ...$rootFiles]);
return '<div class="tor-root-dir">' . (empty($folders) ? '' : htmlCHR($name)) . '</div><ul class="tree-root">' . $allFiles . '</ul>';
}
/**
* Table generation for BitTorrent v2 compatible torrents
*
* @param array $array
* @param string $parent
* @return array
*/
public function fileTreeTable(array $array, string $parent = ''): array
{
$filesList = [];
foreach ($array as $key => $value) {
$key = htmlCHR($key);
$current = "$parent/$key";
if (!isset($value[''])) {
$this->fileTreeTable($value, $current);
} else {
$length = (int)$value['']['length'];
$root = bin2hex($value['']['pieces root'] ?? '');
$filesList[] = '<tr><td>' . $current . '</td><td>' . humn_size($length, 2) . '</td><td>' . $root . '</td></tr><tr>';
}
}
return $filesList;
} }
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

View file

@ -72,8 +72,6 @@ $images['folder_dl_hot_new'] = $_main . 'folder_dl_hot_new.gif';
$images['icon_clip'] = $_img . 'icon_clip.gif'; $images['icon_clip'] = $_img . 'icon_clip.gif';
$images['icon_dn'] = $_img . 'icon_dn.gif'; $images['icon_dn'] = $_img . 'icon_dn.gif';
$images['icon_magnet'] = $_img . 'magnet.png'; $images['icon_magnet'] = $_img . 'magnet.png';
$images['icon_dc_magnet'] = $_img . 'dc_magnet.png';
$images['icon_dc_magnet_ext'] = $_img . 'dc_magnet_ext.png';
// posting_icons // posting_icons
$images['post_new'] = $_lang . 'post.gif'; $images['post_new'] = $_lang . 'post.gif';

View file

@ -144,7 +144,7 @@
<table class="attach bordered med"> <table class="attach bordered med">
<tr class="row3"> <tr class="row3">
<th colspan="3" class="{postrow.attach.tor_reged.DL_LINK_CLASS}">{postrow.attach.tor_reged.DOWNLOAD_NAME}<!-- IF postrow.attach.tor_reged.TOR_FROZEN == 0 --><!-- IF MAGNET_LINKS -->&nbsp;{postrow.attach.tor_reged.MAGNET}<!-- ENDIF --><!-- ENDIF --></th> <th colspan="3" class="{postrow.attach.tor_reged.DL_LINK_CLASS}">{postrow.attach.tor_reged.DOWNLOAD_NAME}<!-- IF MAGNET_LINKS -->&nbsp;{postrow.attach.tor_reged.MAGNET}<!-- ENDIF --></th>
</tr> </tr>
<!-- IF postrow.attach.tor_reged.TOR_TYPE --> <!-- IF postrow.attach.tor_reged.TOR_TYPE -->
<tr class="row4"> <tr class="row4">
@ -156,7 +156,7 @@
<td width="70%"> <td width="70%">
{postrow.attach.tor_reged.TRACKER_LINK} {postrow.attach.tor_reged.TRACKER_LINK}
[ <span title="{postrow.attach.tor_reged.REGED_DELTA}">{postrow.attach.tor_reged.REGED_TIME}</span> ] [ <span title="{postrow.attach.tor_reged.REGED_DELTA}">{postrow.attach.tor_reged.REGED_TIME}</span> ]
<br><br>info_hash: {postrow.attach.tor_reged.HASH} <br><!-- IF postrow.attach.tor_reged.HASH --><br>info_hash: {postrow.attach.tor_reged.HASH}<!-- ENDIF -->
<!-- IF postrow.attach.tor_reged.HASH_V2 --><br>info_hash v2: {postrow.attach.tor_reged.HASH_V2}<!-- ENDIF --> <!-- IF postrow.attach.tor_reged.HASH_V2 --><br>info_hash v2: {postrow.attach.tor_reged.HASH_V2}<!-- ENDIF -->
</td> </td>
<td width="15%" rowspan="4" class="tCenter pad_6"> <td width="15%" rowspan="4" class="tCenter pad_6">
@ -326,6 +326,7 @@ $('#tor-filelist-btn').click(function(){
} }
#tor-filelist i { color: #7A7A7A; padding-left: 4px; } #tor-filelist i { color: #7A7A7A; padding-left: 4px; }
#tor-filelist s { color: #0000FF; text-decoration: none; } #tor-filelist s { color: #0000FF; text-decoration: none; }
#tor-filelist p { color: #7C7C7C; text-decoration: none; }
#tor-filelist .b > s { color: #800000; } #tor-filelist .b > s { color: #800000; }
#tor-filelist .b { font-weight: bold; padding-left: 20px; background: transparent url('styles/images/folder.gif') no-repeat 3px 50%;} #tor-filelist .b { font-weight: bold; padding-left: 20px; background: transparent url('styles/images/folder.gif') no-repeat 3px 50%;}
#tor-filelist ul li span { padding-left: 20px; background: transparent url('styles/images/page.gif') no-repeat 3px 50%;} #tor-filelist ul li span { padding-left: 20px; background: transparent url('styles/images/page.gif') no-repeat 3px 50%;}