mirror of
https://github.com/WhatCD/Gazelle.git
synced 2025-01-19 04:31:36 +00:00
Empty commit
This commit is contained in:
parent
ec1defb946
commit
0a0d9b8aa6
@ -27,7 +27,7 @@ public static function is_int($Val) {
|
|||||||
* The encode class is simple and straightforward. The only thing to
|
* The encode class is simple and straightforward. The only thing to
|
||||||
* note is that empty dictionaries are represented by boolean trues
|
* note is that empty dictionaries are represented by boolean trues
|
||||||
*/
|
*/
|
||||||
class BEnc {
|
class Bencode {
|
||||||
private $DefaultKeys = array( // Get rid of everything except these keys to save some space
|
private $DefaultKeys = array( // Get rid of everything except these keys to save some space
|
||||||
'created by', 'creation date', 'encoding', 'info');
|
'created by', 'creation date', 'encoding', 'info');
|
||||||
private $Data;
|
private $Data;
|
||||||
@ -94,315 +94,3 @@ private function _benc() {
|
|||||||
return $Ret.'e';
|
return $Ret.'e';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* The decode class is simple and straightforward. The only thing to
|
|
||||||
* note is that empty dictionaries are represented by boolean trues
|
|
||||||
*/
|
|
||||||
class BEncDec extends BEnc {
|
|
||||||
private $Data;
|
|
||||||
private $Length;
|
|
||||||
private $Pos = 0;
|
|
||||||
public $Dec = array();
|
|
||||||
public $ExitOnError = true;
|
|
||||||
const SnipLength = 40;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Decode prepararations
|
|
||||||
*
|
|
||||||
* @param string $Arg bencoded string or path to bencoded file to decode
|
|
||||||
* @param bool $IsPath needs to be true if $Arg is a path
|
|
||||||
* @return decoded data with a suitable structure
|
|
||||||
*/
|
|
||||||
function __construct($Arg = false, $IsPath = false) {
|
|
||||||
if ($Arg === false) {
|
|
||||||
if (empty($this->Enc)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if ($IsPath === true) {
|
|
||||||
return $this->bdec_file($Arg);
|
|
||||||
}
|
|
||||||
$this->Data = $Arg;
|
|
||||||
}
|
|
||||||
return $this->decode();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Decodes a bencoded file
|
|
||||||
*
|
|
||||||
* @param $Path path to bencoded file to decode
|
|
||||||
* @return decoded data with a suitable structure
|
|
||||||
*/
|
|
||||||
public function bdec_file($Path = false) {
|
|
||||||
if (empty($Path)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!$this->Data = @file_get_contents($Path, FILE_BINARY)) {
|
|
||||||
return $this->error("Error: file '$Path' could not be opened.\n");
|
|
||||||
}
|
|
||||||
return $this->decode();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Decodes a string with bencoded data
|
|
||||||
*
|
|
||||||
* @param mixed $Arg bencoded data or false to decode the content of $this->Data
|
|
||||||
* @return decoded data with a suitable structure
|
|
||||||
*/
|
|
||||||
public function decode($Arg = false) {
|
|
||||||
if ($Arg !== false) {
|
|
||||||
$this->Data = $Arg;
|
|
||||||
} else if (!$this->Data) {
|
|
||||||
$this->Data = $this->Enc;
|
|
||||||
}
|
|
||||||
if (!$this->Data) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
$this->Length = strlen($this->Data);
|
|
||||||
$this->Pos = 0;
|
|
||||||
$this->Dec = $this->_bdec();
|
|
||||||
if ($this->Pos < $this->Length) {
|
|
||||||
// Not really necessary, but if the torrent is invalid, it's better to warn than to silently truncate it
|
|
||||||
return $this->error();
|
|
||||||
}
|
|
||||||
return $this->Dec;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Internal decoding function that does the actual job
|
|
||||||
*
|
|
||||||
* @return decoded data with a suitable structure
|
|
||||||
*/
|
|
||||||
private function _bdec() {
|
|
||||||
switch ($this->Data[$this->Pos]) {
|
|
||||||
|
|
||||||
case 'i':
|
|
||||||
$this->Pos++;
|
|
||||||
$Value = substr($this->Data, $this->Pos, strpos($this->Data, 'e', $this->Pos) - $this->Pos);
|
|
||||||
if (!ctype_digit($Value) && !($Value[0] == '-' && ctype_digit(substr($Value, 1)))) {
|
|
||||||
return $this->error();
|
|
||||||
}
|
|
||||||
$this->Pos += strlen($Value) + 1;
|
|
||||||
return Int64::make($Value);
|
|
||||||
|
|
||||||
case 'l':
|
|
||||||
$Value = array();
|
|
||||||
$this->Pos++;
|
|
||||||
while ($this->Data[$this->Pos] != 'e') {
|
|
||||||
if ($this->Pos >= $this->Length) {
|
|
||||||
return $this->error();
|
|
||||||
}
|
|
||||||
$Value[] = $this->_bdec();
|
|
||||||
}
|
|
||||||
$this->Pos++;
|
|
||||||
return $Value;
|
|
||||||
|
|
||||||
case 'd':
|
|
||||||
$Value = array();
|
|
||||||
$this->Pos++;
|
|
||||||
while ($this->Data[$this->Pos] != 'e') {
|
|
||||||
$Length = substr($this->Data, $this->Pos, strpos($this->Data, ':', $this->Pos) - $this->Pos);
|
|
||||||
if (!ctype_digit($Length)) {
|
|
||||||
return $this->error();
|
|
||||||
}
|
|
||||||
$this->Pos += strlen($Length) + $Length + 1;
|
|
||||||
$Key = substr($this->Data, $this->Pos - $Length, $Length);
|
|
||||||
if ($this->Pos >= $this->Length) {
|
|
||||||
return $this->error();
|
|
||||||
}
|
|
||||||
$Value[$Key] = $this->_bdec();
|
|
||||||
}
|
|
||||||
$this->Pos++;
|
|
||||||
// Use boolean true to keep track of empty dictionaries
|
|
||||||
return empty($Value) ? true : $Value;
|
|
||||||
|
|
||||||
default:
|
|
||||||
$Length = substr($this->Data, $this->Pos, strpos($this->Data, ':', $this->Pos) - $this->Pos);
|
|
||||||
if (!ctype_digit($Length)) {
|
|
||||||
return $this->error(); // Even if the string is likely to be decoded correctly without this check, it's malformed
|
|
||||||
}
|
|
||||||
$this->Pos += strlen($Length) + $Length + 1;
|
|
||||||
return substr($this->Data, $this->Pos - $Length, $Length);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert everything to the correct data types and optionally escape strings
|
|
||||||
*
|
|
||||||
* @param bool $Escape whether to escape the textual data
|
|
||||||
* @param mixed $Data decoded data or false to use the $Dec property
|
|
||||||
* @return decoded data with more useful data types
|
|
||||||
*/
|
|
||||||
public function dump($Escape = true, $Data = false) {
|
|
||||||
if ($Data === false) {
|
|
||||||
$Data = $this->Dec;
|
|
||||||
}
|
|
||||||
if (Int64::is_int($Data)) {
|
|
||||||
return Int64::get($Data);
|
|
||||||
}
|
|
||||||
if (is_bool($Data)) {
|
|
||||||
return array();
|
|
||||||
}
|
|
||||||
if (is_array($Data)) {
|
|
||||||
$Output = array();
|
|
||||||
foreach ($Data as $Key => $Val) {
|
|
||||||
$Output[$Key] = $this->dump($Escape, $Val);
|
|
||||||
}
|
|
||||||
return $Output;
|
|
||||||
}
|
|
||||||
return $Escape ? htmlentities($Data) : $Data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Display an error and halt the operation unless the $ExitOnError property is false
|
|
||||||
*
|
|
||||||
* @param string $ErrMsg the error message to display
|
|
||||||
*/
|
|
||||||
private function error($ErrMsg = false) {
|
|
||||||
static $ErrorPos;
|
|
||||||
if ($this->Pos === $ErrorPos) {
|
|
||||||
// The recursive nature of the class requires this to avoid duplicate error messages
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if ($ErrMsg === false) {
|
|
||||||
printf("Malformed string. Invalid character at pos 0x%X: %s\n",
|
|
||||||
$this->Pos, str_replace(array("\r","\n"), array('',' '), htmlentities(substr($this->Data, $this->Pos, self::SnipLength))));
|
|
||||||
} else {
|
|
||||||
echo $ErrMsg;
|
|
||||||
}
|
|
||||||
if ($this->ExitOnError) {
|
|
||||||
exit();
|
|
||||||
}
|
|
||||||
$ErrorPos = $this->Pos;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Torrent class that contains some convenient functions related to torrent meta data
|
|
||||||
*/
|
|
||||||
class BEncTorrent extends BEncDec {
|
|
||||||
private $PathKey = 'path';
|
|
||||||
public $Files = array();
|
|
||||||
public $Size = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a list of the files in the torrent and their sizes as well as the total torrent size
|
|
||||||
*
|
|
||||||
* @return array with a list of files and file sizes
|
|
||||||
*/
|
|
||||||
public function file_list() {
|
|
||||||
if (empty($this->Dec)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
$InfoDict =& $this->Dec['info'];
|
|
||||||
if (!isset($InfoDict['files'])) {
|
|
||||||
// Single-file torrent
|
|
||||||
$this->Size = (Int64::is_int($InfoDict['length'])
|
|
||||||
? Int64::get($InfoDict['length'])
|
|
||||||
: $InfoDict['length']);
|
|
||||||
$Name = (isset($InfoDict['name.utf-8'])
|
|
||||||
? $InfoDict['name.utf-8']
|
|
||||||
: $InfoDict['name']);
|
|
||||||
$this->Files[] = array($this->Size, $Name);
|
|
||||||
} else {
|
|
||||||
if (isset($InfoDict['path.utf-8']['files'][0])) {
|
|
||||||
$this->PathKey = 'path.utf-8';
|
|
||||||
}
|
|
||||||
foreach ($InfoDict['files'] as $File) {
|
|
||||||
$TmpPath = array();
|
|
||||||
foreach ($File[$this->PathKey] as $SubPath) {
|
|
||||||
$TmpPath[] = $SubPath;
|
|
||||||
}
|
|
||||||
$CurSize = (Int64::is_int($File['length'])
|
|
||||||
? Int64::get($File['length'])
|
|
||||||
: $File['length']);
|
|
||||||
$this->Files[] = array($CurSize, implode('/', $TmpPath));
|
|
||||||
$this->Size += $CurSize;
|
|
||||||
}
|
|
||||||
uasort($this->Files, function($a, $b) {
|
|
||||||
return strnatcasecmp($a[1], $b[1]);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return array($this->Size, $this->Files);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Find out the name of the torrent
|
|
||||||
*
|
|
||||||
* @return string torrent name
|
|
||||||
*/
|
|
||||||
public function get_name() {
|
|
||||||
if (empty($this->Dec)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (isset($this->Dec['info']['name.utf-8'])) {
|
|
||||||
return $this->Dec['info']['name.utf-8'];
|
|
||||||
}
|
|
||||||
return $this->Dec['info']['name'];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Find out the total size of the torrent
|
|
||||||
*
|
|
||||||
* @return string torrent size
|
|
||||||
*/
|
|
||||||
public function get_size() {
|
|
||||||
if (empty($this->Files)) {
|
|
||||||
if (empty($this->Dec)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
$FileList = $this->file_list();
|
|
||||||
}
|
|
||||||
return $FileList[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if the "private" flag is present in the torrent
|
|
||||||
*
|
|
||||||
* @return true if the "private" flag is set
|
|
||||||
*/
|
|
||||||
public function is_private() {
|
|
||||||
if (empty($this->Dec)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return isset($this->Dec['info']['private']) && Int64::get($this->Dec['info']['private']) == 1;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Add the "private" flag to the torrent
|
|
||||||
*
|
|
||||||
* @return true if a change was required
|
|
||||||
*/
|
|
||||||
public function make_private() {
|
|
||||||
if (empty($this->Dec)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if ($this->is_private()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
$this->Dec['info']['private'] = Int64::make(1);
|
|
||||||
ksort($this->Dec['info']);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Calculate the torrent's info hash
|
|
||||||
*
|
|
||||||
* @return info hash in hexadecimal form
|
|
||||||
*/
|
|
||||||
public function info_hash() {
|
|
||||||
if (empty($this->Dec) || !isset($this->Dec['info'])) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return sha1($this->encode(false, 'info'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add the announce URL to a torrent
|
|
||||||
*/
|
|
||||||
public static function add_announce_url($Data, $Url) {
|
|
||||||
return 'd8:announce'.strlen($Url).':'.$Url . substr($Data, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
?>
|
|
||||||
|
184
classes/class_bencodedecode.php
Normal file
184
classes/class_bencodedecode.php
Normal file
@ -0,0 +1,184 @@
|
|||||||
|
<?
|
||||||
|
/**
|
||||||
|
* The decode class is simple and straightforward. The only thing to
|
||||||
|
* note is that empty dictionaries are represented by boolean trues
|
||||||
|
*/
|
||||||
|
class BencodeDecode extends Bencode {
|
||||||
|
private $Data;
|
||||||
|
private $Length;
|
||||||
|
private $Pos = 0;
|
||||||
|
public $Dec = array();
|
||||||
|
public $ExitOnError = true;
|
||||||
|
const SnipLength = 40;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decode prepararations
|
||||||
|
*
|
||||||
|
* @param string $Arg bencoded string or path to bencoded file to decode
|
||||||
|
* @param bool $IsPath needs to be true if $Arg is a path
|
||||||
|
* @return decoded data with a suitable structure
|
||||||
|
*/
|
||||||
|
function __construct($Arg = false, $IsPath = false) {
|
||||||
|
if ($Arg === false) {
|
||||||
|
if (empty($this->Enc)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if ($IsPath === true) {
|
||||||
|
return $this->bdec_file($Arg);
|
||||||
|
}
|
||||||
|
$this->Data = $Arg;
|
||||||
|
}
|
||||||
|
return $this->decode();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decodes a bencoded file
|
||||||
|
*
|
||||||
|
* @param $Path path to bencoded file to decode
|
||||||
|
* @return decoded data with a suitable structure
|
||||||
|
*/
|
||||||
|
public function bdec_file($Path = false) {
|
||||||
|
if (empty($Path)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!$this->Data = @file_get_contents($Path, FILE_BINARY)) {
|
||||||
|
return $this->error("Error: file '$Path' could not be opened.\n");
|
||||||
|
}
|
||||||
|
return $this->decode();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decodes a string with bencoded data
|
||||||
|
*
|
||||||
|
* @param mixed $Arg bencoded data or false to decode the content of $this->Data
|
||||||
|
* @return decoded data with a suitable structure
|
||||||
|
*/
|
||||||
|
public function decode($Arg = false) {
|
||||||
|
if ($Arg !== false) {
|
||||||
|
$this->Data = $Arg;
|
||||||
|
} else if (!$this->Data) {
|
||||||
|
$this->Data = $this->Enc;
|
||||||
|
}
|
||||||
|
if (!$this->Data) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$this->Length = strlen($this->Data);
|
||||||
|
$this->Pos = 0;
|
||||||
|
$this->Dec = $this->_bdec();
|
||||||
|
if ($this->Pos < $this->Length) {
|
||||||
|
// Not really necessary, but if the torrent is invalid, it's better to warn than to silently truncate it
|
||||||
|
return $this->error();
|
||||||
|
}
|
||||||
|
return $this->Dec;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal decoding function that does the actual job
|
||||||
|
*
|
||||||
|
* @return decoded data with a suitable structure
|
||||||
|
*/
|
||||||
|
private function _bdec() {
|
||||||
|
switch ($this->Data[$this->Pos]) {
|
||||||
|
|
||||||
|
case 'i':
|
||||||
|
$this->Pos++;
|
||||||
|
$Value = substr($this->Data, $this->Pos, strpos($this->Data, 'e', $this->Pos) - $this->Pos);
|
||||||
|
if (!ctype_digit($Value) && !($Value[0] == '-' && ctype_digit(substr($Value, 1)))) {
|
||||||
|
return $this->error();
|
||||||
|
}
|
||||||
|
$this->Pos += strlen($Value) + 1;
|
||||||
|
return Int64::make($Value);
|
||||||
|
|
||||||
|
case 'l':
|
||||||
|
$Value = array();
|
||||||
|
$this->Pos++;
|
||||||
|
while ($this->Data[$this->Pos] != 'e') {
|
||||||
|
if ($this->Pos >= $this->Length) {
|
||||||
|
return $this->error();
|
||||||
|
}
|
||||||
|
$Value[] = $this->_bdec();
|
||||||
|
}
|
||||||
|
$this->Pos++;
|
||||||
|
return $Value;
|
||||||
|
|
||||||
|
case 'd':
|
||||||
|
$Value = array();
|
||||||
|
$this->Pos++;
|
||||||
|
while ($this->Data[$this->Pos] != 'e') {
|
||||||
|
$Length = substr($this->Data, $this->Pos, strpos($this->Data, ':', $this->Pos) - $this->Pos);
|
||||||
|
if (!ctype_digit($Length)) {
|
||||||
|
return $this->error();
|
||||||
|
}
|
||||||
|
$this->Pos += strlen($Length) + $Length + 1;
|
||||||
|
$Key = substr($this->Data, $this->Pos - $Length, $Length);
|
||||||
|
if ($this->Pos >= $this->Length) {
|
||||||
|
return $this->error();
|
||||||
|
}
|
||||||
|
$Value[$Key] = $this->_bdec();
|
||||||
|
}
|
||||||
|
$this->Pos++;
|
||||||
|
// Use boolean true to keep track of empty dictionaries
|
||||||
|
return empty($Value) ? true : $Value;
|
||||||
|
|
||||||
|
default:
|
||||||
|
$Length = substr($this->Data, $this->Pos, strpos($this->Data, ':', $this->Pos) - $this->Pos);
|
||||||
|
if (!ctype_digit($Length)) {
|
||||||
|
return $this->error(); // Even if the string is likely to be decoded correctly without this check, it's malformed
|
||||||
|
}
|
||||||
|
$this->Pos += strlen($Length) + $Length + 1;
|
||||||
|
return substr($this->Data, $this->Pos - $Length, $Length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert everything to the correct data types and optionally escape strings
|
||||||
|
*
|
||||||
|
* @param bool $Escape whether to escape the textual data
|
||||||
|
* @param mixed $Data decoded data or false to use the $Dec property
|
||||||
|
* @return decoded data with more useful data types
|
||||||
|
*/
|
||||||
|
public function dump($Escape = true, $Data = false) {
|
||||||
|
if ($Data === false) {
|
||||||
|
$Data = $this->Dec;
|
||||||
|
}
|
||||||
|
if (Int64::is_int($Data)) {
|
||||||
|
return Int64::get($Data);
|
||||||
|
}
|
||||||
|
if (is_bool($Data)) {
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
if (is_array($Data)) {
|
||||||
|
$Output = array();
|
||||||
|
foreach ($Data as $Key => $Val) {
|
||||||
|
$Output[$Key] = $this->dump($Escape, $Val);
|
||||||
|
}
|
||||||
|
return $Output;
|
||||||
|
}
|
||||||
|
return $Escape ? htmlentities($Data) : $Data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display an error and halt the operation unless the $ExitOnError property is false
|
||||||
|
*
|
||||||
|
* @param string $ErrMsg the error message to display
|
||||||
|
*/
|
||||||
|
private function error($ErrMsg = false) {
|
||||||
|
static $ErrorPos;
|
||||||
|
if ($this->Pos === $ErrorPos) {
|
||||||
|
// The recursive nature of the class requires this to avoid duplicate error messages
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ($ErrMsg === false) {
|
||||||
|
printf("Malformed string. Invalid character at pos 0x%X: %s\n",
|
||||||
|
$this->Pos, str_replace(array("\r","\n"), array('',' '), htmlentities(substr($this->Data, $this->Pos, self::SnipLength))));
|
||||||
|
} else {
|
||||||
|
echo $ErrMsg;
|
||||||
|
}
|
||||||
|
if ($this->ExitOnError) {
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
$ErrorPos = $this->Pos;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
127
classes/class_bencodetorrent.php
Normal file
127
classes/class_bencodetorrent.php
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
<?
|
||||||
|
/**
|
||||||
|
* Torrent class that contains some convenient functions related to torrent meta data
|
||||||
|
*/
|
||||||
|
class BencodeTorrent extends BencodeDecode {
|
||||||
|
private $PathKey = 'path';
|
||||||
|
public $Files = array();
|
||||||
|
public $Size = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a list of the files in the torrent and their sizes as well as the total torrent size
|
||||||
|
*
|
||||||
|
* @return array with a list of files and file sizes
|
||||||
|
*/
|
||||||
|
public function file_list() {
|
||||||
|
if (empty($this->Dec)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$InfoDict =& $this->Dec['info'];
|
||||||
|
if (!isset($InfoDict['files'])) {
|
||||||
|
// Single-file torrent
|
||||||
|
$this->Size = (Int64::is_int($InfoDict['length'])
|
||||||
|
? Int64::get($InfoDict['length'])
|
||||||
|
: $InfoDict['length']);
|
||||||
|
$Name = (isset($InfoDict['name.utf-8'])
|
||||||
|
? $InfoDict['name.utf-8']
|
||||||
|
: $InfoDict['name']);
|
||||||
|
$this->Files[] = array($this->Size, $Name);
|
||||||
|
} else {
|
||||||
|
if (isset($InfoDict['path.utf-8']['files'][0])) {
|
||||||
|
$this->PathKey = 'path.utf-8';
|
||||||
|
}
|
||||||
|
foreach ($InfoDict['files'] as $File) {
|
||||||
|
$TmpPath = array();
|
||||||
|
foreach ($File[$this->PathKey] as $SubPath) {
|
||||||
|
$TmpPath[] = $SubPath;
|
||||||
|
}
|
||||||
|
$CurSize = (Int64::is_int($File['length'])
|
||||||
|
? Int64::get($File['length'])
|
||||||
|
: $File['length']);
|
||||||
|
$this->Files[] = array($CurSize, implode('/', $TmpPath));
|
||||||
|
$this->Size += $CurSize;
|
||||||
|
}
|
||||||
|
uasort($this->Files, function($a, $b) {
|
||||||
|
return strnatcasecmp($a[1], $b[1]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return array($this->Size, $this->Files);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find out the name of the torrent
|
||||||
|
*
|
||||||
|
* @return string torrent name
|
||||||
|
*/
|
||||||
|
public function get_name() {
|
||||||
|
if (empty($this->Dec)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (isset($this->Dec['info']['name.utf-8'])) {
|
||||||
|
return $this->Dec['info']['name.utf-8'];
|
||||||
|
}
|
||||||
|
return $this->Dec['info']['name'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find out the total size of the torrent
|
||||||
|
*
|
||||||
|
* @return string torrent size
|
||||||
|
*/
|
||||||
|
public function get_size() {
|
||||||
|
if (empty($this->Files)) {
|
||||||
|
if (empty($this->Dec)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$FileList = $this->file_list();
|
||||||
|
}
|
||||||
|
return $FileList[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the "private" flag is present in the torrent
|
||||||
|
*
|
||||||
|
* @return true if the "private" flag is set
|
||||||
|
*/
|
||||||
|
public function is_private() {
|
||||||
|
if (empty($this->Dec)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return isset($this->Dec['info']['private']) && Int64::get($this->Dec['info']['private']) == 1;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Add the "private" flag to the torrent
|
||||||
|
*
|
||||||
|
* @return true if a change was required
|
||||||
|
*/
|
||||||
|
public function make_private() {
|
||||||
|
if (empty($this->Dec)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ($this->is_private()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$this->Dec['info']['private'] = Int64::make(1);
|
||||||
|
ksort($this->Dec['info']);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate the torrent's info hash
|
||||||
|
*
|
||||||
|
* @return info hash in hexadecimal form
|
||||||
|
*/
|
||||||
|
public function info_hash() {
|
||||||
|
if (empty($this->Dec) || !isset($this->Dec['info'])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return sha1($this->encode(false, 'info'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the announce URL to a torrent
|
||||||
|
*/
|
||||||
|
public static function add_announce_url($Data, $Url) {
|
||||||
|
return 'd8:announce'.strlen($Url).':'.$Url . substr($Data, 1);
|
||||||
|
}
|
||||||
|
}
|
@ -277,14 +277,14 @@ public function get_sphinx_time() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function get_sphinxql_queries() {
|
public function get_sphinxql_queries() {
|
||||||
if(class_exists(SphinxQL)) {
|
if(class_exists('Sphinxql')) {
|
||||||
return SphinxQL::$Queries;
|
return Sphinxql::$Queries;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function get_sphinxql_time() {
|
public function get_sphinxql_time() {
|
||||||
if(class_exists(SphinxQL)) {
|
if(class_exists('Sphinxql')) {
|
||||||
return SphinxQL::$Time;
|
return Sphinxql::$Time;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
error('Mysqli Extension not loaded.');
|
error('Mysqli Extension not loaded.');
|
||||||
}
|
}
|
||||||
|
|
||||||
class SphinxQL extends mysqli {
|
class Sphinxql extends mysqli {
|
||||||
private static $Connections = array();
|
private static $Connections = array();
|
||||||
private $Server;
|
private $Server;
|
||||||
private $Port;
|
private $Port;
|
||||||
@ -16,7 +16,7 @@ class SphinxQL extends mysqli {
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize SphinxQL object
|
* Initialize Sphinxql object
|
||||||
*
|
*
|
||||||
* @param string $Server server address or hostname
|
* @param string $Server server address or hostname
|
||||||
* @param int $Port listening port
|
* @param int $Port listening port
|
||||||
@ -46,23 +46,23 @@ private function get_ident($Server, $Port, $Socket) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create SphinxQL object or return existing one
|
* Create Sphinxql object or return existing one
|
||||||
*
|
*
|
||||||
* @param string $Server server address or hostname
|
* @param string $Server server address or hostname
|
||||||
* @param int $Port listening port
|
* @param int $Port listening port
|
||||||
* @param string $Socket Unix socket address, overrides $Server:$Port
|
* @param string $Socket Unix socket address, overrides $Server:$Port
|
||||||
* @return SphinxQL object
|
* @return Sphinxql object
|
||||||
*/
|
*/
|
||||||
public static function init_connection($Server, $Port, $Socket) {
|
public static function init_connection($Server, $Port, $Socket) {
|
||||||
$Ident = self::get_ident($Server, $Port, $Socket);
|
$Ident = self::get_ident($Server, $Port, $Socket);
|
||||||
if(!isset(self::$Connections[$Ident])) {
|
if(!isset(self::$Connections[$Ident])) {
|
||||||
self::$Connections[$Ident] = new SphinxQL($Server, $Port, $Socket);
|
self::$Connections[$Ident] = new Sphinxql($Server, $Port, $Socket);
|
||||||
}
|
}
|
||||||
return self::$Connections[$Ident];
|
return self::$Connections[$Ident];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Connect the SphinxQL object to the Sphinx server
|
* Connect the Sphinxql object to the Sphinx server
|
||||||
*/
|
*/
|
||||||
public function connect() {
|
public function connect() {
|
||||||
if(!$this->Connected) {
|
if(!$this->Connected) {
|
||||||
@ -84,7 +84,7 @@ public function connect() {
|
|||||||
*
|
*
|
||||||
* @param string $Msg message to display
|
* @param string $Msg message to display
|
||||||
* @param bool $Halt halt page processing. Default is to continue processing the page
|
* @param bool $Halt halt page processing. Default is to continue processing the page
|
||||||
* @return SphinxQL object
|
* @return Sphinxql object
|
||||||
*/
|
*/
|
||||||
public function error($Msg, $Halt = false) {
|
public function error($Msg, $Halt = false) {
|
||||||
global $Debug;
|
global $Debug;
|
||||||
@ -133,469 +133,7 @@ public function escape_string($String) {
|
|||||||
* @param param $QueryProcessTime time building and processing the query
|
* @param param $QueryProcessTime time building and processing the query
|
||||||
*/
|
*/
|
||||||
public function register_query($QueryString, $QueryProcessTime) {
|
public function register_query($QueryString, $QueryProcessTime) {
|
||||||
SphinxQL::$Queries[] = array($QueryString, $QueryProcessTime);
|
Sphinxql::$Queries[] = array($QueryString, $QueryProcessTime);
|
||||||
SphinxQL::$Time += $QueryProcessTime;
|
Sphinxql::$Time += $QueryProcessTime;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class SphinxQL_Query {
|
|
||||||
private $SphinxQL;
|
|
||||||
|
|
||||||
private $Expressions;
|
|
||||||
private $Filters;
|
|
||||||
private $GroupBy;
|
|
||||||
private $Indexes;
|
|
||||||
private $Limits;
|
|
||||||
private $Options;
|
|
||||||
private $QueryString;
|
|
||||||
private $Select;
|
|
||||||
private $SortBy;
|
|
||||||
private $SortGroupBy;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize SphinxQL object
|
|
||||||
*
|
|
||||||
* @param string $Server server address or hostname
|
|
||||||
* @param int $Port listening port
|
|
||||||
* @param string $Socket Unix socket address, overrides $Server:$Port
|
|
||||||
*/
|
|
||||||
public function __construct($Server = SPHINXQL_HOST, $Port = SPHINXQL_PORT, $Socket = SPHINXQL_SOCK) {
|
|
||||||
$this->SphinxQL = SphinxQL::init_connection($Server, $Port, $Socket);
|
|
||||||
$this->reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Specify what data the Sphinx query is supposed to return
|
|
||||||
*
|
|
||||||
* @param string $Fields Attributes and expressions
|
|
||||||
* @return current SphinxQL query object
|
|
||||||
*/
|
|
||||||
public function select($Fields) {
|
|
||||||
$this->Select = $Fields;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Specify the indexes to use in the search
|
|
||||||
*
|
|
||||||
* @param string $Indexes comma separated list of indexes
|
|
||||||
* @return current SphinxQL query object
|
|
||||||
*/
|
|
||||||
public function from($Indexes) {
|
|
||||||
$this->Indexes = $Indexes;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add attribute filter. Calling this function multiple times results in boolean AND between each condition
|
|
||||||
*
|
|
||||||
* @param string $Attribute attribute which the filter will apply to
|
|
||||||
* @param mixed $Values scalar or array of numerical values. Array uses boolean OR in query condition
|
|
||||||
* @param bool $Exclude whether to exclude or include matching documents. Default mode is to include matches
|
|
||||||
* @return current SphinxQL query object
|
|
||||||
*/
|
|
||||||
public function where($Attribute, $Values, $Exclude = false) {
|
|
||||||
if(empty($Attribute) && empty($Values)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
$Filters = array();
|
|
||||||
if(is_array($Values)) {
|
|
||||||
foreach($Values as $Value) {
|
|
||||||
if(!is_number($Value)) {
|
|
||||||
$this->error("Filters require numeric values");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if($Exclude) {
|
|
||||||
$Filters[] = "$Attribute NOT IN (".implode(",", $Values).")";
|
|
||||||
} else {
|
|
||||||
$Filters[] = "$Attribute IN (".implode(",", $Values).")";
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if(!is_number($Values)) {
|
|
||||||
$this->error("Filters require numeric values");
|
|
||||||
}
|
|
||||||
if($Exclude) {
|
|
||||||
$Filters[] = "$Attribute != $Values";
|
|
||||||
} else {
|
|
||||||
$Filters[] = "$Attribute = $Values";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$this->Filters[] = implode(" AND ", $Filters);
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add attribute range filter. Calling this function multiple times results in boolean AND between each condition
|
|
||||||
*
|
|
||||||
* @param string $Attribute attribute which the filter will apply to
|
|
||||||
* @param array $Values pair of numerical values that defines the filter range
|
|
||||||
* @return current SphinxQL query object
|
|
||||||
*/
|
|
||||||
public function where_between($Attribute, $Values) {
|
|
||||||
if(empty($Attribute) || empty($Values) || count($Values) != 2 || !is_number($Values[0]) || !is_number($Values[1])) {
|
|
||||||
$this->error("Filter range requires array of two numerical boundaries as values.");
|
|
||||||
}
|
|
||||||
$this->Filters[] = "$Attribute BETWEEN $Values[0] AND $Values[1]";
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add fulltext query expression. Calling this function multiple times results in boolean AND between each condition.
|
|
||||||
* Query expression is escaped automatically
|
|
||||||
*
|
|
||||||
* @param string $Expr query expression
|
|
||||||
* @param string $Field field to match $Expr against. Default is *, which means all available fields
|
|
||||||
* @return current SphinxQL query object
|
|
||||||
*/
|
|
||||||
public function where_match($Expr, $Field = '*', $Escape = true) {
|
|
||||||
if(empty($Expr)) {
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
if ($Field !== false) {
|
|
||||||
$Field = "@$Field ";
|
|
||||||
}
|
|
||||||
if ($Escape === true) {
|
|
||||||
$this->Expressions[] = "$Field".SphinxQL::escape_string($Expr);
|
|
||||||
} else {
|
|
||||||
$this->Expressions[] = $Field.$Expr;
|
|
||||||
}
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Specify the order of the matches. Calling this function multiple times sets secondary priorities
|
|
||||||
*
|
|
||||||
* @param string $Attribute attribute to use for sorting.
|
|
||||||
* Passing an empty attribute value will clear the current sort settings
|
|
||||||
* @param string $Mode sort method to apply to the selected attribute
|
|
||||||
* @return current SphinxQL query object
|
|
||||||
*/
|
|
||||||
public function order_by($Attribute = false, $Mode = false) {
|
|
||||||
if (empty($Attribute)) {
|
|
||||||
$this->SortBy = array();
|
|
||||||
} else {
|
|
||||||
$this->SortBy[] = "$Attribute $Mode";
|
|
||||||
}
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Specify how the results are grouped
|
|
||||||
*
|
|
||||||
* @param string $Attribute group matches with the same $Attribute value.
|
|
||||||
* Passing an empty attribute value will clear the current group settings
|
|
||||||
* @return current SphinxQL query object
|
|
||||||
*/
|
|
||||||
public function group_by($Attribute = false) {
|
|
||||||
if (empty($Attribute)) {
|
|
||||||
$this->GroupBy = '';
|
|
||||||
} else {
|
|
||||||
$this->GroupBy = $Attribute;
|
|
||||||
}
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Specify the order of the results within groups
|
|
||||||
*
|
|
||||||
* @param string $Attribute attribute to use for sorting.
|
|
||||||
* Passing an empty attribute will clear the current group sort settings
|
|
||||||
* @param string $Mode sort method to apply to the selected attribute
|
|
||||||
* @return current SphinxQL query object
|
|
||||||
*/
|
|
||||||
public function order_group_by($Attribute = false, $Mode = false) {
|
|
||||||
if (empty($Attribute)) {
|
|
||||||
$this->SortGroupBy = '';
|
|
||||||
} else {
|
|
||||||
$this->SortGroupBy = "$Attribute $Mode";
|
|
||||||
}
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Specify the offset and amount of matches to return
|
|
||||||
*
|
|
||||||
* @param int $Offset number of matches to discard
|
|
||||||
* @param int $Limit number of matches to return
|
|
||||||
* @param int $MaxMatches number of results to store in the Sphinx server's memory. Must be >= ($Offset+$Limit)
|
|
||||||
* @return current SphinxQL query object
|
|
||||||
*/
|
|
||||||
public function limit($Offset, $Limit, $MaxMatches = SPHINX_MAX_MATCHES) {
|
|
||||||
$this->Limits = "$Offset, $Limit";
|
|
||||||
$this->set('max_matches', $MaxMatches);
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tweak the settings to use for the query. Sanity checking shouldn't be needed as Sphinx already does it
|
|
||||||
*
|
|
||||||
* @param string $Name setting name
|
|
||||||
* @param mixed $Value value
|
|
||||||
* @return current SphinxQL query object
|
|
||||||
*/
|
|
||||||
public function set($Name, $Value) {
|
|
||||||
$this->Options[$Name] = $Value;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Combine the query options into a valid Sphinx query segment
|
|
||||||
*
|
|
||||||
* @return string of options
|
|
||||||
*/
|
|
||||||
private function build_options() {
|
|
||||||
$Options = array();
|
|
||||||
foreach($this->Options as $Option => $Value) {
|
|
||||||
$Options[] = "$Option = $Value";
|
|
||||||
}
|
|
||||||
return implode(", ", $Options);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Combine the query conditions into a valid Sphinx query segment
|
|
||||||
*/
|
|
||||||
private function build_query() {
|
|
||||||
if(!$this->Indexes) {
|
|
||||||
$this->error('Index name is required.');
|
|
||||||
}
|
|
||||||
$this->QueryString = "SELECT $this->Select\nFROM $this->Indexes";
|
|
||||||
if(!empty($this->Expressions)) {
|
|
||||||
$this->Filters['expr'] = "MATCH('".implode(" ", $this->Expressions)."')";
|
|
||||||
}
|
|
||||||
if(!empty($this->Filters)) {
|
|
||||||
$this->QueryString .= "\nWHERE ".implode("\n\tAND ", $this->Filters);
|
|
||||||
}
|
|
||||||
if(!empty($this->GroupBy)) {
|
|
||||||
$this->QueryString .= "\nGROUP BY $this->GroupBy";
|
|
||||||
}
|
|
||||||
if(!empty($this->SortGroupBy)) {
|
|
||||||
$this->QueryString .= "\nWITHIN GROUP ORDER BY $this->SortGroupBy";
|
|
||||||
}
|
|
||||||
if(!empty($this->SortBy)) {
|
|
||||||
$this->QueryString .= "\nORDER BY ".implode(", ", $this->SortBy);
|
|
||||||
}
|
|
||||||
if(!empty($this->Limits)) {
|
|
||||||
$this->QueryString .= "\nLIMIT $this->Limits";
|
|
||||||
}
|
|
||||||
if(!empty($this->Options)) {
|
|
||||||
$Options = $this->build_options();
|
|
||||||
$this->QueryString .= "\nOPTION $Options";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Construct and send the query. Register the query in the global SphinxQL object
|
|
||||||
*
|
|
||||||
* @param bool GetMeta whether to fetch meta data for the executed query. Default is yes
|
|
||||||
* @return SphinxQL result object
|
|
||||||
*/
|
|
||||||
public function query($GetMeta = true) {
|
|
||||||
$QueryStartTime = microtime(true);
|
|
||||||
$this->build_query();
|
|
||||||
$QueryString = $this->QueryString;
|
|
||||||
$Result = $this->send_query($GetMeta);
|
|
||||||
$QueryProcessTime = (microtime(true) - $QueryStartTime)*1000;
|
|
||||||
SphinxQL::register_query($QueryString, $QueryProcessTime);
|
|
||||||
return $Result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Run a manually constructed query
|
|
||||||
*
|
|
||||||
* @param string Query query expression
|
|
||||||
* @param bool GetMeta whether to fetch meta data for the executed query. Default is yes
|
|
||||||
* @return SphinxQL result object
|
|
||||||
*/
|
|
||||||
public function raw_query($Query, $GetMeta = true) {
|
|
||||||
$this->QueryString = $Query;
|
|
||||||
return $this->send_query($GetMeta);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Run a pre-processed query. Only used internally
|
|
||||||
*
|
|
||||||
* @param bool GetMeta whether to fetch meta data for the executed query
|
|
||||||
* @return SphinxQL result object
|
|
||||||
*/
|
|
||||||
private function send_query($GetMeta) {
|
|
||||||
if(!$this->QueryString) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
$this->SphinxQL->connect();
|
|
||||||
$Result = $this->SphinxQL->query($this->QueryString);
|
|
||||||
if($Result === false) {
|
|
||||||
$Errno = $this->SphinxQL->errno;
|
|
||||||
$Error = $this->SphinxQL->error;
|
|
||||||
$this->error("Query returned error $Errno ($Error).\n$this->QueryString");
|
|
||||||
} else {
|
|
||||||
$Meta = $GetMeta ? $this->get_meta() : null;
|
|
||||||
}
|
|
||||||
return new SphinxQL_Result($Result, $Meta, $Errno, $Error);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reset all query options and conditions
|
|
||||||
*/
|
|
||||||
public function reset() {
|
|
||||||
$this->Expressions = array();
|
|
||||||
$this->Filters = array();
|
|
||||||
$this->GroupBy = '';
|
|
||||||
$this->Indexes = '';
|
|
||||||
$this->Limits = array();
|
|
||||||
$this->Options = array('ranker' => 'none');
|
|
||||||
$this->QueryString = '';
|
|
||||||
$this->Select = '*';
|
|
||||||
$this->SortBy = array();
|
|
||||||
$this->SortGroupBy = '';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fetch and store meta data for the last executed query
|
|
||||||
*
|
|
||||||
* @return meta data
|
|
||||||
*/
|
|
||||||
private function get_meta() {
|
|
||||||
return $this->raw_query("SHOW META", false)->to_pair(0, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Wrapper for the current SphinxQL connection's error function
|
|
||||||
*/
|
|
||||||
private function error($Msg, $Halt = false) {
|
|
||||||
$this->SphinxQL->error($Msg, $Halt);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class SphinxQL_Result {
|
|
||||||
private $Result;
|
|
||||||
private $Meta;
|
|
||||||
public $Errno;
|
|
||||||
public $Error;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create SphinxQL result object
|
|
||||||
*
|
|
||||||
* @param mysqli_result $Result query results
|
|
||||||
* @param array $Meta meta data for the query
|
|
||||||
* @param int $Errno error code returned by the query upon failure
|
|
||||||
* @param string $Error error message returned by the query upon failure
|
|
||||||
*/
|
|
||||||
public function __construct($Result, $Meta, $Errno, $Error) {
|
|
||||||
$this->Result = $Result;
|
|
||||||
$this->Meta = $Meta;
|
|
||||||
$this->Errno = $Errno;
|
|
||||||
$this->Error = $Error;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Redirect to the Mysqli result object if a nonexistent method is called
|
|
||||||
*
|
|
||||||
* @param string $Name method name
|
|
||||||
* @param array $Arguments arguments used in the function call
|
|
||||||
* @return whatever the parent function returns
|
|
||||||
*/
|
|
||||||
public function __call($Name, $Arguments) {
|
|
||||||
return call_user_func_array(array($this->Result, $Name), $Arguments);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Collect and return the specified key of all results as a list
|
|
||||||
*
|
|
||||||
* @param string $Key key containing the desired data
|
|
||||||
* @return array with the $Key value of all results
|
|
||||||
*/
|
|
||||||
public function collect($Key) {
|
|
||||||
$Return = array();
|
|
||||||
while($Row = $this->fetch_array()) {
|
|
||||||
$Return[] = $Row[$Key];
|
|
||||||
}
|
|
||||||
$this->data_seek(0);
|
|
||||||
return $Return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Collect and return all available data for the matches optionally indexed by a specified key
|
|
||||||
*
|
|
||||||
* @param string $Key key to use as indexing value
|
|
||||||
* @param string $ResultType method to use when fetching data from the mysqli_result object. Default is MYSQLI_ASSOC
|
|
||||||
* @return array with all available data for the matches
|
|
||||||
*/
|
|
||||||
public function to_array($Key, $ResultType = MYSQLI_ASSOC) {
|
|
||||||
$Return = array();
|
|
||||||
while($Row = $this->fetch_array($ResultType)) {
|
|
||||||
if($Key !== false) {
|
|
||||||
$Return[$Row[$Key]] = $Row;
|
|
||||||
} else {
|
|
||||||
$Return[] = $Row;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$this->data_seek(0);
|
|
||||||
return $Return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Collect pairs of keys for all matches
|
|
||||||
*
|
|
||||||
* @param string $Key1 key to use as indexing value
|
|
||||||
* @param string $Key2 key to use as value
|
|
||||||
* @return array with $Key1 => $Key2 pairs for matches
|
|
||||||
*/
|
|
||||||
public function to_pair($Key1, $Key2) {
|
|
||||||
$Return = array();
|
|
||||||
while($Row = $this->fetch_array()) {
|
|
||||||
$Return[$Row[$Key1]] = $Row[$Key2];
|
|
||||||
}
|
|
||||||
$this->data_seek(0);
|
|
||||||
return $Return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return specified portions of the current SphinxQL result object's meta data
|
|
||||||
*
|
|
||||||
* @param mixed $Keys scalar or array with keys to return. Default is false, which returns all meta data
|
|
||||||
* @return array with meta data
|
|
||||||
*/
|
|
||||||
public function get_meta($Keys = false) {
|
|
||||||
if($Keys !== false) {
|
|
||||||
if(is_array($Keys)) {
|
|
||||||
$Return = array();
|
|
||||||
foreach($Keys as $Key) {
|
|
||||||
if(!isset($this->Meta[$Key])) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
$Return[$Key] = $this->Meta[$Key];
|
|
||||||
}
|
|
||||||
return $Return;
|
|
||||||
} else {
|
|
||||||
return isset($this->Meta[$Keys]) ? $this->Meta[$Keys] : false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return $this->Meta;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return specified portions of the current Mysqli result object's information
|
|
||||||
*
|
|
||||||
* @param mixed $Keys scalar or array with keys to return. Default is false, which returns all available information
|
|
||||||
* @return array with result information
|
|
||||||
*/
|
|
||||||
public function get_result_info($Keys = false) {
|
|
||||||
if($Keys !== false) {
|
|
||||||
if(is_array($Keys)) {
|
|
||||||
$Return = array();
|
|
||||||
foreach($Keys as $Key) {
|
|
||||||
if(!isset($this->Result->$Key)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
$Return[$Key] = $this->Result->$Key;
|
|
||||||
}
|
|
||||||
return $Return;
|
|
||||||
} else {
|
|
||||||
return isset($this->Result->$Keys) ? $this->Result->$Keys : false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return $this->Result;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
328
classes/class_sphinxqlquery.php
Normal file
328
classes/class_sphinxqlquery.php
Normal file
@ -0,0 +1,328 @@
|
|||||||
|
<?
|
||||||
|
class SphinxqlQuery {
|
||||||
|
private $Sphinxql;
|
||||||
|
|
||||||
|
private $Expressions;
|
||||||
|
private $Filters;
|
||||||
|
private $GroupBy;
|
||||||
|
private $Indexes;
|
||||||
|
private $Limits;
|
||||||
|
private $Options;
|
||||||
|
private $QueryString;
|
||||||
|
private $Select;
|
||||||
|
private $SortBy;
|
||||||
|
private $SortGroupBy;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize Sphinxql object
|
||||||
|
*
|
||||||
|
* @param string $Server server address or hostname
|
||||||
|
* @param int $Port listening port
|
||||||
|
* @param string $Socket Unix socket address, overrides $Server:$Port
|
||||||
|
*/
|
||||||
|
public function __construct($Server = SPHINXQL_HOST, $Port = SPHINXQL_PORT, $Socket = SPHINXQL_SOCK) {
|
||||||
|
$this->Sphinxql = Sphinxql::init_connection($Server, $Port, $Socket);
|
||||||
|
$this->reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specify what data the Sphinx query is supposed to return
|
||||||
|
*
|
||||||
|
* @param string $Fields Attributes and expressions
|
||||||
|
* @return current Sphinxql query object
|
||||||
|
*/
|
||||||
|
public function select($Fields) {
|
||||||
|
$this->Select = $Fields;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specify the indexes to use in the search
|
||||||
|
*
|
||||||
|
* @param string $Indexes comma separated list of indexes
|
||||||
|
* @return current Sphinxql query object
|
||||||
|
*/
|
||||||
|
public function from($Indexes) {
|
||||||
|
$this->Indexes = $Indexes;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add attribute filter. Calling this function multiple times results in boolean AND between each condition
|
||||||
|
*
|
||||||
|
* @param string $Attribute attribute which the filter will apply to
|
||||||
|
* @param mixed $Values scalar or array of numerical values. Array uses boolean OR in query condition
|
||||||
|
* @param bool $Exclude whether to exclude or include matching documents. Default mode is to include matches
|
||||||
|
* @return current Sphinxql query object
|
||||||
|
*/
|
||||||
|
public function where($Attribute, $Values, $Exclude = false) {
|
||||||
|
if(empty($Attribute) && empty($Values)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$Filters = array();
|
||||||
|
if(is_array($Values)) {
|
||||||
|
foreach($Values as $Value) {
|
||||||
|
if(!is_number($Value)) {
|
||||||
|
$this->error("Filters require numeric values");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if($Exclude) {
|
||||||
|
$Filters[] = "$Attribute NOT IN (".implode(",", $Values).")";
|
||||||
|
} else {
|
||||||
|
$Filters[] = "$Attribute IN (".implode(",", $Values).")";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if(!is_number($Values)) {
|
||||||
|
$this->error("Filters require numeric values");
|
||||||
|
}
|
||||||
|
if($Exclude) {
|
||||||
|
$Filters[] = "$Attribute != $Values";
|
||||||
|
} else {
|
||||||
|
$Filters[] = "$Attribute = $Values";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$this->Filters[] = implode(" AND ", $Filters);
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add attribute range filter. Calling this function multiple times results in boolean AND between each condition
|
||||||
|
*
|
||||||
|
* @param string $Attribute attribute which the filter will apply to
|
||||||
|
* @param array $Values pair of numerical values that defines the filter range
|
||||||
|
* @return current Sphinxql query object
|
||||||
|
*/
|
||||||
|
public function where_between($Attribute, $Values) {
|
||||||
|
if(empty($Attribute) || empty($Values) || count($Values) != 2 || !is_number($Values[0]) || !is_number($Values[1])) {
|
||||||
|
$this->error("Filter range requires array of two numerical boundaries as values.");
|
||||||
|
}
|
||||||
|
$this->Filters[] = "$Attribute BETWEEN $Values[0] AND $Values[1]";
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add fulltext query expression. Calling this function multiple times results in boolean AND between each condition.
|
||||||
|
* Query expression is escaped automatically
|
||||||
|
*
|
||||||
|
* @param string $Expr query expression
|
||||||
|
* @param string $Field field to match $Expr against. Default is *, which means all available fields
|
||||||
|
* @return current Sphinxql query object
|
||||||
|
*/
|
||||||
|
public function where_match($Expr, $Field = '*', $Escape = true) {
|
||||||
|
if(empty($Expr)) {
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
if ($Field !== false) {
|
||||||
|
$Field = "@$Field ";
|
||||||
|
}
|
||||||
|
if ($Escape === true) {
|
||||||
|
$this->Expressions[] = "$Field".Sphinxql::escape_string($Expr);
|
||||||
|
} else {
|
||||||
|
$this->Expressions[] = $Field.$Expr;
|
||||||
|
}
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specify the order of the matches. Calling this function multiple times sets secondary priorities
|
||||||
|
*
|
||||||
|
* @param string $Attribute attribute to use for sorting.
|
||||||
|
* Passing an empty attribute value will clear the current sort settings
|
||||||
|
* @param string $Mode sort method to apply to the selected attribute
|
||||||
|
* @return current Sphinxql query object
|
||||||
|
*/
|
||||||
|
public function order_by($Attribute = false, $Mode = false) {
|
||||||
|
if (empty($Attribute)) {
|
||||||
|
$this->SortBy = array();
|
||||||
|
} else {
|
||||||
|
$this->SortBy[] = "$Attribute $Mode";
|
||||||
|
}
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specify how the results are grouped
|
||||||
|
*
|
||||||
|
* @param string $Attribute group matches with the same $Attribute value.
|
||||||
|
* Passing an empty attribute value will clear the current group settings
|
||||||
|
* @return current Sphinxql query object
|
||||||
|
*/
|
||||||
|
public function group_by($Attribute = false) {
|
||||||
|
if (empty($Attribute)) {
|
||||||
|
$this->GroupBy = '';
|
||||||
|
} else {
|
||||||
|
$this->GroupBy = $Attribute;
|
||||||
|
}
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specify the order of the results within groups
|
||||||
|
*
|
||||||
|
* @param string $Attribute attribute to use for sorting.
|
||||||
|
* Passing an empty attribute will clear the current group sort settings
|
||||||
|
* @param string $Mode sort method to apply to the selected attribute
|
||||||
|
* @return current Sphinxql query object
|
||||||
|
*/
|
||||||
|
public function order_group_by($Attribute = false, $Mode = false) {
|
||||||
|
if (empty($Attribute)) {
|
||||||
|
$this->SortGroupBy = '';
|
||||||
|
} else {
|
||||||
|
$this->SortGroupBy = "$Attribute $Mode";
|
||||||
|
}
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specify the offset and amount of matches to return
|
||||||
|
*
|
||||||
|
* @param int $Offset number of matches to discard
|
||||||
|
* @param int $Limit number of matches to return
|
||||||
|
* @param int $MaxMatches number of results to store in the Sphinx server's memory. Must be >= ($Offset+$Limit)
|
||||||
|
* @return current Sphinxql query object
|
||||||
|
*/
|
||||||
|
public function limit($Offset, $Limit, $MaxMatches = SPHINX_MAX_MATCHES) {
|
||||||
|
$this->Limits = "$Offset, $Limit";
|
||||||
|
$this->set('max_matches', $MaxMatches);
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tweak the settings to use for the query. Sanity checking shouldn't be needed as Sphinx already does it
|
||||||
|
*
|
||||||
|
* @param string $Name setting name
|
||||||
|
* @param mixed $Value value
|
||||||
|
* @return current Sphinxql query object
|
||||||
|
*/
|
||||||
|
public function set($Name, $Value) {
|
||||||
|
$this->Options[$Name] = $Value;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Combine the query options into a valid Sphinx query segment
|
||||||
|
*
|
||||||
|
* @return string of options
|
||||||
|
*/
|
||||||
|
private function build_options() {
|
||||||
|
$Options = array();
|
||||||
|
foreach($this->Options as $Option => $Value) {
|
||||||
|
$Options[] = "$Option = $Value";
|
||||||
|
}
|
||||||
|
return implode(", ", $Options);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Combine the query conditions into a valid Sphinx query segment
|
||||||
|
*/
|
||||||
|
private function build_query() {
|
||||||
|
if(!$this->Indexes) {
|
||||||
|
$this->error('Index name is required.');
|
||||||
|
}
|
||||||
|
$this->QueryString = "SELECT $this->Select\nFROM $this->Indexes";
|
||||||
|
if(!empty($this->Expressions)) {
|
||||||
|
$this->Filters['expr'] = "MATCH('".implode(" ", $this->Expressions)."')";
|
||||||
|
}
|
||||||
|
if(!empty($this->Filters)) {
|
||||||
|
$this->QueryString .= "\nWHERE ".implode("\n\tAND ", $this->Filters);
|
||||||
|
}
|
||||||
|
if(!empty($this->GroupBy)) {
|
||||||
|
$this->QueryString .= "\nGROUP BY $this->GroupBy";
|
||||||
|
}
|
||||||
|
if(!empty($this->SortGroupBy)) {
|
||||||
|
$this->QueryString .= "\nWITHIN GROUP ORDER BY $this->SortGroupBy";
|
||||||
|
}
|
||||||
|
if(!empty($this->SortBy)) {
|
||||||
|
$this->QueryString .= "\nORDER BY ".implode(", ", $this->SortBy);
|
||||||
|
}
|
||||||
|
if(!empty($this->Limits)) {
|
||||||
|
$this->QueryString .= "\nLIMIT $this->Limits";
|
||||||
|
}
|
||||||
|
if(!empty($this->Options)) {
|
||||||
|
$Options = $this->build_options();
|
||||||
|
$this->QueryString .= "\nOPTION $Options";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct and send the query. Register the query in the global Sphinxql object
|
||||||
|
*
|
||||||
|
* @param bool GetMeta whether to fetch meta data for the executed query. Default is yes
|
||||||
|
* @return Sphinxql result object
|
||||||
|
*/
|
||||||
|
public function query($GetMeta = true) {
|
||||||
|
$QueryStartTime = microtime(true);
|
||||||
|
$this->build_query();
|
||||||
|
$QueryString = $this->QueryString;
|
||||||
|
$Result = $this->send_query($GetMeta);
|
||||||
|
$QueryProcessTime = (microtime(true) - $QueryStartTime)*1000;
|
||||||
|
Sphinxql::register_query($QueryString, $QueryProcessTime);
|
||||||
|
return $Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run a manually constructed query
|
||||||
|
*
|
||||||
|
* @param string Query query expression
|
||||||
|
* @param bool GetMeta whether to fetch meta data for the executed query. Default is yes
|
||||||
|
* @return Sphinxql result object
|
||||||
|
*/
|
||||||
|
public function raw_query($Query, $GetMeta = true) {
|
||||||
|
$this->QueryString = $Query;
|
||||||
|
return $this->send_query($GetMeta);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run a pre-processed query. Only used internally
|
||||||
|
*
|
||||||
|
* @param bool GetMeta whether to fetch meta data for the executed query
|
||||||
|
* @return Sphinxql result object
|
||||||
|
*/
|
||||||
|
private function send_query($GetMeta) {
|
||||||
|
if(!$this->QueryString) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$this->Sphinxql->connect();
|
||||||
|
$Result = $this->Sphinxql->query($this->QueryString);
|
||||||
|
if($Result === false) {
|
||||||
|
$Errno = $this->Sphinxql->errno;
|
||||||
|
$Error = $this->Sphinxql->error;
|
||||||
|
$this->error("Query returned error $Errno ($Error).\n$this->QueryString");
|
||||||
|
} else {
|
||||||
|
$Meta = $GetMeta ? $this->get_meta() : null;
|
||||||
|
}
|
||||||
|
return new SphinxqlResult($Result, $Meta, $Errno, $Error);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reset all query options and conditions
|
||||||
|
*/
|
||||||
|
public function reset() {
|
||||||
|
$this->Expressions = array();
|
||||||
|
$this->Filters = array();
|
||||||
|
$this->GroupBy = '';
|
||||||
|
$this->Indexes = '';
|
||||||
|
$this->Limits = array();
|
||||||
|
$this->Options = array('ranker' => 'none');
|
||||||
|
$this->QueryString = '';
|
||||||
|
$this->Select = '*';
|
||||||
|
$this->SortBy = array();
|
||||||
|
$this->SortGroupBy = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch and store meta data for the last executed query
|
||||||
|
*
|
||||||
|
* @return meta data
|
||||||
|
*/
|
||||||
|
private function get_meta() {
|
||||||
|
return $this->raw_query("SHOW META", false)->to_pair(0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrapper for the current Sphinxql connection's error function
|
||||||
|
*/
|
||||||
|
private function error($Msg, $Halt = false) {
|
||||||
|
$this->Sphinxql->error($Msg, $Halt);
|
||||||
|
}
|
||||||
|
}
|
134
classes/class_sphinxqlresult.php
Normal file
134
classes/class_sphinxqlresult.php
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
<?
|
||||||
|
class SphinxqlResult {
|
||||||
|
private $Result;
|
||||||
|
private $Meta;
|
||||||
|
public $Errno;
|
||||||
|
public $Error;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create Sphinxql result object
|
||||||
|
*
|
||||||
|
* @param mysqli_result $Result query results
|
||||||
|
* @param array $Meta meta data for the query
|
||||||
|
* @param int $Errno error code returned by the query upon failure
|
||||||
|
* @param string $Error error message returned by the query upon failure
|
||||||
|
*/
|
||||||
|
public function __construct($Result, $Meta, $Errno, $Error) {
|
||||||
|
$this->Result = $Result;
|
||||||
|
$this->Meta = $Meta;
|
||||||
|
$this->Errno = $Errno;
|
||||||
|
$this->Error = $Error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Redirect to the Mysqli result object if a nonexistent method is called
|
||||||
|
*
|
||||||
|
* @param string $Name method name
|
||||||
|
* @param array $Arguments arguments used in the function call
|
||||||
|
* @return whatever the parent function returns
|
||||||
|
*/
|
||||||
|
public function __call($Name, $Arguments) {
|
||||||
|
return call_user_func_array(array($this->Result, $Name), $Arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Collect and return the specified key of all results as a list
|
||||||
|
*
|
||||||
|
* @param string $Key key containing the desired data
|
||||||
|
* @return array with the $Key value of all results
|
||||||
|
*/
|
||||||
|
public function collect($Key) {
|
||||||
|
$Return = array();
|
||||||
|
while($Row = $this->fetch_array()) {
|
||||||
|
$Return[] = $Row[$Key];
|
||||||
|
}
|
||||||
|
$this->data_seek(0);
|
||||||
|
return $Return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Collect and return all available data for the matches optionally indexed by a specified key
|
||||||
|
*
|
||||||
|
* @param string $Key key to use as indexing value
|
||||||
|
* @param string $ResultType method to use when fetching data from the mysqli_result object. Default is MYSQLI_ASSOC
|
||||||
|
* @return array with all available data for the matches
|
||||||
|
*/
|
||||||
|
public function to_array($Key, $ResultType = MYSQLI_ASSOC) {
|
||||||
|
$Return = array();
|
||||||
|
while($Row = $this->fetch_array($ResultType)) {
|
||||||
|
if($Key !== false) {
|
||||||
|
$Return[$Row[$Key]] = $Row;
|
||||||
|
} else {
|
||||||
|
$Return[] = $Row;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$this->data_seek(0);
|
||||||
|
return $Return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Collect pairs of keys for all matches
|
||||||
|
*
|
||||||
|
* @param string $Key1 key to use as indexing value
|
||||||
|
* @param string $Key2 key to use as value
|
||||||
|
* @return array with $Key1 => $Key2 pairs for matches
|
||||||
|
*/
|
||||||
|
public function to_pair($Key1, $Key2) {
|
||||||
|
$Return = array();
|
||||||
|
while($Row = $this->fetch_array()) {
|
||||||
|
$Return[$Row[$Key1]] = $Row[$Key2];
|
||||||
|
}
|
||||||
|
$this->data_seek(0);
|
||||||
|
return $Return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return specified portions of the current Sphinxql result object's meta data
|
||||||
|
*
|
||||||
|
* @param mixed $Keys scalar or array with keys to return. Default is false, which returns all meta data
|
||||||
|
* @return array with meta data
|
||||||
|
*/
|
||||||
|
public function get_meta($Keys = false) {
|
||||||
|
if($Keys !== false) {
|
||||||
|
if(is_array($Keys)) {
|
||||||
|
$Return = array();
|
||||||
|
foreach($Keys as $Key) {
|
||||||
|
if(!isset($this->Meta[$Key])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$Return[$Key] = $this->Meta[$Key];
|
||||||
|
}
|
||||||
|
return $Return;
|
||||||
|
} else {
|
||||||
|
return isset($this->Meta[$Keys]) ? $this->Meta[$Keys] : false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return $this->Meta;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return specified portions of the current Mysqli result object's information
|
||||||
|
*
|
||||||
|
* @param mixed $Keys scalar or array with keys to return. Default is false, which returns all available information
|
||||||
|
* @return array with result information
|
||||||
|
*/
|
||||||
|
public function get_result_info($Keys = false) {
|
||||||
|
if($Keys !== false) {
|
||||||
|
if(is_array($Keys)) {
|
||||||
|
$Return = array();
|
||||||
|
foreach($Keys as $Key) {
|
||||||
|
if(!isset($this->Result->$Key)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$Return[$Key] = $this->Result->$Key;
|
||||||
|
}
|
||||||
|
return $Return;
|
||||||
|
} else {
|
||||||
|
return isset($this->Result->$Keys) ? $this->Result->$Keys : false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return $this->Result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -63,7 +63,7 @@ functions:
|
|||||||
|
|
||||||
|
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
class BENCODE {
|
class BENCODE2 {
|
||||||
var $Val; // Decoded array
|
var $Val; // Decoded array
|
||||||
var $Pos = 1; // Pointer that indicates our position in the string
|
var $Pos = 1; // Pointer that indicates our position in the string
|
||||||
var $Str = ''; // Torrent string
|
var $Str = ''; // Torrent string
|
||||||
@ -131,7 +131,7 @@ function encode($Val){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class BENCODE_LIST extends BENCODE {
|
class BENCODE_LIST extends BENCODE2 {
|
||||||
function enc(){
|
function enc(){
|
||||||
if (empty($this->Val)) {
|
if (empty($this->Val)) {
|
||||||
return 'le';
|
return 'le';
|
||||||
@ -168,7 +168,7 @@ function dec(){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class BENCODE_DICT extends BENCODE {
|
class BENCODE_DICT extends BENCODE2 {
|
||||||
function enc(){
|
function enc(){
|
||||||
if (empty($this->Val)) {
|
if (empty($this->Val)) {
|
||||||
return 'de';
|
return 'de';
|
||||||
|
@ -72,7 +72,7 @@ functions:
|
|||||||
discovered that floats aren't accurate enough to use. :(
|
discovered that floats aren't accurate enough to use. :(
|
||||||
|
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
class BENCODE {
|
class BENCODE2 {
|
||||||
var $Val; // Decoded array
|
var $Val; // Decoded array
|
||||||
var $Pos = 1; // Pointer that indicates our position in the string
|
var $Pos = 1; // Pointer that indicates our position in the string
|
||||||
var $Str = ''; // Torrent string
|
var $Str = ''; // Torrent string
|
||||||
@ -140,7 +140,7 @@ function encode($Val){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class BENCODE_LIST extends BENCODE {
|
class BENCODE_LIST extends BENCODE2 {
|
||||||
function enc(){
|
function enc(){
|
||||||
$Str = 'l';
|
$Str = 'l';
|
||||||
reset($this->Val);
|
reset($this->Val);
|
||||||
@ -174,7 +174,7 @@ function dec(){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class BENCODE_DICT extends BENCODE {
|
class BENCODE_DICT extends BENCODE2 {
|
||||||
function enc(){
|
function enc(){
|
||||||
$Str = 'd';
|
$Str = 'd';
|
||||||
reset($this->Val);
|
reset($this->Val);
|
||||||
|
@ -475,7 +475,7 @@ public static function regenerate_filelist($TorrentID) {
|
|||||||
if($DB->record_count() > 0) {
|
if($DB->record_count() > 0) {
|
||||||
list($GroupID, $Contents) = $DB->next_record(MYSQLI_NUM, false);
|
list($GroupID, $Contents) = $DB->next_record(MYSQLI_NUM, false);
|
||||||
if (Misc::is_new_torrent($Contents)) {
|
if (Misc::is_new_torrent($Contents)) {
|
||||||
$Tor = new BEncTorrent($Contents);
|
$Tor = new BencodeTorrent($Contents);
|
||||||
$FilePath = isset($Tor->Dec['info']['files']) ? Format::make_utf8($Tor->get_name()) : "";
|
$FilePath = isset($Tor->Dec['info']['files']) ? Format::make_utf8($Tor->get_name()) : "";
|
||||||
} else {
|
} else {
|
||||||
$Tor = new TORRENT(unserialize(base64_decode($Contents)), true);
|
$Tor = new TORRENT(unserialize(base64_decode($Contents)), true);
|
||||||
@ -748,5 +748,28 @@ public static function has_snatched($TorrentID, $AllUsers = false) {
|
|||||||
}
|
}
|
||||||
return isset($CurSnatchedTorrents[$TorrentID]);
|
return isset($CurSnatchedTorrents[$TorrentID]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static function edition_string(array $Torrent, array $Group) {
|
||||||
|
if ($Torrent['Remastered'] && $Torrent['RemasterYear'] != 0) {
|
||||||
|
$EditionName = $Torrent['RemasterYear'];
|
||||||
|
$AddExtra = " - ";
|
||||||
|
if ($Torrent['RemasterRecordLabel']) { $EditionName .= $AddExtra . display_str($Torrent['RemasterRecordLabel']); $AddExtra = ' / '; }
|
||||||
|
if ($Torrent['RemasterCatalogueNumber']) { $EditionName .= $AddExtra . display_str($Torrent['RemasterCatalogueNumber']); $AddExtra = ' / '; }
|
||||||
|
if ($Torrent['RemasterTitle']) { $EditionName .= $AddExtra . display_str($Torrent['RemasterTitle']); $AddExtra = ' / '; }
|
||||||
|
$EditionName .= $AddExtra . display_str($Torrent['Media']);
|
||||||
|
} else {
|
||||||
|
$AddExtra = " / ";
|
||||||
|
if(!$Torrent['Remastered']) {
|
||||||
|
$EditionName = "Original Release";
|
||||||
|
if ($Group['RecordLabel']) { $EditionName .= $AddExtra . $Group['RecordLabel']; $AddExtra = ' / '; }
|
||||||
|
if ($Group['CatalogueNumber']) { $EditionName .= $AddExtra . $Group['CatalogueNumber']; $AddExtra = ' / '; }
|
||||||
|
} else {
|
||||||
|
$EditionName = "Unknown Release(s)";
|
||||||
|
}
|
||||||
|
$EditionName .= $AddExtra . display_str($Torrent['Media']);
|
||||||
|
}
|
||||||
|
return $EditionName;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
|
@ -227,7 +227,7 @@ public static function construct_file_name($Artist, $Album, $Year, $Media, $Form
|
|||||||
*/
|
*/
|
||||||
public static function get_file(&$TorrentData, $AnnounceURL) {
|
public static function get_file(&$TorrentData, $AnnounceURL) {
|
||||||
if (Misc::is_new_torrent($TorrentData)) {
|
if (Misc::is_new_torrent($TorrentData)) {
|
||||||
return BEncTorrent::add_announce_url($TorrentData, $AnnounceURL);
|
return BencodeTorrent::add_announce_url($TorrentData, $AnnounceURL);
|
||||||
}
|
}
|
||||||
$Tor = new TORRENT(unserialize(base64_decode($TorrentData)), true);
|
$Tor = new TORRENT(unserialize(base64_decode($TorrentData)), true);
|
||||||
$Tor->set_announce_url($AnnounceURL);
|
$Tor->set_announce_url($AnnounceURL);
|
||||||
|
@ -87,9 +87,15 @@
|
|||||||
case 'Artists':
|
case 'Artists':
|
||||||
$FileName = 'class_artists';
|
$FileName = 'class_artists';
|
||||||
break;
|
break;
|
||||||
case 'BEncTorrent':
|
case 'Bencode':
|
||||||
$FileName = 'class_bencode';
|
$FileName = 'class_bencode';
|
||||||
break;
|
break;
|
||||||
|
case 'BencodeDecode':
|
||||||
|
$FileName = 'class_bencodedecode';
|
||||||
|
break;
|
||||||
|
case 'BencodeTorrent':
|
||||||
|
$FileName = 'class_bencodetorrent';
|
||||||
|
break;
|
||||||
case 'Format':
|
case 'Format':
|
||||||
$FileName = 'class_format';
|
$FileName = 'class_format';
|
||||||
break;
|
break;
|
||||||
@ -120,11 +126,15 @@
|
|||||||
case 'Rippy':
|
case 'Rippy':
|
||||||
$FileName = 'rippy.class';
|
$FileName = 'rippy.class';
|
||||||
break;
|
break;
|
||||||
case 'SphinxQL':
|
case 'Sphinxql':
|
||||||
case 'SphinxQL_Query':
|
|
||||||
case 'SphinxQL_Result':
|
|
||||||
$FileName = 'class_sphinxql';
|
$FileName = 'class_sphinxql';
|
||||||
break;
|
break;
|
||||||
|
case 'SphinxqlQuery':
|
||||||
|
$FileName = 'class_sphinxqlquery';
|
||||||
|
break;
|
||||||
|
case 'SphinxqlResult':
|
||||||
|
$FileName = 'class_sphinxqlresult';
|
||||||
|
break;
|
||||||
case 'Tags':
|
case 'Tags':
|
||||||
$FileName = 'class_tags';
|
$FileName = 'class_tags';
|
||||||
break;
|
break;
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
$_GET['type'] = display_str($_GET['type']);
|
$_GET['type'] = display_str($_GET['type']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$SphQL = new SphinxQL_Query();
|
$SphQL = new SphinxqlQuery();
|
||||||
$SphQL->select('id, groupid')
|
$SphQL->select('id, groupid')
|
||||||
->from('better_transcode')
|
->from('better_transcode')
|
||||||
->where('logscore', 100)
|
->where('logscore', 100)
|
||||||
|
@ -119,8 +119,8 @@ function header_link($SortKey,$DefaultWay="desc") {
|
|||||||
/** End preparation of property arrays **/
|
/** End preparation of property arrays **/
|
||||||
|
|
||||||
/** Start query preparation **/
|
/** Start query preparation **/
|
||||||
$SphQL = new SphinxQL_Query();
|
$SphQL = new SphinxqlQuery();
|
||||||
$SphQLTor = new SphinxQL_Query();
|
$SphQLTor = new SphinxqlQuery();
|
||||||
|
|
||||||
if ($OrderBy == 'random') {
|
if ($OrderBy == 'random') {
|
||||||
$SphQL->select('id, groupid, categoryid')
|
$SphQL->select('id, groupid, categoryid')
|
||||||
@ -149,7 +149,7 @@ function header_link($SortKey,$DefaultWay="desc") {
|
|||||||
if (!empty($_GET['filelist'])) {
|
if (!empty($_GET['filelist'])) {
|
||||||
$SearchString = trim($_GET['filelist']);
|
$SearchString = trim($_GET['filelist']);
|
||||||
if ($SearchString != '') {
|
if ($SearchString != '') {
|
||||||
$SearchString = '"'.SphinxQL::escape_string($_GET['filelist']).'"~20';
|
$SearchString = '"'.Sphinxql::escape_string($_GET['filelist']).'"~20';
|
||||||
$SphQL->where_match($SearchString, 'filelist', false);
|
$SphQL->where_match($SearchString, 'filelist', false);
|
||||||
$SphQLTor->where_match($SearchString, 'filelist', false);
|
$SphQLTor->where_match($SearchString, 'filelist', false);
|
||||||
$EnableNegation = true;
|
$EnableNegation = true;
|
||||||
@ -229,11 +229,11 @@ function header_link($SortKey,$DefaultWay="desc") {
|
|||||||
}
|
}
|
||||||
$QueryParts = array();
|
$QueryParts = array();
|
||||||
foreach ($BasicSearch['include'] as $Word) {
|
foreach ($BasicSearch['include'] as $Word) {
|
||||||
$QueryParts[] = SphinxQL::escape_string($Word);
|
$QueryParts[] = Sphinxql::escape_string($Word);
|
||||||
}
|
}
|
||||||
if (!empty($BasicSearch['exclude'])) {
|
if (!empty($BasicSearch['exclude'])) {
|
||||||
foreach ($BasicSearch['exclude'] as $Word) {
|
foreach ($BasicSearch['exclude'] as $Word) {
|
||||||
$QueryParts[] = '!'.SphinxQL::escape_string(substr($Word,1));
|
$QueryParts[] = '!'.Sphinxql::escape_string(substr($Word,1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!empty($FilterBitrates)) {
|
if (!empty($FilterBitrates)) {
|
||||||
@ -265,11 +265,11 @@ function header_link($SortKey,$DefaultWay="desc") {
|
|||||||
unset($Tags['exclude']);
|
unset($Tags['exclude']);
|
||||||
}
|
}
|
||||||
foreach ($Tags['include'] as &$Tag) {
|
foreach ($Tags['include'] as &$Tag) {
|
||||||
$Tag = SphinxQL::escape_string($Tag);
|
$Tag = Sphinxql::escape_string($Tag);
|
||||||
}
|
}
|
||||||
if (!empty($Tags['exclude'])) {
|
if (!empty($Tags['exclude'])) {
|
||||||
foreach ($Tags['exclude'] as &$Tag) {
|
foreach ($Tags['exclude'] as &$Tag) {
|
||||||
$Tag = '!'.SphinxQL::escape_string(substr($Tag,1));
|
$Tag = '!'.Sphinxql::escape_string(substr($Tag,1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -309,11 +309,11 @@ function header_link($SortKey,$DefaultWay="desc") {
|
|||||||
unset($Words['exclude']);
|
unset($Words['exclude']);
|
||||||
}
|
}
|
||||||
foreach ($Words['include'] as $Word) {
|
foreach ($Words['include'] as $Word) {
|
||||||
$QueryParts[] = SphinxQL::escape_string($Word);
|
$QueryParts[] = Sphinxql::escape_string($Word);
|
||||||
}
|
}
|
||||||
if (!empty($Words['exclude'])) {
|
if (!empty($Words['exclude'])) {
|
||||||
foreach ($Words['exclude'] as $Word) {
|
foreach ($Words['exclude'] as $Word) {
|
||||||
$QueryParts[] = '!'.SphinxQL::escape_string(substr($Word,1));
|
$QueryParts[] = '!'.Sphinxql::escape_string(substr($Word,1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!empty($QueryParts)) {
|
if (!empty($QueryParts)) {
|
||||||
@ -614,26 +614,6 @@ function header_link($SortKey,$DefaultWay="desc") {
|
|||||||
|| $FirstUnknown
|
|| $FirstUnknown
|
||||||
|| $Data['Media'] != $LastMedia) {
|
|| $Data['Media'] != $LastMedia) {
|
||||||
$EditionID++;
|
$EditionID++;
|
||||||
|
|
||||||
if ($Data['Remastered'] && $Data['RemasterYear'] != 0) {
|
|
||||||
|
|
||||||
$RemasterName = $Data['RemasterYear'];
|
|
||||||
$AddExtra = " - ";
|
|
||||||
if ($Data['RemasterRecordLabel']) { $RemasterName .= $AddExtra.display_str($Data['RemasterRecordLabel']); $AddExtra=' / '; }
|
|
||||||
if ($Data['RemasterCatalogueNumber']) { $RemasterName .= $AddExtra.display_str($Data['RemasterCatalogueNumber']); $AddExtra=' / '; }
|
|
||||||
if ($Data['RemasterTitle']) { $RemasterName .= $AddExtra.display_str($Data['RemasterTitle']); $AddExtra=' / '; }
|
|
||||||
$RemasterName .= $AddExtra.display_str($Data['Media']);
|
|
||||||
} else {
|
|
||||||
$AddExtra = " / ";
|
|
||||||
if (!$Data['Remastered']) {
|
|
||||||
$MasterName = "Original Release";
|
|
||||||
if ($GroupRecordLabel) { $MasterName .= $AddExtra.$GroupRecordLabel; $AddExtra=' / '; }
|
|
||||||
if ($GroupCatalogueNumber) { $MasterName .= $AddExtra.$GroupCatalogueNumber; $AddExtra=' / '; }
|
|
||||||
} else {
|
|
||||||
$MasterName = "Unknown Release(s)";
|
|
||||||
}
|
|
||||||
$MasterName .= $AddExtra.display_str($Data['Media']);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
$LastRemasterTitle = $Data['RemasterTitle'];
|
$LastRemasterTitle = $Data['RemasterTitle'];
|
||||||
$LastRemasterYear = $Data['RemasterYear'];
|
$LastRemasterYear = $Data['RemasterYear'];
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
}
|
}
|
||||||
list($Contents) = $DB->next_record(MYSQLI_NUM, array(0));
|
list($Contents) = $DB->next_record(MYSQLI_NUM, array(0));
|
||||||
if (Misc::is_new_torrent($Contents)) {
|
if (Misc::is_new_torrent($Contents)) {
|
||||||
$Tor = new BEncTorrent($Contents);
|
$Tor = new BencodeTorrent($Contents);
|
||||||
$Private = $Tor->is_private();
|
$Private = $Tor->is_private();
|
||||||
} else {
|
} else {
|
||||||
$Tor = new TORRENT(unserialize(base64_decode($Contents)), true); // New TORRENT object
|
$Tor = new TORRENT(unserialize(base64_decode($Contents)), true); // New TORRENT object
|
||||||
|
@ -409,35 +409,11 @@ function compare($X, $Y){
|
|||||||
|
|
||||||
$EditionID++;
|
$EditionID++;
|
||||||
|
|
||||||
if($Torrent['Remastered'] && $Torrent['RemasterYear'] != 0) {
|
|
||||||
$RemasterName = $Torrent['RemasterYear'];
|
|
||||||
$AddExtra = " - ";
|
|
||||||
if($Torrent['RemasterRecordLabel']) { $RemasterName .= $AddExtra.display_str($Torrent['RemasterRecordLabel']); $AddExtra=' / '; }
|
|
||||||
if($Torrent['RemasterCatalogueNumber']) { $RemasterName .= $AddExtra.display_str($Torrent['RemasterCatalogueNumber']); $AddExtra=' / '; }
|
|
||||||
if($Torrent['RemasterTitle']) { $RemasterName .= $AddExtra.display_str($Torrent['RemasterTitle']); $AddExtra=' / '; }
|
|
||||||
$RemasterName .= $AddExtra.display_str($Torrent['Media']);
|
|
||||||
|
|
||||||
?>
|
?>
|
||||||
<tr class="releases_<?=$ReleaseType?> groupid_<?=$GroupID?> edition group_torrent discog<?=$SnatchedGroupClass . $HideDiscog . $HideTorrents?>">
|
<tr class="releases_<?=$ReleaseType?> groupid_<?=$GroupID?> edition group_torrent discog<?=$SnatchedGroupClass . $HideDiscog . $HideTorrents?>">
|
||||||
<td colspan="6" class="edition_info"><strong><a href="#" onclick="toggle_edition(<?=$GroupID?>, <?=$EditionID?>, this, event)" title="Collapse this edition. Hold "Ctrl" while clicking to collapse all editions in this torrent group.">−</a> <?=$RemasterName?></strong></td>
|
<td colspan="6" class="edition_info"><strong><a href="#" onclick="toggle_edition(<?=$GroupID?>, <?=$EditionID?>, this, event)" title="Collapse this edition. Hold "Ctrl" while clicking to collapse all editions in this torrent group.">−</a> <?=Torrents::edition_string($Torrent, $TorrentList[$Group['GroupID']])?></strong></td>
|
||||||
</tr>
|
</tr>
|
||||||
<?
|
<?
|
||||||
} else {
|
|
||||||
$AddExtra = " / ";
|
|
||||||
if (!$Torrent['Remastered']) {
|
|
||||||
$MasterName = "Original Release";
|
|
||||||
if($GroupRecordLabel) { $MasterName .= $AddExtra.$GroupRecordLabel; $AddExtra=' / '; }
|
|
||||||
if($GroupCatalogueNumber) { $MasterName .= $AddExtra.$GroupCatalogueNumber; $AddExtra=' / '; }
|
|
||||||
} else {
|
|
||||||
$MasterName = "Unknown Release(s)";
|
|
||||||
}
|
|
||||||
$MasterName .= $AddExtra.display_str($Torrent['Media']);
|
|
||||||
?>
|
|
||||||
<tr class="releases_<?=$ReleaseType?> groupid_<?=$GroupID?> edition group_torrent discog<?=$SnatchedGroupClass . $HideDiscog . $HideTorrents?>">
|
|
||||||
<td colspan="6" class="edition_info"><strong><a href="#" onclick="toggle_edition(<?=$GroupID?>, <?=$EditionID?>, this, event)" title="Collapse this edition. Hold "Ctrl" while clicking to collapse all editions in this torrent group.">−</a> <?=$MasterName?></strong></td>
|
|
||||||
</tr>
|
|
||||||
<?
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
$LastRemasterTitle = $Torrent['RemasterTitle'];
|
$LastRemasterTitle = $Torrent['RemasterTitle'];
|
||||||
$LastRemasterYear = $Torrent['RemasterYear'];
|
$LastRemasterYear = $Torrent['RemasterYear'];
|
||||||
|
@ -1,673 +0,0 @@
|
|||||||
<?
|
|
||||||
//~~~~~~~~~~~ Main artist page ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
|
|
||||||
|
|
||||||
//For sorting tags
|
|
||||||
function compare($X, $Y){
|
|
||||||
return($Y['count'] - $X['count']);
|
|
||||||
}
|
|
||||||
|
|
||||||
include(SERVER_ROOT.'/sections/bookmarks/functions.php'); // has_bookmarked()
|
|
||||||
include(SERVER_ROOT.'/sections/requests/functions.php');
|
|
||||||
include(SERVER_ROOT.'/classes/class_text.php'); // Text formatting class
|
|
||||||
$Text = new TEXT;
|
|
||||||
|
|
||||||
|
|
||||||
// Similar artist map
|
|
||||||
include(SERVER_ROOT.'/classes/class_artists_similar.php');
|
|
||||||
|
|
||||||
$ArtistID = $_GET['id'];
|
|
||||||
if(!is_number($ArtistID)) { error(0); }
|
|
||||||
|
|
||||||
|
|
||||||
if(!empty($_GET['revisionid'])) { // if they're viewing an old revision
|
|
||||||
$RevisionID=$_GET['revisionid'];
|
|
||||||
if(!is_number($RevisionID)){ error(0); }
|
|
||||||
$Data = $Cache->get_value("artist_$ArtistID"."_revision_$RevisionID");
|
|
||||||
} else { // viewing the live version
|
|
||||||
$Data = $Cache->get_value('artist_'.$ArtistID);
|
|
||||||
$RevisionID = false;
|
|
||||||
}
|
|
||||||
if($Data) {
|
|
||||||
$Data = unserialize($Data);
|
|
||||||
list($K, list($Name, $Image, $Body, $NumSimilar, $SimilarArray, $TorrentList, $GroupMeta)) = each($Data);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
$sql = "SELECT
|
|
||||||
a.Name,
|
|
||||||
wiki.Image,
|
|
||||||
wiki.body,
|
|
||||||
a.VanityHouse
|
|
||||||
FROM artists_group AS a
|
|
||||||
LEFT JOIN wiki_artists AS wiki ON wiki.RevisionID=a.RevisionID
|
|
||||||
WHERE ";
|
|
||||||
if($RevisionID){
|
|
||||||
$sql.=" wiki.RevisionID='$RevisionID' ";
|
|
||||||
} else {
|
|
||||||
$sql.=" a.ArtistID='$ArtistID' ";
|
|
||||||
}
|
|
||||||
$sql .= " GROUP BY a.ArtistID";
|
|
||||||
$DB->query($sql, MYSQLI_NUM, true);
|
|
||||||
|
|
||||||
if($DB->record_count()==0) { error(404); }
|
|
||||||
|
|
||||||
list($Name, $Image, $Body, $VanityHouseArtist) = $DB->next_record();
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------- Build list and get stats
|
|
||||||
|
|
||||||
ob_start();
|
|
||||||
|
|
||||||
|
|
||||||
// Requests
|
|
||||||
$Requests = $Cache->get_value('artists_requests_'.$ArtistID);
|
|
||||||
if(!is_array($Requests)) {
|
|
||||||
$DB->query("SELECT
|
|
||||||
r.ID,
|
|
||||||
r.CategoryID,
|
|
||||||
r.Title,
|
|
||||||
r.Year,
|
|
||||||
r.TimeAdded,
|
|
||||||
COUNT(rv.UserID) AS Votes,
|
|
||||||
SUM(rv.Bounty) AS Bounty
|
|
||||||
FROM requests AS r
|
|
||||||
LEFT JOIN requests_votes AS rv ON rv.RequestID=r.ID
|
|
||||||
LEFT JOIN requests_artists AS ra ON r.ID=ra.RequestID
|
|
||||||
WHERE ra.ArtistID = ".$ArtistID."
|
|
||||||
AND r.TorrentID = 0
|
|
||||||
GROUP BY r.ID
|
|
||||||
ORDER BY Votes DESC");
|
|
||||||
|
|
||||||
if($DB->record_count() > 0) {
|
|
||||||
$Requests = $DB->to_array();
|
|
||||||
} else {
|
|
||||||
$Requests = array();
|
|
||||||
}
|
|
||||||
$Cache->cache_value('artists_requests_'.$ArtistID, $Requests);
|
|
||||||
}
|
|
||||||
$NumRequests = count($Requests);
|
|
||||||
|
|
||||||
$LastReleaseType = 0;
|
|
||||||
if(empty($GroupMeta) || empty($TorrentList)) {
|
|
||||||
$DB->query("SELECT
|
|
||||||
DISTINCT ta.GroupID, ta.Importance, tg.VanityHouse
|
|
||||||
FROM torrents_artists AS ta
|
|
||||||
JOIN torrents_group AS tg ON tg.ID=ta.GroupID
|
|
||||||
WHERE ta.ArtistID='$ArtistID'
|
|
||||||
ORDER BY ta.Importance, tg.ReleaseType ASC, tg.Year DESC");
|
|
||||||
|
|
||||||
$GroupIDs = $DB->collect('GroupID');
|
|
||||||
$GroupMeta = $DB->to_array('GroupID', MYSQLI_BOTH, false);
|
|
||||||
if(count($GroupIDs)>0) {
|
|
||||||
$TorrentList = Torrents::get_groups($GroupIDs, true, true);
|
|
||||||
$TorrentList = $TorrentList['matches'];
|
|
||||||
} else {
|
|
||||||
$TorrentList = array();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$NumGroups = count($TorrentList);
|
|
||||||
|
|
||||||
if(!empty($TorrentList)) {
|
|
||||||
?>
|
|
||||||
<div id="discog_table">
|
|
||||||
<?
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get list of used release types
|
|
||||||
$UsedReleases = array();
|
|
||||||
$TorrentListByReleaseType = array();
|
|
||||||
// Check if user has preferences for ordering/showing
|
|
||||||
if (isset($LoggedUser['ArtistOptions']) && is_array($LoggedUser['ArtistOptions'])) {
|
|
||||||
$ReleaseTypesOrder = $LoggedUser['ArtistOptions'];
|
|
||||||
$HasShown = in_array(1, $ReleaseTypesOrder);
|
|
||||||
// Add releasetypes from default order, useful when new types are added
|
|
||||||
foreach($ReleaseTypesDefaultOrder as $Key => $ReleaseType) {
|
|
||||||
if(!array_key_exists($ReleaseType, $ReleaseTypesOrder)) {
|
|
||||||
$ReleaseTypesOrder[$ReleaseType] = $HasShown ? 1 : 0; // If no releasetype is open by default assume (s)he wants them all closed
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Load defaults
|
|
||||||
$ReleaseTypesOrder = array_flip($ReleaseTypesDefaultOrder);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach($ReleaseTypesOrder as $ReleaseType => $ReleaseTypeName) {
|
|
||||||
$TorrentListByReleaseType[$ReleaseType] = array();
|
|
||||||
}
|
|
||||||
|
|
||||||
//Names for releasetypes that are not uploadable but exist in the defaultordering
|
|
||||||
$ReleaseTypes[1023] = "Remixed By";
|
|
||||||
$ReleaseTypes[1024] = "Guest Appearance";
|
|
||||||
|
|
||||||
foreach($TorrentList as $GroupID=>$Group) {
|
|
||||||
if($GroupMeta[$GroupID]['Importance'] == '2') {
|
|
||||||
$TorrentList[$GroupID]['ReleaseType'] = 1024;
|
|
||||||
}
|
|
||||||
if($GroupMeta[$GroupID]['Importance'] == '3') {
|
|
||||||
$TorrentList[$GroupID]['ReleaseType'] = 1023;
|
|
||||||
}
|
|
||||||
if(!in_array($TorrentList[$GroupID]['ReleaseType'], $UsedReleases)) {
|
|
||||||
$UsedReleases[] = $TorrentList[$GroupID]['ReleaseType'];
|
|
||||||
}
|
|
||||||
$TorrentListByReleaseType[$TorrentList[$GroupID]['ReleaseType']][$GroupID] = $Group;
|
|
||||||
}
|
|
||||||
|
|
||||||
reset($TorrentList);
|
|
||||||
if(!empty($UsedReleases)) { ?>
|
|
||||||
<div id="releasetypes" class="box center">
|
|
||||||
<span id="releasetype_links">
|
|
||||||
<?
|
|
||||||
foreach($ReleaseTypesOrder as $ReleaseID => $Torrents) {
|
|
||||||
if(!in_array($ReleaseID, $UsedReleases)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
switch($ReleaseTypes[$ReleaseID]) {
|
|
||||||
case "Remix" :
|
|
||||||
$DisplayName = "Remixes";
|
|
||||||
break;
|
|
||||||
case "Anthology" :
|
|
||||||
$DisplayName = "Anthologies";
|
|
||||||
break;
|
|
||||||
default :
|
|
||||||
$DisplayName = $ReleaseTypes[$ReleaseID]."s";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
?>
|
|
||||||
<a href="#torrents_<?=str_replace(" ", "_", strtolower($ReleaseTypes[$ReleaseID]))?>" id="torrents_<?=$ReleaseID?>_anchorlink" class="brackets"><?=$DisplayName?></a>
|
|
||||||
<?
|
|
||||||
}
|
|
||||||
if ($NumRequests > 0) {
|
|
||||||
?>
|
|
||||||
<a href="#requests" id="requests_anchorlink" class="brackets">Requests</a>
|
|
||||||
</span>
|
|
||||||
<span style="position:right" id="torrents_allopenclose" class="hidden">
|
|
||||||
<a href="#" class="brackets" onclick="setDefaultShow('all', true);return false;">All default open</a>
|
|
||||||
<a href="#" class="brackets" onclick="setDefaultShow('all', false);return false;">All default closed</a>
|
|
||||||
</span>
|
|
||||||
<? } ?>
|
|
||||||
</div>
|
|
||||||
<? }
|
|
||||||
|
|
||||||
$NumTorrents = 0;
|
|
||||||
$NumSeeders = 0;
|
|
||||||
$NumLeechers = 0;
|
|
||||||
$NumSnatches = 0;
|
|
||||||
|
|
||||||
function display_name($ReleaseType) {
|
|
||||||
global $ReleaseTypes;
|
|
||||||
return $DisplayName;
|
|
||||||
}
|
|
||||||
?>
|
|
||||||
<div id="torrents_tables">
|
|
||||||
<?
|
|
||||||
$OpenTable = false;
|
|
||||||
foreach ($TorrentListByReleaseType as $ReleaseType => $TorrentListForReleaseType) {
|
|
||||||
$NumTorrentsReleaseType = count($TorrentListForReleaseType);
|
|
||||||
if($OpenTable) {
|
|
||||||
?></table><?
|
|
||||||
$OpenTable = false;
|
|
||||||
}
|
|
||||||
switch($ReleaseTypes[$ReleaseType]) {
|
|
||||||
case "Remix" :
|
|
||||||
$DisplayName = "Remixes";
|
|
||||||
break;
|
|
||||||
case "Anthology" :
|
|
||||||
$DisplayName = "Anthologies";
|
|
||||||
break;
|
|
||||||
default :
|
|
||||||
$DisplayName = $ReleaseTypes[$ReleaseType]."s";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
$ReleaseTypeLabel = strtolower(str_replace(' ','_',$ReleaseTypes[$ReleaseType]));
|
|
||||||
|
|
||||||
if ((isset($LoggedUser['ArtistOptions']) && array_key_exists($ReleaseType, $LoggedUser['ArtistOptions'])) && $LoggedUser['ArtistOptions'][$ReleaseType] == 0) {
|
|
||||||
$HideDiscog = " hidden";
|
|
||||||
$HideDiscogDefault = true;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$HideDiscog = "";
|
|
||||||
$HideDiscogDefault = false;
|
|
||||||
}
|
|
||||||
?>
|
|
||||||
<table class="torrent_table grouped release_table releases_<?=$ReleaseType?>_table<?=$NumTorrentsReleaseType==0?" empty hidden":""?>" id="torrents_<?=$ReleaseTypeLabel?>">
|
|
||||||
<tr class="colhead_dark">
|
|
||||||
<td class="small" style="width: 28px;"></td>
|
|
||||||
<td width="70%">
|
|
||||||
<span class="artist_normalcol">
|
|
||||||
<? if($NumTorrentsReleaseType > 0) { ?>
|
|
||||||
<a href="#">↑</a>
|
|
||||||
<? } ?>
|
|
||||||
</span>
|
|
||||||
<strong><?=$DisplayName?></strong>
|
|
||||||
<span class="artist_normalcol">
|
|
||||||
<? if($NumTorrentsReleaseType > 0) { ?>
|
|
||||||
(<a href="#"<?=!$HideDiscogDefault?'class="hidden"':''?> id="releases_<?=$ReleaseType?>_viewlink" onclick="setShow('<?=$ReleaseType?>',true);return false;">View</a><a href="#"<?=$HideDiscogDefault?'class="hidden"':''?> id="releases_<?=$ReleaseType?>_hidelink" onclick="setShow('<?=$ReleaseType?>',false);return false;">Hide</a>)
|
|
||||||
<? } ?>
|
|
||||||
</span>
|
|
||||||
</td>
|
|
||||||
<td class="artist_normalcol">Size</td>
|
|
||||||
<td class="artist_normalcol sign"><img src="static/styles/<?=$LoggedUser['StyleName'] ?>/images/snatched.png" alt="Snatches" title="Snatches" /></td>
|
|
||||||
<td class="artist_normalcol sign"><img src="static/styles/<?=$LoggedUser['StyleName'] ?>/images/seeders.png" alt="Seeders" title="Seeders" /></td>
|
|
||||||
<td class="artist_normalcol sign"><img src="static/styles/<?=$LoggedUser['StyleName'] ?>/images/leechers.png" alt="Leechers" title="Leechers" /></td>
|
|
||||||
<td class="artist_editcol hidden" align="right">
|
|
||||||
<a href="#"<?=!$HideDiscogDefault?' class="hidden"':''?> id="releases_<?=$ReleaseType?>_openlink" onclick="setDefaultShow('<?=$ReleaseType?>',true);return false;" class="brackets">default closed</a>
|
|
||||||
<a href="#"<?=$HideDiscogDefault?' class="hidden"':''?> id="releases_<?=$ReleaseType?>_closedlink" onclick="setDefaultShow('<?=$ReleaseType?>',false);return false;" class="brackets">default open</a>
|
|
||||||
<input class="hidden" id="releases_<?=$ReleaseType?>_defaultopen"<?=!$HideDiscogDefault?' checked="checked"':''?> type="checkbox" title="Show" />
|
|
||||||
|
|
||||||
<span style="cursor:move;" id="torrents_<?=$ReleaseTypeLabel?>_handle">☰</span>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<?
|
|
||||||
$OpenTable = true;
|
|
||||||
|
|
||||||
foreach($TorrentListForReleaseType as $GroupID => $Group) {
|
|
||||||
extract(Torrents::array_group($Group));
|
|
||||||
$GroupVanityHouse = $GroupMeta[$GroupID]['VanityHouse'];
|
|
||||||
|
|
||||||
$TorrentTags = new Tags($TagList);
|
|
||||||
|
|
||||||
if (($ReleaseType == 1023) || ($ReleaseType == 1024)) {
|
|
||||||
$ArtistPrefix = Artists::display_artists(array(1 => $Artists));
|
|
||||||
} else {
|
|
||||||
$ArtistPrefix = '';
|
|
||||||
}
|
|
||||||
|
|
||||||
$DisplayName = $ArtistPrefix . '<a href="torrents.php?id='.$GroupID.'" title="View Torrent">'.$GroupName.'</a>';
|
|
||||||
if($GroupYear>0) { $DisplayName = $GroupYear. ' - '.$DisplayName; }
|
|
||||||
|
|
||||||
if($GroupVanityHouse) { $DisplayName .= ' [<abbr title="This is a vanity house release">VH</abbr>]'; }
|
|
||||||
|
|
||||||
?>
|
|
||||||
<tr class="releases_<?=$ReleaseType?> group discog<?=$HideDiscog?>">
|
|
||||||
<td class="center">
|
|
||||||
<div class="show_torrents"><a href="#" class="show_torrents_link" onclick="toggle_group(<?=$GroupID?>, this, event)" title="Collapse this group"></a></div>
|
|
||||||
</td>
|
|
||||||
<td class="artist_normalcol" colspan="6">
|
|
||||||
<strong><?=$DisplayName?></strong>
|
|
||||||
<div class="tags"><?=$TorrentTags->format()?></div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<?
|
|
||||||
$LastRemasterYear = '-';
|
|
||||||
$LastRemasterTitle = '';
|
|
||||||
$LastRemasterRecordLabel = '';
|
|
||||||
$LastRemasterCatalogueNumber = '';
|
|
||||||
$LastMedia = '';
|
|
||||||
|
|
||||||
$EditionID = 0;
|
|
||||||
|
|
||||||
foreach ($Torrents as $TorrentID => $Torrent) {
|
|
||||||
$NumTorrents++;
|
|
||||||
|
|
||||||
$Torrent['Seeders'] = (int)$Torrent['Seeders'];
|
|
||||||
$Torrent['Leechers'] = (int)$Torrent['Leechers'];
|
|
||||||
$Torrent['Snatched'] = (int)$Torrent['Snatched'];
|
|
||||||
|
|
||||||
$NumSeeders+=$Torrent['Seeders'];
|
|
||||||
$NumLeechers+=$Torrent['Leechers'];
|
|
||||||
$NumSnatches+=$Torrent['Snatched'];
|
|
||||||
|
|
||||||
if($Torrent['RemasterTitle'] != $LastRemasterTitle || $Torrent['RemasterYear'] != $LastRemasterYear ||
|
|
||||||
$Torrent['RemasterRecordLabel'] != $LastRemasterRecordLabel || $Torrent['RemasterCatalogueNumber'] != $LastRemasterCatalogueNumber || $Torrent['Media'] != $LastMedia) {
|
|
||||||
|
|
||||||
$EditionID++;
|
|
||||||
|
|
||||||
if($Torrent['RemasterTitle'] || $Torrent['RemasterYear'] || $Torrent['RemasterRecordLabel'] || $Torrent['RemasterCatalogueNumber']) {
|
|
||||||
$RemasterName = $Torrent['RemasterYear'];
|
|
||||||
$AddExtra = " - ";
|
|
||||||
if($Torrent['RemasterRecordLabel']) { $RemasterName .= $AddExtra.display_str($Torrent['RemasterRecordLabel']); $AddExtra=' / '; }
|
|
||||||
if($Torrent['RemasterCatalogueNumber']) { $RemasterName .= $AddExtra.display_str($Torrent['RemasterCatalogueNumber']); $AddExtra=' / '; }
|
|
||||||
if($Torrent['RemasterTitle']) { $RemasterName .= $AddExtra.display_str($Torrent['RemasterTitle']); $AddExtra=' / '; }
|
|
||||||
$RemasterName .= $AddExtra.display_str($Torrent['Media']);
|
|
||||||
|
|
||||||
?>
|
|
||||||
<tr class="releases_<?=$ReleaseType?> groupid_<?=$GroupID?> edition group_torrent discog <?=$HideDiscog?>">
|
|
||||||
<td colspan="7" class="artist_normalcol edition_info"><strong><a href="#" onclick="toggle_edition(<?=$GroupID?>, <?=$EditionID?>, this, event)" title="Collapse this edition. Hold "Ctrl" while clicking to collapse all editions in this torrent group.">−</a> <?=$RemasterName?></strong></a></td>
|
|
||||||
</tr>
|
|
||||||
<?
|
|
||||||
} else {
|
|
||||||
$MasterName = "Original Release";
|
|
||||||
$AddExtra = " / ";
|
|
||||||
if($GroupRecordLabel) { $MasterName .= $AddExtra.$GroupRecordLabel; $AddExtra=' / '; }
|
|
||||||
if($GroupCatalogueNumber) { $MasterName .= $AddExtra.$GroupCatalogueNumber; $AddExtra=' / '; }
|
|
||||||
$MasterName .= $AddExtra.display_str($Torrent['Media']);
|
|
||||||
?>
|
|
||||||
<tr class="releases_<?=$ReleaseType?> groupid_<?=$GroupID?> edition group_torrent <?=$HideDiscog?>">
|
|
||||||
<td colspan="7" class="artist_normalcol edition_info"><strong><a href="#" onclick="toggle_edition(<?=$GroupID?>, <?=$EditionID?>, this, event)" title="Collapse this edition. Hold "Ctrl" while clicking to collapse all editions in this torrent group.">−</a> <?=$MasterName?></strong></a></td>
|
|
||||||
</tr>
|
|
||||||
<?
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$LastRemasterTitle = $Torrent['RemasterTitle'];
|
|
||||||
$LastRemasterYear = $Torrent['RemasterYear'];
|
|
||||||
$LastRemasterRecordLabel = $Torrent['RemasterRecordLabel'];
|
|
||||||
$LastRemasterCatalogueNumber = $Torrent['RemasterCatalogueNumber'];
|
|
||||||
$LastMedia = $Torrent['Media'];
|
|
||||||
?>
|
|
||||||
<tr class="releases_<?=$ReleaseType?> groupid_<?=$GroupID?> edition_<?=$EditionID?> group_torrent discog <?=$HideDiscog?>">
|
|
||||||
<td class="artist_normalcol" colspan="2">
|
|
||||||
<span>
|
|
||||||
<a href="torrents.php?action=download&id=<?=$TorrentID?>&authkey=<?=$LoggedUser['AuthKey']?>&torrent_pass=<?=$LoggedUser['torrent_pass']?>" title="Download" class="brackets">DL</a>
|
|
||||||
</span>
|
|
||||||
» <a href="torrents.php?id=<?=$GroupID?>&torrentid=<?=$TorrentID?>"><?=Torrents::torrent_info($Torrent)?></a>
|
|
||||||
</td>
|
|
||||||
<td class="artist_normalcol nobr"><?=Format::get_size($Torrent['Size'])?></td>
|
|
||||||
<td class="artist_normalcol"><?=number_format($Torrent['Snatched'])?></td>
|
|
||||||
<td class="artist_normalcol<?=($Torrent['Seeders']==0)?' r00':''?>"><?=number_format($Torrent['Seeders'])?></td>
|
|
||||||
<td class="artist_normalcol"><?=number_format($Torrent['Leechers'])?></td>
|
|
||||||
<td class="artist_editcol hidden"></td>
|
|
||||||
</tr>
|
|
||||||
<?
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(!empty($TorrentList)) { ?>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
<?}
|
|
||||||
?>
|
|
||||||
</div>
|
|
||||||
<?
|
|
||||||
|
|
||||||
$TorrentDisplayList = ob_get_clean();
|
|
||||||
|
|
||||||
//----------------- End building list and getting stats
|
|
||||||
|
|
||||||
View::show_header($Name, 'browse,requests,artists,bbcode');
|
|
||||||
?>
|
|
||||||
<div class="thin">
|
|
||||||
<div class="header">
|
|
||||||
<h2><?=$Name?><? if ($RevisionID) { ?> (Revision #<?=$RevisionID?>)<? } if ($VanityHouseArtist) { ?> [Vanity House] <? } ?></h2>
|
|
||||||
<span style="font-size: 0.7em;float:right;">
|
|
||||||
<a href="#" onclick="editOrdering();return false;" class="brackets" id="editlayout">Edit ordering</a>
|
|
||||||
<span class="hidden" id="savinglayout">Saving ordering...</span>
|
|
||||||
<a href="#" onclick="saveOrdering();return false;" class="brackets hidden" id="savelayout">Save ordering</a>
|
|
||||||
</span>
|
|
||||||
</h2>
|
|
||||||
<div id="emptylinkbox" class="linkbox hidden"></div>
|
|
||||||
<div id="linkbox" class="linkbox">
|
|
||||||
<? if (check_perms('site_submit_requests')) { ?>
|
|
||||||
<a href="requests.php?action=new&artistid=<?=$ArtistID?>" class="brackets">Add request</a>
|
|
||||||
<? }
|
|
||||||
|
|
||||||
if (check_perms('site_torrents_notify')) {
|
|
||||||
if (($Notify = $Cache->get_value('notify_artists_'.$LoggedUser['ID'])) === FALSE) {
|
|
||||||
$DB->query("SELECT ID, Artists FROM users_notify_filters WHERE UserID='$LoggedUser[ID]' AND Label='Artist notifications' LIMIT 1");
|
|
||||||
$Notify = $DB->next_record(MYSQLI_ASSOC);
|
|
||||||
$Cache->cache_value('notify_artists_'.$LoggedUser['ID'], $Notify, 0);
|
|
||||||
}
|
|
||||||
if (stripos($Notify['Artists'], '|'.$Name.'|') === FALSE) {
|
|
||||||
?>
|
|
||||||
<a href="artist.php?action=notify&artistid=<?=$ArtistID?>&auth=<?=$LoggedUser['AuthKey']?>" class="brackets">Notify of new uploads</a>
|
|
||||||
<?
|
|
||||||
} else {
|
|
||||||
?>
|
|
||||||
<a href="artist.php?action=notifyremove&artistid=<?=$ArtistID?>&auth=<?=$LoggedUser['AuthKey']?>" class="brackets">Do not notify of new uploads</a>
|
|
||||||
<?
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (has_bookmarked('artist', $ArtistID)) {
|
|
||||||
?>
|
|
||||||
<a href="#" id="bookmarklink_artist_<?=$ArtistID?>" class="brackets" onclick="Unbookmark('artist', <?=$ArtistID?>,'Bookmark');return false;">Remove bookmark</a>
|
|
||||||
|
|
||||||
<?
|
|
||||||
} else {
|
|
||||||
?>
|
|
||||||
<a href="#" id="bookmarklink_artist_<?=$ArtistID?>" class="brackets" onclick="Bookmark('artist', <?=$ArtistID?>,'Remove bookmark');return false;">Bookmark</a>
|
|
||||||
<?
|
|
||||||
}
|
|
||||||
|
|
||||||
if (check_perms('site_edit_wiki')) {
|
|
||||||
?>
|
|
||||||
<a href="artist.php?action=edit&artistid=<?=$ArtistID?>" class="brackets">Edit</a>
|
|
||||||
<? } ?>
|
|
||||||
<a href="artist.php?action=history&artistid=<?=$ArtistID?>" class="brackets">View history</a>
|
|
||||||
<? if (check_perms('site_delete_artist') && check_perms('torrents_delete')) { ?>
|
|
||||||
<a href="artist.php?action=delete&artistid=<?=$ArtistID?>&auth=<?=$LoggedUser['AuthKey']?>" class="brackets">Delete</a>
|
|
||||||
<? }
|
|
||||||
|
|
||||||
if ($RevisionID && check_perms('site_edit_wiki')) {
|
|
||||||
?>
|
|
||||||
<a href="artist.php?action=revert&artistid=<?=$ArtistID?>&revisionid=<?=$RevisionID?>&auth=<?=$LoggedUser['AuthKey']?>" class="brackets">
|
|
||||||
Revert to this revision
|
|
||||||
</a>
|
|
||||||
<? } ?>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="sidebar">
|
|
||||||
<? if($Image) { ?>
|
|
||||||
<div class="box box_image">
|
|
||||||
<div class="head"><strong><?=$Name?></strong></div>
|
|
||||||
<div style="text-align:center;padding:10px 0px;">
|
|
||||||
<img style="max-width: 220px;" src="<?=$Image?>" alt="<?=$Name?>" onclick="lightbox.init(this,220);" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<? }
|
|
||||||
|
|
||||||
?>
|
|
||||||
<div class="box">
|
|
||||||
<div class="head"><strong>Tags</strong></div>
|
|
||||||
<ul class="stats nobullet">
|
|
||||||
<?
|
|
||||||
Tags::format_top(50);
|
|
||||||
?>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
<?
|
|
||||||
|
|
||||||
// Stats
|
|
||||||
?>
|
|
||||||
<div class="box box_info box_statistics_artist">
|
|
||||||
<div class="head"><strong>Statistics</strong></div>
|
|
||||||
<ul class="stats nobullet">
|
|
||||||
<li>Number of groups: <?=number_format($NumGroups)?></li>
|
|
||||||
<li>Number of torrents: <?=number_format($NumTorrents)?></li>
|
|
||||||
<li>Number of seeders: <?=number_format($NumSeeders)?></li>
|
|
||||||
<li>Number of leechers: <?=number_format($NumLeechers)?></li>
|
|
||||||
<li>Number of snatches: <?=number_format($NumSnatches)?></li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
<?
|
|
||||||
|
|
||||||
|
|
||||||
if(empty($SimilarArray)) {
|
|
||||||
$DB->query("
|
|
||||||
SELECT
|
|
||||||
s2.ArtistID,
|
|
||||||
a.Name,
|
|
||||||
ass.Score,
|
|
||||||
ass.SimilarID
|
|
||||||
FROM artists_similar AS s1
|
|
||||||
JOIN artists_similar AS s2 ON s1.SimilarID=s2.SimilarID AND s1.ArtistID!=s2.ArtistID
|
|
||||||
JOIN artists_similar_scores AS ass ON ass.SimilarID=s1.SimilarID
|
|
||||||
JOIN artists_group AS a ON a.ArtistID=s2.ArtistID
|
|
||||||
WHERE s1.ArtistID='$ArtistID'
|
|
||||||
ORDER BY ass.Score DESC
|
|
||||||
LIMIT 30
|
|
||||||
");
|
|
||||||
$SimilarArray = $DB->to_array();
|
|
||||||
$NumSimilar = count($SimilarArray);
|
|
||||||
}
|
|
||||||
?>
|
|
||||||
<div class="box box_artists box_artists_similar">
|
|
||||||
<div class="head"><strong>Similar artists</strong></div>
|
|
||||||
<ul class="stats nobullet">
|
|
||||||
<?
|
|
||||||
if($NumSimilar == 0) { ?>
|
|
||||||
<li><span style="font-style: italic;">None found</span></li>
|
|
||||||
<? }
|
|
||||||
$First = true;
|
|
||||||
foreach ($SimilarArray as $SimilarArtist) {
|
|
||||||
list($Artist2ID, $Artist2Name, $Score, $SimilarID) = $SimilarArtist;
|
|
||||||
$Score = $Score/100;
|
|
||||||
if($First) {
|
|
||||||
$Max = $Score + 1;
|
|
||||||
$First = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$FontSize = (ceil((((($Score - 2)/$Max - 2) * 4)))) + 8;
|
|
||||||
|
|
||||||
?>
|
|
||||||
<li>
|
|
||||||
<span title=<?=$Score?>><a href="artist.php?id=<?=$Artist2ID?>" style="float:left; display:block;"><?=$Artist2Name?></a></span> <div style="float:right; display:block; letter-spacing: -1px;">
|
|
||||||
<a href="artist.php?action=vote_similar&artistid=<?=$ArtistID?>&similarid=<?=$SimilarID?>&way=down" style="font-family: monospace;" class="brackets">−</a>
|
|
||||||
<a href="artist.php?action=vote_similar&artistid=<?=$ArtistID?>&similarid=<?=$SimilarID?>&way=up" style="font-family: monospace;" class="brackets">+</a>
|
|
||||||
<? if(check_perms('site_delete_tag')) { ?>
|
|
||||||
<a href="artist.php?action=delete_similar&similarid=<?=$SimilarID?>&auth=<?=$LoggedUser['AuthKey']?>" class="brackets">X</a>
|
|
||||||
<? } ?>
|
|
||||||
</div>
|
|
||||||
<br style="clear:both" />
|
|
||||||
</li>
|
|
||||||
<? } ?>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
<div class="box box_addartists box_addartists_similar">
|
|
||||||
<div class="head"><strong>Add similar artist</strong></div>
|
|
||||||
<ul class="nobullet">
|
|
||||||
<li>
|
|
||||||
<form class="add_form" name="similar_artists" action="artist.php" method="post">
|
|
||||||
<input type="hidden" name="action" value="add_similar" />
|
|
||||||
<input type="hidden" name="auth" value="<?=$LoggedUser['AuthKey']?>" />
|
|
||||||
<input type="hidden" name="artistid" value="<?=$ArtistID?>" />
|
|
||||||
<input type="text" autocomplete="off" id="artistsimilar" name="artistname" size="20" />
|
|
||||||
<input type="submit" value="+" />
|
|
||||||
</form>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="main_column">
|
|
||||||
<?
|
|
||||||
|
|
||||||
echo $TorrentDisplayList;
|
|
||||||
|
|
||||||
if($NumRequests > 0) {
|
|
||||||
|
|
||||||
?>
|
|
||||||
<table cellpadding="6" cellspacing="1" border="0" class="requests_table border" width="100%" id="requests">
|
|
||||||
<tr class="colhead_dark">
|
|
||||||
<td style="width:48%;">
|
|
||||||
<a href="#">↑</a>
|
|
||||||
<strong>Request name</strong>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<strong>Vote</strong>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<strong>Bounty</strong>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<strong>Added</strong>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<?
|
|
||||||
foreach($Requests as $Request) {
|
|
||||||
list($RequestID, $CategoryID, $Title, $Year, $TimeAdded, $Votes, $Bounty) = $Request;
|
|
||||||
|
|
||||||
$CategoryName = $Categories[$CategoryID - 1];
|
|
||||||
|
|
||||||
if($CategoryName == "Music") {
|
|
||||||
$ArtistForm = get_request_artists($RequestID);
|
|
||||||
$ArtistLink = Artists::display_artists($ArtistForm, true, true);
|
|
||||||
$FullName = $ArtistLink."<a href='requests.php?action=view&id=".$RequestID."'>".$Title." [".$Year."]</a>";
|
|
||||||
} else if($CategoryName == "Audiobooks" || $CategoryName == "Comedy") {
|
|
||||||
$FullName = "<a href='requests.php?action=view&id=".$RequestID."'>".$Title." [".$Year."]</a>";
|
|
||||||
} else {
|
|
||||||
$FullName ="<a href='requests.php?action=view&id=".$RequestID."'>".$Title."</a>";
|
|
||||||
}
|
|
||||||
|
|
||||||
$Row = ($Row == 'a') ? 'b' : 'a';
|
|
||||||
|
|
||||||
$Tags = get_request_tags($RequestID);
|
|
||||||
?>
|
|
||||||
<tr class="row<?=$Row?>">
|
|
||||||
<td>
|
|
||||||
<?=$FullName?>
|
|
||||||
<div class="tags">
|
|
||||||
<?
|
|
||||||
$TagList = array();
|
|
||||||
foreach($Tags as $TagID => $TagName) {
|
|
||||||
$TagList[] = "<a href='requests.php?tags=".$TagName."'>".display_str($TagName)."</a>";
|
|
||||||
}
|
|
||||||
$TagList = implode(', ', $TagList);
|
|
||||||
?>
|
|
||||||
<?=$TagList?>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<?=$Votes?>
|
|
||||||
<? if(check_perms('site_vote')){ ?>
|
|
||||||
<input type="hidden" id="auth" name="auth" value="<?=$LoggedUser['AuthKey']?>" />
|
|
||||||
<a href="javascript:Vote(0)"><strong>(+)</strong></a>
|
|
||||||
<? } ?>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<?=Format::get_size($Bounty)?>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<?=time_diff($TimeAdded)?>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<? } ?>
|
|
||||||
</table>
|
|
||||||
<?
|
|
||||||
}
|
|
||||||
|
|
||||||
// Similar artist map
|
|
||||||
|
|
||||||
if($NumSimilar>0) {
|
|
||||||
$SimilarData = $Cache->get_value('similar_positions_'.$ArtistID);
|
|
||||||
|
|
||||||
if(!$Data) {
|
|
||||||
include(SERVER_ROOT.'/classes/class_image.php');
|
|
||||||
$Img = new IMAGE;
|
|
||||||
$Img->create(WIDTH, HEIGHT);
|
|
||||||
$Img->color(255,255,255, 127);
|
|
||||||
|
|
||||||
$Similar = new ARTISTS_SIMILAR($ArtistID, $Name);
|
|
||||||
$Similar->set_up();
|
|
||||||
$Similar->set_positions();
|
|
||||||
$Similar->background_image();
|
|
||||||
|
|
||||||
|
|
||||||
$SimilarData = $Similar->dump_data();
|
|
||||||
|
|
||||||
$Cache->cache_value('similar_positions_'.$ArtistID, $SimilarData, 3600*24);
|
|
||||||
} else {
|
|
||||||
$Similar = new ARTISTS_SIMILAR($ArtistID);
|
|
||||||
$Similar->load_data($SimilarData);
|
|
||||||
}
|
|
||||||
?>
|
|
||||||
|
|
||||||
<div id="similar_artist_map" class="box">
|
|
||||||
<div class="head"><strong>Similar artist map</strong></div>
|
|
||||||
<div style="width:<?=WIDTH?>px;height:<?=HEIGHT?>px;position:relative;background-image:url(static/similar/<?=$ArtistID?>.png?t=<?=time()?>)">
|
|
||||||
<?
|
|
||||||
$Similar->write_artists();
|
|
||||||
?>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<? } // if $NumSimilar>0 ?>
|
|
||||||
<div class="box">
|
|
||||||
<div class="head"><strong>Artist info</strong></div>
|
|
||||||
<div class="body"><?=$Text->full_format($Body)?></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<?
|
|
||||||
View::show_footer();
|
|
||||||
|
|
||||||
|
|
||||||
// Cache page for later use
|
|
||||||
|
|
||||||
if($RevisionID) {
|
|
||||||
$Key = "artist_$ArtistID"."_revision_$RevisionID";
|
|
||||||
} else {
|
|
||||||
$Key = 'artist_'.$ArtistID;
|
|
||||||
}
|
|
||||||
|
|
||||||
$Data = serialize(array(array($Name, $Image, $Body, $NumSimilar, $SimilarArray, $TorrentList, $GroupMeta)));
|
|
||||||
|
|
||||||
$Cache->cache_value($Key, $Data, 3600);
|
|
||||||
?>
|
|
@ -17,7 +17,7 @@
|
|||||||
$_GET['type'] = display_str($_GET['type']);
|
$_GET['type'] = display_str($_GET['type']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$SphQL = new SphinxQL_Query();
|
$SphQL = new SphinxqlQuery();
|
||||||
$SphQL->select('id, groupid')
|
$SphQL->select('id, groupid')
|
||||||
->from('better_transcode')
|
->from('better_transcode')
|
||||||
->where('logscore', 100)
|
->where('logscore', 100)
|
||||||
|
@ -28,8 +28,8 @@
|
|||||||
$Encodings = array('v0' => 'V0 (VBR)', 'v2' => 'V2 (VBR)', '320' => '320');
|
$Encodings = array('v0' => 'V0 (VBR)', 'v2' => 'V2 (VBR)', '320' => '320');
|
||||||
|
|
||||||
function transcode_init_sphql() {
|
function transcode_init_sphql() {
|
||||||
// Initializes a basic SphinxQL_Query object
|
// Initializes a basic SphinxqlQuery object
|
||||||
$SphQL = new SphinxQL_Query();
|
$SphQL = new SphinxqlQuery();
|
||||||
$SphQL->select('groupid')
|
$SphQL->select('groupid')
|
||||||
->from('better_transcode')
|
->from('better_transcode')
|
||||||
->where('logscore', 100)
|
->where('logscore', 100)
|
||||||
@ -153,7 +153,7 @@ function transcode_parse_groups($Groups) {
|
|||||||
$ResultsTmp = $SphQLResult->collect('groupid');
|
$ResultsTmp = $SphQLResult->collect('groupid');
|
||||||
$GroupsTmp = Torrents::get_groups(array_values($ResultsTmp));
|
$GroupsTmp = Torrents::get_groups(array_values($ResultsTmp));
|
||||||
$GroupsTmp = transcode_parse_groups($GroupsTmp['matches']);
|
$GroupsTmp = transcode_parse_groups($GroupsTmp['matches']);
|
||||||
// Since we're asking SphinxQL about groups and remidents, the result can/will contain different editions that are transcodable but weren't snatched, so let's filter them out
|
// Since we're asking Sphinxql about groups and remidents, the result can/will contain different editions that are transcodable but weren't snatched, so let's filter them out
|
||||||
foreach($GroupsTmp as $GroupID => $Group) {
|
foreach($GroupsTmp as $GroupID => $Group) {
|
||||||
foreach($Group['Editions'] as $RemIdent => $Edition) {
|
foreach($Group['Editions'] as $RemIdent => $Edition) {
|
||||||
$EditionSnatched = false;
|
$EditionSnatched = false;
|
||||||
|
@ -113,36 +113,11 @@ function compare($X, $Y){
|
|||||||
$Torrent['RemasterRecordLabel'] != $LastRemasterRecordLabel || $Torrent['RemasterCatalogueNumber'] != $LastRemasterCatalogueNumber || $FirstUnknown || $Torrent['Media'] != $LastMedia) {
|
$Torrent['RemasterRecordLabel'] != $LastRemasterRecordLabel || $Torrent['RemasterCatalogueNumber'] != $LastRemasterCatalogueNumber || $FirstUnknown || $Torrent['Media'] != $LastMedia) {
|
||||||
|
|
||||||
$EditionID++;
|
$EditionID++;
|
||||||
if($Torrent['Remastered'] && $Torrent['RemasterYear'] != 0) {
|
|
||||||
|
|
||||||
$RemasterName = $Torrent['RemasterYear'];
|
|
||||||
$AddExtra = " - ";
|
|
||||||
if($Torrent['RemasterRecordLabel']) { $RemasterName .= $AddExtra.display_str($Torrent['RemasterRecordLabel']); $AddExtra=' / '; }
|
|
||||||
if($Torrent['RemasterCatalogueNumber']) { $RemasterName .= $AddExtra.display_str($Torrent['RemasterCatalogueNumber']); $AddExtra=' / '; }
|
|
||||||
if($Torrent['RemasterTitle']) { $RemasterName .= $AddExtra.display_str($Torrent['RemasterTitle']); $AddExtra=' / '; }
|
|
||||||
$RemasterName .= $AddExtra.display_str($Torrent['Media']);
|
|
||||||
|
|
||||||
?>
|
?>
|
||||||
<tr class="group_torrent groupid_<?=$GroupID?> edition<?=$SnatchedGroupClass . (!empty($LoggedUser['TorrentGrouping']) && $LoggedUser['TorrentGrouping'] == 1 ? ' hidden' : '')?>">
|
<tr class="group_torrent groupid_<?=$GroupID?> edition<?=$SnatchedGroupClass . (!empty($LoggedUser['TorrentGrouping']) && $LoggedUser['TorrentGrouping'] == 1 ? ' hidden' : '')?>">
|
||||||
<td colspan="7" class="edition_info"><strong><a href="#" onclick="toggle_edition(<?=$GroupID?>, <?=$EditionID?>, this, event)" title="Collapse this edition. Hold "Ctrl" while clicking to collapse all editions in this torrent group.">−</a> <?=$RemasterName?></strong></td>
|
<td colspan="7" class="edition_info"><strong><a href="#" onclick="toggle_edition(<?=$GroupID?>, <?=$EditionID?>, this, event)" title="Collapse this edition. Hold "Ctrl" while clicking to collapse all editions in this torrent group.">−</a> <?=Torrents::edition_string($Torrent, $Group)?></strong></td>
|
||||||
</tr>
|
</tr>
|
||||||
<?
|
<?
|
||||||
} else {
|
|
||||||
$AddExtra = " / ";
|
|
||||||
if (!$Torrent['Remastered']) {
|
|
||||||
$MasterName = "Original Release";
|
|
||||||
if($GroupRecordLabel) { $MasterName .= $AddExtra.$GroupRecordLabel; $AddExtra=' / '; }
|
|
||||||
if($GroupCatalogueNumber) { $MasterName .= $AddExtra.$GroupCatalogueNumber; $AddExtra=' / '; }
|
|
||||||
} else {
|
|
||||||
$MasterName = "Unknown Release(s)";
|
|
||||||
}
|
|
||||||
$MasterName .= $AddExtra.display_str($Torrent['Media']);
|
|
||||||
?>
|
|
||||||
<tr class="group_torrent groupid_<?=$GroupID?> edition<?=$SnatchedGroupClass . (!empty($LoggedUser['TorrentGrouping']) && $LoggedUser['TorrentGrouping'] == 1 ? ' hidden' : '')?>">
|
|
||||||
<td colspan="7" class="edition_info"><strong><a href="#" onclick="toggle_edition(<?=$GroupID?>, <?=$EditionID?>, this, event)" title="Collapse this edition. Hold "Ctrl" while clicking to collapse all editions in this torrent group.">−</a> <?=$MasterName?></strong></td>
|
|
||||||
</tr>
|
|
||||||
<?
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
$LastRemasterTitle = $Torrent['RemasterTitle'];
|
$LastRemasterTitle = $Torrent['RemasterTitle'];
|
||||||
$LastRemasterYear = $Torrent['RemasterYear'];
|
$LastRemasterYear = $Torrent['RemasterYear'];
|
||||||
|
@ -189,35 +189,11 @@ function compare($X, $Y){
|
|||||||
if($Torrent['RemasterTitle'] != $LastRemasterTitle || $Torrent['RemasterYear'] != $LastRemasterYear ||
|
if($Torrent['RemasterTitle'] != $LastRemasterTitle || $Torrent['RemasterYear'] != $LastRemasterYear ||
|
||||||
$Torrent['RemasterRecordLabel'] != $LastRemasterRecordLabel || $Torrent['RemasterCatalogueNumber'] != $LastRemasterCatalogueNumber || $FirstUnknown || $Torrent['Media'] != $LastMedia) {
|
$Torrent['RemasterRecordLabel'] != $LastRemasterRecordLabel || $Torrent['RemasterCatalogueNumber'] != $LastRemasterCatalogueNumber || $FirstUnknown || $Torrent['Media'] != $LastMedia) {
|
||||||
$EditionID++;
|
$EditionID++;
|
||||||
if($Torrent['Remastered'] && $Torrent['RemasterYear'] != 0) {
|
|
||||||
$RemasterName = $Torrent['RemasterYear'];
|
|
||||||
$AddExtra = " - ";
|
|
||||||
if($Torrent['RemasterRecordLabel']) { $RemasterName .= $AddExtra.display_str($Torrent['RemasterRecordLabel']); $AddExtra=' / '; }
|
|
||||||
if($Torrent['RemasterCatalogueNumber']) { $RemasterName .= $AddExtra.display_str($Torrent['RemasterCatalogueNumber']); $AddExtra=' / '; }
|
|
||||||
if($Torrent['RemasterTitle']) { $RemasterName .= $AddExtra.display_str($Torrent['RemasterTitle']); $AddExtra=' / '; }
|
|
||||||
$RemasterName .= $AddExtra.display_str($Torrent['Media']);
|
|
||||||
|
|
||||||
?>
|
?>
|
||||||
<tr class="group_torrent groupid_<?=$GroupID?> edition<?=$SnatchedGroupClass . (!empty($LoggedUser['TorrentGrouping']) && $LoggedUser['TorrentGrouping'] == 1 ? ' hidden' : '')?>">
|
<tr class="group_torrent groupid_<?=$GroupID?> edition<?=$SnatchedGroupClass . (!empty($LoggedUser['TorrentGrouping']) && $LoggedUser['TorrentGrouping'] == 1 ? ' hidden' : '')?>">
|
||||||
<td colspan="7" class="edition_info"><strong><a href="#" onclick="toggle_edition(<?=$GroupID?>, <?=$EditionID?>, this, event)" title="Collapse this edition. Hold "Ctrl" while clicking to collapse all editions in this torrent group.">−</a> <?=$RemasterName?></strong></td>
|
<td colspan="7" class="edition_info"><strong><a href="#" onclick="toggle_edition(<?=$GroupID?>, <?=$EditionID?>, this, event)" title="Collapse this edition. Hold "Ctrl" while clicking to collapse all editions in this torrent group.">−</a> <?=Torrents::edition_string($Torrent, $Group)?></strong></td>
|
||||||
</tr>
|
</tr>
|
||||||
<?
|
<?
|
||||||
} else {
|
|
||||||
$AddExtra = " / ";
|
|
||||||
if (!$Torrent['Remastered']) {
|
|
||||||
$MasterName = "Original Release";
|
|
||||||
if($GroupRecordLabel) { $MasterName .= $AddExtra.$GroupRecordLabel; $AddExtra=' / '; }
|
|
||||||
if($GroupCatalogueNumber) { $MasterName .= $AddExtra.$GroupCatalogueNumber; $AddExtra=' / '; }
|
|
||||||
} else {
|
|
||||||
$MasterName = "Unknown Release(s)";
|
|
||||||
}
|
|
||||||
$MasterName .= $AddExtra.display_str($Torrent['Media']);
|
|
||||||
?>
|
|
||||||
<tr class="group_torrent groupid_<?=$GroupID?> edition<?=$SnatchedGroupClass . (!empty($LoggedUser['TorrentGrouping']) && $LoggedUser['TorrentGrouping'] == 1 ? ' hidden' : '')?>">
|
|
||||||
<td colspan="7" class="edition_info"><strong><a href="#" onclick="toggle_edition(<?=$GroupID?>, <?=$EditionID?>, this, event)" title="Collapse this edition. Hold "Ctrl" while clicking to collapse all editions in this torrent group.">−</a> <?=$MasterName?></strong></td>
|
|
||||||
</tr>
|
|
||||||
<?
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
$LastRemasterTitle = $Torrent['RemasterTitle'];
|
$LastRemasterTitle = $Torrent['RemasterTitle'];
|
||||||
$LastRemasterYear = $Torrent['RemasterYear'];
|
$LastRemasterYear = $Torrent['RemasterYear'];
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
$TotalMatches = 0;
|
$TotalMatches = 0;
|
||||||
} elseif($NumResults == LOG_ENTRIES_PER_PAGE) {
|
} elseif($NumResults == LOG_ENTRIES_PER_PAGE) {
|
||||||
// This is a lot faster than SQL_CALC_FOUND_ROWS
|
// This is a lot faster than SQL_CALC_FOUND_ROWS
|
||||||
$SphQL = new SphinxQL_Query();
|
$SphQL = new SphinxqlQuery();
|
||||||
$Result = $SphQL->select('id')->from('log, log_delta')->limit(0, 1, 1)->query();
|
$Result = $SphQL->select('id')->from('log, log_delta')->limit(0, 1, 1)->query();
|
||||||
$Debug->log_var($Result, '$Result');
|
$Debug->log_var($Result, '$Result');
|
||||||
$TotalMatches = min(SPHINX_MAX_MATCHES, $Result->get_meta('total_found'));
|
$TotalMatches = min(SPHINX_MAX_MATCHES, $Result->get_meta('total_found'));
|
||||||
@ -23,7 +23,7 @@
|
|||||||
$QueryStatus = 0;
|
$QueryStatus = 0;
|
||||||
} else {
|
} else {
|
||||||
$Page = min(SPHINX_MAX_MATCHES/TORRENTS_PER_PAGE, $Page);
|
$Page = min(SPHINX_MAX_MATCHES/TORRENTS_PER_PAGE, $Page);
|
||||||
$SphQL = new SphinxQL_Query();
|
$SphQL = new SphinxqlQuery();
|
||||||
$SphQL->select('id')
|
$SphQL->select('id')
|
||||||
->from('log, log_delta')
|
->from('log, log_delta')
|
||||||
->where_match($_GET['search'], 'message')
|
->where_match($_GET['search'], 'message')
|
||||||
|
@ -246,35 +246,11 @@
|
|||||||
if($Torrent['RemasterTitle'] != $LastRemasterTitle || $Torrent['RemasterYear'] != $LastRemasterYear ||
|
if($Torrent['RemasterTitle'] != $LastRemasterTitle || $Torrent['RemasterYear'] != $LastRemasterYear ||
|
||||||
$Torrent['RemasterRecordLabel'] != $LastRemasterRecordLabel || $Torrent['RemasterCatalogueNumber'] != $LastRemasterCatalogueNumber || $FirstUnknown || $Torrent['Media'] != $LastMedia) {
|
$Torrent['RemasterRecordLabel'] != $LastRemasterRecordLabel || $Torrent['RemasterCatalogueNumber'] != $LastRemasterCatalogueNumber || $FirstUnknown || $Torrent['Media'] != $LastMedia) {
|
||||||
$EditionID++;
|
$EditionID++;
|
||||||
if($Torrent['Remastered'] && $Torrent['RemasterYear'] != 0) {
|
|
||||||
$RemasterName = $Torrent['RemasterYear'];
|
|
||||||
$AddExtra = " - ";
|
|
||||||
if($Torrent['RemasterRecordLabel']) { $RemasterName .= $AddExtra.display_str($Torrent['RemasterRecordLabel']); $AddExtra=' / '; }
|
|
||||||
if($Torrent['RemasterCatalogueNumber']) { $RemasterName .= $AddExtra.display_str($Torrent['RemasterCatalogueNumber']); $AddExtra=' / '; }
|
|
||||||
if($Torrent['RemasterTitle']) { $RemasterName .= $AddExtra.display_str($Torrent['RemasterTitle']); $AddExtra=' / '; }
|
|
||||||
$RemasterName .= $AddExtra.display_str($Torrent['Media']);
|
|
||||||
|
|
||||||
?>
|
?>
|
||||||
<tr class="group_torrent groupid_<?=$GroupID?> edition<?=$SnatchedGroupClass?> hidden">
|
<tr class="group_torrent groupid_<?=$GroupID?> edition<?=$SnatchedGroupClass?> hidden">
|
||||||
<td colspan="7" class="edition_info"><strong><a href="#" onclick="toggle_edition(<?=$GroupID?>, <?=$EditionID?>, this, event)" title="Collapse this edition. Hold "Ctrl" while clicking to collapse all editions in this torrent group.">−</a> <?=$RemasterName?></strong></td>
|
<td colspan="7" class="edition_info"><strong><a href="#" onclick="toggle_edition(<?=$GroupID?>, <?=$EditionID?>, this, event)" title="Collapse this edition. Hold "Ctrl" while clicking to collapse all editions in this torrent group.">−</a> <?=Torrents::edition_string($Torrent, $Group)?></strong></td>
|
||||||
</tr>
|
</tr>
|
||||||
<?
|
<?
|
||||||
} else {
|
|
||||||
$AddExtra = " / ";
|
|
||||||
if (!$Torrent['Remastered']) {
|
|
||||||
$MasterName = "Original Release";
|
|
||||||
if($GroupRecordLabel) { $MasterName .= $AddExtra.$GroupRecordLabel; $AddExtra=' / '; }
|
|
||||||
if($GroupCatalogueNumber) { $MasterName .= $AddExtra.$GroupCatalogueNumber; $AddExtra=' / '; }
|
|
||||||
} else {
|
|
||||||
$MasterName = "Unknown Release(s)";
|
|
||||||
}
|
|
||||||
$MasterName .= $AddExtra.display_str($Torrent['Media']);
|
|
||||||
?>
|
|
||||||
<tr class="group_torrent groupid_<?=$GroupID?> edition<?=$SnatchedGroupClass?> hidden">
|
|
||||||
<td colspan="7" class="edition_info"><strong><a href="#" onclick="toggle_edition(<?=$GroupID?>, <?=$EditionID?>, this, event)" title="Collapse this edition. Hold "Ctrl" while clicking to collapse all editions in this torrent group.">−</a> <?=$MasterName?></strong></td>
|
|
||||||
</tr>
|
|
||||||
<?
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
$LastRemasterTitle = $Torrent['RemasterTitle'];
|
$LastRemasterTitle = $Torrent['RemasterTitle'];
|
||||||
$LastRemasterYear = $Torrent['RemasterYear'];
|
$LastRemasterYear = $Torrent['RemasterYear'];
|
||||||
|
@ -157,8 +157,8 @@ function header_link($SortKey,$DefaultWay="desc") {
|
|||||||
/** End preparation of property arrays **/
|
/** End preparation of property arrays **/
|
||||||
|
|
||||||
/** Start query preparation **/
|
/** Start query preparation **/
|
||||||
$SphQL = new SphinxQL_Query();
|
$SphQL = new SphinxqlQuery();
|
||||||
$SphQLTor = new SphinxQL_Query();
|
$SphQLTor = new SphinxqlQuery();
|
||||||
|
|
||||||
if ($OrderBy == 'random') {
|
if ($OrderBy == 'random') {
|
||||||
$SphQL->select('id, groupid, categoryid')
|
$SphQL->select('id, groupid, categoryid')
|
||||||
@ -187,7 +187,7 @@ function header_link($SortKey,$DefaultWay="desc") {
|
|||||||
if (!empty($_GET['filelist'])) {
|
if (!empty($_GET['filelist'])) {
|
||||||
$SearchString = trim($_GET['filelist']);
|
$SearchString = trim($_GET['filelist']);
|
||||||
if ($SearchString != '') {
|
if ($SearchString != '') {
|
||||||
$SearchString = '"'.SphinxQL::escape_string($_GET['filelist']).'"~20';
|
$SearchString = '"'.Sphinxql::escape_string($_GET['filelist']).'"~20';
|
||||||
$SphQL->where_match($SearchString, 'filelist', false);
|
$SphQL->where_match($SearchString, 'filelist', false);
|
||||||
$SphQLTor->where_match($SearchString, 'filelist', false);
|
$SphQLTor->where_match($SearchString, 'filelist', false);
|
||||||
$EnableNegation = true;
|
$EnableNegation = true;
|
||||||
@ -275,11 +275,11 @@ function header_link($SortKey,$DefaultWay="desc") {
|
|||||||
}
|
}
|
||||||
$QueryParts = array();
|
$QueryParts = array();
|
||||||
foreach ($BasicSearch['include'] as $Word) {
|
foreach ($BasicSearch['include'] as $Word) {
|
||||||
$QueryParts[] = SphinxQL::escape_string($Word);
|
$QueryParts[] = Sphinxql::escape_string($Word);
|
||||||
}
|
}
|
||||||
if (!empty($BasicSearch['exclude'])) {
|
if (!empty($BasicSearch['exclude'])) {
|
||||||
foreach ($BasicSearch['exclude'] as $Word) {
|
foreach ($BasicSearch['exclude'] as $Word) {
|
||||||
$QueryParts[] = '!'.SphinxQL::escape_string(substr($Word,1));
|
$QueryParts[] = '!'.Sphinxql::escape_string(substr($Word,1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!empty($FilterBitrates)) {
|
if (!empty($FilterBitrates)) {
|
||||||
@ -311,11 +311,11 @@ function header_link($SortKey,$DefaultWay="desc") {
|
|||||||
unset($Tags['exclude']);
|
unset($Tags['exclude']);
|
||||||
}
|
}
|
||||||
foreach ($Tags['include'] as &$Tag) {
|
foreach ($Tags['include'] as &$Tag) {
|
||||||
$Tag = SphinxQL::escape_string($Tag);
|
$Tag = Sphinxql::escape_string($Tag);
|
||||||
}
|
}
|
||||||
if (!empty($Tags['exclude'])) {
|
if (!empty($Tags['exclude'])) {
|
||||||
foreach ($Tags['exclude'] as &$Tag) {
|
foreach ($Tags['exclude'] as &$Tag) {
|
||||||
$Tag = '!'.SphinxQL::escape_string(substr($Tag,1));
|
$Tag = '!'.Sphinxql::escape_string(substr($Tag,1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -355,11 +355,11 @@ function header_link($SortKey,$DefaultWay="desc") {
|
|||||||
unset($Words['exclude']);
|
unset($Words['exclude']);
|
||||||
}
|
}
|
||||||
foreach ($Words['include'] as $Word) {
|
foreach ($Words['include'] as $Word) {
|
||||||
$QueryParts[] = SphinxQL::escape_string($Word);
|
$QueryParts[] = Sphinxql::escape_string($Word);
|
||||||
}
|
}
|
||||||
if (!empty($Words['exclude'])) {
|
if (!empty($Words['exclude'])) {
|
||||||
foreach ($Words['exclude'] as $Word) {
|
foreach ($Words['exclude'] as $Word) {
|
||||||
$QueryParts[] = '!'.SphinxQL::escape_string(substr($Word,1));
|
$QueryParts[] = '!'.Sphinxql::escape_string(substr($Word,1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!empty($QueryParts)) {
|
if (!empty($QueryParts)) {
|
||||||
@ -1012,36 +1012,11 @@ function header_link($SortKey,$DefaultWay="desc") {
|
|||||||
|| $Data['Media'] != $LastMedia) {
|
|| $Data['Media'] != $LastMedia) {
|
||||||
$EditionID++;
|
$EditionID++;
|
||||||
|
|
||||||
if ($Data['Remastered'] && $Data['RemasterYear'] != 0) {
|
|
||||||
|
|
||||||
$RemasterName = $Data['RemasterYear'];
|
|
||||||
$AddExtra = " - ";
|
|
||||||
if ($Data['RemasterRecordLabel']) { $RemasterName .= $AddExtra.display_str($Data['RemasterRecordLabel']); $AddExtra=' / '; }
|
|
||||||
if ($Data['RemasterCatalogueNumber']) { $RemasterName .= $AddExtra.display_str($Data['RemasterCatalogueNumber']); $AddExtra=' / '; }
|
|
||||||
if ($Data['RemasterTitle']) { $RemasterName .= $AddExtra.display_str($Data['RemasterTitle']); $AddExtra=' / '; }
|
|
||||||
$RemasterName .= $AddExtra.display_str($Data['Media']);
|
|
||||||
|
|
||||||
?>
|
?>
|
||||||
<tr class="group_torrent groupid_<?=$GroupID?> edition<?=$SnatchedGroupClass . (!empty($LoggedUser['TorrentGrouping']) && $LoggedUser['TorrentGrouping'] == 1 ? ' hidden' : '')?>">
|
<tr class="group_torrent groupid_<?=$GroupID?> edition<?=$SnatchedGroupClass . (!empty($LoggedUser['TorrentGrouping']) && $LoggedUser['TorrentGrouping'] == 1 ? ' hidden' : '')?>">
|
||||||
<td colspan="9" class="edition_info"><strong><a href="#" onclick="toggle_edition(<?=$GroupID?>, <?=$EditionID?>, this, event)" title="Collapse this edition. Hold "Ctrl" while clicking to collapse all editions in this torrent group.">−</a> <?=$RemasterName?></strong></td>
|
<td colspan="9" class="edition_info"><strong><a href="#" onclick="toggle_edition(<?=$GroupID?>, <?=$EditionID?>, this, event)" title="Collapse this edition. Hold "Ctrl" while clicking to collapse all editions in this torrent group.">−</a> <?=Torrents::edition_string($Data, $GroupInfo)?></strong></td>
|
||||||
</tr>
|
</tr>
|
||||||
<?
|
<?
|
||||||
} else {
|
|
||||||
$AddExtra = " / ";
|
|
||||||
if (!$Data['Remastered']) {
|
|
||||||
$MasterName = "Original Release";
|
|
||||||
if ($GroupRecordLabel) { $MasterName .= $AddExtra.$GroupRecordLabel; $AddExtra=' / '; }
|
|
||||||
if ($GroupCatalogueNumber) { $MasterName .= $AddExtra.$GroupCatalogueNumber; $AddExtra=' / '; }
|
|
||||||
} else {
|
|
||||||
$MasterName = "Unknown Release(s)";
|
|
||||||
}
|
|
||||||
$MasterName .= $AddExtra.display_str($Data['Media']);
|
|
||||||
?>
|
|
||||||
<tr class="group_torrent groupid_<?=$GroupID?> edition<?=$SnatchedGroupClass . (!empty($LoggedUser['TorrentGrouping']) && $LoggedUser['TorrentGrouping'] == 1 ? ' hidden' : '')?>">
|
|
||||||
<td colspan="9" class="edition_info"><strong><a href="#" onclick="toggle_edition(<?=$GroupID?>, <?=$EditionID?>, this, event)" title="Collapse this edition. Hold "Ctrl" while clicking to collapse all editions in this torrent group.">−</a> <?=$MasterName?></strong></td>
|
|
||||||
</tr>
|
|
||||||
<?
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
$LastRemasterTitle = $Data['RemasterTitle'];
|
$LastRemasterTitle = $Data['RemasterTitle'];
|
||||||
$LastRemasterYear = $Data['RemasterYear'];
|
$LastRemasterYear = $Data['RemasterYear'];
|
||||||
|
@ -525,35 +525,11 @@ function filelist($Str) {
|
|||||||
|
|
||||||
$EditionID++;
|
$EditionID++;
|
||||||
|
|
||||||
if($Remastered && $RemasterYear != 0){
|
|
||||||
|
|
||||||
$RemasterName = $RemasterYear;
|
|
||||||
$AddExtra = " - ";
|
|
||||||
if($RemasterRecordLabel) { $RemasterName .= $AddExtra.display_str($RemasterRecordLabel); $AddExtra=' / '; }
|
|
||||||
if($RemasterCatalogueNumber) { $RemasterName .= $AddExtra.display_str($RemasterCatalogueNumber); $AddExtra=' / '; }
|
|
||||||
if($RemasterTitle) { $RemasterName .= $AddExtra.display_str($RemasterTitle); $AddExtra=' / '; }
|
|
||||||
$RemasterName .= $AddExtra.display_str($Media);
|
|
||||||
?>
|
?>
|
||||||
<tr class="releases_<?=$ReleaseType?> groupid_<?=$GroupID?> edition group_torrent">
|
<tr class="releases_<?=$ReleaseType?> groupid_<?=$GroupID?> edition group_torrent">
|
||||||
<td colspan="5" class="edition_info"><strong><a href="#" onclick="toggle_edition(<?=$GroupID?>, <?=$EditionID?>, this, event)" title="Collapse this edition. Hold "Ctrl" while clicking to collapse all editions in this torrent group.">−</a> <?=$RemasterName?></strong></td>
|
<td colspan="5" class="edition_info"><strong><a href="#" onclick="toggle_edition(<?=$GroupID?>, <?=$EditionID?>, this, event)" title="Collapse this edition. Hold "Ctrl" while clicking to collapse all editions in this torrent group.">−</a> <?=Torrents::edition_string($Torrent, $TorrentDetails)?></strong></td>
|
||||||
</tr>
|
</tr>
|
||||||
<?
|
<?
|
||||||
} else {
|
|
||||||
$AddExtra = " / ";
|
|
||||||
if(!$Remastered) {
|
|
||||||
$MasterName = "Original Release";
|
|
||||||
if($GroupRecordLabel) { $MasterName .= $AddExtra.$GroupRecordLabel; $AddExtra=' / '; }
|
|
||||||
if($GroupCatalogueNumber) { $MasterName .= $AddExtra.$GroupCatalogueNumber; $AddExtra=' / '; }
|
|
||||||
} else {
|
|
||||||
$MasterName = "Unknown Release(s)";
|
|
||||||
}
|
|
||||||
$MasterName .= $AddExtra.display_str($Media);
|
|
||||||
?>
|
|
||||||
<tr class="releases_<?=$ReleaseType?> groupid_<?=$GroupID?> edition group_torrent">
|
|
||||||
<td colspan="5" class="edition_info"><strong><a href="#" onclick="toggle_edition(<?=$GroupID?>, <?=$EditionID?>, this, event)" title="Collapse this edition. Hold "Ctrl" while clicking to collapse all editions in this torrent group.">−</a> <?=$MasterName?></strong></td>
|
|
||||||
</tr>
|
|
||||||
<?
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
$LastRemasterTitle = $RemasterTitle;
|
$LastRemasterTitle = $RemasterTitle;
|
||||||
$LastRemasterYear = $RemasterYear;
|
$LastRemasterYear = $RemasterYear;
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
$Name = $ExtraTorrent['Name'];
|
$Name = $ExtraTorrent['Name'];
|
||||||
$ExtraTorrentsInsert[$Name] = $ExtraTorrent;
|
$ExtraTorrentsInsert[$Name] = $ExtraTorrent;
|
||||||
$ThisInsert =& $ExtraTorrentsInsert[$Name];
|
$ThisInsert =& $ExtraTorrentsInsert[$Name];
|
||||||
$ExtraTor = new BEncTorrent($Name, true);
|
$ExtraTor = new BencodeTorrent($Name, true);
|
||||||
if (isset($ExtraTor->Dec['encrypted_files'])) {
|
if (isset($ExtraTor->Dec['encrypted_files'])) {
|
||||||
$Err = "At least one of the torrents contain an encrypted file list which is not supported here";
|
$Err = "At least one of the torrents contain an encrypted file list which is not supported here";
|
||||||
break;
|
break;
|
||||||
|
@ -344,7 +344,7 @@
|
|||||||
//******************************************************************************//
|
//******************************************************************************//
|
||||||
//--------------- Generate torrent file ----------------------------------------//
|
//--------------- Generate torrent file ----------------------------------------//
|
||||||
|
|
||||||
$Tor = new BEncTorrent($TorrentName, true);
|
$Tor = new BencodeTorrent($TorrentName, true);
|
||||||
$PublicTorrent = $Tor->make_private(); // The torrent is now private.
|
$PublicTorrent = $Tor->make_private(); // The torrent is now private.
|
||||||
$TorEnc = db_string($Tor->encode());
|
$TorEnc = db_string($Tor->encode());
|
||||||
$InfoHash = pack('H*', $Tor->info_hash());
|
$InfoHash = pack('H*', $Tor->info_hash());
|
||||||
|
@ -291,6 +291,12 @@ function num_compare($Field, $Operand, $Num1, $Num2 = ''){
|
|||||||
$Where[]='ui1.AdminComment'.$Match.wrap($_GET['comment']);
|
$Where[]='ui1.AdminComment'.$Match.wrap($_GET['comment']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!empty($_GET['lastfm'])) {
|
||||||
|
$Distinct = 'DISTINCT ';
|
||||||
|
$Join['lastfm'] = ' JOIN lastfm_users AS lfm ON lfm.ID = um1.ID ';
|
||||||
|
$Where[] = ' lfm.Username'.$Match.wrap($_GET['lastfm']);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if(strlen($_GET['invites1'])){
|
if(strlen($_GET['invites1'])){
|
||||||
$Invites1 = round($_GET['invites1']);
|
$Invites1 = round($_GET['invites1']);
|
||||||
@ -636,8 +642,9 @@ function num_compare($Field, $Operand, $Num1, $Num2 = ''){
|
|||||||
<td>
|
<td>
|
||||||
<input type="text" name="tracker_ip" size="20" value="<?=display_str($_GET['tracker_ip'])?>" />
|
<input type="text" name="tracker_ip" size="20" value="<?=display_str($_GET['tracker_ip'])?>" />
|
||||||
</td>
|
</td>
|
||||||
<td class="label nobr"></td>
|
<td class="label nobr">Last.fm Username:</td>
|
||||||
<td>
|
<td>
|
||||||
|
<input type="text" name="lastfm" size="20" value="<?=display_str($_GET['lastfm'])?>" />
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
|
@ -160,38 +160,12 @@
|
|||||||
|
|
||||||
if($Torrent['RemasterTitle'] != $LastRemasterTitle || $Torrent['RemasterYear'] != $LastRemasterYear ||
|
if($Torrent['RemasterTitle'] != $LastRemasterTitle || $Torrent['RemasterYear'] != $LastRemasterYear ||
|
||||||
$Torrent['RemasterRecordLabel'] != $LastRemasterRecordLabel || $Torrent['RemasterCatalogueNumber'] != $LastRemasterCatalogueNumber || $FirstUnknown || $Torrent['Media'] != $LastMedia) {
|
$Torrent['RemasterRecordLabel'] != $LastRemasterRecordLabel || $Torrent['RemasterCatalogueNumber'] != $LastRemasterCatalogueNumber || $FirstUnknown || $Torrent['Media'] != $LastMedia) {
|
||||||
if($Torrent['Remastered'] && $Torrent['RemasterYear'] != 0) {
|
|
||||||
|
|
||||||
$EditionID++;
|
$EditionID++;
|
||||||
|
|
||||||
$RemasterName = $Torrent['RemasterYear'];
|
|
||||||
$AddExtra = " - ";
|
|
||||||
if($Torrent['RemasterRecordLabel']) { $RemasterName .= $AddExtra.display_str($Torrent['RemasterRecordLabel']); $AddExtra=' / '; }
|
|
||||||
if($Torrent['RemasterCatalogueNumber']) { $RemasterName .= $AddExtra.display_str($Torrent['RemasterCatalogueNumber']); $AddExtra=' / '; }
|
|
||||||
if($Torrent['RemasterTitle']) { $RemasterName .= $AddExtra.display_str($Torrent['RemasterTitle']); $AddExtra=' / '; }
|
|
||||||
$RemasterName .= $AddExtra.display_str($Torrent['Media']);
|
|
||||||
|
|
||||||
?>
|
?>
|
||||||
<tr class="group_torrent groupid_<?=$CollageID . $GroupID?> edition<?=$SnatchedGroupClass?> hidden">
|
<tr class="group_torrent groupid_<?=$CollageID . $GroupID?> edition<?=$SnatchedGroupClass?> hidden">
|
||||||
<td colspan="6" class="edition_info"><strong><a href="#" onclick="toggle_edition(<?=$CollageID?><?=$GroupID?>, <?=$EditionID?>, this, event)" title="Collapse this edition. Hold "Ctrl" while clicking to collapse all editions in this torrent group.">−</a> <?=$RemasterName?></strong></td>
|
<td colspan="6" class="edition_info"><strong><a href="#" onclick="toggle_edition(<?=$CollageID?><?=$GroupID?>, <?=$EditionID?>, this, event)" title="Collapse this edition. Hold "Ctrl" while clicking to collapse all editions in this torrent group.">−</a> <?=Torrents::edition_string($Torrent, $Group)?></strong></td>
|
||||||
</tr>
|
</tr>
|
||||||
<?
|
<?
|
||||||
} else {
|
|
||||||
$AddExtra = " / ";
|
|
||||||
if (!$Torrent['Remastered']) {
|
|
||||||
$MasterName = "Original Release";
|
|
||||||
if($GroupRecordLabel) { $MasterName .= $AddExtra.$GroupRecordLabel; $AddExtra=' / '; }
|
|
||||||
if($GroupCatalogueNumber) { $MasterName .= $AddExtra.$GroupCatalogueNumber; $AddExtra=' / '; }
|
|
||||||
} else {
|
|
||||||
$MasterName = "Unknown Release(s)";
|
|
||||||
}
|
|
||||||
$MasterName .= $AddExtra.display_str($Torrent['Media']);
|
|
||||||
?>
|
|
||||||
<tr class="group_torrent groupid_<?=$CollageID . $GroupID?> edition<?=$SnatchedGroupClass?> hidden">
|
|
||||||
<td colspan="6" class="edition_info"><strong><a href="#" onclick="toggle_edition(<?=$CollageID?><?=$GroupID?>, <?=$EditionID?>, this, event)" title="Collapse this edition. Hold "Ctrl" while clicking to collapse all editions in this torrent group.">−</a> <?=$MasterName?></strong></td>
|
|
||||||
</tr>
|
|
||||||
<?
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
$LastRemasterTitle = $Torrent['RemasterTitle'];
|
$LastRemasterTitle = $Torrent['RemasterTitle'];
|
||||||
$LastRemasterYear = $Torrent['RemasterYear'];
|
$LastRemasterYear = $Torrent['RemasterYear'];
|
||||||
|
Loading…
Reference in New Issue
Block a user