This commit is contained in:
chudov
2010-03-04 05:56:17 +00:00
parent b36069871c
commit ff3259e08a
19 changed files with 660 additions and 404 deletions

View File

@@ -0,0 +1,35 @@
<?php include 'logo_start.php'; ?>
<h2>What's it for?</h2>
You probably heard about <a href=http://www.accuraterip.com/>AccurateRip</a>, a wonderfull database of CD rip checksums, which helps you make sure your CD rip is an exact copy of original CD. What it can tell you is how many other people got the same data when copying this CD.
CUETools Database is an extension of this idea.
<h2>What are the advantages?</h2>
<ul>
<li>The most important feature is the ability not only to detect, but also correct small amounts of errors that occured in the ripping process.
<li>It's free of the offset problems. You don't even need to set up offset correction for your CD drive to be able to verify and what's more important, submit rips to the database. Different pressings of the same CD are treated as the same disc by the database, it doesn't care.
<li>Verification results are easier to deal with. There are exactly three possible outcomes: rip is correct, rip contains correctable errors, rip is unknown (or contains errors beyond repair).
<li>If there's a match, you can be certain it's really a match, because in addition to recovery record database uses a well-known CRC32 checksum of the whole CD image (except for 10*588 offset samples in the first and last seconds of the disc). This checksum is used as a rip ID in CTDB.
</ul>
<h2>What are the downsides and limitations?</h2>
<ul>
<li>CUETools DB doesn't bother with tracks. Your rip as a whole is either good/correctable, or it isn't. If one of the tracks is damaged beyound repair, CTDB cannot tell which one.
<li>If your rip contains errors, verification/correction process will involve downloading about 200kb of data, which is much more than it takes for AccurateRp.
<li>Verification process is slower than with AR.
<li>Database was just born and at the moment contains much less CDs than AR.
</ul>
<h2>How many errors can a rip contain and still be repairable?</h2>
<ul>
<li>That depends. The best case scenario is when there's one continuous damaged area up to 30-40 sectors (about half a second) long.
<li>The worst case scenario is 4 non-continuous damaged sectors in (very) unlucky positions.
</ul>
<h2>What information does the database contain per each submission?</h2>
<ul>
<li>CD TOC (Table Of Contents), i.e. length of every track.
<li>Offset-finding checksum, i.e. small (16 byte) recovery record for a set of samples throughout the CD, which allows to detect the offset difference between the rip in database and your rip, even if your rip contains some errors.
<li>CRC32 of the whole disc (except for some leadin/leadout samples).
<li>Submission date, artist, title.
<li>180kb recovery record, which is stored separately and accessed only when verifying a broken rip or repairing it.
</ul>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 293 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 290 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 293 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 293 B

View File

@@ -1,76 +1,48 @@
<?php <?php
$listfile="parity/list.txt";
$last_modified_time = filemtime($listfile);
$etag = md5_file($listfile);
header("Last-Modified: ".gmdate("D, d M Y H:i:s", $last_modified_time)." GMT");
header("ETag: $etag");
if (@strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) == $last_modified_time ||
@trim($_SERVER['HTTP_IF_NONE_MATCH']) == $etag) {
header("HTTP/1.1 304 Not Modified");
exit;
}
include 'logo_start.php'; include 'logo_start.php';
require_once( 'phpmb/mbQuery.php' ); require_once( 'phpmb/mbQuery.php' );
require_once( 'phpctdb/ctdb.php' ); require_once( 'phpctdb/ctdb.php' );
$lines=false; //$dbconn = pg_connect("dbname=ctdb user=ctdb_user")
$totaldiscs=filesize($listfile)/57; // or die('Could not connect: ' . pg_last_error());
$fp = fopen($listfile,'r');
$count = 10; $count = 20;
$query = 'SELECT * FROM submissions';
$term = ' WHERE ';
$url = '';
$where_discid=@$_GET['discid'];
if ($where_discid != '')
{
$query = $query . $term . "discid='" . pg_escape_string($where_discid) . "'";
$term = ' AND ';
$url = $url . '&discid=' . urlencode($where_discid);
}
$where_artist=@$_GET['artist'];
if ($where_artist != '')
{
$query = $query . $term . "artist ilike '%" . pg_escape_string($where_artist) . "%'";
$term = ' AND ';
$url = $url . '&artist=' . urlencode($where_artist);
}
$where_uid=@$_GET['uid'];
if ($where_uid != '')
{
$query = $query . $term . "userid='" . pg_escape_string($where_uid) . "'";
$term = ' AND ';
$url = $url . '&uid=' . urlencode($where_uid);
}
$query = $query . " ORDER BY id";
$result = pg_query($query) or die('Query failed: ' . pg_last_error());
$start = @$_GET['start']; $start = @$_GET['start'];
if ($start == "" || $start > $totaldiscs || $start < 0) $start = $totaldiscs - $count; if (pg_num_rows($result) == 0)
fseek($fp, 57 * $start, SEEK_SET); die('nothing found');
$n = $count; if ($count > pg_num_rows($result))
while($line=fgets($fp)) { $count = pg_num_rows($result);
$name = trim($line); if ($start == '') $start = pg_num_rows($result) - $count;
if (file_exists($name))
$lines[]=$name;
if (--$n <= 0)
break;
}
fclose($fp);
printf("<center><h3>Recent additions:</h3>"); printf("<center><h3>Recent additions:</h3>");
include 'table_start.php'; include 'list.php';
?> pg_free_result($result);
<table class=classy_table cellpadding=3 cellspacing=0><tr bgcolor=#D0D0D0><th>Artist</th><th>Album</th><th>Disc Id</th><th>CTDB Id</th></tr>
<?php
//<tr background="img/bg_top_border.jpg"><td></td><td width=8 rowspan=12 bgcolor=#FFFFFF></td><td background="img/bg_right_border.jpg" width=4 rowspan=12></td><td></td><td></td><td></td></tr>
$imgs = '';
if ($lines) foreach(array_reverse($lines) as $line) {
$ctdb = new phpCTDB($line);
$disc = $ctdb->db['discs'][0];
$ctdb->ParseToc();
//$id = @$disc['MBID']['value'];
$artist = @$disc['ART ']['value'];
$title = @$disc['nam ']['value'];
$discid = substr($line,13,30);
$ctdbid = $ctdb->db['discs'][0]['CRC ']['int'];
if ($artist == "" && $title == "")
{
//$q = new MusicBrainzQuery(new WebService('db4.cuetools.net'));
$q = new MusicBrainzQuery();
$rf = new ReleaseFilter();
try {
$rresults = $q->getReleases( $rf->discId($ctdb->mbid) );
foreach ( $rresults as $key => $rr ) {
$rr = $rr->getRelease();
$artist = $rr->getArtist()->getName();
$title = $rr->getTitle();
$imgs = $imgs . '<img src="http://ec1.images-amazon.com/images/P/' . $rr->getAsin() . '.01.MZZZZZZZ.jpg">';
}
}
catch ( ResponseError $e ) {
// echo $e->getMessage() . " ";
}
}
printf('<tr><td class=td_artist>%s</td><td class=td_album>%s</td><td class=td_discid><a href="http://musicbrainz.org/bare/cdlookup.html?id=%s">%s</a></td><td class=td_ctdbid><a href=show.php?discid=%s&ctdbid=%08x>%08x</a></td></tr>', htmlspecialchars($artist), htmlspecialchars($title), $ctdb->mbid, $discid, $discid, $ctdbid, $ctdbid);
}
printf('<tr><td colspan=4 align=right><a class=style1 href="?start=%d">More</a></td></tr>', $count * floor(($start - 1) / $count));
printf("</table>");
include 'table_end.php' ;
//printf('%s', $imgs);
printf("</center>"); printf("</center>");
?> ?>
</body> </body>

