forked from len0rd/rockbox
(Tag) Database v2. this fixes all bugs in the old songdb.pl, should react like
v1, except this has albums with multiple artists support. *prays nothing breaks* :X git-svn-id: svn://svn.rockbox.org/rockbox/trunk@6347 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
parent
de4ef019b9
commit
d41d44f073
2 changed files with 304 additions and 153 deletions
|
|
@ -57,16 +57,21 @@
|
||||||
#define BE32(_x_) _x_
|
#define BE32(_x_) _x_
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define ID3DB_VERSION 1
|
#define SONGENTRY_SIZE (songlen+12+genrelen+4)
|
||||||
|
#define FILEENTRY_SIZE (filelen+12)
|
||||||
|
#define ALBUMENTRY_SIZE (albumlen+4+songarraylen*4)
|
||||||
|
#define ARTISTENTRY_SIZE (artistlen+albumarraylen*4)
|
||||||
|
|
||||||
|
#define ID3DB_VERSION 2
|
||||||
|
|
||||||
static int fd;
|
static int fd;
|
||||||
|
|
||||||
static int
|
static int
|
||||||
songstart, albumstart, artiststart,
|
songstart, albumstart, artiststart, filestart,
|
||||||
songcount, albumcount, artistcount,
|
songcount, albumcount, artistcount, filecount,
|
||||||
songlen, songarraylen,
|
songlen, songarraylen, genrelen, filelen,
|
||||||
albumlen, albumarraylen,
|
albumlen, albumarraylen,
|
||||||
artistlen, initialized = 0;
|
artistlen, rundbdirty,initialized = 0;
|
||||||
|
|
||||||
static int db_play_folder(struct tree_context* c);
|
static int db_play_folder(struct tree_context* c);
|
||||||
static int db_search(struct tree_context* c, char* string);
|
static int db_search(struct tree_context* c, char* string);
|
||||||
|
|
@ -76,7 +81,7 @@ static char searchstring[32];
|
||||||
int db_init(void)
|
int db_init(void)
|
||||||
{
|
{
|
||||||
unsigned int version;
|
unsigned int version;
|
||||||
unsigned int buf[12];
|
unsigned int buf[17];
|
||||||
unsigned char* ptr = (char*)buf;
|
unsigned char* ptr = (char*)buf;
|
||||||
|
|
||||||
fd = open(ROCKBOX_DIR "/rockbox.id3db", O_RDONLY);
|
fd = open(ROCKBOX_DIR "/rockbox.id3db", O_RDONLY);
|
||||||
|
|
@ -84,7 +89,7 @@ int db_init(void)
|
||||||
DEBUGF("Failed opening database\n");
|
DEBUGF("Failed opening database\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
read(fd, buf, 48);
|
read(fd, buf, 68);
|
||||||
|
|
||||||
if (ptr[0] != 'R' ||
|
if (ptr[0] != 'R' ||
|
||||||
ptr[1] != 'D' ||
|
ptr[1] != 'D' ||
|
||||||
|
|
@ -94,29 +99,35 @@ int db_init(void)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
version = BE32(buf[0]) & 0xff;
|
version = BE32(buf[0])&0xFF;
|
||||||
if (version != ID3DB_VERSION)
|
if (version != ID3DB_VERSION)
|
||||||
{
|
{
|
||||||
splash(HZ,true,"Unsupported database version %d!", version);
|
splash(HZ,true,"Unsupported database version %d!", version);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
songstart = BE32(buf[1]);
|
artiststart = BE32(buf[1]);
|
||||||
songcount = BE32(buf[2]);
|
albumstart = BE32(buf[2]);
|
||||||
songlen = BE32(buf[3]);
|
songstart = BE32(buf[3]);
|
||||||
|
filestart = BE32(buf[4]);
|
||||||
|
|
||||||
|
artistcount = BE32(buf[5]);
|
||||||
|
albumcount = BE32(buf[6]);
|
||||||
|
songcount = BE32(buf[7]);
|
||||||
|
filecount = BE32(buf[8]);
|
||||||
|
|
||||||
|
artistlen = BE32(buf[9]);
|
||||||
|
albumlen = BE32(buf[10]);
|
||||||
|
songlen = BE32(buf[11]);
|
||||||
|
genrelen = BE32(buf[12]);
|
||||||
|
filelen = BE32(buf[13]);
|
||||||
|
songarraylen = BE32(buf[14]);
|
||||||
|
albumarraylen = BE32(buf[15]);
|
||||||
|
rundbdirty = BE32(buf[16]);
|
||||||
|
|
||||||
albumstart = BE32(buf[4]);
|
if (songstart > filestart ||
|
||||||
albumcount = BE32(buf[5]);
|
albumstart > songstart ||
|
||||||
albumlen = BE32(buf[6]);
|
artiststart > albumstart)
|
||||||
songarraylen = BE32(buf[7]);
|
|
||||||
|
|
||||||
artiststart = BE32(buf[8]);
|
|
||||||
artistcount = BE32(buf[9]);
|
|
||||||
artistlen = BE32(buf[10]);
|
|
||||||
albumarraylen = BE32(buf[11]);
|
|
||||||
|
|
||||||
if (songstart > albumstart ||
|
|
||||||
albumstart > artiststart)
|
|
||||||
{
|
{
|
||||||
splash(HZ,true,"Corrupt ID3 database!");
|
splash(HZ,true,"Corrupt ID3 database!");
|
||||||
return -1;
|
return -1;
|
||||||
|
|
@ -150,7 +161,7 @@ int db_load(struct tree_context* c)
|
||||||
c->dentry_size = 2;
|
c->dentry_size = 2;
|
||||||
c->dirfull = false;
|
c->dirfull = false;
|
||||||
|
|
||||||
DEBUGF("db_load(%d, %x, %d)\n", table, extra, c->firstpos);
|
DEBUGF("db_load() table: %d extra: 0x%x firstpos: %d\n", table, extra, c->firstpos);
|
||||||
|
|
||||||
if (!table) {
|
if (!table) {
|
||||||
table = root;
|
table = root;
|
||||||
|
|
@ -166,7 +177,7 @@ int db_load(struct tree_context* c)
|
||||||
str(LANG_ID3DB_ALBUMS),
|
str(LANG_ID3DB_ALBUMS),
|
||||||
str(LANG_ID3DB_SONGS),
|
str(LANG_ID3DB_SONGS),
|
||||||
str(LANG_ID3DB_SEARCH)};
|
str(LANG_ID3DB_SEARCH)};
|
||||||
|
DEBUGF("dbload table root\n");
|
||||||
for (i=0; i < 4; i++) {
|
for (i=0; i < 4; i++) {
|
||||||
strcpy(nbuf, labels[i]);
|
strcpy(nbuf, labels[i]);
|
||||||
dptr[0] = (unsigned long)nbuf;
|
dptr[0] = (unsigned long)nbuf;
|
||||||
|
|
@ -186,7 +197,7 @@ int db_load(struct tree_context* c)
|
||||||
char* labels[] = { str(LANG_ID3DB_SEARCH_ARTISTS),
|
char* labels[] = { str(LANG_ID3DB_SEARCH_ARTISTS),
|
||||||
str(LANG_ID3DB_SEARCH_ALBUMS),
|
str(LANG_ID3DB_SEARCH_ALBUMS),
|
||||||
str(LANG_ID3DB_SEARCH_SONGS)};
|
str(LANG_ID3DB_SEARCH_SONGS)};
|
||||||
|
DEBUGF("dbload table search\n");
|
||||||
for (i=0; i < 3; i++) {
|
for (i=0; i < 3; i++) {
|
||||||
strcpy(nbuf, labels[i]);
|
strcpy(nbuf, labels[i]);
|
||||||
dptr[0] = (unsigned long)nbuf;
|
dptr[0] = (unsigned long)nbuf;
|
||||||
|
|
@ -201,6 +212,7 @@ int db_load(struct tree_context* c)
|
||||||
case searchartists:
|
case searchartists:
|
||||||
case searchalbums:
|
case searchalbums:
|
||||||
case searchsongs:
|
case searchsongs:
|
||||||
|
DEBUGF("dbload table searchsongs/searchartists/searchalbums\n");
|
||||||
i = db_search(c, searchstring);
|
i = db_search(c, searchstring);
|
||||||
c->dirlength = c->filesindir = i;
|
c->dirlength = c->filesindir = i;
|
||||||
if (c->dirfull) {
|
if (c->dirfull) {
|
||||||
|
|
@ -214,26 +226,28 @@ int db_load(struct tree_context* c)
|
||||||
return i;
|
return i;
|
||||||
|
|
||||||
case allsongs:
|
case allsongs:
|
||||||
offset = songstart + c->firstpos * (songlen + 12);
|
DEBUGF("dbload table allsongs\n");
|
||||||
|
offset = songstart + c->firstpos * SONGENTRY_SIZE;
|
||||||
itemcount = songcount;
|
itemcount = songcount;
|
||||||
stringlen = songlen;
|
stringlen = songlen;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case allalbums:
|
case allalbums:
|
||||||
offset = albumstart +
|
DEBUGF("dbload table allalbums\n");
|
||||||
c->firstpos * (albumlen + 4 + songarraylen * 4);
|
offset = albumstart + c->firstpos * ALBUMENTRY_SIZE;
|
||||||
itemcount = albumcount;
|
itemcount = albumcount;
|
||||||
stringlen = albumlen;
|
stringlen = albumlen;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case allartists:
|
case allartists:
|
||||||
offset = artiststart +
|
DEBUGF("dbload table allartists\n");
|
||||||
c->firstpos * (artistlen + albumarraylen * 4);
|
offset = artiststart + c->firstpos * ARTISTENTRY_SIZE;
|
||||||
itemcount = artistcount;
|
itemcount = artistcount;
|
||||||
stringlen = artistlen;
|
stringlen = artistlen;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case albums4artist:
|
case albums4artist:
|
||||||
|
DEBUGF("dbload table albums4artist\n");
|
||||||
/* 'extra' is offset to the artist */
|
/* 'extra' is offset to the artist */
|
||||||
safeplacelen = albumarraylen * 4;
|
safeplacelen = albumarraylen * 4;
|
||||||
safeplace = (void*)(end_of_nbuf - safeplacelen);
|
safeplace = (void*)(end_of_nbuf - safeplacelen);
|
||||||
|
|
@ -252,6 +266,7 @@ int db_load(struct tree_context* c)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case songs4album:
|
case songs4album:
|
||||||
|
DEBUGF("dbload table songs4album\n");
|
||||||
/* 'extra' is offset to the album */
|
/* 'extra' is offset to the album */
|
||||||
safeplacelen = songarraylen * 4;
|
safeplacelen = songarraylen * 4;
|
||||||
safeplace = (void*)(end_of_nbuf - safeplacelen);
|
safeplace = (void*)(end_of_nbuf - safeplacelen);
|
||||||
|
|
@ -261,8 +276,10 @@ int db_load(struct tree_context* c)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
#ifdef LITTLE_ENDIAN
|
#ifdef LITTLE_ENDIAN
|
||||||
for (i=0; i<songarraylen; i++)
|
for (i=0; i<songarraylen; i++) {
|
||||||
safeplace[i] = BE32(safeplace[i]);
|
safeplace[i] = BE32(safeplace[i]);
|
||||||
|
DEBUGF("db_load songs4album song %d: 0x%x\n",i,safeplace[i]);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
offset = safeplace[0];
|
offset = safeplace[0];
|
||||||
itemcount = songarraylen;
|
itemcount = songarraylen;
|
||||||
|
|
@ -270,8 +287,9 @@ int db_load(struct tree_context* c)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case songs4artist:
|
case songs4artist:
|
||||||
|
DEBUGF("dbload table songs4artist\n");
|
||||||
/* 'extra' is offset to the artist, used as filter */
|
/* 'extra' is offset to the artist, used as filter */
|
||||||
offset = songstart + c->firstpos * (songlen + 12);
|
offset = songstart + c->firstpos * SONGENTRY_SIZE;
|
||||||
itemcount = songcount;
|
itemcount = songcount;
|
||||||
stringlen = songlen;
|
stringlen = songlen;
|
||||||
break;
|
break;
|
||||||
|
|
@ -318,13 +336,16 @@ int db_load(struct tree_context* c)
|
||||||
case songs4album:
|
case songs4album:
|
||||||
case songs4artist:
|
case songs4artist:
|
||||||
rc = read(fd, intbuf, 12);
|
rc = read(fd, intbuf, 12);
|
||||||
|
skip = SONGENTRY_SIZE-stringlen-12; /* skip the rest of the song info */
|
||||||
if (rc < 12) {
|
if (rc < 12) {
|
||||||
DEBUGF("%d read(%d) returned %d\n", i, 12, rc);
|
DEBUGF("%d read(%d) returned %d\n", i, 12, rc);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
/* continue to next song if wrong artist */
|
/* continue to next song if wrong artist */
|
||||||
if (table == songs4artist && (int)BE32(intbuf[0]) != extra)
|
if (table == songs4artist && (int)BE32(intbuf[0]) != extra) {
|
||||||
|
lseek(fd, skip, SEEK_CUR);
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
/* save offset of filename */
|
/* save offset of filename */
|
||||||
dptr[1] = BE32(intbuf[2]);
|
dptr[1] = BE32(intbuf[2]);
|
||||||
|
|
@ -400,19 +421,19 @@ static int db_search(struct tree_context* c, char* string)
|
||||||
case searchartists:
|
case searchartists:
|
||||||
start = artiststart;
|
start = artiststart;
|
||||||
count = artistcount;
|
count = artistcount;
|
||||||
size = artistlen + albumarraylen * 4;
|
size = ARTISTENTRY_SIZE;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case searchalbums:
|
case searchalbums:
|
||||||
start = albumstart;
|
start = albumstart;
|
||||||
count = albumcount;
|
count = albumcount;
|
||||||
size = albumlen + 4 + songarraylen * 4;
|
size = ALBUMENTRY_SIZE;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case searchsongs:
|
case searchsongs:
|
||||||
start = songstart;
|
start = songstart;
|
||||||
count = songcount;
|
count = songcount;
|
||||||
size = songlen + 12;
|
size = SONGENTRY_SIZE;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
@ -497,7 +518,7 @@ int db_enter(struct tree_context* c)
|
||||||
case searchalbums:
|
case searchalbums:
|
||||||
/* virtual <all albums> entry points to the artist,
|
/* virtual <all albums> entry points to the artist,
|
||||||
all normal entries point to the album */
|
all normal entries point to the album */
|
||||||
if (newextra >= artiststart)
|
if (newextra < albumstart)
|
||||||
c->currtable = songs4artist;
|
c->currtable = songs4artist;
|
||||||
else
|
else
|
||||||
c->currtable = songs4album;
|
c->currtable = songs4album;
|
||||||
|
|
|
||||||
360
tools/songdb.pl
360
tools/songdb.pl
|
|
@ -12,6 +12,8 @@ my $dir;
|
||||||
my $strip;
|
my $strip;
|
||||||
my $verbose;
|
my $verbose;
|
||||||
my $help;
|
my $help;
|
||||||
|
my $dirisalbum;
|
||||||
|
my $dirisalbumname;
|
||||||
|
|
||||||
while($ARGV[0]) {
|
while($ARGV[0]) {
|
||||||
if($ARGV[0] eq "--db") {
|
if($ARGV[0] eq "--db") {
|
||||||
|
|
@ -33,6 +35,14 @@ while($ARGV[0]) {
|
||||||
$verbose = 1;
|
$verbose = 1;
|
||||||
shift @ARGV;
|
shift @ARGV;
|
||||||
}
|
}
|
||||||
|
elsif($ARGV[0] eq "--dirisalbum") {
|
||||||
|
$dirisalbum = 1;
|
||||||
|
shift @ARGV;
|
||||||
|
}
|
||||||
|
elsif($ARGV[0] eq "--dirisalbumname") {
|
||||||
|
$dirisalbumname = 1;
|
||||||
|
shift @ARGV;
|
||||||
|
}
|
||||||
elsif($ARGV[0] eq "--help" or ($ARGV[0] eq "-h")) {
|
elsif($ARGV[0] eq "--help" or ($ARGV[0] eq "-h")) {
|
||||||
$help = 1;
|
$help = 1;
|
||||||
shift @ARGV;
|
shift @ARGV;
|
||||||
|
|
@ -50,11 +60,13 @@ my %filename;
|
||||||
my %lcartists;
|
my %lcartists;
|
||||||
my %lcalbums;
|
my %lcalbums;
|
||||||
|
|
||||||
my $dbver = 1;
|
my %dir2albumname;
|
||||||
|
|
||||||
|
my $dbver = 2;
|
||||||
|
|
||||||
if(! -d $dir or $help) {
|
if(! -d $dir or $help) {
|
||||||
print "'$dir' is not a directory\n" if ($dir ne "" and ! -d $dir);
|
print "'$dir' is not a directory\n" if ($dir ne "" and ! -d $dir);
|
||||||
print "songdb --path <dir> [--db <file>] [--strip <path>] [--verbose] [--help]\n";
|
print "songdb --path <dir> [--dirisalbum] [--dirisalbumname] [--db <file>] [--strip <path>] [--verbose] [--help]\n";
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -140,6 +152,7 @@ sub dodir {
|
||||||
# YEAR
|
# YEAR
|
||||||
|
|
||||||
# don't index songs without tags
|
# don't index songs without tags
|
||||||
|
# um. yes we do.
|
||||||
if (not defined $$id3{'ARTIST'} and
|
if (not defined $$id3{'ARTIST'} and
|
||||||
not defined $$id3{'ALBUM'} and
|
not defined $$id3{'ALBUM'} and
|
||||||
not defined $$id3{'TITLE'})
|
not defined $$id3{'TITLE'})
|
||||||
|
|
@ -178,29 +191,56 @@ sub dodir {
|
||||||
|
|
||||||
# fallback names
|
# fallback names
|
||||||
$$id3{'ARTIST'} = "<no artist tag>" if ($$id3{'ARTIST'} eq "");
|
$$id3{'ARTIST'} = "<no artist tag>" if ($$id3{'ARTIST'} eq "");
|
||||||
# Fall back on the directory name (not full path dirname),
|
# Fall back on the directory name (not full path dirname),
|
||||||
# if no album tag
|
# if no album tag
|
||||||
$$id3{'ALBUM'} = (split m[/], $dir)[-1] if ($$id3{'ALBUM'} eq "");
|
if ($dirisalbum) {
|
||||||
#if that doesn't work, fall back.
|
if($dir2albumname{$dir} eq "") {
|
||||||
|
$dir2albumname{$dir} = $$id3{'ALBUM'};
|
||||||
|
}
|
||||||
|
elsif($dir2albumname{$dir} ne $$id3{'ALBUM'}) {
|
||||||
|
$dir2albumname{$dir} = (split m[/], $dir)[-1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
# if no directory
|
||||||
|
if ($dirisalbumname) {
|
||||||
|
$$id3{'ALBUM'} = (split m[/], $dir)[-1] if ($$id3{'ALBUM'} eq "");
|
||||||
|
}
|
||||||
$$id3{'ALBUM'} = "<no album tag>" if ($$id3{'ALBUM'} eq "");
|
$$id3{'ALBUM'} = "<no album tag>" if ($$id3{'ALBUM'} eq "");
|
||||||
# fall back on basename of the file if no title tag.
|
# fall back on basename of the file if no title tag.
|
||||||
my $base;
|
my $base;
|
||||||
($base = $f) =~ s/\.\w+$//;
|
($base = $f) =~ s/\.\w+$//;
|
||||||
$$id3{'TITLE'} = $base if ($$id3{'TITLE'} eq "");
|
$$id3{'TITLE'} = $base if ($$id3{'TITLE'} eq "");
|
||||||
|
|
||||||
# Append dirname, to handle multi-artist albums
|
# Append dirname, to handle multi-artist albums
|
||||||
$$id3{'DIR'} = $dir;
|
$$id3{'DIR'} = $dir;
|
||||||
my $albumid = $id3->{'ALBUM'}."___".$$id3{'DIR'};
|
my $albumid;
|
||||||
|
if ($dirisalbum) {
|
||||||
if($id3->{'ALBUM'}."___".$id3->{'DIR'} ne "<no album tag>___<no artist tag>") {
|
$albumid=$$id3{'DIR'};
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$albumid= $id3->{'ALBUM'}."___".$$id3{'DIR'};
|
||||||
|
}
|
||||||
|
#printf "album id: %s\n", $albumid;
|
||||||
|
|
||||||
|
# if($id3->{'ALBUM'}."___".$id3->{'DIR'} ne "<no album tag>___<no artist tag>") {
|
||||||
my $num = ++$albums{$albumid};
|
my $num = ++$albums{$albumid};
|
||||||
if($num > $maxsongperalbum) {
|
if($num > $maxsongperalbum) {
|
||||||
$maxsongperalbum = $num;
|
$maxsongperalbum = $num;
|
||||||
$longestalbum = $albumid;
|
$longestalbum = $albumid;
|
||||||
}
|
}
|
||||||
$album2songs{$albumid}{$$id3{TITLE}} = $id3;
|
$album2songs{$albumid}{$$id3{TITLE}} = $id3;
|
||||||
$artist2albums{$$id3{ARTIST}}{$$id3{ALBUM}} = $id3;
|
if($dirisalbum) {
|
||||||
}
|
$artist2albums{$$id3{ARTIST}}{$$id3{DIR}} = $id3;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$artist2albums{$$id3{ARTIST}}{$$id3{ALBUM}} = $id3;
|
||||||
|
}
|
||||||
|
# }
|
||||||
|
}
|
||||||
|
|
||||||
|
if($dirisalbum and $dir2albumname{$dir} eq "") {
|
||||||
|
$dir2albumname{$dir} = (split m[/], $dir)[-1];
|
||||||
|
printf "%s\n", $dir2albumname{$dir};
|
||||||
}
|
}
|
||||||
|
|
||||||
# extractdirs filters out only subdirectories from all given entries
|
# extractdirs filters out only subdirectories from all given entries
|
||||||
|
|
@ -217,17 +257,24 @@ dodir($dir);
|
||||||
print "\n";
|
print "\n";
|
||||||
|
|
||||||
print "File name table\n" if ($verbose);
|
print "File name table\n" if ($verbose);
|
||||||
my $fc;
|
|
||||||
for(sort keys %entries) {
|
for(sort keys %entries) {
|
||||||
printf(" %s\n", $_) if ($verbose);
|
printf(" %s\n", $_) if ($verbose);
|
||||||
$fc += length($_)+1;
|
my $l = length($_);
|
||||||
|
if($l > $maxfilelen) {
|
||||||
|
$maxfilelen = $l;
|
||||||
|
$longestfilename = $_;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
$maxfilelen++; # include zero termination byte
|
||||||
|
while($maxfilelen&3) {
|
||||||
|
$maxfilelen++;
|
||||||
|
}
|
||||||
|
|
||||||
my $maxsonglen = 0;
|
my $maxsonglen = 0;
|
||||||
my $sc;
|
my $sc;
|
||||||
print "\nSong title table\n" if ($verbose);
|
print "\nSong title table\n" if ($verbose);
|
||||||
|
|
||||||
for(sort {$entries{$a}->{'TITLE'} cmp $entries{$b}->{'TITLE'}} keys %entries) {
|
for(sort {uc($entries{$a}->{'TITLE'}) cmp uc($entries{$b}->{'TITLE'})} keys %entries) {
|
||||||
printf(" %s\n", $entries{$_}->{'TITLE'} ) if ($verbose);
|
printf(" %s\n", $entries{$_}->{'TITLE'} ) if ($verbose);
|
||||||
my $l = length($entries{$_}->{'TITLE'});
|
my $l = length($entries{$_}->{'TITLE'});
|
||||||
if($l > $maxsonglen) {
|
if($l > $maxsonglen) {
|
||||||
|
|
@ -244,8 +291,8 @@ my $maxartistlen = 0;
|
||||||
print "\nArtist table\n" if ($verbose);
|
print "\nArtist table\n" if ($verbose);
|
||||||
my $i=0;
|
my $i=0;
|
||||||
my %artistcount;
|
my %artistcount;
|
||||||
for(sort keys %artists) {
|
for(sort {uc($a) cmp uc($b)} keys %artists) {
|
||||||
printf(" %s\n", $_) if ($verbose);
|
printf(" %s: %d\n", $_, $i) if ($verbose);
|
||||||
$artistcount{$_}=$i++;
|
$artistcount{$_}=$i++;
|
||||||
my $l = length($_);
|
my $l = length($_);
|
||||||
if($l > $maxartistlen) {
|
if($l > $maxartistlen) {
|
||||||
|
|
@ -256,6 +303,7 @@ for(sort keys %artists) {
|
||||||
$l = scalar keys %{$artist2albums{$_}};
|
$l = scalar keys %{$artist2albums{$_}};
|
||||||
if ($l > $maxalbumsperartist) {
|
if ($l > $maxalbumsperartist) {
|
||||||
$maxalbumsperartist = $l;
|
$maxalbumsperartist = $l;
|
||||||
|
$longestartistalbum = $_;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$maxartistlen++; # include zero termination byte
|
$maxartistlen++; # include zero termination byte
|
||||||
|
|
@ -263,12 +311,22 @@ while($maxartistlen&3) {
|
||||||
$maxartistlen++;
|
$maxartistlen++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($verbose) {
|
print "\nGenre table\n" if ($verbose);
|
||||||
print "\nGenre table\n";
|
for(sort keys %genres) {
|
||||||
for(sort keys %genres) {
|
my $l = length($_);
|
||||||
printf(" %s\n", $_);
|
if($l > $maxgenrelen) {
|
||||||
}
|
$maxgenrelen = $l;
|
||||||
|
$longestgenrename = $_;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$maxgenrelen++; #include zero termination byte
|
||||||
|
while($maxgenrelen&3) {
|
||||||
|
$maxgenrelen++;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if ($verbose) {
|
||||||
print "\nYear table\n";
|
print "\nYear table\n";
|
||||||
for(sort keys %years) {
|
for(sort keys %years) {
|
||||||
printf(" %s\n", $_);
|
printf(" %s\n", $_);
|
||||||
|
|
@ -279,14 +337,32 @@ print "\nAlbum table\n" if ($verbose);
|
||||||
my $maxalbumlen = 0;
|
my $maxalbumlen = 0;
|
||||||
my %albumcount;
|
my %albumcount;
|
||||||
$i=0;
|
$i=0;
|
||||||
for(sort keys %albums) {
|
my @albumssort;
|
||||||
|
if($dirisalbum) {
|
||||||
|
@albumssort = sort {uc($dir2albumname{$a}) cmp uc($dir2albumname{$b})} keys %albums;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
@albumssort = sort {uc($a) cmp uc($b)} keys %albums;
|
||||||
|
}
|
||||||
|
for(@albumssort) {
|
||||||
my @moo=split(/___/, $_);
|
my @moo=split(/___/, $_);
|
||||||
printf(" %s\n", $moo[0]) if ($verbose);
|
printf(" %s\n", $moo[0]) if ($verbose);
|
||||||
$albumcount{$_} = $i++;
|
$albumcount{$_} = $i++;
|
||||||
my $l = length($moo[0]);
|
my $l;
|
||||||
|
if($dirisalbum) {
|
||||||
|
$l = length($dir2albumname{$_});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$l = length($moo[0]);
|
||||||
|
}
|
||||||
if($l > $maxalbumlen) {
|
if($l > $maxalbumlen) {
|
||||||
$maxalbumlen = $l;
|
$maxalbumlen = $l;
|
||||||
$longestalbumname = $moo[0];
|
if($dirisalbum) {
|
||||||
|
$longestalbumname = $dir2albumname{$_};
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$longestalbumname = $moo[0];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$maxalbumlen++; # include zero termination byte
|
$maxalbumlen++; # include zero termination byte
|
||||||
|
|
@ -296,6 +372,14 @@ while($maxalbumlen&3) {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
sub dumpshort {
|
||||||
|
my ($num)=@_;
|
||||||
|
|
||||||
|
# print "int: $num\n";
|
||||||
|
|
||||||
|
print DB pack "n", $num;
|
||||||
|
}
|
||||||
|
|
||||||
sub dumpint {
|
sub dumpint {
|
||||||
my ($num)=@_;
|
my ($num)=@_;
|
||||||
|
|
||||||
|
|
@ -311,111 +395,124 @@ if (!scalar keys %entries) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($db) {
|
if ($db) {
|
||||||
my $songentrysize = $maxsonglen + 12;
|
my $songentrysize = $maxsonglen + 12 + $maxgenrelen+ 4;
|
||||||
my $albumentrysize = $maxalbumlen + 4 + $maxsongperalbum*4;
|
my $albumentrysize = $maxalbumlen + 4 + $maxsongperalbum*4;
|
||||||
my $artistentrysize = $maxartistlen + $maxalbumsperartist*4;
|
my $artistentrysize = $maxartistlen + $maxalbumsperartist*4;
|
||||||
|
my $fileentrysize = $maxfilelen + 12;
|
||||||
|
|
||||||
printf "Number of artists : %d\n", scalar keys %artists;
|
printf "Number of artists : %d\n", scalar keys %artists;
|
||||||
printf "Number of albums : %d\n", scalar keys %albums;
|
printf "Number of albums : %d\n", scalar keys %albums;
|
||||||
printf "Number of songs : %d\n", scalar keys %entries;
|
printf "Number of songs / files : %d\n", scalar keys %entries;
|
||||||
print "Max artist length : $maxartistlen ($longestartist)\n";
|
print "Max artist length : $maxartistlen ($longestartist)\n";
|
||||||
print "Max album length : $maxalbumlen ($longestalbumname)\n";
|
print "Max album length : $maxalbumlen ($longestalbumname)\n";
|
||||||
print "Max song length : $maxsonglen ($longestsong)\n";
|
print "Max song length : $maxsonglen ($longestsong)\n";
|
||||||
print "Max songs per album: $maxsongperalbum ($longestalbum)\n";
|
print "Max songs per album : $maxsongperalbum ($longestalbum)\n";
|
||||||
|
print "Max albums per artist: $maxalbumsperartist ($longestartistalbum)\n";
|
||||||
|
print "Max genre length : $maxgenrelen ($longestgenrename)\n";
|
||||||
|
print "Max file length : $maxfilelen ($longestfilename)\n";
|
||||||
print "Database version: $dbver\n" if ($verbose);
|
print "Database version: $dbver\n" if ($verbose);
|
||||||
|
print "Song Entry Size : $songentrysize ($maxsonglen + 12 + $maxgenrelen + 4)\n" if ($verbose);
|
||||||
|
print "Album Entry Size: $albumentrysize ($maxalbumlen + 4 + $maxsongperalbum * 4)\n" if ($verbose);
|
||||||
|
print "Artist Entry Size: $artistentrysize ($maxartistlen + $maxalbumsperartist * 4)\n" if ($verbose);
|
||||||
|
print "File Entry Size: $fileentrysize ($maxfilelen + 12)\n" if ($verbose);
|
||||||
|
|
||||||
|
|
||||||
open(DB, ">$db") || die "couldn't make $db";
|
open(DB, ">$db") || die "couldn't make $db";
|
||||||
binmode(DB);
|
binmode(DB);
|
||||||
printf DB "RDB%c", $dbver;
|
printf DB "RDB%c", $dbver;
|
||||||
|
|
||||||
$pathindex = 48; # paths always start at index 48
|
$pathindex = 68; # paths always start at index 68
|
||||||
|
|
||||||
$songindex = $pathindex + $fc; # fc is size of all paths
|
$artistindex = $pathindex;
|
||||||
$songindex++ while ($songindex & 3); # align to 32 bits
|
|
||||||
|
|
||||||
dumpint($songindex); # file position index of song table
|
|
||||||
dumpint(scalar(keys %entries)); # number of songs
|
|
||||||
dumpint($maxsonglen); # length of song name field
|
|
||||||
|
|
||||||
# set total size of song title table
|
# set total size of song title table
|
||||||
$sc = scalar(keys %entries) * $songentrysize;
|
$sc = scalar(keys %entries) * $songentrysize;
|
||||||
|
|
||||||
$albumindex = $songindex + $sc; # sc is size of all songs
|
|
||||||
dumpint($albumindex); # file position index of album table
|
|
||||||
dumpint(scalar(keys %albums)); # number of albums
|
|
||||||
dumpint($maxalbumlen); # length of album name field
|
|
||||||
dumpint($maxsongperalbum); # number of entries in songs-per-album array
|
|
||||||
|
|
||||||
my $ac = scalar(keys %albums) * $albumentrysize;
|
my $ac = scalar(keys %albums) * $albumentrysize;
|
||||||
|
my $arc = scalar(keys %artists) * $artistentrysize;
|
||||||
$artistindex = $albumindex + $ac; # ac is size of all albums
|
$albumindex = $artistindex + $arc; # arc is size of all artists
|
||||||
|
$songindex = $albumindex + $ac; # ac is size of all albums
|
||||||
|
my $fileindex = $songindex + $sc; # sc is size of all songs
|
||||||
|
|
||||||
dumpint($artistindex); # file position index of artist table
|
dumpint($artistindex); # file position index of artist table
|
||||||
|
dumpint($albumindex); # file position index of album table
|
||||||
|
dumpint($songindex); # file position index of song table
|
||||||
|
dumpint($fileindex); # file position index of file table
|
||||||
dumpint(scalar(keys %artists)); # number of artists
|
dumpint(scalar(keys %artists)); # number of artists
|
||||||
|
dumpint(scalar(keys %albums)); # number of albums
|
||||||
|
dumpint(scalar(keys %entries)); # number of songs
|
||||||
|
dumpint(scalar(keys %entries)); # number of files
|
||||||
dumpint($maxartistlen); # length of artist name field
|
dumpint($maxartistlen); # length of artist name field
|
||||||
|
dumpint($maxalbumlen); # length of album name field
|
||||||
|
dumpint($maxsonglen); # length of song name field
|
||||||
|
dumpint($maxgenrelen); #length of genre field
|
||||||
|
dumpint($maxfilelen); # length of file field
|
||||||
|
dumpint($maxsongperalbum); # number of entries in songs-per-album array
|
||||||
dumpint($maxalbumsperartist); # number of entries in albums-per-artist array
|
dumpint($maxalbumsperartist); # number of entries in albums-per-artist array
|
||||||
|
dumpint(-1); # rundb dirty
|
||||||
|
|
||||||
my $l=0;
|
#### TABLE of artists ###
|
||||||
|
# name of artist1
|
||||||
|
# pointers to albums of artist1
|
||||||
|
|
||||||
#### TABLE of file names ###
|
for (sort {uc($a) cmp uc($b)} keys %artists) {
|
||||||
# path1
|
my $artist = $_;
|
||||||
|
my $str = $_."\x00" x ($maxartistlen - length($_));
|
||||||
|
print DB $str;
|
||||||
|
|
||||||
|
for (sort keys %{$artist2albums{$artist}}) {
|
||||||
|
my $id3 = $artist2albums{$artist}{$_};
|
||||||
|
my $a;
|
||||||
|
if($dirisalbum) {
|
||||||
|
$a = $albumcount{"$$id3{'DIR'}"} * $albumentrysize;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$a = $albumcount{"$$id3{'ALBUM'}___$$id3{'DIR'}"} * $albumentrysize;
|
||||||
|
}
|
||||||
|
dumpint($a + $albumindex);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (scalar keys %{$artist2albums{$artist}} .. $maxalbumsperartist-1) {
|
||||||
|
print DB "\x00\x00\x00\x00";
|
||||||
|
}
|
||||||
|
|
||||||
my %filenamepos;
|
|
||||||
for $f (sort keys %entries) {
|
|
||||||
printf DB ("%s\x00", $f);
|
|
||||||
$filenamepos{$f}= $l;
|
|
||||||
$l += length($f)+1;
|
|
||||||
}
|
|
||||||
while ($l & 3) {
|
|
||||||
print DB "\x00";
|
|
||||||
$l++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#### TABLE of songs ###
|
### Build song offset info.
|
||||||
# title of song1
|
my $offset = $songindex;
|
||||||
# pointer to artist of song1
|
for(sort {uc($entries{$a}->{'TITLE'}) cmp uc($entries{$b}->{'TITLE'})} keys %entries) {
|
||||||
# pointer to album of song1
|
my $id3 = $entries{$_};
|
||||||
# pointer to filename of song1
|
$$id3{'songoffset'} = $offset;
|
||||||
|
$offset += $songentrysize;
|
||||||
my $offset = $songindex;
|
}
|
||||||
for(sort {uc($entries{$a}->{'TITLE'}) cmp uc($entries{$b}->{'TITLE'})} keys %entries) {
|
|
||||||
my $f = $_;
|
|
||||||
my $id3 = $entries{$f};
|
|
||||||
my $t = $id3->{'TITLE'};
|
|
||||||
my $str = $t."\x00" x ($maxsonglen- length($t));
|
|
||||||
|
|
||||||
print DB $str; # title
|
|
||||||
|
|
||||||
my $a = $artistcount{$id3->{'ARTIST'}} * $artistentrysize;
|
|
||||||
dumpint($a + $artistindex); # pointer to artist of this song
|
|
||||||
|
|
||||||
$a = $albumcount{"$$id3{ALBUM}___$$id3{DIR}"} * $albumentrysize;
|
|
||||||
dumpint($a + $albumindex); # pointer to album of this song
|
|
||||||
|
|
||||||
# pointer to filename of this song
|
|
||||||
dumpint($filenamepos{$f} + $pathindex);
|
|
||||||
|
|
||||||
$$id3{'songoffset'} = $offset;
|
|
||||||
$offset += $songentrysize;
|
|
||||||
}
|
|
||||||
|
|
||||||
#### TABLE of albums ###
|
#### TABLE of albums ###
|
||||||
# name of album1
|
# name of album1
|
||||||
# pointers to artists of album1
|
# pointers to artists of album1
|
||||||
# pointers to songs on album1
|
# pointers to songs on album1
|
||||||
|
|
||||||
for(sort {uc($a) cmp uc($b)} keys %albums) {
|
for(@albumssort) {
|
||||||
my $albumid = $_;
|
my $albumid = $_;
|
||||||
my @moo=split(/___/, $_);
|
my @moo=split(/___/, $_);
|
||||||
my $t = $moo[0];
|
my $t;
|
||||||
my $str = $t."\x00" x ($maxalbumlen - length($t));
|
my $str;
|
||||||
print DB $str;
|
if($dirisalbum) {
|
||||||
|
$t = $dir2albumname{$albumid};
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$t = $moo[0];
|
||||||
|
}
|
||||||
|
$str = $t."\x00" x ($maxalbumlen - length($t));
|
||||||
|
print DB $str;
|
||||||
|
|
||||||
my @songlist = keys %{$album2songs{$albumid}};
|
my @songlist = keys %{$album2songs{$albumid}};
|
||||||
my $id3 = $album2songs{$albumid}{$songlist[0]};
|
my $id3 = $album2songs{$albumid}{$songlist[0]};
|
||||||
|
|
||||||
|
#printf "(d) albumid: %s artist: %s\n",$albumid, $id3->{'ARTIST'};
|
||||||
|
|
||||||
my $aoffset = $artistcount{$id3->{'ARTIST'}} * $artistentrysize;
|
my $aoffset = $artistcount{$id3->{'ARTIST'}} * $artistentrysize;
|
||||||
dumpint($aoffset + $artistindex); # pointer to artist of this album
|
dumpint($aoffset + $artistindex); # pointer to artist of this album
|
||||||
|
|
||||||
if (defined $id3->{'TRACKNUM'}) {
|
if (defined $id3->{'TRACKNUM'}) {
|
||||||
@songlist = sort {
|
@songlist = sort {
|
||||||
$album2songs{$albumid}{$a}->{'TRACKNUM'} <=>
|
$album2songs{$albumid}{$a}->{'TRACKNUM'} <=>
|
||||||
|
|
@ -435,26 +532,59 @@ if ($db) {
|
||||||
print DB "\x00\x00\x00\x00";
|
print DB "\x00\x00\x00\x00";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#### TABLE of artists ###
|
|
||||||
# name of artist1
|
|
||||||
# pointers to albums of artist1
|
|
||||||
|
|
||||||
for (sort {uc($a) cmp uc($b)} keys %artists) {
|
#### Build filename offset info
|
||||||
my $artist = $_;
|
my $l=$fileindex;
|
||||||
my $str = $_."\x00" x ($maxartistlen - length($_));
|
my %filenamepos;
|
||||||
|
for $f (sort keys %entries) {
|
||||||
|
$filenamepos{$f}= $l;
|
||||||
|
$l += $fileentrysize;
|
||||||
|
}
|
||||||
|
|
||||||
|
#### TABLE of songs ###
|
||||||
|
# title of song1
|
||||||
|
# pointer to artist of song1
|
||||||
|
# pointer to album of song1
|
||||||
|
# pointer to filename of song1
|
||||||
|
|
||||||
|
for(sort {uc($entries{$a}->{'TITLE'}) cmp uc($entries{$b}->{'TITLE'})} keys %entries) {
|
||||||
|
my $f = $_;
|
||||||
|
my $id3 = $entries{$f};
|
||||||
|
my $t = $id3->{'TITLE'};
|
||||||
|
my $g = $id3->{'GENRE'};
|
||||||
|
my $str = $t."\x00" x ($maxsonglen- length($t));
|
||||||
|
|
||||||
|
print DB $str; # title
|
||||||
|
$str = $g."\x00" x ($maxgenrelen - length($g));
|
||||||
|
|
||||||
|
my $a = $artistcount{$id3->{'ARTIST'}} * $artistentrysize;
|
||||||
|
dumpint($a + $artistindex); # pointer to artist of this song
|
||||||
|
|
||||||
|
if($dirisalbum) {
|
||||||
|
$a = $albumcount{"$$id3{DIR}"} * $albumentrysize;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$a = $albumcount{"$$id3{ALBUM}___$$id3{DIR}"} * $albumentrysize;
|
||||||
|
}
|
||||||
|
dumpint($a + $albumindex); # pointer to album of this song
|
||||||
|
|
||||||
|
# pointer to filename of this song
|
||||||
|
dumpint($filenamepos{$f});
|
||||||
|
print DB $str; #genre
|
||||||
|
dumpshort(-1);
|
||||||
|
dumpshort($id3->{'YEAR'});
|
||||||
|
}
|
||||||
|
|
||||||
|
#### TABLE of file names ###
|
||||||
|
# path1
|
||||||
|
|
||||||
|
for $f (sort keys %entries) {
|
||||||
|
my $str = $f."\x00" x ($maxfilelen- length($f));
|
||||||
|
my $id3 = $entries{$f};
|
||||||
print DB $str;
|
print DB $str;
|
||||||
|
dumpint(0);
|
||||||
for (sort keys %{$artist2albums{$artist}}) {
|
dumpint($id3->{'songoffset'});
|
||||||
my $id3 = $artist2albums{$artist}{$_};
|
dumpint(-1);
|
||||||
my $a = $albumcount{"$$id3{'ALBUM'}___$$id3{'DIR'}"} * $albumentrysize;
|
|
||||||
dumpint($a + $albumindex);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (scalar keys %{$artist2albums{$artist}} .. $maxalbumsperartist-1) {
|
|
||||||
print DB "\x00\x00\x00\x00";
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
close(DB);
|
close(DB);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue