Add daap.songcodectype, normalize daap.songformat and daap.songdescription.
This commit is contained in:
parent
33e6284639
commit
622171c1b1
|
@ -27,12 +27,10 @@
|
|||
#
|
||||
|
||||
#
|
||||
# This is quite rudimentary. Obvious TODO list is as follows:
|
||||
# This is quite rudimentary but handles most cases quite well.
|
||||
#
|
||||
# - Speedup the streaming start.
|
||||
# TODO-list:
|
||||
# - Make the guessing of the wav length reliable.
|
||||
# - Implement Apple Lossless, somehow, someone, PLEASE! It could be done
|
||||
# by integrating QuickTime 6.5 codecs to MPlayer (currently 6.3)
|
||||
# - Possibly implement some kind of caching.
|
||||
#
|
||||
# I'll probably never have time for above things, but now it should
|
||||
|
@ -71,23 +69,33 @@ $SIG{PIPE} = 'IGNORE';
|
|||
if ($off < 0) {
|
||||
usage();
|
||||
}
|
||||
if ($fn =~ m/^..*\.wav/i) {
|
||||
if ($fn =~ m/^..*\.wav$/i) {
|
||||
passthru_proc($fn, $off, $forgelen);
|
||||
} elsif ($fn =~ m/^..*\.wave/i) {
|
||||
} elsif ($fn =~ m/^..*\.wave$/i) {
|
||||
passthru_proc($fn, $off, $forgelen);
|
||||
} elsif ($fn =~ m/^..*\.flac/i) {
|
||||
} elsif ($fn =~ m/^..*\.flac$/i) {
|
||||
flac_proc($fn, $off, $forgelen);
|
||||
} elsif ($fn =~ m/^..*\.fla/i) {
|
||||
} elsif ($fn =~ m/^..*\.fla$/i) {
|
||||
flac_proc($fn, $off, $forgelen);
|
||||
} elsif ($fn =~ m/^..*\.mp3/i) {
|
||||
} elsif ($fn =~ m/^..*\.mp4$/i) {
|
||||
mpeg4_proc($fn, $off, $forgelen);
|
||||
} elsif ($fn =~ m/^..*\.m4a$/i) {
|
||||
mpeg4_proc($fn, $off, $forgelen);
|
||||
} elsif ($fn =~ m/^..*\.m4p$/i) {
|
||||
mpeg4_proc($fn, $off, $forgelen);
|
||||
} elsif ($fn =~ m/^..*\.aac$/i) {
|
||||
mpeg4_proc($fn, $off, $forgelen);
|
||||
} elsif ($fn =~ m/^..*\.shn$/i) {
|
||||
ffmpeg_proc($fn, $off, $forgelen);
|
||||
} elsif ($fn =~ m/^..*\.mpg/i) {
|
||||
} elsif ($fn =~ m/^..*\.mp3$/i) {
|
||||
ffmpeg_proc($fn, $off, $forgelen);
|
||||
} elsif ($fn =~ m/^..*\.ogg/i) {
|
||||
} elsif ($fn =~ m/^..*\.mpg$/i) {
|
||||
ffmpeg_proc($fn, $off, $forgelen);
|
||||
} elsif ($fn =~ m/^..*\.avi/i) {
|
||||
} elsif ($fn =~ m/^..*\.ogg$/i) {
|
||||
ffmpeg_proc($fn, $off, $forgelen);
|
||||
} elsif ($fn =~ m/^..*\.au/i) {
|
||||
} elsif ($fn =~ m/^..*\.avi$/i) {
|
||||
ffmpeg_proc($fn, $off, $forgelen);
|
||||
} elsif ($fn =~ m/^..*\.au$/i) {
|
||||
ffmpeg_proc($fn, $off, $forgelen);
|
||||
} else {
|
||||
mplayer_proc($fn, $off, $forgelen);
|
||||
|
@ -513,3 +521,54 @@ sub mplayer_proc
|
|||
close($w);
|
||||
unlink($tf);
|
||||
}
|
||||
|
||||
sub mpeg4_proc
|
||||
{
|
||||
my ($fn) = shift;
|
||||
my ($off) = shift;
|
||||
my ($forgelen) = shift;
|
||||
my ($f) = undef;
|
||||
my ($hdr) = undef;
|
||||
my ($r) = undef;
|
||||
|
||||
if (open($f, "< $fn")) {
|
||||
my ($rl) = sysread($f, $hdr, 512);
|
||||
close($f);
|
||||
if ($rl != 512) {
|
||||
return undef;
|
||||
}
|
||||
} else {
|
||||
return undef;
|
||||
}
|
||||
|
||||
#
|
||||
# This detection is really rudimentary, but seems to
|
||||
# do the job for now.
|
||||
#
|
||||
if (index($hdr, "Halac") >= 0) {
|
||||
$r = alac_proc($fn, $off, $forgelen);
|
||||
} else {
|
||||
$r = ffmpeg_proc($fn, $off, $forgelen);
|
||||
}
|
||||
|
||||
return $r;
|
||||
}
|
||||
|
||||
sub alac_proc
|
||||
{
|
||||
my ($fn) = shift;
|
||||
my ($off) = shift;
|
||||
my ($forgelen) = shift;
|
||||
my ($r) = undef;
|
||||
my ($w) = undef;
|
||||
my ($pid);
|
||||
|
||||
$pid = open2($r, $w, 'alac', "$fn");
|
||||
wav_loop($r, $off, undef); # Ignore $forgelen
|
||||
close($r);
|
||||
close($w);
|
||||
if (waitpid($pid, WNOHANG) <= 0) {
|
||||
kill(SIGKILL, $pid);
|
||||
waitpid($pid, 0);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -732,6 +732,29 @@ int db_dmap_add_string(char *where, char *tag, char *value) {
|
|||
return 8 + strlen(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* add a literal chunk of data to a dmap block
|
||||
*
|
||||
* \param where where to serialize the dmap info
|
||||
* \param tag what four byte tag
|
||||
* \param value what to put there
|
||||
* \param size how much data to cram in there
|
||||
*/
|
||||
int db_dmap_add_literal(char *where, char *tag, char *value, int size) {
|
||||
/* tag */
|
||||
memcpy(where,tag,4);
|
||||
|
||||
/* length */
|
||||
where[4]=(size >> 24) & 0xFF;
|
||||
where[5]=(size >> 16) & 0xFF;
|
||||
where[6]=(size >> 8) & 0xFF;
|
||||
where[7]=size & 0xFF;
|
||||
|
||||
memcpy(where+8,value,size);
|
||||
return 8+size;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* add a container type to a dmap block (type 0x0C)
|
||||
*
|
||||
|
|
|
@ -171,6 +171,7 @@ extern int db_dmap_add_char(char *where, char *tag, char value);
|
|||
extern int db_dmap_add_short(char *where, char *tag, short value);
|
||||
extern int db_dmap_add_int(char *where, char *tag, int value);
|
||||
extern int db_dmap_add_string(char *where, char *tag, char *value);
|
||||
extern int db_dmap_add_literal(char *where, char *tag, char *value, int size);
|
||||
extern int db_dmap_add_container(char *where, char *tag, int size);
|
||||
|
||||
/* Holdover functions from old db interface...
|
||||
|
|
|
@ -244,6 +244,8 @@ int db_sqlite_init(int reload) {
|
|||
db_sqlite_reload=1;
|
||||
db_sqlite_exec(E_DBG,"DROP INDEX idx_path");
|
||||
db_sqlite_exec(E_FATAL,"DELETE FROM songs");
|
||||
} else {
|
||||
db_sqlite_exec(E_FATAL,"VACUUM");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -435,7 +437,8 @@ int db_sqlite_add(MP3FILE *pmp3) {
|
|||
"%d," // db_timestamp
|
||||
"%d," // disabled
|
||||
"%d," // sample_count
|
||||
"0)", // force_update
|
||||
"0," // force_update
|
||||
"'%q')", // codectype
|
||||
STR(pmp3->path),
|
||||
STR(pmp3->fname),
|
||||
STR(pmp3->title),
|
||||
|
@ -468,7 +471,9 @@ int db_sqlite_add(MP3FILE *pmp3) {
|
|||
pmp3->time_modified,
|
||||
pmp3->time_played,
|
||||
pmp3->db_timestamp,
|
||||
pmp3->disabled);
|
||||
pmp3->disabled,
|
||||
pmp3->sample_count,
|
||||
STR(pmp3->codectype));
|
||||
|
||||
if(err == SQLITE_CONSTRAINT) {
|
||||
/* probably because the path already exists... */
|
||||
|
@ -529,7 +534,8 @@ int db_sqlite_update(MP3FILE *pmp3) {
|
|||
"bpm=%d," // bpm
|
||||
"compilation=%d," // compilation
|
||||
"rating=%d," // rating
|
||||
"sample_count=%d" // sample_count
|
||||
"sample_count=%d," // sample_count
|
||||
"codectype='%q'" // codec
|
||||
" WHERE path='%q'",
|
||||
STR(pmp3->title),
|
||||
STR(pmp3->artist),
|
||||
|
@ -557,6 +563,7 @@ int db_sqlite_update(MP3FILE *pmp3) {
|
|||
pmp3->compilation,
|
||||
pmp3->rating,
|
||||
pmp3->sample_count,
|
||||
STR(pmp3->codectype),
|
||||
pmp3->path);
|
||||
|
||||
if((db_sqlite_in_scan) && (!db_sqlite_reload)) {
|
||||
|
@ -1021,7 +1028,9 @@ int db_sqlite_get_size(DBQUERYINFO *pinfo, char **valarray) {
|
|||
if(db_wantsmeta(pinfo->meta, metaContainerItemId))
|
||||
/* mcti */
|
||||
size += 12;
|
||||
|
||||
if(ISSTR(valarray[37]) && db_wantsmeta(pinfo->meta, metaSongCodecType))
|
||||
/* ascd */
|
||||
size += 12;
|
||||
return size;
|
||||
break;
|
||||
|
||||
|
@ -1146,6 +1155,8 @@ int db_sqlite_build_dmap(DBQUERYINFO *pinfo, char **valarray, char *presult, int
|
|||
current += db_dmap_add_char(current,"asur",(char)atoi(valarray[25]));
|
||||
if(valarray[18] && atoi(valarray[18]) && db_wantsmeta(pinfo->meta, metaSongYear))
|
||||
current += db_dmap_add_short(current,"asyr",(short)atoi(valarray[18]));
|
||||
if(ISSTR(valarray[37]) && db_wantsmeta(pinfo->meta, metaSongCodecType))
|
||||
current += db_dmap_add_literal(current,"ascd",valarray[37],4);
|
||||
if(db_wantsmeta(pinfo->meta, metaContainerItemId))
|
||||
current += db_dmap_add_int(current,"mcti",atoi(valarray[0]));
|
||||
return 0;
|
||||
|
@ -1205,6 +1216,7 @@ void db_sqlite_build_mp3file(char **valarray, MP3FILE *pmp3) {
|
|||
pmp3->disabled=db_sqlite_atoi(valarray[34]);
|
||||
pmp3->sample_count=db_sqlite_atoi(valarray[35]);
|
||||
pmp3->force_update=db_sqlite_atoi(valarray[36]);
|
||||
pmp3->codectype=db_sqlite_strdup(valarray[37]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1289,6 +1301,7 @@ void db_sqlite_dispose_item(MP3FILE *pmp3) {
|
|||
MAYBEFREE(pmp3->grouping);
|
||||
MAYBEFREE(pmp3->description);
|
||||
MAYBEFREE(pmp3->url);
|
||||
MAYBEFREE(pmp3->codectype);
|
||||
free(pmp3);
|
||||
}
|
||||
|
||||
|
@ -1411,6 +1424,71 @@ char *db_sqlite_upgrade_scripts[] = {
|
|||
"REPLACE INTO config VALUES('rescan',NULL,1);\n"
|
||||
"UPDATE config SET value=2 WHERE term='version';\n",
|
||||
|
||||
/* version 2 -> version 3 */
|
||||
/* add daap.songcodectype, normalize daap.songformat and daap.songdescription */
|
||||
"drop index idx_path;\n"
|
||||
"create temp table tempsongs as select * from songs;\n"
|
||||
"drop table songs;\n"
|
||||
"CREATE TABLE songs (\n"
|
||||
" id INTEGER PRIMARY KEY NOT NULL,\n"
|
||||
" path VARCHAR(4096) UNIQUE NOT NULL,\n"
|
||||
" fname VARCHAR(255) NOT NULL,\n"
|
||||
" title VARCHAR(1024) DEFAULT NULL,\n"
|
||||
" artist VARCHAR(1024) DEFAULT NULL,\n"
|
||||
" album VARCHAR(1024) DEFAULT NULL,\n"
|
||||
" genre VARCHAR(255) DEFAULT NULL,\n"
|
||||
" comment VARCHAR(4096) DEFAULT NULL,\n"
|
||||
" type VARCHAR(255) DEFAULT NULL,\n"
|
||||
" composer VARCHAR(1024) DEFAULT NULL,\n"
|
||||
" orchestra VARCHAR(1024) DEFAULT NULL,\n"
|
||||
" conductor VARCHAR(1024) DEFAULT NULL,\n"
|
||||
" grouping VARCHAR(1024) DEFAULT NULL,\n"
|
||||
" url VARCHAR(1024) DEFAULT NULL,\n"
|
||||
" bitrate INTEGER DEFAULT 0,\n"
|
||||
" samplerate INTEGER DEFAULT 0,\n"
|
||||
" song_length INTEGER DEFAULT 0,\n"
|
||||
" file_size INTEGER DEFAULT 0,\n"
|
||||
" year INTEGER DEFAULT 0,\n"
|
||||
" track INTEGER DEFAULT 0,\n"
|
||||
" total_tracks INTEGER DEFAULT 0,\n"
|
||||
" disc INTEGER DEFAULT 0,\n"
|
||||
" total_discs INTEGER DEFAULT 0,\n"
|
||||
" bpm INTEGER DEFAULT 0,\n"
|
||||
" compilation INTEGER DEFAULT 0,\n"
|
||||
" rating INTEGER DEFAULT 0,\n"
|
||||
" play_count INTEGER DEFAULT 0,\n"
|
||||
" data_kind INTEGER DEFAULT 0,\n"
|
||||
" item_kind INTEGER DEFAULT 0,\n"
|
||||
" description INTEGER DEFAULT 0,\n"
|
||||
" time_added INTEGER DEFAULT 0,\n"
|
||||
" time_modified INTEGER DEFAULT 0,\n"
|
||||
" time_played INTEGER DEFAULT 0,\n"
|
||||
" db_timestamp INTEGER DEFAULT 0,\n"
|
||||
" disabled INTEGER DEFAULT 0,\n"
|
||||
" sample_count INTEGER DEFAULT 0,\n"
|
||||
" force_update INTEGER DEFAULT 0,\n"
|
||||
" codectype VARCHAR(5) DEFAULT NULL\n"
|
||||
");\n"
|
||||
"begin transaction;\n"
|
||||
"insert into songs select *,NULL from tempsongs;\n"
|
||||
"commit transaction;\n"
|
||||
"update songs set type=lower(type);\n"
|
||||
"update songs set type='m4a' where type='aac' or type='mp4';\n"
|
||||
"update songs set type='flac' where type='fla';\n"
|
||||
"update songs set description='AAC audio file' where type='m4a';\n"
|
||||
"update songs set description='MPEG audio file' where type='mp3';\n"
|
||||
"update songs set description='WAV audio file' where type='wav';\n"
|
||||
"update songs set description='Playlist URL' where type='pls';\n"
|
||||
"update songs set description='Ogg Vorbis audio file' where type='ogg';\n"
|
||||
"update songs set description='FLAC audio file' where type='flac';\n"
|
||||
"update songs set codectype='mp4a' where type='m4a' or type='m4p';\n"
|
||||
"update songs set codectype='mpeg' where type='mp3';\n"
|
||||
"update songs set codectype='ogg' where type='ogg';\n"
|
||||
"update songs set codectype='flac' where type='flac';\n"
|
||||
"update songs set force_update=1 where type='m4a';\n" /* look for alac */
|
||||
"create index idx_path on songs(path);\n"
|
||||
"drop table tempsongs;\n"
|
||||
"update config set value=3 where term='version';\n",
|
||||
NULL /* No more versions! */
|
||||
};
|
||||
|
||||
|
|
|
@ -264,6 +264,20 @@ char *scan_winamp_genre[] = {
|
|||
|
||||
#define WINAMP_GENRE_UNKNOWN 148
|
||||
|
||||
/*
|
||||
* Typedefs
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
char *suffix;
|
||||
int (*tags)(char* file, MP3FILE* pmp3);
|
||||
int (*files)(char* file, MP3FILE* pmp3);
|
||||
char *type; /* daap.songformat */
|
||||
char *codectype; /* song.codectype */
|
||||
char *description; /* daap.songdescription */
|
||||
} TAGHANDLER;
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Forwards
|
||||
|
@ -287,6 +301,8 @@ static void scan_music_file(char *path, struct dirent *pde, struct stat *psb);
|
|||
static int scan_decode_mp3_frame(unsigned char *frame, SCAN_FRAMEINFO *pfi);
|
||||
static time_t mac_to_unix_time(int t);
|
||||
|
||||
static TAGHANDLER *scan_gethandler(char *type);
|
||||
|
||||
#ifdef OGGVORBIS
|
||||
extern int scan_get_oggfileinfo(char *filename, MP3FILE *pmp3);
|
||||
#endif
|
||||
|
@ -296,35 +312,46 @@ extern int scan_get_flacfileinfo(char *filename, MP3FILE *pmp3);
|
|||
extern int scan_get_flactags(char *filename, MP3FILE *pmp3);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Typedefs
|
||||
|
||||
/* For known types, I'm gong to use the "official" apple
|
||||
* daap.songformat, daap.songdescription, and daap.songcodecsubtype.
|
||||
* If I we don't have "official" ones, we can make them up the
|
||||
* way we currently are: using extension or whatver.
|
||||
*
|
||||
* This means that you can test to see if something is, say, an un-drmed
|
||||
* aac file by just testing for ->type "m4a", rather than checking every different
|
||||
* flavor of file extension.
|
||||
*
|
||||
* NOTE: Although they are represented here as strings, the codectype is *really*
|
||||
* an unsigned short. So when it gets serialized, it gets serialized as a short int.
|
||||
* If you put something other than 3 or 4 characters as your codectype, you'll see
|
||||
* strange results.
|
||||
*
|
||||
* FIXME: url != pls -- this method of dispatching handlers based on file type
|
||||
* is completely wrong. There needs to be a separate type that gets carried around
|
||||
* with it, at least outside the database that says where the info CAME FROM.
|
||||
*
|
||||
* This system is broken, and won't work with something like a .cue file
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
char* suffix;
|
||||
int (*tags)(char* file, MP3FILE* pmp3);
|
||||
int (*files)(char* file, MP3FILE* pmp3);
|
||||
} taghandler;
|
||||
|
||||
static taghandler taghandlers[] = {
|
||||
{ "aac", scan_get_aactags, scan_get_aacfileinfo },
|
||||
{ "mp4", scan_get_aactags, scan_get_aacfileinfo },
|
||||
{ "m4a", scan_get_aactags, scan_get_aacfileinfo },
|
||||
{ "m4p", scan_get_aactags, scan_get_aacfileinfo },
|
||||
{ "mp3", scan_get_mp3tags, scan_get_mp3fileinfo },
|
||||
{ "wav", scan_get_nultags, scan_get_wavfileinfo },
|
||||
{ "url", scan_get_nultags, scan_get_urlfileinfo },
|
||||
static TAGHANDLER taghandlers[] = {
|
||||
{ "aac", scan_get_aactags, scan_get_aacfileinfo, "m4a", "mp4a", "AAC audio file" },
|
||||
{ "mp4", scan_get_aactags, scan_get_aacfileinfo, "m4a", "mp4a", "AAC audio file" },
|
||||
{ "m4a", scan_get_aactags, scan_get_aacfileinfo, "m4a", "mp4a", "AAC audio file" },
|
||||
{ "m4p", scan_get_aactags, scan_get_aacfileinfo, "m4p", "mp4a", "AAC audio file" },
|
||||
{ "mp3", scan_get_mp3tags, scan_get_mp3fileinfo, "mp3", "mpeg", "MPEG audio file" },
|
||||
{ "wav", scan_get_nultags, scan_get_wavfileinfo, "wav", "wav", "WAV audio file" },
|
||||
{ "url", scan_get_nultags, scan_get_urlfileinfo, "pls", NULL, "Playlist URL" },
|
||||
{ "pls", scan_get_nultags, scan_get_urlfileinfo, "pls", NULL, "Playlist URL" },
|
||||
#ifdef OGGVORBIS
|
||||
{ "ogg", scan_get_nultags, scan_get_oggfileinfo },
|
||||
{ "ogg", scan_get_nultags, scan_get_oggfileinfo, "ogg", "ogg", "Ogg Vorbis audio file" },
|
||||
#endif
|
||||
#ifdef FLAC
|
||||
{ "flac", scan_get_flactags, scan_get_flacfileinfo },
|
||||
{ "fla", scan_get_flactags, scan_get_flacfileinfo },
|
||||
{ "flac", scan_get_flactags, scan_get_flacfileinfo, "flac","flac", "FLAC audio file" },
|
||||
{ "fla", scan_get_flactags, scan_get_flacfileinfo, "flac","flac", "FLAC audio file" },
|
||||
#endif
|
||||
{ NULL, 0 }
|
||||
{ NULL, NULL, NULL, NULL, NULL, NULL }
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Convert mac time to unix time (different epochs)
|
||||
*
|
||||
|
@ -520,6 +547,7 @@ void scan_static_playlist(char *path, struct dirent *pde, struct stat *psb) {
|
|||
DPRINTF(E_WARN,L_SCAN|L_PL,"Done processing playlist\n");
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
* scan_music_file
|
||||
*
|
||||
|
@ -528,6 +556,10 @@ void scan_static_playlist(char *path, struct dirent *pde, struct stat *psb) {
|
|||
void scan_music_file(char *path, struct dirent *pde, struct stat *psb) {
|
||||
MP3FILE mp3file;
|
||||
char mp3_path[PATH_MAX];
|
||||
char *current=NULL;
|
||||
char *type;
|
||||
TAGHANDLER *ptaghandler;
|
||||
char fdescr[50];
|
||||
|
||||
snprintf(mp3_path,sizeof(mp3_path),"%s/%s",path,pde->d_name);
|
||||
|
||||
|
@ -537,14 +569,38 @@ void scan_music_file(char *path, struct dirent *pde, struct stat *psb) {
|
|||
memset((void*)&mp3file,0,sizeof(mp3file));
|
||||
mp3file.path=strdup(mp3_path);
|
||||
mp3file.fname=strdup(pde->d_name);
|
||||
if(strlen(pde->d_name) > 4)
|
||||
mp3file.type=strdup(strrchr(pde->d_name, '.') + 1);
|
||||
if(strlen(pde->d_name) > 4) {
|
||||
type = strrchr(pde->d_name, '.') + 1;
|
||||
if(type) {
|
||||
/* see if there is "official" format and info for it */
|
||||
ptaghandler=scan_gethandler(type);
|
||||
if(ptaghandler) {
|
||||
/* yup, use the official format */
|
||||
mp3file.type=strdup(ptaghandler->type);
|
||||
if(ptaghandler->description)
|
||||
mp3file.description=strdup(ptaghandler->description);
|
||||
|
||||
/* FIXME: assumes that st_ino is a u_int_32
|
||||
DWB: also assumes that the library is contained entirely within
|
||||
one file system
|
||||
*/
|
||||
mp3file.id=psb->st_ino;
|
||||
if(ptaghandler->codectype)
|
||||
mp3file.codectype=strdup(ptaghandler->codectype);
|
||||
|
||||
DPRINTF(E_DBG,L_SCAN,"Codec type: %s\n",mp3file.codectype);
|
||||
} else {
|
||||
/* just dummy up songformat, codectype and description */
|
||||
mp3file.type=strdup(type);
|
||||
|
||||
/* upper-case types cause some problems */
|
||||
current=mp3file.type;
|
||||
while(*current) {
|
||||
*current=tolower(*current);
|
||||
current++;
|
||||
}
|
||||
|
||||
sprintf(fdescr,"%s audio file",mp3file.type);
|
||||
mp3file.description = strdup(fdescr);
|
||||
/* we'll just dodge the codectype */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Do the tag lookup here */
|
||||
if(!scan_gettags(mp3file.path,&mp3file) &&
|
||||
|
@ -559,12 +615,11 @@ void scan_music_file(char *path, struct dirent *pde, struct stat *psb) {
|
|||
mp3file.time_added=psb->st_ctime;
|
||||
mp3file.time_modified=psb->st_mtime;
|
||||
|
||||
// server_side_convert_set(&mp3file);
|
||||
|
||||
DPRINTF(E_DBG,L_SCAN," Date Added: %d\n",mp3file.time_added);
|
||||
|
||||
DPRINTF(E_DBG,L_SCAN," Codec: %s\n",mp3file.codectype);
|
||||
|
||||
db_add(&mp3file);
|
||||
// pl_eval(&mp3file); /* FIXME: move to db_add? */
|
||||
} else {
|
||||
DPRINTF(E_WARN,L_SCAN,"Skipping %s - scan_gettags failed\n",pde->d_name);
|
||||
}
|
||||
|
@ -720,27 +775,37 @@ int scan_get_aactags(char *file, MP3FILE *pmp3) {
|
|||
}
|
||||
|
||||
|
||||
/*
|
||||
* scan_gettags
|
||||
/**
|
||||
* fetch the taghandler for this file type
|
||||
*/
|
||||
TAGHANDLER *scan_gethandler(char *type) {
|
||||
TAGHANDLER *phdl = taghandlers;
|
||||
|
||||
while((phdl->suffix) && (strcasecmp(phdl->suffix,type)))
|
||||
phdl++;
|
||||
|
||||
if(phdl->suffix)
|
||||
return phdl;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Dispatch the appropriate handler to get specific tag metainfomation
|
||||
*
|
||||
* Scan an mp3 file for id3 tags using libid3tag
|
||||
* \param file file to get tag info for
|
||||
* \param pmp3 mp3 file struct to fill info into
|
||||
*/
|
||||
int scan_gettags(char *file, MP3FILE *pmp3) {
|
||||
taghandler *hdl;
|
||||
TAGHANDLER *hdl;
|
||||
|
||||
/* dispatch to appropriate tag handler */
|
||||
for(hdl = taghandlers ; hdl->suffix ; ++hdl)
|
||||
if(!strcasecmp(hdl->suffix, pmp3->type))
|
||||
break;
|
||||
|
||||
if(hdl->tags)
|
||||
hdl = scan_gethandler(pmp3->type);
|
||||
if(hdl && hdl->tags)
|
||||
return hdl->tags(file,pmp3);
|
||||
|
||||
/* maybe this is an extension that we've manually
|
||||
* specified in the config file, but don't know how
|
||||
* to extract tags from. Ogg, maybe.
|
||||
*/
|
||||
|
||||
/* otherwise, it's a file type we don't understand yet */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -760,9 +825,6 @@ int scan_get_mp3tags(char *file, MP3FILE *pmp3) {
|
|||
char *tmp;
|
||||
int got_numeric_genre;
|
||||
|
||||
if(strcasecmp(pmp3->type,"mp3")) /* can't get tags for non-mp3 */
|
||||
return 0;
|
||||
|
||||
pid3file=id3_file_open(file,ID3_FILE_MODE_READONLY);
|
||||
if(!pid3file) {
|
||||
DPRINTF(E_WARN,L_SCAN,"Cannot open %s\n",file);
|
||||
|
@ -963,28 +1025,27 @@ int scan_freetags(MP3FILE *pmp3) {
|
|||
MAYBEFREE(pmp3->conductor);
|
||||
MAYBEFREE(pmp3->grouping);
|
||||
MAYBEFREE(pmp3->description);
|
||||
MAYBEFREE(pmp3->codectype);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* scan_get_fileinfo
|
||||
*
|
||||
/**
|
||||
* Dispatch to actual file info handlers
|
||||
*
|
||||
* \param file file to read file metainfo for
|
||||
* \param pmp3 struct to stuff with info gleaned
|
||||
*/
|
||||
int scan_get_fileinfo(char *file, MP3FILE *pmp3) {
|
||||
FILE *infile;
|
||||
off_t file_size;
|
||||
|
||||
taghandler *hdl;
|
||||
TAGHANDLER *hdl;
|
||||
|
||||
/* dispatch to appropriate tag handler */
|
||||
for(hdl = taghandlers ; hdl->suffix ; ++hdl)
|
||||
if(!strcasecmp(hdl->suffix, pmp3->type))
|
||||
break;
|
||||
|
||||
if(hdl->files)
|
||||
hdl = scan_gethandler(pmp3->type);
|
||||
if(hdl && hdl->files)
|
||||
return hdl->files(file,pmp3);
|
||||
|
||||
/* a file we don't know anything about... ogg or aiff maybe */
|
||||
|
@ -1148,6 +1209,7 @@ int scan_get_aacfileinfo(char *file, MP3FILE *pmp3) {
|
|||
|
||||
pmp3->file_size=file_size;
|
||||
|
||||
|
||||
/* now, hunt for the mvhd atom */
|
||||
atom_offset = aac_drilltoatom(infile, "moov:mvhd", &atom_length);
|
||||
if(atom_offset != -1) {
|
||||
|
@ -1180,6 +1242,17 @@ int scan_get_aacfileinfo(char *file, MP3FILE *pmp3) {
|
|||
|
||||
pmp3->bitrate = 0;
|
||||
|
||||
|
||||
/* see if it is aac or alac */
|
||||
atom_offset = aac_drilltoatom(infile, "moov:trak:mdia:minf:stbl:stsd:alac", &atom_length);
|
||||
if(atom_offset != -1) {
|
||||
/* should we still pull samplerate, etc from the this atom? */
|
||||
if(pmp3->codectype) {
|
||||
free(pmp3->codectype);
|
||||
}
|
||||
pmp3->codectype=strdup("alac");
|
||||
}
|
||||
|
||||
/* Get the sample rate from the 'mp4a' atom (timescale). This is also
|
||||
found in the 'mdhd' atom which is a bit closer but we need to
|
||||
navigate to the 'mp4a' atom anyways to get to the 'esds' atom. */
|
||||
|
@ -1207,6 +1280,14 @@ int scan_get_aacfileinfo(char *file, MP3FILE *pmp3) {
|
|||
fread((void *)&bit_rate, sizeof(unsigned int), 1, infile);
|
||||
|
||||
pmp3->bitrate = ntohl(bit_rate) / 1000;
|
||||
|
||||
DPRINTF(E_DBG,L_SCAN,"esds bitrate: %d\n",pmp3->bitrate);
|
||||
|
||||
if(pmp3->bitrate > 320) {
|
||||
DPRINTF(E_LOG,L_SCAN,"Capping AAC bitrate. Please report this "
|
||||
"message to the forums on www.mt-daapd.org. Thx.\n");
|
||||
pmp3->bitrate = 320;
|
||||
}
|
||||
} else {
|
||||
DPRINTF(E_DBG,L_SCAN, "Could not find 'esds' atom to determine bit rate.\n");
|
||||
}
|
||||
|
@ -1225,7 +1306,6 @@ int scan_get_aacfileinfo(char *file, MP3FILE *pmp3) {
|
|||
if ((atom_offset != -1) && (pmp3->song_length)) {
|
||||
pmp3->bitrate = atom_length / ((pmp3->song_length / 1000) * 128);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fclose(infile);
|
||||
|
@ -1809,10 +1889,8 @@ int scan_get_mp3fileinfo(char *file, MP3FILE *pmp3) {
|
|||
*
|
||||
* @param song MP3FILE of the file to build composite tags for
|
||||
*/
|
||||
void make_composite_tags(MP3FILE *song)
|
||||
{
|
||||
void make_composite_tags(MP3FILE *song) {
|
||||
int len;
|
||||
char fdescr[50];
|
||||
|
||||
len=0;
|
||||
|
||||
|
@ -1837,16 +1915,8 @@ void make_composite_tags(MP3FILE *song)
|
|||
}
|
||||
}
|
||||
|
||||
sprintf(fdescr,"%s audio file",song->type);
|
||||
song->description = strdup(fdescr);
|
||||
|
||||
if(song->url) {
|
||||
song->description = strdup("Playlist URL");
|
||||
song->data_kind=1;
|
||||
/* bit of a hack for the roku soundbridge - type *has* to be pls */
|
||||
if(song->type)
|
||||
free(song->type);
|
||||
song->type = strdup("pls");
|
||||
} else {
|
||||
song->data_kind=0;
|
||||
}
|
||||
|
@ -1854,7 +1924,6 @@ void make_composite_tags(MP3FILE *song)
|
|||
if(!song->title)
|
||||
song->title = strdup(song->fname);
|
||||
|
||||
/* Ogg used to be set as an item_kind of 4. Dunno why */
|
||||
song->item_kind = 2;
|
||||
song->item_kind = 2; /* music, I think. */
|
||||
}
|
||||
|
||||
|
|
|
@ -64,6 +64,7 @@ typedef struct tag_mp3file {
|
|||
unsigned int id;
|
||||
|
||||
char *description; /* long file type */
|
||||
char *codectype; /* song.codectype */
|
||||
int item_kind; /* song or movie */
|
||||
int data_kind; /* dmap.datakind (asdk) */
|
||||
int force_update;
|
||||
|
|
Loading…
Reference in New Issue