View File

@@ -0,0 +1,13 @@
<?php
include 'table_start.php';
?>
<table class=classy_table cellpadding=3 cellspacing=0><tr bgcolor=#D0D0D0><th>Artist</th><th>Album</th><th>Disc Id</th><th>CTDB Id</th><th>AR</th></tr>
<?php
for($i = $start + $count - 1; $i >= $start; $i--) {
$record = pg_fetch_array($result, $i);
printf('<tr><td class=td_artist><a href=?artist=%s>%s</a></td><td class=td_album>%s</td><td class=td_discid><a href="?discid=%s">%s</a></td><td class=td_ctdbid><a href=show.php?discid=%s&ctdbid=%08x>%08x</a></td><td class=td_ar>%d</td></tr>', urlencode($record['artist']), $record['artist'], $record['title'], $record['discid'], $record['discid'], $record['discid'], $record['ctdbid'], $record['ctdbid'], $record['confidence']);
}
if ($start > 0) printf('<tr><td colspan=5 align=right><a class=style1 href="?start=%d%s">More</a></td></tr>', $count * floor(($start - 1) / $count), $url);
printf("</table>");
include 'table_end.php' ;
?>

View File

@@ -34,6 +34,11 @@
padding: 1px 5px; padding: 1px 5px;
font-family: Courier; font-family: Courier;
} }
.td_ar {
padding: 1px 5px;
text-align: right;
font-family: Courier;
}
.classy_table { .classy_table {
border-style:none; border-style:none;
# border-color-right: #D0D0D0 # border-color-right: #D0D0D0
@@ -43,20 +48,34 @@
</head> </head>
<body> <body>
<table border=0 cellspacing=0 cellpadding=3 align=center> <table border=0 cellspacing=0 cellpadding=3 align=center>
<tr> <tr>
<td rowspan=3><img src=ctdb.png></td> <td rowspan=3><img width=128 height=128 border=0 alt="" src=ctdb.png></td>
<td colspan=2 class=td_status> <td class=td_status>
<?php <?php
printf("%d unique discs", filesize("parity/list.txt")/57); $dbconn = pg_connect("dbname=ctdb user=ctdb_user")
or die('Could not connect: ' . pg_last_error());
$dbresult = pg_query('SELECT * FROM submissions');
printf("%d unique discs", pg_num_rows($dbresult));
pg_free_result($dbresult);
?> ?>
</td> </td>
</tr> </tr>
<tr> <tr align=center height=34%>
<td class=style_logo colspan=2>CUETools Database</td> <td class=style_logo>CUETools Database</td>
</tr> </tr>
<tr align=center> <tr align=center height=33%>
<td>About</td> <td>
<td><a href=http://www.cuetools.net>CUETools</a></td> <?php include 'table_start.php'; ?>
</tr> <table width=300 border=0 cellspacing=8 cellpadding=0 align=center>
<tr align=center>
<td><a href=/>Home</a></td>
<td><a href=/top.php>Popular</a></td>
<td><a href=/about.php>About</a></td>
<td><a href=http://www.cuetools.net>CUETools</a></td>
</tr>
</table>
<?php include 'table_end.php'; ?>
</td>
</tr>
</table> </table>
<br clear=all> <br clear=all>

View File

@@ -3,88 +3,267 @@
class phpCTDB{ class phpCTDB{
private $fp; private $fp;
private $fpstats; private $fpstats;
private $atoms; private $atoms;
public $db; public $db;
public $fulltoc; public $fulltoc;
public $mbid;
function __construct($target_file) { function __construct($target_file) {
$this->fp = fopen($target_file, 'rb'); $this->fp = fopen($target_file, 'rb');
$this->fpstats = fstat($this->fp); $this->fpstats = fstat($this->fp);
$this->atoms = $this->parse_container_atom(0, $this->fpstats['size']); $this->atoms = $this->parse_container_atom(0, $this->fpstats['size']);
$this->db = false; $this->db = false;
foreach ($this->atoms as $entry) if($entry['name'] == 'CTDB') $this->db = $entry; foreach ($this->atoms as $entry) if($entry['name'] == 'CTDB') $this->db = $entry;
} }
function __destruct() { function __destruct() {
fclose($this->fp); fclose($this->fp);
} }
function ParseTOC() function ParseTOC()
{ {
$disc = $this->db['discs'][0]; $disc = $this->db['discs'][0];
$this->fulltoc = ''; $this->fulltoc = '';
$mbtoc = ''; $totalcount = 0;
$firstaudio = 0;
$lastaudio = 0;
foreach ($disc['TOC ']['subatoms'] as $track) foreach ($disc['TOC ']['subatoms'] as $track)
{ {
if ($track['name']=='INFO') { if ($track['name']=='INFO') {
$trackcount = phpCTDB::BigEndian2Int(substr($track['value'],0,4)); $trackcount = phpCTDB::BigEndian2Int(substr($track['value'],0,4));
$pregap = phpCTDB::BigEndian2Int(substr($track['value'],4,4)); $pregap = phpCTDB::BigEndian2Int(substr($track['value'],4,4));
$pos = $pregap + 150; $pos = $pregap + 150;
} }
if ($track['name']=='TRAK') { if ($track['name']=='TRAK') {
$isaudio = phpCTDB::BigEndian2Int(substr($track['value'],0,4)); $isaudio = phpCTDB::BigEndian2Int(substr($track['value'],0,4));
$length = phpCTDB::BigEndian2Int(substr($track['value'],4,4)); $length = phpCTDB::BigEndian2Int(substr($track['value'],4,4));
$this->fulltoc = sprintf('%s %d', $this->fulltoc, $pos); if ($isaudio == 0 && $totalcount!=0)
$mbtoc = sprintf('%s%08X', $mbtoc, $pos); $pos += 11400;
$pos += $length; $this->fulltoc = sprintf('%s %d', $this->fulltoc, $pos);
} $pos += $length;
$totalcount ++;
if ($isaudio != 0)
$lastaudio = $totalcount;
if ($isaudio != 0 && $firstaudio == 0)
$firstaudio = $totalcount;
}
} }
$this->fulltoc = sprintf('1 %d %d%s', $trackcount, $pos, $this->fulltoc); if ($trackcount != $totalcount)
$mbtoc = sprintf('01%02X%08X%s', $trackcount, $pos, $mbtoc); die('wrong trackcount');
$this->fulltoc = sprintf('%d %d %d %d%s', $firstaudio, $lastaudio, $totalcount, $pos, $this->fulltoc);
}
static function toc2mbtoc($fulltoc)
{
$ids = explode(' ', $fulltoc);
$mbtoc = sprintf('%d %d', $ids[0], $ids[1]);
if ($ids[1] == $ids[2])
{
for ($tr = 3; $tr < count($ids); $tr++)
$mbtoc = sprintf('%s %d', $mbtoc, $ids[$tr]);
} else // Enhanced CD
{
$mbtoc = sprintf('%s %d', $mbtoc, $ids[$ids[1] + 4] - 11400);
for ($tr = 4; $tr < $ids[1] + 4; $tr++)
$mbtoc = sprintf('%s %d', $mbtoc, $ids[$tr]);
}
return $mbtoc;
}
static function toc2mbid($fulltoc)
{
$ids = explode(' ', $fulltoc);
$mbtoc = sprintf('%02X%02X', $ids[0], $ids[1]);
if ($ids[1] == $ids[2])
{
for ($tr = 3; $tr < count($ids); $tr++)
$mbtoc = sprintf('%s%08X', $mbtoc, $ids[$tr]);
} else // Enhanced CD
{
$mbtoc = sprintf('%s%08X', $mbtoc, $ids[$ids[1] + 4] - 11400);
for ($tr = 4; $tr < $ids[1] + 4; $tr++)
$mbtoc = sprintf('%s%08X', $mbtoc, $ids[$tr]);
}
// echo $fulltoc . ':' . $mbtoc . '<br>';
$mbtoc = str_pad($mbtoc,804,'0'); $mbtoc = str_pad($mbtoc,804,'0');
$this->mbid = str_replace('+', '.', str_replace('/', '_', str_replace('=', '-', base64_encode(pack("H*" , sha1($mbtoc)))))); $mbid = str_replace('+', '.', str_replace('/', '_', str_replace('=', '-', base64_encode(pack("H*" , sha1($mbtoc))))));
return $mbid;
}
static function mblookup($mbid)
{
$mbconn = pg_connect("dbname=musicbrainz_db user=musicbrainz_user");
if (!$mbconn)
return false;
$mbresult = pg_query_params('SELECT DISTINCT album'
. ' FROM album_cdtoc, cdtoc'
. ' WHERE album_cdtoc.cdtoc = cdtoc.id'
. ' AND cdtoc.discid = $1',
array($mbid)
);
$mbmeta = false;
while(true == ($mbrecord = pg_fetch_array($mbresult)))
{
$mbresult2 = pg_query_params('SELECT a.name as albumname, ar.name as artistname, coverarturl'
. ' FROM album a INNER JOIN albummeta m ON m.id = a.id, artist ar'
. ' WHERE a.id = $1'
. ' AND ar.id = a.artist',
array($mbrecord[0]));
$mbmeta[] = pg_fetch_array($mbresult2);
pg_free_result($mbresult2);
}
pg_free_result($mbresult);
return $mbmeta;
}
function ctdb2pg($discid)
{
$disc = $this->db['discs'][0];
$record = false;
$record['discid'] = $discid;
$record['ctdbid'] = $disc['CRC ']['int'];
$record['confidence'] = $disc['CONF']['int'];
$record['parity'] = base64_encode($this->read($disc['PAR ']['offset'], 16));
$record['fulltoc'] = $this->fulltoc;
$record['userid'] = $disc['USER']['value'];
$record['agent'] = $disc['TOOL']['value'];
$record['time'] = date ("Y-m-d H:i:s");
$record['artist'] = @$disc['ART ']['value'];
$record['title'] = @$disc['nam ']['value'];
return $record;
}
static function pg2ctdb($dbconn, $id)
{
$target_path = phpCTDB::discid2path($id);
$result = pg_query_params($dbconn, "SELECT * FROM submissions WHERE discid=$1", array($id))
or die('Query failed: ' . pg_last_error());
if (pg_num_rows($result) < 1) die('not found');
$totalconf = 0;
$newctdb = false;
$newctdb['name'] = 'CTDB';
$newhead = false;
$newhead['name'] = 'HEAD';
$newtotal = false;
$newtotal['name'] = 'TOTL';
$newtotal['value'] = phpCTDB::BigEndian2String($totalconf,4);
$newhead['subatoms'][] = $newtotal;
$newctdb['subatoms'][] = $newhead;
while (TRUE == ($record = pg_fetch_array($result)))
{
$totalconf += $record['confidence'];
$newdisc = false;
$newdisc['name'] = 'DISC';
$newatom = false;
$newatom['name'] = 'CRC ';
$newatom['value'] = phpCTDB::Hex2String(sprintf('%08x',$record['ctdbid']));
$newdisc['subatoms'][] = $newatom;
$newatom = false;
$newatom['name'] = 'NPAR';
$newatom['value'] = phpCTDB::BigEndian2String(8,4);
$newdisc['subatoms'][] = $newatom;
$newatom = false;
$newatom['name'] = 'CONF';
$newatom['value'] = phpCTDB::BigEndian2String((int)($record['confidence']),4);
$newdisc['subatoms'][] = $newatom;
$newatom = false;
$newatom['name'] = 'PAR ';
$newatom['value'] = base64_decode($record['parity']);
$newdisc['subatoms'][] = $newatom;
$newctdb['subatoms'][] = $newdisc;
}
pg_free_result($result);
$newctdb['subatoms'][0]['subatoms'][0]['value'] = phpCTDB::BigEndian2String($totalconf,4);
$ftyp=false;
$ftyp['name'] = 'ftyp';
$ftyp['value'] = 'CTDB';
$tname = sprintf("%s/ctdb.tmp", $target_path);
$tfp = fopen($tname, 'wb');
phpCTDB::unparse_atom($tfp,$ftyp);
phpCTDB::unparse_atom($tfp,$newctdb);
fclose($tfp);
if(!rename($tname,sprintf("%s/ctdb.bin", $target_path)))
die('error uploading file ' . $target_path);
}
static function Hex2Int($hex_word, $signed = false)
{
$int_value = 0;
$byte_wordlen = strlen($hex_word);
for ($i = 0; $i < $byte_wordlen; $i++) {
sscanf($hex_word{$i}, "%x", $digit);
$int_value += $digit * pow(16, ($byte_wordlen - 1 - $i));
}
if ($signed) {
$sign_mask_bit = 0x80 << 24;
if ($int_value & $sign_mask_bit) {
$int_value = 0 - ($int_value & ($sign_mask_bit - 1));
}
}
return $int_value;
} }
static function BigEndian2Int($byte_word, $signed = false) { static function BigEndian2Int($byte_word, $signed = false) {
$int_value = 0; $int_value = 0;
$byte_wordlen = strlen($byte_word); $byte_wordlen = strlen($byte_word);
for ($i = 0; $i < $byte_wordlen; $i++) { for ($i = 0; $i < $byte_wordlen; $i++) {
$int_value += ord($byte_word{$i}) * pow(256, ($byte_wordlen - 1 - $i)); $int_value += ord($byte_word{$i}) * pow(256, ($byte_wordlen - 1 - $i));
} }
if ($signed) { if ($signed) {
$sign_mask_bit = 0x80 << (8 * ($byte_wordlen - 1)); $sign_mask_bit = 0x80 << (8 * ($byte_wordlen - 1));
if ($int_value & $sign_mask_bit) { if ($int_value & $sign_mask_bit) {
$int_value = 0 - ($int_value & ($sign_mask_bit - 1)); $int_value = 0 - ($int_value & ($sign_mask_bit - 1));
} }
} }
return $int_value; return $int_value;
}
static function Hex2String($number)
{
$intstring = '';
$hex_word = str_pad($number, 8, '0', STR_PAD_LEFT);
for ($i = 0; $i < 4; $i++) {
sscanf(substr($hex_word, $i*2, 2), "%x", $number);
$intstring = $intstring.chr($number);
}
return $intstring;
} }
static function LittleEndian2String($number, $minbytes=1, $synchsafe=false) { static function LittleEndian2String($number, $minbytes=1, $synchsafe=false) {
$intstring = ''; $intstring = '';
while ($number > 0) { while ($number > 0) {
if ($synchsafe) { if ($synchsafe) {
$intstring = $intstring.chr($number & 127); $intstring = $intstring.chr($number & 127);
$number >>= 7; $number >>= 7;
} else { } else {
$intstring = $intstring.chr($number & 255); $intstring = $intstring.chr($number & 255);
$number >>= 8; $number >>= 8;
} }
} }
return str_pad($intstring, $minbytes, "\x00", STR_PAD_RIGHT); return str_pad($intstring, $minbytes, "\x00", STR_PAD_RIGHT);
} }
static function BigEndian2String($number, $minbytes=1, $synchsafe=false) { static function BigEndian2String($number, $minbytes=1, $synchsafe=false) {
return strrev(phpCTDB::LittleEndian2String($number, $minbytes, $synchsafe)); return strrev(phpCTDB::LittleEndian2String($number, $minbytes, $synchsafe));
} }
static function discid2path($id) static function discid2path($id)
{ {
$err = sscanf($id, "%03d-%04x%04x-%04x%04x-%04x%04x", $tracks, $id1a, $id1b, $id2a, $id2b, $cddbida, $cddbidb); $err = sscanf($id, "%03d-%04x%04x-%04x%04x-%04x%04x", $tracks, $id1a, $id1b, $id2a, $id2b, $cddbida, $cddbidb);
$parsedid = sprintf("%03d-%04x%04x-%04x%04x-%04x%04x", $tracks, $id1a, $id1b, $id2a, $id2b, $cddbida, $cddbidb); $parsedid = sprintf("%03d-%04x%04x-%04x%04x-%04x%04x", $tracks, $id1a, $id1b, $id2a, $id2b, $cddbida, $cddbidb);
@@ -105,85 +284,87 @@ class phpCTDB{
static function unparse_atom($fp, $atom) static function unparse_atom($fp, $atom)
{ {
// printf('unparse_atom(%s)<br>', $atom['name']); // printf('unparse_atom(%s)<br>', $atom['name']);
$offset = ftell($fp); $offset = ftell($fp);
fwrite($fp, phpCTDB::BigEndian2String(0, 4)); fwrite($fp, phpCTDB::BigEndian2String(0, 4));
fwrite($fp, $atom['name']); fwrite($fp, $atom['name']);
if (@$atom['subatoms']) if (@$atom['subatoms'])
foreach ($atom['subatoms'] as $subatom) foreach ($atom['subatoms'] as $subatom)
phpCTDB::unparse_atom($fp, $subatom); phpCTDB::unparse_atom($fp, $subatom);
else if ($atom['value']) else if ($atom['value'])
fwrite($fp, $atom['value']); fwrite($fp, $atom['value']);
else else
die(sprintf("couldn't write long atom %s: size %d", $atom['name'], $atom['size'])); die(sprintf("couldn't write long atom %s: size %d", $atom['name'], $atom['size']));
$pos = ftell($fp); $pos = ftell($fp);
fseek($fp, $offset, SEEK_SET); fseek($fp, $offset, SEEK_SET);
fwrite($fp, phpCTDB::BigEndian2String($pos - $offset, 4)); fwrite($fp, phpCTDB::BigEndian2String($pos - $offset, 4));
fseek($fp, $pos, SEEK_SET); fseek($fp, $pos, SEEK_SET);
} }
function read($offset, $len) function read($offset, $len)
{ {
fseek($this->fp, $offset, SEEK_SET); fseek($this->fp, $offset, SEEK_SET);
return fread($this->fp, $len); return fread($this->fp, $len);
} }
function parse_container_atom($offset, $len) function parse_container_atom($offset, $len)
{ {
// printf('parse_container_atom(%d, %d)<br>', $offset, $len); // printf('parse_container_atom(%d, %d)<br>', $offset, $len);
$atoms = false; $atoms = false;
$fin = $offset + $len; $fin = $offset + $len;
while ($offset < $fin) { while ($offset < $fin) {
fseek($this->fp, $offset, SEEK_SET); fseek($this->fp, $offset, SEEK_SET);
$atom_header = fread($this->fp, 8); $atom_header = fread($this->fp, 8);
$atom_size = phpCTDB::BigEndian2Int(substr($atom_header, 0, 4)); $atom_size = phpCTDB::BigEndian2Int(substr($atom_header, 0, 4));
$atom_name = substr($atom_header, 4, 4); $atom_name = substr($atom_header, 4, 4);
$atom['name'] = $atom_name; $atom['name'] = $atom_name;
$atom['size'] = $atom_size - 8; $atom['size'] = $atom_size - 8;
$atom['offset'] = $offset + 8; $atom['offset'] = $offset + 8;
if ($atom_size - 8 <= 256) if ($atom_size - 8 <= 256)
$atom['value'] = fread($this->fp, $atom_size - 8); $atom['value'] = fread($this->fp, $atom_size - 8);
else else
$atom['value'] = false; $atom['value'] = false;
// echo $len, ':', $offset, ":", $atom_size, ":", $atom_name, '<br>'; // echo $len, ':', $offset, ":", $atom_size, ":", $atom_name, '<br>';
if ($atom_name == 'CTDB' || $atom_name == 'DISC' || $atom_name == 'TOC ' || ($atom_name == 'HEAD' && ($atom_size != 28 || 256 != phpCTDB::BigEndian2Int(substr($atom['value'],0,4))))) if ($atom_name == 'CTDB' || $atom_name == 'DISC' || $atom_name == 'TOC ' || ($atom_name == 'HEAD' && ($atom_size != 28 || 256 != phpCTDB::BigEndian2Int(substr($atom['value'],0,4)))))
{ {
$atom['subatoms'] = $this->parse_container_atom($offset + 8, $atom_size - 8); $atom['subatoms'] = $this->parse_container_atom($offset + 8, $atom_size - 8);
foreach ($atom['subatoms'] as $param) foreach ($atom['subatoms'] as $param)
switch ($param['name']) { switch ($param['name']) {
case 'HEAD': case 'HEAD':
case 'TOC ': case 'TOC ':
case 'CRC ': case 'CRC ':
case 'MBID': case 'USER':
case 'ART ': case 'TOOL':
case 'nam ': case 'MBID':
case 'NPAR': case 'ART ':
case 'CONF': case 'nam ':
case 'TOTL': case 'NPAR':
case 'PAR ': case 'CONF':
$atom[$param['name']] = $param; case 'TOTL':
break; case 'PAR ':
case 'DISC': $atom[$param['name']] = $param;
$atom['discs'][] = $param; break;
break; case 'DISC':
} $atom['discs'][] = $param;
} else break;
$atom['subatoms'] = false; }
switch ($atom_name) } else
{ $atom['subatoms'] = false;
case 'CRC ': switch ($atom_name)
case 'NPAR': {
case 'CONF': case 'CRC ':
case 'TOTL': case 'NPAR':
$atom['int'] = phpCTDB::BigEndian2Int($atom['value']); case 'CONF':
break; case 'TOTL':
} $atom['int'] = phpCTDB::BigEndian2Int($atom['value']);
$offset += $atom_size; break;
$atoms[] = $atom; }
} $offset += $atom_size;
if ($offset > $fin) $atoms[] = $atom;
die(printf("bad atom: offset=%d, fin=%d", $offset, $fin)); }
return $atoms; if ($offset > $fin)
die(printf("bad atom: offset=%d, fin=%d", $offset, $fin));
return $atoms;
} }
} }
?> ?>

View File

@@ -0,0 +1,4 @@
User-agent: *
Disallow: /show.php
Disallow: /top.php
Disallow: /parity/

View File

@@ -1,37 +1,47 @@
<?php <?php
//mb_http_output('UTF-8');
//mb_internal_encoding('UTF-8');
include 'logo_start.php'; include 'logo_start.php';
require_once( 'phpmb/mbQuery.php' ); //require_once( 'phpmb/mbQuery.php' );
require_once( 'phpctdb/ctdb.php' ); require_once( 'phpctdb/ctdb.php' );
$discid = $_GET['discid']; $discid = $_GET['discid'];
$ctdbid = $_GET['ctdbid']; $ctdbid = $_GET['ctdbid'];
$path = phpCTDB::ctdbid2path($discid, $ctdbid); $path = phpCTDB::ctdbid2path($discid, $ctdbid);
$ctdb = new phpCTDB($path);
$disc = $ctdb->db['discs'][0]; $last_modified_time = filemtime($path);
//$id = @$disc['MBID']['value']; $etag = md5_file($path);
$ctdb->ParseTOC();
$artist = @$disc['ART ']['value']; header("Last-Modified: ".gmdate("D, d M Y H:i:s", $last_modified_time)." GMT");
$title = @$disc['nam ']['value']; header("ETag: $etag");
$link = '<a href="http://musicbrainz.org/bare/cdlookup.html?id=' . $ctdb->mbid . '">';
$q = new MusicBrainzQuery(); if (@strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) == $last_modified_time ||
$rf = new ReleaseFilter(); @trim($_SERVER['HTTP_IF_NONE_MATCH']) == $etag) {
$mbrr = false; header("HTTP/1.1 304 Not Modified");
try { exit;
$rresults = $q->getReleases( $rf->discId($ctdb->mbid) );
foreach ( $rresults as $key => $rr ) {
$mbrr = $rr->getRelease();
}
}
catch ( ResponseError $e ) {
// echo $e->getMessage() . " ";
} }
$result = pg_query_params($dbconn, "SELECT * FROM submissions WHERE discid=$1 AND ctdbid=$2", array($discid, (int)phpCTDB::Hex2Int($ctdbid)))
or die('Query failed: ' . pg_last_error());
if (pg_num_rows($result) < 1) die('not found');
if (pg_num_rows($result) > 1) die('not unique');
$record = pg_fetch_array($result);
pg_free_result($result);
$mbid = phpCTDB::toc2mbid($record['fulltoc']);
$mbmeta = phpCTDB::mblookup($mbid);
printf('<center>'); printf('<center>');
if ($mbrr && $mbrr->getAsin()) $imgfound = false;
{ if ($mbmeta)
include 'table_start.php'; foreach ($mbmeta as $mbr)
$imgurl = 'http://ec1.images-amazon.com/images/P/' . $mbrr->getAsin() . '.01.MZZZZZZZ.jpg'; if ($mbr['coverarturl'])
#$imgurl = 'http://images.amazon.com/images/P/' . $mbrr->getAsin() . '.01._SCLZZZZZZZ_PU_PU-5_.jpg'; {
printf('<img src="%s">', $imgurl); if (!$imgfound) include 'table_start.php';
printf('<img src="%s">', $mbr['coverarturl']);
$imgfound = true;
}
if ($imgfound) {
include 'table_end.php'; include 'table_end.php';
printf('<br><br>'); printf('<br><br>');
} }
@@ -39,14 +49,47 @@ include 'table_start.php';
?> ?>
<table border=0 cellspacing=0 cellpadding=6> <table border=0 cellspacing=0 cellpadding=6>
<?php <?php
printf('<tr><td>Full TOC</td><td>%s</td></tr>', $ctdb->fulltoc); printf('<tr><td>Disc ID</td><td>%s</td></tr>', $discid);
printf('<tr><td>Artist</td><td>%s</td></tr>', $artist); printf('<tr><td>CTDB ID</td><td>%s</td></tr>', $ctdbid);
if ($mbrr && $mbrr->getArtist()->getName() != $artist) printf('<tr><td>Musicbrainz ID</td><td><a href="http://musicbrainz.org/bare/cdlookup.html?toc=%s">%s</a> (%s)</tr>', phpCTDB::toc2mbtoc($record['fulltoc']), $mbid, $mbmeta ? count($mbmeta) : "-");
printf('<tr><td>Artist (MB)</td><td>%s</td></tr>', $mbrr->getArtist()->getName()); //printf('<tr><td>Full TOC</td><td>%s</td></tr>', $record['fulltoc']);
printf('<tr><td>Title</td><td>%s</td></tr>', $title); printf('<tr><td colspan=2>');
if ($mbrr && $mbrr->getTitle() != $title) ?>
printf('<tr><td>Title (MB)</td><td>%s</td></tr>', $mbrr->getTitle()); <table width=100% class=classy_table cellpadding=3 cellspacing=0><tr bgcolor=#D0D0D0><th>Track</th><th>Start</th><th>Length</th><th>Start sector</th><th>End sector</th></tr>
printf('<tr><td>MusicbrainzId</td><td>%s%s</a></tr>', $link, $ctdb->mbid); <?php
function TimeToString($time)
{
$frame = $time % 75;
$time = floor($time/75);
$sec = $time % 60;
$time = floor($time/60);
$min = $time;
return sprintf('%d:%02d.%02d',$min,$sec,$frame);
}
$ids = explode(' ', $record['fulltoc']);
for ($tr = 4; $tr < count($ids); $tr++)
{
$trno = $tr + $ids[0] - 4;
$trstart = $ids[$tr] - 150;
$trend = (($tr + 1) < count($ids) ? $ids[$tr+1] : $ids[3]) - 151;
$trstartmsf = TimeToString($trstart);
$trlenmsf = TimeToString($trend + 1 - $trstart);
printf('<tr><td class=td_ar>%d</td><td class=td_ar>%s</td><td class=td_ar>%s</td><td class=td_ar>%d</td><td class=td_ar>%d</td></tr>', $trno, $trstartmsf, $trlenmsf, $trstart, $trend);
}
printf("</table>");
printf('</td></tr>');
if ($record['artist'] != '')
printf('<tr><td>Artist</td><td>%s</td></tr>', $record['artist']);
if ($mbmeta)
foreach ($mbmeta as $mbr)
if ($mbr['artistname'] != $record['artist'])
printf('<tr><td>Artist (MB)</td><td>%s</td></tr>', $mbr['artistname']);
if ($record['title'] != '')
printf('<tr><td>Title</td><td>%s</td></tr>', $record['title']);
if ($mbmeta)
foreach ($mbmeta as $mbr)
if ($mbr['albumname'] != $record['title'])
printf('<tr><td>Title (MB)</td><td>%s</td></tr>', $mbr['albumname']);
?> ?>
</table> </table>
<?php include 'table_end.php'; ?> <?php include 'table_end.php'; ?>

View File

@@ -74,86 +74,27 @@ if ($size == 0) {
return; return;
} }
$dbconn = pg_connect("dbname=ctdb user=ctdb_user")
or die('Could not connect: ' . pg_last_error());
$id = $_POST['id']; $id = $_POST['id'];
$target_path = phpCTDB::discid2path($id); $target_path = phpCTDB::discid2path($id);
@mkdir($target_path, 0777, true); @mkdir($target_path, 0777, true);
$target_file = sprintf("%s/ctdb.bin", $target_path); $target_file = sprintf("%s/ctdb.bin", $target_path);
$ctdb = new phpCTDB($tmpname); $ctdb = new phpCTDB($tmpname);
$ctdb1 = @file_exists($target_file) ? new phpCTDB($target_file) : false; $merging = @file_exists($target_file);
$merging = $ctdb1 ? true : false; $ctdb->ParseTOC();
$record = $ctdb->ctdb2pg($id);
$ftyp['name'] = 'ftyp';
$ftyp['value'] = 'CTDB';
$newctdb['name'] = 'CTDB';
$newhead['name'] = 'HEAD';
$newtotal['name'] = 'TOTL';
$newtotal['value'] = $ctdb1 ? phpCTDB::BigEndian2String($ctdb1->db['HEAD']['TOTL']['int'] + 1,4) : $ctdb->db['HEAD']['TOTL']['value'];
$newhead['subatoms'][] = $newtotal;
$newctdb['subatoms'][] = $newhead;
if ($ctdb1)
foreach ($ctdb1->db['subatoms'] as $disc)
if ($disc['name'] == 'DISC')
{
if ($crc == $disc['CRC ']['value'])
die("duplicate entry");
$newdisc = false;
$newdisc['name'] = 'DISC';
$newdisc['subatoms'][] = $disc['CRC '];
$newdisc['subatoms'][] = $disc['NPAR'];
$newdisc['subatoms'][] = $disc['CONF'];
$newpar['name'] = 'PAR ';
$newpar['value'] = $ctdb1->read($disc['PAR ']['offset'], 16);
$newdisc['subatoms'][] = $newpar;
$newctdb['subatoms'][] = $newdisc;
}
$discs = 0;
foreach ($ctdb->db['subatoms'] as $disc)
if ($disc['name'] == 'DISC')
{
$crc = $disc['CRC ']['value'];
$newdisc = false;
$newdisc['name'] = 'DISC';
$newdisc['subatoms'][] = $disc['CRC '];
$newdisc['subatoms'][] = $disc['NPAR'];
$newdisc['subatoms'][] = $disc['CONF'];
$newpar['name'] = 'PAR ';
$newpar['value'] = $ctdb->read($disc['PAR ']['offset'], 16);
$newdisc['subatoms'][] = $newpar;
$newctdb['subatoms'][] = $newdisc;
$discs++;
}
if ($discs > 1)
die('One disc at a time, please');
if ($discs < 1)
die('No disc records found');
$tname = sprintf("%s/ctdb.tmp", $target_path);
$tfp = fopen($tname, 'wb');
phpCTDB::unparse_atom($tfp,$ftyp);
phpCTDB::unparse_atom($tfp,$newctdb);
fclose($tfp);
unset($ctdb); unset($ctdb);
unset($ctdb1);
$crca = phpCTDB::BigEndian2Int(substr($crc,0,2)); $destname = sprintf("%s/%08x.bin", $target_path, $record['ctdbid']);
$crcb = phpCTDB::BigEndian2Int(substr($crc,2,2));
$destname = sprintf("%s/%04x%04x.bin", $target_path, $crca, $crcb);
if(!move_uploaded_file($tmpname, $destname)) if(!move_uploaded_file($tmpname, $destname))
die('error uploading file ' . $tmpname . ' to ' . $destname); die('error uploading file ' . $tmpname . ' to ' . $destname);
if(!rename($tname,sprintf("%s/ctdb.bin", $target_path))) $subres = pg_insert($dbconn, 'submissions', $record);
die('error uploading file ' . $target_path);
$listfp = fopen("parity/list.txt", 'a'); phpCTDB::pg2ctdb($dbconn, $id);
fwrite($listfp, $destname);
fwrite($listfp, "\n");
fclose($listfp);
if ($merging) if ($merging)
printf("%s has been updated", $id); printf("%s has been updated", $id);

48
CUETools.CTDB/Web/top.php Normal file
View File

@@ -0,0 +1,48 @@
<?php
include 'logo_start.php';
require_once( 'phpmb/mbQuery.php' );
require_once( 'phpctdb/ctdb.php' );
//$dbconn = pg_connect("dbname=ctdb user=ctdb_user")
// or die('Could not connect: ' . pg_last_error());
$count = 20;
$query = 'SELECT * FROM submissions';
$term = ' WHERE ';
$url = '';
$where_discid=@$_GET['discid'];
if ($where_discid != '')
{
$query = $query . $term . "discid='" . pg_escape_string($where_discid) . "'";
$term = ' AND ';
$url = $url . '&discid=' . urlencode($where_discid);
}
$where_artist=@$_GET['artist'];
if ($where_artist != '')
{
$query = $query . $term . "artist ilike '" . pg_escape_string($where_artist) . "'";
$term = ' AND ';
$url = $url . '&artist=' . urlencode($where_artist);
}
if ($term == ' WHERE ')
{
$query = $query . $term . "confidence>=100";
$term = ' AND ';
}
$query = $query . " ORDER BY confidence";
$result = pg_query($query) or die('Query failed: ' . pg_last_error());
$start = @$_GET['start'];
if (pg_num_rows($result) == 0)
die('nothing found');
if ($count > pg_num_rows($result))
$count = pg_num_rows($result);
if ($start == '') $start = pg_num_rows($result) - $count;
printf("<center><h3>Popular discs:</h3>");
include 'list.php';
pg_free_result($result);
printf("</center>");
?>
</body>
</html>