BioTorrents.de’s version of Gazelle
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

browse.php 41KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090
  1. <?php
  2. #declare(strict_types = 1);
  3. require_once SERVER_ROOT.'/sections/torrents/functions.php';
  4. // The "order by x" links on columns headers
  5. function header_link($SortKey, $DefaultWay = 'desc')
  6. {
  7. global $OrderBy, $OrderWay;
  8. if ($SortKey === $OrderBy) {
  9. if ($OrderWay === 'desc') {
  10. $NewWay = 'asc';
  11. } else {
  12. $NewWay = 'desc';
  13. }
  14. } else {
  15. $NewWay = $DefaultWay;
  16. }
  17. return "torrents.php?order_way=$NewWay&amp;order_by=$SortKey&amp;".Format::get_url(['order_way', 'order_by']);
  18. }
  19. if (!empty($_GET['searchstr']) || !empty($_GET['groupname'])) {
  20. if (!empty($_GET['searchstr'])) {
  21. $InfoHash = $_GET['searchstr'];
  22. } else {
  23. $InfoHash = $_GET['groupname'];
  24. }
  25. // Search by info hash
  26. if ($InfoHash = is_valid_torrenthash($InfoHash)) {
  27. $InfoHash = db_string(pack('H*', $InfoHash));
  28. $DB->query("
  29. SELECT ID, GroupID
  30. FROM torrents
  31. WHERE info_hash = '$InfoHash'");
  32. if ($DB->has_results()) {
  33. list($ID, $GroupID) = $DB->next_record();
  34. header("Location: torrents.php?id=$GroupID&torrentid=$ID");
  35. error();
  36. }
  37. }
  38. }
  39. // Setting default search options
  40. if (!empty($_GET['setdefault'])) {
  41. $UnsetList = ['page', 'setdefault'];
  42. $UnsetRegexp = '/(&|^)('.implode('|', $UnsetList).')=.*?(&|$)/i';
  43. $DB->query("
  44. SELECT SiteOptions
  45. FROM users_info
  46. WHERE UserID = ?", $LoggedUser['ID']);
  47. list($SiteOptions) = $DB->next_record(MYSQLI_NUM, false);
  48. $SiteOptions = json_decode($SiteOptions, true) ?? [];
  49. $SiteOptions['DefaultSearch'] = preg_replace($UnsetRegexp, '', $_SERVER['QUERY_STRING']);
  50. $DB->query("
  51. UPDATE users_info
  52. SET SiteOptions = ?
  53. WHERE UserID = ?", json_encode($SiteOptions), $LoggedUser['ID']);
  54. $Cache->begin_transaction("user_info_heavy_$UserID");
  55. $Cache->update_row(false, ['DefaultSearch' => $SiteOptions['DefaultSearch']]);
  56. $Cache->commit_transaction(0);
  57. // Clearing default search options
  58. } elseif (!empty($_GET['cleardefault'])) {
  59. $DB->query("
  60. SELECT SiteOptions
  61. FROM users_info
  62. WHERE UserID = ?", $LoggedUser['ID']);
  63. list($SiteOptions) = $DB->next_record(MYSQLI_NUM, false);
  64. $SiteOptions = json_decode($SiteOptions, true) ?? [];
  65. $SiteOptions['DefaultSearch'] = '';
  66. $DB->query("
  67. UPDATE users_info
  68. SET SiteOptions = ?
  69. WHERE UserID = ?", json_encode($SiteOptions), $LoggedUser['ID']);
  70. $Cache->begin_transaction("user_info_heavy_$UserID");
  71. $Cache->update_row(false, ['DefaultSearch' => '']);
  72. $Cache->commit_transaction(0);
  73. // Use default search options
  74. } elseif (empty($_SERVER['QUERY_STRING']) || (count($_GET) === 1 && isset($_GET['page']))) {
  75. if (!empty($LoggedUser['DefaultSearch'])) {
  76. if (!empty($_GET['page'])) {
  77. $Page = $_GET['page'];
  78. parse_str($LoggedUser['DefaultSearch'], $_GET);
  79. $_GET['page'] = $Page;
  80. } else {
  81. parse_str($LoggedUser['DefaultSearch'], $_GET);
  82. }
  83. }
  84. }
  85. // Terms were not submitted via the search form
  86. if (isset($_GET['searchsubmit'])) {
  87. $GroupResults = !empty($_GET['group_results']);
  88. } else {
  89. $GroupResults = !$LoggedUser['DisableGrouping2'];
  90. }
  91. if (!empty($_GET['order_way']) && $_GET['order_way'] === 'asc') {
  92. $OrderWay = 'asc';
  93. } else {
  94. $OrderWay = 'desc';
  95. }
  96. if (empty($_GET['order_by']) || !isset(TorrentSearch::$SortOrders[$_GET['order_by']])) {
  97. $OrderBy = 'time'; // For header links
  98. } else {
  99. $OrderBy = $_GET['order_by'];
  100. }
  101. $Page = !empty($_GET['page']) ? (int) $_GET['page'] : 1;
  102. $Search = new TorrentSearch($GroupResults, $OrderBy, $OrderWay, $Page, TORRENTS_PER_PAGE);
  103. # Three profile toggle options
  104. if (isset($LoggedUser['HideLolicon']) && $LoggedUser['HideLolicon'] === 1) {
  105. $Search->insert_hidden_tags('!lolicon !shotacon !toddlercon');
  106. }
  107. # 2
  108. if (isset($LoggedUser['HideScat']) && $LoggedUser['HideScat'] === 1) {
  109. $Search->insert_hidden_tags('!scat');
  110. }
  111. # 3
  112. if (isset($LoggedUser['HideSnuff']) && $LoggedUser['HideSnuff'] === 1) {
  113. $Search->insert_hidden_tags('!snuff');
  114. }
  115. $Results = $Search->query($_GET);
  116. $Groups = $Search->get_groups();
  117. $NumResults = $Search->record_count();
  118. $HideFilter = isset($LoggedUser['ShowTorFilter']) && $LoggedUser['ShowTorFilter'] === 0;
  119. // This is kinda ugly, but the enormous if paragraph was really hard to read
  120. $AdvancedSearch = !empty($_GET['action']) && $_GET['action'] === 'advanced';
  121. $AdvancedSearch |= !empty($LoggedUser['SearchType']) && (empty($_GET['action']) || $_GET['action'] === 'advanced');
  122. $AdvancedSearch &= check_perms('site_advanced_search');
  123. if ($AdvancedSearch) {
  124. $Action = 'action=advanced';
  125. $HideBasic = ' hidden';
  126. $HideAdvanced = '';
  127. } else {
  128. $Action = 'action=basic';
  129. $HideBasic = '';
  130. $HideAdvanced = ' hidden';
  131. }
  132. # Start the search form
  133. # Fortunately it's very easy to search via
  134. # torrentsearch.class.php
  135. View::show_header('Browse Torrents', 'browse');
  136. ?>
  137. <div>
  138. <div class="header">
  139. <h2>Torrents</h2>
  140. </div>
  141. <form class="search_form" name="torrents" method="get" onsubmit="$(this).disableUnset();">
  142. <div class="box filter_torrents">
  143. <div class="head">
  144. <strong>
  145. <span id="ft_basic" class="<?=$HideBasic?>">Basic Search
  146. (<a class="clickable" onclick="toggleTorrentSearch('advanced')">Advanced</a>)</span>
  147. <span id="ft_advanced" class="<?=$HideAdvanced?>">Advanced
  148. Search (<a class="clickable" onclick="toggleTorrentSearch('basic')">Basic</a>)</span>
  149. </strong>
  150. <span class="float_right">
  151. <a onclick="return toggleTorrentSearch(0);" id="ft_toggle" class="brackets"><?=$HideFilter ? 'Show' : 'Hide'?></a>
  152. </span>
  153. </div>
  154. <div id="ft_container"
  155. class="pad<?=$HideFilter ? ' hidden' : ''?>">
  156. <?php
  157. # Three profile toggles
  158. if ((isset($LoggedUser['HideLolicon']) && $LoggedUser['HideLolicon'] === 1)
  159. || (isset($LoggedUser['HideScat']) && $LoggedUser['HideScat'] === 1)
  160. || (isset($LoggedUser['HideSnuff']) && $LoggedUser['HideSnuff'] === 1)
  161. ) { ?>
  162. <svg title="Your profile settings exclude some results" class="search_warning tooltip" width="10" height="15">
  163. <rect x=3 width="4" height="10" rx="2" ry="2" />
  164. <circle cx="5" cy="13" r="2" />
  165. </svg>
  166. <?php
  167. } ?>
  168. <table class="layout">
  169. <tr id="numbers" class="ftr_advanced<?=$HideAdvanced?>">
  170. <td class="label">
  171. <!--
  172. Accession Number / Version
  173. -->
  174. </td>
  175. <td class="ft_numbers">
  176. <input type="search" size="30" name="numbers" class="inputtext smallest fti_advanced"
  177. placeholder="Accession Number / Version" value="<?Format::form('numbers')?>" />
  178. </td>
  179. </tr>
  180. <tr id="album_torrent_title"
  181. class="ftr_advanced<?=$HideAdvanced?>">
  182. <td class="label">
  183. <!-- Torrent Title / Organism / Strain or Variety -->
  184. </td>
  185. <td class="ft_groupname">
  186. <input type="search" spellcheck="false" size="65" name="advgroupname"
  187. class="inputtext smaller fti_advanced" placeholder="Torrent Title / Organism / Strain or Variety"
  188. value="<?Format::form('advgroupname')?>" />
  189. </td>
  190. </tr>
  191. <tr id="artist_name"
  192. class="ftr_advanced<?=$HideAdvanced?>">
  193. <td class="label">
  194. <!-- Artist Name -->
  195. </td>
  196. <td class="ft_artistname">
  197. <input type="search" spellcheck="false" size="65" id="artist" name="artistname"
  198. class="inputtext smaller fti_advanced" placeholder="Author (ORCiD pending)"
  199. value="<?Format::form('artistname')?>" <?php Users::has_autocomplete_enabled('other'); ?>/>
  200. </td>
  201. </tr>
  202. <tr id="location" class="ftr_advanced<?=$HideAdvanced?>">
  203. <td class="label">
  204. <!-- Studio / Series -->
  205. </td>
  206. <td class="ft_location">
  207. <input type="search" name="location" class="inputtext smallest fti_advanced"
  208. placeholder="Department or Lab / Location" value="<?Format::form('location')?>" size="40" />
  209. <!-- Year -->
  210. <input type="search" name="year" class="inputtext smallest fti_advanced" placeholder="Year"
  211. value="<?Format::form('year')?>" size="20" />
  212. </td>
  213. </tr>
  214. <tr id="torrent_description"
  215. class="ftr_advanced<?=$HideAdvanced?>">
  216. <td class="label">
  217. <!-- Torrent Description -->
  218. </td>
  219. <td class="ft_description">
  220. <input type="search" spellcheck="false" size="65" name="description" class="inputtext fti_advanced"
  221. placeholder="Torrent Description"
  222. value="<?php Format::form('description') ?>" /><br /><br />
  223. Search torrent descriptions (not group information)
  224. </td>
  225. </tr>
  226. <tr id="file_list" class="ftr_advanced<?=$HideAdvanced?>">
  227. <td class="label">
  228. <!-- File List -->
  229. </td>
  230. <td class="ft_filelist">
  231. <input type="search" spellcheck="false" size="65" name="filelist" class="inputtext fti_advanced"
  232. placeholder="File List" value="<?Format::form('filelist')?>" /><br /><br />
  233. Universal Search finds info hashes
  234. </td>
  235. </tr>
  236. <!-- Platforms -->
  237. <tr id="rip_specifics"
  238. class="ftr_advanced<?=$HideAdvanced?>">
  239. <td class="label">Platforms</td>
  240. <td class="nobr ft_ripspecifics">
  241. <select name="media" class="ft_media fti_advanced">
  242. <option value="">Sequences</option>
  243. <?php foreach ($SeqPlatforms as $Platform) { ?>
  244. <option
  245. value="<?=display_str($Platform); # pcs-comment-start; keep quote?>"
  246. <?Format::selected('media', $Platform)?>><?=display_str($Platform); ?>
  247. </option>
  248. <?php } ?>
  249. </select>
  250. <select name="media" class="ft_media fti_advanced">
  251. <option value="">Graphs</option>
  252. <?php foreach ($GraphPlatforms as $Platform) { ?>
  253. <option
  254. value="<?=display_str($Platform); # pcs-comment-start; keep quote?>"
  255. <?Format::selected('media', $Platform)?>><?=display_str($Platform); ?>
  256. </option>
  257. <?php } ?>
  258. </select>
  259. <select name="media" class="ft_media fti_advanced">
  260. <option value="">Images</option>
  261. <?php foreach ($ImgPlatforms as $Platform) { ?>
  262. <option
  263. value="<?=display_str($Platform); # pcs-comment-start; keep quote?>"
  264. <?Format::selected('media', $Platform)?>><?=display_str($Platform); ?>
  265. </option>
  266. <?php } ?>
  267. </select>
  268. <select name="media" class="ft_media fti_advanced">
  269. <option value="">Documents</option>
  270. <?php foreach ($DocPlatforms as $Platform) { ?>
  271. <option
  272. value="<?=display_str($Platform); # pcs-comment-start; keep quote?>"
  273. <?Format::selected('media', $Platform)?>><?=display_str($Platform); ?>
  274. </option>
  275. <?php } ?>
  276. </select>
  277. </td>
  278. </tr>
  279. <!-- Formats -->
  280. <tr id="rip_specifics"
  281. class="ftr_advanced<?=$HideAdvanced?>">
  282. <td class="label">Formats</td>
  283. <td class="nobr ft_ripspecifics">
  284. <select id=" container" name="container" class="ft_container fti_advanced">
  285. <option value="">NucleoSeq</option>
  286. <?php foreach (array_merge($SeqFormats, $PlainFormats) as $Key => $Container) { ?>
  287. <option value="<?=display_str($Key);?>"
  288. <?Format::selected('container', $Key)?>><?=display_str($Key);?>
  289. </option>
  290. <?php } ?>
  291. </select>
  292. <select id=" container" name="container" class="ft_container fti_advanced">
  293. <option value="">ProtSeq</option>
  294. <?php foreach (array_merge($ProtFormats, $PlainFormats) as $Key => $Container) { ?>
  295. <option value="<?=display_str($Key);?>"
  296. <?Format::selected('container', $Key)?>><?=display_str($Key);?>
  297. </option>
  298. <?php } ?>
  299. </select>
  300. <select id=" container" name="container" class="ft_container fti_advanced">
  301. <option value="">XMLs</option>
  302. <?php foreach (array_merge($GraphXmlFormats, $GraphTxtFormats, $PlainFormats) as $Key => $Container) { ?>
  303. <option value="<?=display_str($Key);?>"
  304. <?Format::selected('container', $Key)?>><?=display_str($Key);?>
  305. </option>
  306. <?php } ?>
  307. </select>
  308. <select id=" container" name="container" class="ft_container fti_advanced">
  309. <option value="">Raster</option>
  310. <?php foreach (array_merge($ImgFormats, $MapRasterFormats, $PlainFormats) as $Key => $Container) { ?>
  311. <option value="<?=display_str($Key);?>"
  312. <?Format::selected('container', $Key)?>><?=display_str($Key);?>
  313. </option>
  314. <?php } ?>
  315. </select>
  316. <select id=" container" name="container" class="ft_container fti_advanced">
  317. <option value="">Vector</option>
  318. <?php foreach (array_merge($MapVectorFormats, $PlainFormats) as $Key => $Container) { ?>
  319. <option value="<?=display_str($Key);?>"
  320. <?Format::selected('container', $Key)?>><?=display_str($Key);?>
  321. </option>
  322. <?php } ?>
  323. </select>
  324. <select id=" container" name="container" class="ft_container fti_advanced">
  325. <option value="">Extras</option>
  326. <?php foreach (array_merge($BinDocFormats, $CpuGenFormats, $PlainFormats) as $Key => $Container) { ?>
  327. <option value="<?=display_str($Key);?>"
  328. <?Format::selected('container', $Key)?>><?=display_str($Key);?>
  329. </option>
  330. <?php } ?>
  331. </select>
  332. </td>
  333. </tr>
  334. <!-- Misc -->
  335. <tr id="misc" class="ftr_advanced<?=$HideAdvanced?>">
  336. <td class="label">Misc</td>
  337. <td class="nobr ft_misc">
  338. <select name="resolution" class="ft_resolution fti_advanced">
  339. <option value="">Scope</option>
  340. <?php foreach ($Resolutions as $Resolution) { ?>
  341. <option
  342. value="<?=display_str($Resolution); # pcs-comment-start; keep quote?>"
  343. <?Format::selected('resolution', $Resolution)?>><?=display_str($Resolution); ?>
  344. </option>
  345. <?php } ?>
  346. </select>
  347. <!-- Aligned/Censored -->
  348. <select name=" censored" class="ft_censored fti_advanced">
  349. <option value="">Alignment</option>
  350. <option value="1" <?Format::selected('censored', 1)?>>Aligned
  351. </option>
  352. <option value="0" <?Format::selected('censored', 0)?>>Not Aligned
  353. </option>
  354. </select>
  355. <!-- Leech Status -->
  356. <select name="freetorrent" class="ft_freetorrent fti_advanced">
  357. <option value="">Leech Status</option>
  358. <option value="1" <?Format::selected('freetorrent', 1)?>>Freeleech</option>
  359. <option value="2" <?Format::selected('freetorrent', 2)?>>Neutral Leech</option>
  360. <option value="3" <?Format::selected('freetorrent', 3)?>>Either</option>
  361. <option value="0" <?Format::selected('freetorrent', 0)?>>Normal</option>
  362. </select>
  363. <!-- Codec/License -->
  364. <select name="codec" class="ft_codec fti_advanced">
  365. <option value="">License</option>
  366. <?php foreach ($Codecs as $Codec) { ?>
  367. <option value="<?=display_str($Codec); ?>"
  368. <?Format::selected('codec', $Codec)?>><?=display_str($Codec); ?>
  369. </option>
  370. <?php } ?>
  371. </select>
  372. </td>
  373. </tr>
  374. <!-- Size -->
  375. <tr id="size" class="ftr_advanced<?=$HideAdvanced?>">
  376. <td class="label">Size</td>
  377. <td class="ft_size">
  378. <input type="size_min" spellcheck="false" size="6" name="size_min" class="inputtext smaller fti_advanced"
  379. placeholder="Min" value="<?Format::form('size_min')?>" />
  380. &ndash;
  381. <input type="size_max" spellcheck="false" size="6" name="size_max" class="inputtext smaller fti_advanced"
  382. placeholder="Max" value="<?Format::form('size_max')?>" />
  383. <select name="size_unit" class="ft_size fti_advanced">
  384. <option value="">Unit</option>
  385. <option value="0" <?Format::selected('size_unit', 0)?>>B
  386. </option>
  387. <option value="1" <?Format::selected('size_unit', 1)?>>KiB
  388. </option>
  389. <option value="2" <?Format::selected('size_unit', 2)?>>MiB
  390. </option>
  391. <option value="3" <?Format::selected('size_unit', 3)?>>GiB
  392. </option>
  393. <option value="4" <?Format::selected('size_unit', 4)?>>TiB
  394. </option>
  395. </select>
  396. </td>
  397. </tr>
  398. <!-- Start basic search options -->
  399. <tr id="search_terms" class="ftr_basic<?=$HideBasic?>">
  400. <td class="label">
  401. <!-- Universal Search -->
  402. </td>
  403. <td class="ftb_searchstr">
  404. <input type="search" spellcheck="false" size="48" name="searchstr" class="inputtext fti_basic"
  405. placeholder="Universal Search" value="<?Format::form('searchstr')?>" aria-label="Terms to search">
  406. </td>
  407. </tr>
  408. <tr id="tagfilter">
  409. <td class="label">
  410. <!-- Tags (comma-separated) -->
  411. </td>
  412. <td class="ft_taglist">
  413. <input type="search" size="37" id="tags" name="taglist" class="inputtext smaller"
  414. placeholder="Tags (comma-separated)"
  415. value="<?=display_str($Search->get_terms('taglist'))?>"
  416. <?php Users::has_autocomplete_enabled('other'); ?>
  417. aria-label="Tags to search">&nbsp;
  418. <input type="radio" name="tags_type" id="tags_type0" value="0" <?Format::selected(
  419. 'tags_type',
  420. 0,
  421. 'checked'
  422. )?>
  423. /><label for="tags_type0"> Any</label>&nbsp;&nbsp;
  424. <input type="radio" name="tags_type" id="tags_type1" value="1" <?Format::selected(
  425. 'tags_type',
  426. 1,
  427. 'checked'
  428. )?>
  429. /><label for="tags_type1"> All</label><br /><br />
  430. Use !tag to exclude tags
  431. </td>
  432. </tr>
  433. <!-- Order By -->
  434. <tr id="order">
  435. <td class="label">Order By</td>
  436. <td class="ft_order">
  437. <select name="order_by" style="width: auto;" class="ft_order_by" aria-label="Property to order by">
  438. <option value="time" <?Format::selected('order_by', 'time')?>>Time
  439. Added</option>
  440. <option value="year" <?Format::selected('order_by', 'year')?>>Year
  441. </option>
  442. <option value="size" <?Format::selected('order_by', 'size')?>>Size
  443. </option>
  444. <option value="snatched" <?Format::selected('order_by', 'snatched')?>>Snatched
  445. </option>
  446. <option value="seeders" <?Format::selected('order_by', 'seeders')?>>Seeders
  447. </option>
  448. <option value="leechers" <?Format::selected('order_by', 'leechers')?>>Leechers
  449. </option>
  450. <option value="cataloguenumber" <?Format::selected('order_by', 'cataloguenumber')?>>Accession
  451. Number</option>
  452. <option value="random" <?Format::selected('order_by', 'random')?>>Random
  453. </option>
  454. </select>
  455. <select name="order_way" class="ft_order_way" aria-label="Direction to order">
  456. <option value="desc" <?Format::selected('order_way', 'desc')?>>Descending
  457. </option>
  458. <option value="asc" <?Format::selected('order_way', 'asc')?>>Ascending
  459. </option>
  460. </select>
  461. </td>
  462. </tr>
  463. <!-- Use torrent groups? -->
  464. <tr id="search_group_results">
  465. <td class="label">
  466. <label for="group_results">Group Torrents</label>
  467. </td>
  468. <td class="ft_group_results">
  469. <input type="checkbox" value="1" name="group_results" id="group_results" <?=$GroupResults ? ' checked="checked"' : ''?>
  470. />
  471. </td>
  472. </tr>
  473. </table>
  474. <table class="layout cat_list ft_cat_list">
  475. <?php
  476. $x = 0;
  477. reset($Categories);
  478. foreach ($Categories as $CatKey => $CatName) {
  479. if ($x % 7 === 0) {
  480. if ($x > 0) {
  481. ?>
  482. </tr>
  483. <?php
  484. } ?>
  485. <tr>
  486. <?php
  487. }
  488. $x++; ?>
  489. <td>
  490. <input type="checkbox"
  491. name="filter_cat[<?=($CatKey + 1)?>]"
  492. id="cat_<?=($CatKey + 1)?>" value="1" <?php if (isset($_GET['filter_cat'][$CatKey + 1])) { ?>
  493. checked="checked"<?php } ?> />
  494. <label for="cat_<?=($CatKey + 1)?>"><?=$CatName?></label>
  495. </td>
  496. <?php
  497. } ?>
  498. </tr>
  499. </table>
  500. <table
  501. class="layout cat_list<?php if (empty($LoggedUser['ShowTags'])) { ?> hidden<?php } ?>"
  502. id="taglist">
  503. <tr>
  504. <?php
  505. $GenreTags = $Cache->get_value('genre_tags');
  506. if (!$GenreTags) {
  507. $DB->query('
  508. SELECT Name
  509. FROM tags
  510. WHERE TagType = \'genre\'
  511. ORDER BY Name');
  512. $GenreTags = $DB->collect('Name');
  513. $Cache->cache_value('genre_tags', $GenreTags, 3600 * 6);
  514. }
  515. $x = 0;
  516. foreach ($GenreTags as $Tag) {
  517. ?>
  518. <td><a href="#"
  519. onclick="add_tag('<?=$Tag?>'); return false;"><?=$Tag?></a></td>
  520. <?php
  521. $x++;
  522. if ($x % 7 === 0) {
  523. ?>
  524. </tr>
  525. <tr>
  526. <?php
  527. }
  528. }
  529. if ($x % 7 !== 0) { // Padding
  530. ?>
  531. <td colspan="<?=(7 - ($x % 7))?>"> </td>
  532. <?php } ?>
  533. </tr>
  534. </table>
  535. <!-- Categories -->
  536. <table class="layout cat_list">
  537. <tr>
  538. <td class="label">
  539. <a class="brackets" data-toggle-target="#taglist"
  540. data-toggle-replace="<?=(empty($LoggedUser['ShowTags']) ? 'Hide tags' : 'View tags')?>"><?=(empty($LoggedUser['ShowTags']) ? 'View tags' : 'Hide tags')?></a>
  541. </td>
  542. </tr>
  543. </table>
  544. <!-- Result count and submit button -->
  545. <div class="submit ft_submit">
  546. <span class="float_left"><?=number_format($NumResults)?>
  547. Results</span>
  548. <input type="submit" value="Search" />
  549. <input type="hidden" name="action" id="ft_type"
  550. value="<?=($AdvancedSearch ? 'advanced' : 'basic')?>" />
  551. <input type="hidden" name="searchsubmit" value="1" />
  552. <input type="button" value="Reset" <input type="button" value="Reset"
  553. onclick="window.location.href = 'torrents.php<?php if (isset($_GET['action']) && $_GET['action'] === 'advanced') { ?>?action=advanced<?php } ?>'" />
  554. &emsp;
  555. <?php if ($Search->has_filters()) { ?>
  556. <input type="submit" name="setdefault" value="Make Default" />
  557. <?php }
  558. if (!empty($LoggedUser['DefaultSearch'])) { ?>
  559. <input type="submit" name="cleardefault" value="Clear Default" />
  560. <?php } ?>
  561. </div>
  562. </div>
  563. </div>
  564. </form>
  565. <!-- No results message -->
  566. <?php if ($NumResults === 0) { ?>
  567. <div class="torrents_nomatch box pad" align="center">
  568. <h2>Your search did not match anything</h2>
  569. <p>Make sure all names are spelled correctly, or try making your search less specific</p>
  570. </div>
  571. </div>
  572. <?php
  573. View::show_footer();
  574. die();
  575. }
  576. if ($NumResults < ($Page - 1) * TORRENTS_PER_PAGE + 1) {
  577. $LastPage = ceil($NumResults / TORRENTS_PER_PAGE);
  578. $Pages = Format::get_pages(0, $NumResults, TORRENTS_PER_PAGE); ?>
  579. <div class="torrents_nomatch box pad" align="center">
  580. <h2>The requested page contains no matches</h2>
  581. <p>You are requesting page <?=$Page?>, but the search returned only
  582. <?=number_format($LastPage) ?> pages
  583. </p>
  584. </div>
  585. <div class="linkbox">Go to page <?=$Pages?>
  586. </div>
  587. </div>
  588. <?php
  589. View::show_footer();
  590. error();
  591. }
  592. // List of pages
  593. $Pages = Format::get_pages($Page, $NumResults, TORRENTS_PER_PAGE);
  594. $Bookmarks = Bookmarks::all_bookmarks('torrent');
  595. ?>
  596. <div class="linkbox"><?=$Pages?>
  597. </div>
  598. <!-- Results table headings -->
  599. <table
  600. class="box torrent_table cats <?=$GroupResults ? 'grouping' : 'no_grouping'?>"
  601. id="torrent_table">
  602. <tr class="colhead">
  603. <?php if ($GroupResults) { ?>
  604. <td class="small"></td>
  605. <?php } ?>
  606. <td class="small cats_col"></td>
  607. <td>Name / <a
  608. href="<?=header_link('year')?>">Year</a>
  609. </td>
  610. <td>Files</td>
  611. <td><a
  612. href="<?=header_link('time')?>">Time</a>
  613. </td>
  614. <td><a
  615. href="<?=header_link('size')?>">Size</a>
  616. </td>
  617. <td class="sign snatches">
  618. <a href="<?=header_link('snatched')?>"
  619. aria-label="Sort by snatches">
  620. </a>
  621. </td>
  622. <td class="sign seeders">
  623. <a href="<?=header_link('seeders')?>"
  624. aria-label="Sort by seeders">
  625. &uarr;
  626. </a>
  627. </td>
  628. <td class="sign leechers">
  629. <a href="<?=header_link('leechers')?>"
  630. aria-label="Sort by leechers">
  631. &darr;
  632. </a>
  633. </td>
  634. </tr>
  635. <?php
  636. // Start printing torrent list
  637. foreach ($Results as $Key => $GroupID) {
  638. $GroupInfo = $Groups[$GroupID];
  639. if (empty($GroupInfo['Torrents'])) {
  640. continue;
  641. }
  642. $CategoryID = $GroupInfo['CategoryID'];
  643. $GroupYear = $GroupInfo['Year'];
  644. $Artists = $GroupInfo['Artists'];
  645. $GroupCatalogueNumber = $GroupInfo['CatalogueNumber'];
  646. $GroupStudio = $GroupInfo['Studio'];
  647. $GroupName = empty($GroupInfo['Name']) ? (empty($GroupInfo['Title2']) ? $GroupInfo['NameJP'] : $GroupInfo['Title2']) : $GroupInfo['Name'];
  648. $GroupTitle2 = $GroupInfo['Title2'];
  649. $GroupNameJP = $GroupInfo['NameJP'];
  650. if ($GroupResults) {
  651. $Torrents = $GroupInfo['Torrents'];
  652. $GroupTime = $MaxSize = $TotalLeechers = $TotalSeeders = $TotalSnatched = 0;
  653. foreach ($Torrents as $T) {
  654. $GroupTime = max($GroupTime, strtotime($T['Time']));
  655. $MaxSize = max($MaxSize, $T['Size']);
  656. $TotalLeechers += $T['Leechers'];
  657. $TotalSeeders += $T['Seeders'];
  658. $TotalSnatched += $T['Snatched'];
  659. }
  660. } else {
  661. $TorrentID = $Key;
  662. $Torrents = [$TorrentID => $GroupInfo['Torrents'][$TorrentID]];
  663. }
  664. $TorrentTags = new Tags($GroupInfo['TagList']);
  665. # Start making $DisplayName (first torrent result line)
  666. $DisplayName = '';
  667. /*
  668. if (isset($Artists)) {
  669. $DisplayName = '<div class="torrent_artists">'.Artists::display_artists($Artists).'</div> ';
  670. } else {
  671. $DisplayName = '';
  672. }
  673. */
  674. $SnatchedGroupClass = $GroupInfo['Flags']['IsSnatched'] ? ' snatched_group' : '';
  675. # Similar to the logic down the page, and on
  676. # torrents.class.php and sections/artist/artist.php
  677. if ($GroupResults && (count($Torrents) > 1 && isset($GroupedCategories[$CategoryID - 1]))) {
  678. // These torrents are in a group
  679. $CoverArt = $GroupInfo['WikiImage'];
  680. $DisplayName .= "<a class='torrent_title' href='torrents.php?id=$GroupID' ";
  681. # No cover art
  682. if (!isset($LoggedUser['CoverArt']) || $LoggedUser['CoverArt']) {
  683. $DisplayName .= 'data-cover="'.ImageTools::process($CoverArt, 'thumb').'" ';
  684. }
  685. # Japanese
  686. $DisplayName .= "dir='ltr'>$GroupName</a>";
  687. # Year
  688. if ($GroupYear) {
  689. $Label = '<br />📅&nbsp;';
  690. $DisplayName .= $Label."<a href='torrents.php?".Format::get_url($_GET)."&year=$GroupYear'>$GroupYear</a>";
  691. }
  692. # Studio
  693. if ($GroupStudio) {
  694. $Label = '&ensp;📍&nbsp;';
  695. $DisplayName .= $Label."<a href='torrents.php?".Format::get_url($_GET)."&location=$GroupStudio'>$GroupStudio</a>";
  696. }
  697. # Catalogue Number
  698. if ($GroupCatalogueNumber) {
  699. $Label = '&ensp;🔑&nbsp;';
  700. $DisplayName .= $Label."<a href='torrents.php?".Format::get_url($_GET)."&numbers=$GroupCatalogueNumber'>$GroupCatalogueNumber</a>";
  701. }
  702. # Organism
  703. if ($GroupTitle2) {
  704. $Label = '&ensp;🦠&nbsp;';
  705. $DisplayName .= $Label."<a href='torrents.php?".Format::get_url($_GET)."&advgroupname=$GroupTitle2'><em>$GroupTitle2</em></a>";
  706. }
  707. # Strain/Variety
  708. if ($GroupNameJP) {
  709. $Label = '&nbsp;';
  710. $DisplayName .= $Label."<a href='torrents.php?".Format::get_url($_GET)."&advgroupname=$GroupNameJP'>$GroupNameJP</a>";
  711. }
  712. # Authors
  713. if (isset($Artists)) {
  714. # Emoji in classes/astists.class.php
  715. $Label = '&ensp;';
  716. $DisplayName .= $Label.'<div class="torrent_artists">'.Artists::display_artists($Artists).'</div>';
  717. } ?>
  718. <tr class="group<?=$SnatchedGroupClass?>">
  719. <?php
  720. $ShowGroups = !(!empty($LoggedUser['TorrentGrouping']) && $LoggedUser['TorrentGrouping'] === 1); ?>
  721. <td class="center">
  722. <div id="showimg_<?=$GroupID?>"
  723. class="<?=($ShowGroups ? 'hide' : 'show')?>_torrents">
  724. <a class="tooltip show_torrents_link"
  725. onclick="toggle_group(<?=$GroupID?>, this, event)"
  726. title="Toggle this group (Hold &quot;Shift&quot; to toggle all groups)"></a>
  727. </div>
  728. </td>
  729. <!-- Category icon -->
  730. <td class="center cats_col">
  731. <div title="<?=Format::pretty_category($CategoryID)?>"
  732. class="tooltip <?=Format::css_category($CategoryID)?>">
  733. </div>
  734. </td>
  735. <!-- [ DL | RP ] and [Bookmark] -->
  736. <td colspan="2" class="big_info">
  737. <div class="group_info clear">
  738. <?=$DisplayName?>
  739. <?php if (in_array($GroupID, $Bookmarks)) { ?>
  740. <span class="remove_bookmark float_right">
  741. <a href="#" id="bookmarklink_torrent_<?=$GroupID?>"
  742. class="brackets"
  743. onclick="Unbookmark('torrent', <?=$GroupID?>, 'Bookmark'); return false;">Remove
  744. bookmark</a>
  745. </span>
  746. <?php } else { ?>
  747. <span class="add_bookmark float_right">
  748. <a href="#" id="bookmarklink_torrent_<?=$GroupID?>"
  749. class="brackets"
  750. onclick="Bookmark('torrent', <?=$GroupID?>, 'Remove bookmark'); return false;">Bookmark</a>
  751. </span>
  752. <?php } ?>
  753. <br />
  754. <!-- Tags -->
  755. <div class="tags"><?=$TorrentTags->format('torrents.php?'.$Action.'&amp;taglist=')?>
  756. </div>
  757. </div>
  758. </td>
  759. <!-- Time -->
  760. <td class="nobr"><?=time_diff($GroupTime, 1)?>
  761. </td>
  762. <!-- Size -->
  763. <td class="number_column nobr"><?=Format::get_size($MaxSize)?>(Max)</td>
  764. <!-- Snatches, seeders, and leechers -->
  765. <td class="number_column"><?=number_format($TotalSnatched)?>
  766. </td>
  767. <td
  768. class="number_column<?=($TotalSeeders === 0 ? ' r00' : '')?>">
  769. <?=number_format($TotalSeeders)?>
  770. </td>
  771. <td class="number_column"><?=number_format($TotalLeechers)?>
  772. </td>
  773. </tr>
  774. <?php
  775. foreach ($Torrents as $TorrentID => $Data) {
  776. $Data['CategoryID'] = $CategoryID;
  777. // All of the individual torrents in the group
  778. // Get report info for each torrent, use the cache if available, if not, add to it
  779. $Reported = false;
  780. $Reports = Torrents::get_reports($TorrentID);
  781. if (count($Reports) > 0) {
  782. $Reported = true;
  783. }
  784. $SnatchedTorrentClass = $Data['IsSnatched'] ? ' snatched_torrent' : '';
  785. $TorrentDL = "torrents.php?action=download&amp;id=".$TorrentID."&amp;authkey=".$LoggedUser['AuthKey']."&amp;torrent_pass=".$LoggedUser['torrent_pass'];
  786. if (!($TorrentFileName = $Cache->get_value('torrent_file_name_'.$TorrentID))) {
  787. $TorrentFile = file_get_contents(TORRENT_STORE.$TorrentID.'.torrent');
  788. $Tor = new BencodeTorrent($TorrentFile, false, false);
  789. $TorrentFileName = $Tor->Dec['info']['name'];
  790. $Cache->cache_value('torrent_file_name_'.$TorrentID, $TorrentFileName);
  791. } ?>
  792. <tr
  793. class="group_torrent groupid_<?=$GroupID?> <?=$SnatchedTorrentClass . $SnatchedGroupClass . (!empty($LoggedUser['TorrentGrouping']) && $LoggedUser['TorrentGrouping'] === 1 ? ' hidden' : '')?>">
  794. <td colspan="3">
  795. <span>
  796. [ <a href="<?=$TorrentDL?>" class="tooltip"
  797. title="Download"><?=$Data['HasFile'] ? 'DL' : 'Missing'?></a>
  798. <?php
  799. if (Torrents::can_use_token($Data)) { ?>
  800. | <a
  801. href="torrents.php?action=download&amp;id=<?=$TorrentID?>&amp;authkey=<?=$LoggedUser['AuthKey']?>&amp;torrent_pass=<?=$LoggedUser['torrent_pass']?>&amp;usetoken=1"
  802. class="tooltip" title="Use a FL Token"
  803. onclick="return confirm('Are you sure you want to use a freeleech token here?');">FL</a>
  804. <?php } ?>
  805. | <a
  806. href="reportsv2.php?action=report&amp;id=<?=$TorrentID?>"
  807. class="tooltip" title="Report">RP</a> ]
  808. </span>
  809. <a href="torrents.php?id=<?=$GroupID?>&amp;torrentid=<?=$TorrentID?>#torrent<?=$TorrentID?>"
  810. class="torrent_label tl_reported tooltip search_link"><strong>Details</strong></a>
  811. | <?=Torrents::torrent_info($Data)?>
  812. <?php if ($Reported) { ?>
  813. | <strong class="torrent_label tl_reported tooltip search_link important_text"
  814. title="Type: <?=ucfirst($Reports[0]['Type'])?><br>
  815. Comment: <?=htmlentities(htmlentities($Reports[0]['UserComment']))?>">Reported</strong><?php } ?>
  816. </td>
  817. <td class="number_column"><?=$Data['FileCount']?>
  818. </td>
  819. <td class="nobr"><?=time_diff($Data['Time'], 1)?>
  820. </td>
  821. <td class="number_column nobr"><?=Format::get_size($Data['Size'])?>
  822. </td>
  823. <td class="number_column"><?=number_format($Data['Snatched'])?>
  824. </td>
  825. <td
  826. class="number_column<?=($Data['Seeders'] === 0) ? ' r00' : ''?>">
  827. <?=number_format($Data['Seeders'])?>
  828. </td>
  829. <td class="number_column"><?=number_format($Data['Leechers'])?>
  830. </td>
  831. </tr>
  832. <?php
  833. }
  834. } else {
  835. // Viewing a type that does not require grouping
  836. $TorrentID = key($Torrents);
  837. $Data = current($Torrents);
  838. $Reported = false;
  839. $Reports = Torrents::get_reports($TorrentID);
  840. if (count($Reports) > 0) {
  841. $Reported = true;
  842. }
  843. # Main search result title link
  844. # These are the main torrent search results
  845. $Data['CategoryID'] = $CategoryID;
  846. $CoverArt = $GroupInfo['WikiImage'];
  847. $DisplayName .= "<a class='torrent_title' href='torrents.php?id=$GroupID&amp;torrentid=$TorrentID' ";
  848. if (!isset($LoggedUser['CoverArt']) || $LoggedUser['CoverArt']) {
  849. $DisplayName .= 'data-cover="'.ImageTools::process($CoverArt, 'thumb').'" ';
  850. }
  851. # Japanese
  852. $DisplayName .= "dir='ltr'>$GroupName</a>";
  853. if (isset($GroupedCategories[$CategoryID - 1])) {
  854. # Year
  855. # Sh!t h4x; Year is mandatory
  856. if ($GroupYear) {
  857. $Label = '<br />📅&nbsp;';
  858. $DisplayName .= $Label."<a href='torrents.php?".Format::get_url($_GET)."&year=$GroupYear'>$GroupYear</a>";
  859. }
  860. # Studio
  861. if ($GroupStudio) {
  862. $DisplayName .= "&nbsp;&nbsp;📍&nbsp;<a href='torrents.php?".Format::get_url($_GET)."&location=$GroupStudio'>$GroupStudio</a>";
  863. }
  864. # Catalogue Number
  865. if ($GroupCatalogueNumber) {
  866. $Label = '&ensp;🔑&nbsp;';
  867. $DisplayName .= $Label."<a href='torrents.php?".Format::get_url($_GET)."&numbers=$GroupCatalogueNumber'>$GroupCatalogueNumber</a>";
  868. }
  869. # Organism
  870. if ($GroupTitle2) {
  871. $Label = '&ensp;🦠&nbsp;';
  872. $DisplayName .= $Label."<a href='torrents.php?".Format::get_url($_GET)."&advgroupname=$GroupTitle2'><em>$GroupTitle2</em></a>";
  873. }
  874. # Strain/Variety
  875. if ($GroupNameJP) {
  876. $Label = '&nbsp;';
  877. $DisplayName .= $Label."<a href='torrents.php?".Format::get_url($_GET)."&advgroupname=$GroupNameJP'>$GroupNameJP</a>";
  878. }
  879. # Authors
  880. if (isset($Artists)) {
  881. # Emoji in classes/astists.class.php
  882. $Label = '&ensp;';
  883. $DisplayName .= $Label.'<div class="torrent_artists">'.Artists::display_artists($Artists).'</div>';
  884. }
  885. $ExtraInfo = Torrents::torrent_info($Data, true, true);
  886. } elseif ($Data['IsSnatched']) {
  887. $ExtraInfo = Format::torrent_label('Snatched!');
  888. } else {
  889. $ExtraInfo = '';
  890. }
  891. $SnatchedTorrentClass = $Data['IsSnatched'] ? ' snatched_torrent' : '';
  892. $TorrentDL = "torrents.php?action=download&amp;id=".$TorrentID."&amp;authkey=".$LoggedUser['AuthKey']."&amp;torrent_pass=".$LoggedUser['torrent_pass'];
  893. if (!($TorrentFileName = $Cache->get_value('torrent_file_name_'.$TorrentID))) {
  894. $TorrentFile = file_get_contents(TORRENT_STORE.$TorrentID.'.torrent');
  895. $Tor = new BencodeTorrent($TorrentFile, false, false);
  896. $TorrentFileName = $Tor->Dec['info']['name'];
  897. $Cache->cache_value('torrent_file_name_'.$TorrentID, $TorrentFileName);
  898. } ?>
  899. <tr
  900. class="torrent<?=$SnatchedTorrentClass . $SnatchedGroupClass?>">
  901. <?php if ($GroupResults) { ?>
  902. <td></td>
  903. <?php } ?>
  904. <td class="center cats_col">
  905. <div title="<?=Format::pretty_category($CategoryID)?>"
  906. class="tooltip <?=Format::css_category($CategoryID)?>"></div>
  907. </td>
  908. <td class="big_info">
  909. <div class="group_info clear">
  910. <div class="float_right">
  911. <span>
  912. [ <a href="<?=$TorrentDL?>" class="tooltip"
  913. title="Download">DL</a>
  914. <?php
  915. if (Torrents::can_use_token($Data)) { ?>
  916. | <a
  917. href="torrents.php?action=download&amp;id=<?=$TorrentID?>&amp;authkey=<?=$LoggedUser['AuthKey']?>&amp;torrent_pass=<?=$LoggedUser['torrent_pass']?>&amp;usetoken=1"
  918. class="tooltip" title="Use a FL Token"
  919. onclick="return confirm('Are you sure you want to use a freeleech token here?');">FL</a>
  920. <?php } ?>
  921. | <a
  922. href="reportsv2.php?action=report&amp;id=<?=$TorrentID?>"
  923. class="tooltip" title="Report">RP</a> ]
  924. </span>
  925. <br />
  926. <?php if (in_array($GroupID, $Bookmarks)) { ?>
  927. <span class="remove_bookmark float_right">
  928. <a href="#" id="bookmarklink_torrent_<?=$GroupID?>"
  929. class="brackets"
  930. onclick="Unbookmark('torrent', <?=$GroupID?>, 'Bookmark'); return false;">Remove
  931. bookmark</a>
  932. </span>
  933. <?php } else { ?>
  934. <span class="add_bookmark float_right">
  935. <a href="#" id="bookmarklink_torrent_<?=$GroupID?>"
  936. class="brackets"
  937. onclick="Bookmark('torrent', <?=$GroupID?>, 'Remove bookmark'); return false;">Bookmark</a>
  938. </span>
  939. <?php } ?>
  940. </div>
  941. <?=$DisplayName?>
  942. <br />
  943. <div style="display: inline;" class="torrent_info"><?=$ExtraInfo?><?php if ($Reported) { ?>
  944. / <strong class="torrent_label tl_reported tooltip important_text"
  945. title="Type: <?=ucfirst($Reports[0]['Type'])?><br>Comment: <?=htmlentities(htmlentities($Reports[0]['UserComment']))?>">Reported</strong><?php } ?>
  946. </div>
  947. <div class="tags"><?=$TorrentTags->format("torrents.php?$Action&amp;taglist=")?>
  948. </div>
  949. </div>
  950. </td>
  951. <td class="number_column"><?=$Data['FileCount']?>
  952. </td>
  953. <td class="nobr"><?=time_diff($Data['Time'], 1)?>
  954. </td>
  955. <td class="number_column nobr"><?=Format::get_size($Data['Size'])?>
  956. </td>
  957. <td class="number_column"><?=number_format($Data['Snatched'])?>
  958. </td>
  959. <td
  960. class="number_column<?=($Data['Seeders'] === 0) ? ' r00' : ''?>">
  961. <?=number_format($Data['Seeders'])?>
  962. </td>
  963. <td class="number_column"><?=number_format($Data['Leechers'])?>
  964. </td>
  965. </tr>
  966. <?php
  967. }
  968. }
  969. ?>
  970. </table>
  971. <div class="linkbox"><?=$Pages?>
  972. </div>
  973. </div>
  974. <?php
  975. View::show_footer();