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

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