mirror of
https://github.com/WhatCD/Gazelle.git
synced 2025-01-18 12:11: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
|
||||
* 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
|
||||
'created by', 'creation date', 'encoding', 'info');
|
||||
private $Data;
|
||||
@ -94,315 +94,3 @@ private function _benc() {
|
||||
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() {
|
||||
if(class_exists(SphinxQL)) {
|
||||
return SphinxQL::$Queries;
|
||||
if(class_exists('Sphinxql')) {
|
||||
return Sphinxql::$Queries;
|
||||
}
|
||||
}
|
||||
|
||||
public function get_sphinxql_time() {
|
||||
if(class_exists(SphinxQL)) {
|
||||
return SphinxQL::$Time;
|
||||
if(class_exists('Sphinxql')) {
|
||||
return Sphinxql::$Time;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
error('Mysqli Extension not loaded.');
|
||||
}
|
||||
|
||||
class SphinxQL extends mysqli {
|
||||
class Sphinxql extends mysqli {
|
||||
private static $Connections = array();
|
||||
private $Server;
|
||||
private $Port;
|
||||
@ -16,7 +16,7 @@ class SphinxQL extends mysqli {
|
||||
|
||||
|
||||
/**
|
||||
* Initialize SphinxQL object
|
||||
* Initialize Sphinxql object
|
||||
*
|
||||
* @param string $Server server address or hostname
|
||||
* @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 int $Port listening port
|
||||
* @param string $Socket Unix socket address, overrides $Server:$Port
|
||||
* @return SphinxQL object
|
||||
* @return Sphinxql object
|
||||
*/
|
||||
public static function init_connection($Server, $Port, $Socket) {
|
||||
$Ident = self::get_ident($Server, $Port, $Socket);
|
||||
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];
|
||||
}
|
||||
|
||||
/**
|
||||
* Connect the SphinxQL object to the Sphinx server
|
||||
* Connect the Sphinxql object to the Sphinx server
|
||||
*/
|
||||
public function connect() {
|
||||
if(!$this->Connected) {
|
||||
@ -84,7 +84,7 @@ public function connect() {
|
||||
*
|
||||
* @param string $Msg message to display
|
||||
* @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) {
|
||||
global $Debug;
|
||||
@ -133,469 +133,7 @@ public function escape_string($String) {
|
||||
* @param param $QueryProcessTime time building and processing the query
|
||||
*/
|
||||
public function register_query($QueryString, $QueryProcessTime) {
|
||||
SphinxQL::$Queries[] = array($QueryString, $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;
|
||||
}
|
||||
Sphinxql::$Queries[] = array($QueryString, $QueryProcessTime);
|
||||
Sphinxql::$Time += $QueryProcessTime;
|
||||
}
|
||||
}
|
||||
|
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 $Pos = 1; // Pointer that indicates our position in the string
|
||||
var $Str = ''; // Torrent string
|
||||
@ -131,7 +131,7 @@ function encode($Val){
|
||||
}
|
||||
}
|
||||
|
||||
class BENCODE_LIST extends BENCODE {
|
||||
class BENCODE_LIST extends BENCODE2 {
|
||||
function enc(){
|
||||
if (empty($this->Val)) {
|
||||
return 'le';
|
||||
@ -168,7 +168,7 @@ function dec(){
|
||||
}
|
||||
}
|
||||
|
||||
class BENCODE_DICT extends BENCODE {
|
||||
class BENCODE_DICT extends BENCODE2 {
|
||||
function enc(){
|
||||
if (empty($this->Val)) {
|
||||
return 'de';
|
||||
|
@ -72,7 +72,7 @@ functions:
|
||||
discovered that floats aren't accurate enough to use. :(
|
||||
|
||||
*******************************************************************************/
|
||||
class BENCODE {
|
||||
class BENCODE2 {
|
||||
var $Val; // Decoded array
|
||||
var $Pos = 1; // Pointer that indicates our position in the string
|
||||
var $Str = ''; // Torrent string
|
||||
@ -140,7 +140,7 @@ function encode($Val){
|
||||
}
|
||||
}
|
||||
|
||||
class BENCODE_LIST extends BENCODE {
|
||||
class BENCODE_LIST extends BENCODE2 {
|
||||
function enc(){
|
||||
$Str = 'l';
|
||||
reset($this->Val);
|
||||
@ -174,7 +174,7 @@ function dec(){
|
||||
}
|
||||
}
|
||||
|
||||
class BENCODE_DICT extends BENCODE {
|
||||
class BENCODE_DICT extends BENCODE2 {
|
||||
function enc(){
|
||||
$Str = 'd';
|
||||
reset($this->Val);
|
||||
|
@ -475,7 +475,7 @@ public static function regenerate_filelist($TorrentID) {
|
||||
if($DB->record_count() > 0) {
|
||||
list($GroupID, $Contents) = $DB->next_record(MYSQLI_NUM, false);
|
||||
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()) : "";
|
||||
} else {
|
||||
$Tor = new TORRENT(unserialize(base64_decode($Contents)), true);
|
||||
@ -748,5 +748,28 @@ public static function has_snatched($TorrentID, $AllUsers = false) {
|
||||
}
|
||||
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) {
|
||||
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->set_announce_url($AnnounceURL);
|
||||
|
@ -87,9 +87,15 @@
|
||||
case 'Artists':
|
||||
$FileName = 'class_artists';
|
||||
break;
|
||||
case 'BEncTorrent':
|
||||
case 'Bencode':
|
||||
$FileName = 'class_bencode';
|
||||
break;
|
||||
case 'BencodeDecode':
|
||||
$FileName = 'class_bencodedecode';
|
||||
break;
|
||||
case 'BencodeTorrent':
|
||||
$FileName = 'class_bencodetorrent';
|
||||
break;
|
||||
case 'Format':
|
||||
$FileName = 'class_format';
|
||||
break;
|
||||
@ -120,11 +126,15 @@
|
||||
case 'Rippy':
|
||||
$FileName = 'rippy.class';
|
||||
break;
|
||||
case 'SphinxQL':
|
||||
case 'SphinxQL_Query':
|
||||
case 'SphinxQL_Result':
|
||||
case 'Sphinxql':
|
||||
$FileName = 'class_sphinxql';
|
||||
break;
|
||||
case 'SphinxqlQuery':
|
||||
$FileName = 'class_sphinxqlquery';
|
||||
break;
|
||||
case 'SphinxqlResult':
|
||||
$FileName = 'class_sphinxqlresult';
|
||||
break;
|
||||
case 'Tags':
|
||||
$FileName = 'class_tags';
|
||||
break;
|
||||
|
@ -17,7 +17,7 @@
|
||||
$_GET['type'] = display_str($_GET['type']);
|
||||
}
|
||||
}
|
||||
$SphQL = new SphinxQL_Query();
|
||||
$SphQL = new SphinxqlQuery();
|
||||
$SphQL->select('id, groupid')
|
||||
->from('better_transcode')
|
||||
->where('logscore', 100)
|
||||
|
@ -119,8 +119,8 @@ function header_link($SortKey,$DefaultWay="desc") {
|
||||
/** End preparation of property arrays **/
|
||||
|
||||
/** Start query preparation **/
|
||||
$SphQL = new SphinxQL_Query();
|
||||
$SphQLTor = new SphinxQL_Query();
|
||||
$SphQL = new SphinxqlQuery();
|
||||
$SphQLTor = new SphinxqlQuery();
|
||||
|
||||
if ($OrderBy == 'random') {
|
||||
$SphQL->select('id, groupid, categoryid')
|
||||
@ -149,7 +149,7 @@ function header_link($SortKey,$DefaultWay="desc") {
|
||||
if (!empty($_GET['filelist'])) {
|
||||
$SearchString = trim($_GET['filelist']);
|
||||
if ($SearchString != '') {
|
||||
$SearchString = '"'.SphinxQL::escape_string($_GET['filelist']).'"~20';
|
||||
$SearchString = '"'.Sphinxql::escape_string($_GET['filelist']).'"~20';
|
||||
$SphQL->where_match($SearchString, 'filelist', false);
|
||||
$SphQLTor->where_match($SearchString, 'filelist', false);
|
||||
$EnableNegation = true;
|
||||
@ -229,11 +229,11 @@ function header_link($SortKey,$DefaultWay="desc") {
|
||||
}
|
||||
$QueryParts = array();
|
||||
foreach ($BasicSearch['include'] as $Word) {
|
||||
$QueryParts[] = SphinxQL::escape_string($Word);
|
||||
$QueryParts[] = Sphinxql::escape_string($Word);
|
||||
}
|
||||
if (!empty($BasicSearch['exclude'])) {
|
||||
foreach ($BasicSearch['exclude'] as $Word) {
|
||||
$QueryParts[] = '!'.SphinxQL::escape_string(substr($Word,1));
|
||||
$QueryParts[] = '!'.Sphinxql::escape_string(substr($Word,1));
|
||||
}
|
||||
}
|
||||
if (!empty($FilterBitrates)) {
|
||||
@ -265,11 +265,11 @@ function header_link($SortKey,$DefaultWay="desc") {
|
||||
unset($Tags['exclude']);
|
||||
}
|
||||
foreach ($Tags['include'] as &$Tag) {
|
||||
$Tag = SphinxQL::escape_string($Tag);
|
||||
$Tag = Sphinxql::escape_string($Tag);
|
||||
}
|
||||
if (!empty($Tags['exclude'])) {
|
||||
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']);
|
||||
}
|
||||
foreach ($Words['include'] as $Word) {
|
||||
$QueryParts[] = SphinxQL::escape_string($Word);
|
||||
$QueryParts[] = Sphinxql::escape_string($Word);
|
||||
}
|
||||
if (!empty($Words['exclude'])) {
|
||||
foreach ($Words['exclude'] as $Word) {
|
||||
$QueryParts[] = '!'.SphinxQL::escape_string(substr($Word,1));
|
||||
$QueryParts[] = '!'.Sphinxql::escape_string(substr($Word,1));
|
||||
}
|
||||
}
|
||||
if (!empty($QueryParts)) {
|
||||
@ -614,26 +614,6 @@ function header_link($SortKey,$DefaultWay="desc") {
|
||||
|| $FirstUnknown
|
||||
|| $Data['Media'] != $LastMedia) {
|
||||
$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'];
|
||||
$LastRemasterYear = $Data['RemasterYear'];
|
||||
|
@ -12,7 +12,7 @@
|
||||
}
|
||||
list($Contents) = $DB->next_record(MYSQLI_NUM, array(0));
|
||||
if (Misc::is_new_torrent($Contents)) {
|
||||
$Tor = new BEncTorrent($Contents);
|
||||
$Tor = new BencodeTorrent($Contents);
|
||||
$Private = $Tor->is_private();
|
||||
} else {
|
||||
$Tor = new TORRENT(unserialize(base64_decode($Contents)), true); // New TORRENT object
|
||||
|
@ -409,35 +409,11 @@ function compare($X, $Y){
|
||||
|
||||
$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?>">
|
||||
<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>
|
||||
<?
|
||||
} 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'];
|
||||
$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']);
|
||||
}
|
||||
}
|
||||
$SphQL = new SphinxQL_Query();
|
||||
$SphQL = new SphinxqlQuery();
|
||||
$SphQL->select('id, groupid')
|
||||
->from('better_transcode')
|
||||
->where('logscore', 100)
|
||||
|
@ -28,8 +28,8 @@
|
||||
$Encodings = array('v0' => 'V0 (VBR)', 'v2' => 'V2 (VBR)', '320' => '320');
|
||||
|
||||
function transcode_init_sphql() {
|
||||
// Initializes a basic SphinxQL_Query object
|
||||
$SphQL = new SphinxQL_Query();
|
||||
// Initializes a basic SphinxqlQuery object
|
||||
$SphQL = new SphinxqlQuery();
|
||||
$SphQL->select('groupid')
|
||||
->from('better_transcode')
|
||||
->where('logscore', 100)
|
||||
@ -153,7 +153,7 @@ function transcode_parse_groups($Groups) {
|
||||
$ResultsTmp = $SphQLResult->collect('groupid');
|
||||
$GroupsTmp = Torrents::get_groups(array_values($ResultsTmp));
|
||||
$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($Group['Editions'] as $RemIdent => $Edition) {
|
||||
$EditionSnatched = false;
|
||||
|
@ -113,36 +113,11 @@ function compare($X, $Y){
|
||||
$Torrent['RemasterRecordLabel'] != $LastRemasterRecordLabel || $Torrent['RemasterCatalogueNumber'] != $LastRemasterCatalogueNumber || $FirstUnknown || $Torrent['Media'] != $LastMedia) {
|
||||
|
||||
$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' : '')?>">
|
||||
<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>
|
||||
<?
|
||||
} 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'];
|
||||
$LastRemasterYear = $Torrent['RemasterYear'];
|
||||
|
@ -189,35 +189,11 @@ function compare($X, $Y){
|
||||
if($Torrent['RemasterTitle'] != $LastRemasterTitle || $Torrent['RemasterYear'] != $LastRemasterYear ||
|
||||
$Torrent['RemasterRecordLabel'] != $LastRemasterRecordLabel || $Torrent['RemasterCatalogueNumber'] != $LastRemasterCatalogueNumber || $FirstUnknown || $Torrent['Media'] != $LastMedia) {
|
||||
$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' : '')?>">
|
||||
<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>
|
||||
<?
|
||||
} 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'];
|
||||
$LastRemasterYear = $Torrent['RemasterYear'];
|
||||
|
@ -13,7 +13,7 @@
|
||||
$TotalMatches = 0;
|
||||
} elseif($NumResults == LOG_ENTRIES_PER_PAGE) {
|
||||
// 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();
|
||||
$Debug->log_var($Result, '$Result');
|
||||
$TotalMatches = min(SPHINX_MAX_MATCHES, $Result->get_meta('total_found'));
|
||||
@ -23,7 +23,7 @@
|
||||
$QueryStatus = 0;
|
||||
} else {
|
||||
$Page = min(SPHINX_MAX_MATCHES/TORRENTS_PER_PAGE, $Page);
|
||||
$SphQL = new SphinxQL_Query();
|
||||
$SphQL = new SphinxqlQuery();
|
||||
$SphQL->select('id')
|
||||
->from('log, log_delta')
|
||||
->where_match($_GET['search'], 'message')
|
||||
|
@ -246,35 +246,11 @@
|
||||
if($Torrent['RemasterTitle'] != $LastRemasterTitle || $Torrent['RemasterYear'] != $LastRemasterYear ||
|
||||
$Torrent['RemasterRecordLabel'] != $LastRemasterRecordLabel || $Torrent['RemasterCatalogueNumber'] != $LastRemasterCatalogueNumber || $FirstUnknown || $Torrent['Media'] != $LastMedia) {
|
||||
$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">
|
||||
<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>
|
||||
<?
|
||||
} 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'];
|
||||
$LastRemasterYear = $Torrent['RemasterYear'];
|
||||
|
@ -157,8 +157,8 @@ function header_link($SortKey,$DefaultWay="desc") {
|
||||
/** End preparation of property arrays **/
|
||||
|
||||
/** Start query preparation **/
|
||||
$SphQL = new SphinxQL_Query();
|
||||
$SphQLTor = new SphinxQL_Query();
|
||||
$SphQL = new SphinxqlQuery();
|
||||
$SphQLTor = new SphinxqlQuery();
|
||||
|
||||
if ($OrderBy == 'random') {
|
||||
$SphQL->select('id, groupid, categoryid')
|
||||
@ -187,7 +187,7 @@ function header_link($SortKey,$DefaultWay="desc") {
|
||||
if (!empty($_GET['filelist'])) {
|
||||
$SearchString = trim($_GET['filelist']);
|
||||
if ($SearchString != '') {
|
||||
$SearchString = '"'.SphinxQL::escape_string($_GET['filelist']).'"~20';
|
||||
$SearchString = '"'.Sphinxql::escape_string($_GET['filelist']).'"~20';
|
||||
$SphQL->where_match($SearchString, 'filelist', false);
|
||||
$SphQLTor->where_match($SearchString, 'filelist', false);
|
||||
$EnableNegation = true;
|
||||
@ -275,11 +275,11 @@ function header_link($SortKey,$DefaultWay="desc") {
|
||||
}
|
||||
$QueryParts = array();
|
||||
foreach ($BasicSearch['include'] as $Word) {
|
||||
$QueryParts[] = SphinxQL::escape_string($Word);
|
||||
$QueryParts[] = Sphinxql::escape_string($Word);
|
||||
}
|
||||
if (!empty($BasicSearch['exclude'])) {
|
||||
foreach ($BasicSearch['exclude'] as $Word) {
|
||||
$QueryParts[] = '!'.SphinxQL::escape_string(substr($Word,1));
|
||||
$QueryParts[] = '!'.Sphinxql::escape_string(substr($Word,1));
|
||||
}
|
||||
}
|
||||
if (!empty($FilterBitrates)) {
|
||||
@ -311,11 +311,11 @@ function header_link($SortKey,$DefaultWay="desc") {
|
||||
unset($Tags['exclude']);
|
||||
}
|
||||
foreach ($Tags['include'] as &$Tag) {
|
||||
$Tag = SphinxQL::escape_string($Tag);
|
||||
$Tag = Sphinxql::escape_string($Tag);
|
||||
}
|
||||
if (!empty($Tags['exclude'])) {
|
||||
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']);
|
||||
}
|
||||
foreach ($Words['include'] as $Word) {
|
||||
$QueryParts[] = SphinxQL::escape_string($Word);
|
||||
$QueryParts[] = Sphinxql::escape_string($Word);
|
||||
}
|
||||
if (!empty($Words['exclude'])) {
|
||||
foreach ($Words['exclude'] as $Word) {
|
||||
$QueryParts[] = '!'.SphinxQL::escape_string(substr($Word,1));
|
||||
$QueryParts[] = '!'.Sphinxql::escape_string(substr($Word,1));
|
||||
}
|
||||
}
|
||||
if (!empty($QueryParts)) {
|
||||
@ -1012,36 +1012,11 @@ function header_link($SortKey,$DefaultWay="desc") {
|
||||
|| $Data['Media'] != $LastMedia) {
|
||||
$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' : '')?>">
|
||||
<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>
|
||||
<?
|
||||
} 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'];
|
||||
$LastRemasterYear = $Data['RemasterYear'];
|
||||
|
@ -525,35 +525,11 @@ function filelist($Str) {
|
||||
|
||||
$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">
|
||||
<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>
|
||||
</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>
|
||||
<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>
|
||||
<?
|
||||
}
|
||||
}
|
||||
$LastRemasterTitle = $RemasterTitle;
|
||||
$LastRemasterYear = $RemasterYear;
|
||||
|
@ -4,7 +4,7 @@
|
||||
$Name = $ExtraTorrent['Name'];
|
||||
$ExtraTorrentsInsert[$Name] = $ExtraTorrent;
|
||||
$ThisInsert =& $ExtraTorrentsInsert[$Name];
|
||||
$ExtraTor = new BEncTorrent($Name, true);
|
||||
$ExtraTor = new BencodeTorrent($Name, true);
|
||||
if (isset($ExtraTor->Dec['encrypted_files'])) {
|
||||
$Err = "At least one of the torrents contain an encrypted file list which is not supported here";
|
||||
break;
|
||||
|
@ -344,7 +344,7 @@
|
||||
//******************************************************************************//
|
||||
//--------------- Generate torrent file ----------------------------------------//
|
||||
|
||||
$Tor = new BEncTorrent($TorrentName, true);
|
||||
$Tor = new BencodeTorrent($TorrentName, true);
|
||||
$PublicTorrent = $Tor->make_private(); // The torrent is now private.
|
||||
$TorEnc = db_string($Tor->encode());
|
||||
$InfoHash = pack('H*', $Tor->info_hash());
|
||||
|
@ -290,6 +290,12 @@ function num_compare($Field, $Operand, $Num1, $Num2 = ''){
|
||||
if(!empty($_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'])){
|
||||
@ -636,8 +642,9 @@ function num_compare($Field, $Operand, $Num1, $Num2 = ''){
|
||||
<td>
|
||||
<input type="text" name="tracker_ip" size="20" value="<?=display_str($_GET['tracker_ip'])?>" />
|
||||
</td>
|
||||
<td class="label nobr"></td>
|
||||
<td class="label nobr">Last.fm Username:</td>
|
||||
<td>
|
||||
<input type="text" name="lastfm" size="20" value="<?=display_str($_GET['lastfm'])?>" />
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
|
@ -160,38 +160,12 @@
|
||||
|
||||
if($Torrent['RemasterTitle'] != $LastRemasterTitle || $Torrent['RemasterYear'] != $LastRemasterYear ||
|
||||
$Torrent['RemasterRecordLabel'] != $LastRemasterRecordLabel || $Torrent['RemasterCatalogueNumber'] != $LastRemasterCatalogueNumber || $FirstUnknown || $Torrent['Media'] != $LastMedia) {
|
||||
if($Torrent['Remastered'] && $Torrent['RemasterYear'] != 0) {
|
||||
|
||||
$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']);
|
||||
|
||||
$EditionID++;
|
||||
?>
|
||||
<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>
|
||||
<?
|
||||
} 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'];
|
||||
$LastRemasterYear = $Torrent['RemasterYear'];
|
||||
|
Loading…
Reference in New Issue
Block a user