merge changes from metadata-rewrite branch

git-svn-id: https://svn.musicpd.org/mpd/trunk@2589 09075e82-0dd4-0310-85a5-a0d7c8717e4f
This commit is contained in:
Warren Dukes 2004-11-10 21:58:27 +00:00
parent 86cf70dcb2
commit c5d27d8eaa
31 changed files with 1038 additions and 723 deletions

23
TODO
View File

@ -1,18 +1,21 @@
0.12
----
*) disable mod support by default
*) add genre, date, composer metadata
*) rewrite metadata/db handling
*) store all metadata entries in table
*) each contains a counter reference
*) new MpdDBTag, which instead of strings allocated for each metadata
entry, store a char * string to the metadata entry in the table
*) multiple artist support
*) multiple genre support {char *, int pairs for each metadata entry
indicating the type of metadata and its value)
*) MpdDBTag <-> MpdTag interface
*) rewrite search and find to be more flexible and elegant
*) implemnt list command
*) for each TagTrackerItem, include a temp varaible for storing
if it has been printed already
*) reset this variable before list command processing
*) rewrite filename handling
*) use memory more efficiently, by iteratively constructing filename
*) create a function for creating directory names:
*) returns a static string
*) when creating the string, check that the same directory
string wasn't just created (store last Directory * ptr)
*) this should be very fast! and save memory
*) implement listener socket protocol as documented here:
http://www.musicpd.org/wiki/moin.cgi/MpdListenerProtocol

View File

@ -42,7 +42,7 @@ AC_ARG_ENABLE(flac,[ --disable-flac disable flac support],,enable_flac=yes)
AC_ARG_ENABLE(mp3,[ --disable-mp3 disable mp3 support],,enable_mp3=yes)
AC_ARG_ENABLE(aac,[ --disable-aac disable AAC support],,enable_aac=yes)
AC_ARG_ENABLE(audiofile,[ --disable-audiofile disable audiofile support, disables wave support],,enable_audiofile=yes)
AC_ARG_ENABLE(mod,[ --disable-mod disable MOD support],,enable_mod=yes)
AC_ARG_ENABLE(mod,[ --enable-mod enable MOD support],enable_mod=no,)
AC_ARG_ENABLE(id3,[ --disable-id3 disable id3 support],,enable_id3=yes)
AC_ARG_ENABLE(mpd_mad,[ --enable-mpd-mad use mpd libmad],use_mpd_mad=yes,)
AC_ARG_ENABLE(mpd_id3tag,[ --enable-mpd-id3tag use mpd libid3tag],use_mpd_id3tag=yes,)

View File

@ -199,6 +199,10 @@ audio_output {
################ MISCELLANEOUS OPTIONS ###################
#
# This sets the metadata mpd will use, to disable all metadata, set to "none"
#
#metadata_to_use "artist,album,title,genre,date,track"
#
# This setting exists as precaution against attacks.
#
#max_playlist_length "16384"

View File

@ -24,6 +24,7 @@ mpd_headers = \
charConv.h \
command.h \
conf.h \
dbUtils.h \
decode.h \
directory.h \
inputPlugin.h \
@ -51,7 +52,7 @@ mpd_headers = \
song.h \
stats.h \
tag.h \
tables.h \
tagTracker.h \
utf8.h \
utils.h \
volume.h
@ -67,6 +68,7 @@ mpd_SOURCES = \
charConv.c \
command.c \
conf.c \
dbUtils.c \
decode.c \
directory.c \
inputPlugin.c \
@ -93,8 +95,8 @@ mpd_SOURCES = \
signal_check.c \
song.c \
stats.c \
tables.c \
tag.c \
tagTracker.c \
utils.c \
volume.c \
utf8.c

View File

@ -375,9 +375,21 @@ static void myShout_closeDevice(AudioOutput * audioOutput) {
static void copyTagToVorbisComment(ShoutData * sd) {
if(sd->tag) {
addTag("ARTIST", sd->tag->artist);
addTag("ALBUM", sd->tag->album);
addTag("TITLE", sd->tag->title);
int i;
for(i = 0; i < sd->tag->numOfItems; i++) {
switch(sd->tag->items[i].type) {
case TAG_ITEM_ARTIST:
addTag("ARTIST", sd->tag->items[i].value);
break;
case TAG_ITEM_ALBUM:
addTag("ALBUM", sd->tag->items[i].value);
break;
case TAG_ITEM_TITLE:
addTag("TITLE", sd->tag->items[i].value);
break;
}
}
}
}

View File

@ -21,7 +21,6 @@
#include "playlist.h"
#include "ls.h"
#include "directory.h"
#include "tables.h"
#include "volume.h"
#include "path.h"
#include "stats.h"
@ -32,6 +31,7 @@
#include "audio.h"
#include "buffer2array.h"
#include "log.h"
#include "dbUtils.h"
#include <stdlib.h>
#include <string.h>
@ -442,13 +442,41 @@ int handlePlaylistId(FILE * fp, unsigned int * permission,
int handleFind(FILE * fp, unsigned int * permission, int argArrayLength,
char ** argArray)
{
return findSongsIn(fp,NULL,argArray[1],argArray[2]);
int ret;
LocateTagItem * item = newLocateTagItem(argArray[1], argArray[2]);
if(!item) {
commandError(fp, ACK_ERROR_ARG, "\%s\" isn't recognized",
argArray[1]);
return -1;
}
ret = findSongsIn(fp, NULL, item);
freeLocateTagItem(item);
return ret;
}
int handleSearch(FILE * fp, unsigned int * permission, int argArrayLength,
char ** argArray)
{
return searchForSongsIn(fp,NULL,argArray[1],argArray[2]);
int ret;
LocateTagItem * item = newLocateTagItem(argArray[1], argArray[2]);
if(!item) {
commandError(fp, ACK_ERROR_ARG, "\%s\" isn't recognized",
argArray[1]);
return -1;
}
ret = searchForSongsIn(fp, NULL, item);
freeLocateTagItem(item);
return ret;
}
int listHandleUpdate(FILE * fp, unsigned int * permission, int argArrayLength,
@ -585,10 +613,35 @@ int handleClearError(FILE * fp, unsigned int * permission, int argArrayLength,
int handleList(FILE * fp, unsigned int * permission, int argArrayLength,
char ** argArray)
{
char * arg1 = NULL;
int numConditionals = 0;
LocateTagItem * conditionals = NULL;
int tagType = getLocateTagItemType(argArray[1]);
int ret;
if(argArrayLength==3) arg1 = argArray[2];
return printAllKeysOfTable(fp,argArray[1],arg1);
if(tagType < 0) {
commandError(fp, ACK_ERROR_ARG,
"\"%s\" is not known", argArray[1]);
return -1;
}
/* for compatibility with < 0.12.0 */
if(argArrayLength==3) {
if(tagType != TAG_ITEM_ALBUM) {
commandError(fp, ACK_ERROR_ARG,
"should be \"%s\" for 3 arguments",
mpdTagItemKeys[TAG_ITEM_ALBUM]);
return -1;
}
conditionals = newLocateTagItem(mpdTagItemKeys[TAG_ITEM_ARTIST],
argArray[2]);
numConditionals = 1;
}
ret = listAllUniqueTags(fp, tagType, numConditionals,conditionals);
if(conditionals) free(conditionals);
return ret;
}
int handleMove(FILE * fp, unsigned int * permission, int argArrayLength,

View File

@ -151,6 +151,7 @@ void initConf() {
registerConfigParam(CONF_HTTP_PREBUFFER_SIZE, 0, 0);
registerConfigParam(CONF_REPLAYGAIN_PREAMP, 0, 0);
registerConfigParam(CONF_ID3V1_ENCODING, 0, 0);
registerConfigParam(CONF_METADATA_TO_USE, 0, 0);
}
static void addBlockParam(ConfigParam * param, char * name, char * value,

View File

@ -57,6 +57,7 @@
#define CONF_HTTP_BUFFER_SIZE "http_buffer_size"
#define CONF_HTTP_PREBUFFER_SIZE "http_prebuffer_size"
#define CONF_ID3V1_ENCODING "id3v1_encoding"
#define CONF_METADATA_TO_USE "metadata_to_use"
typedef struct _BlockParam {
char * name;

267
src/dbUtils.c Normal file
View File

@ -0,0 +1,267 @@
#include "dbUtils.h"
#include "directory.h"
#include "myfprintf.h"
#include "utils.h"
#include "playlist.h"
#include "tag.h"
#include "tagTracker.h"
typedef struct ListCommandItem {
mpd_sint8 tagType;
int numConditionals;
LocateTagItem * conditionals;
} ListCommandItem;
int getLocateTagItemType(char * str) {
int i;
if(0 == strcasecmp(str, LOCATE_TAG_FILE_KEY)) {
return LOCATE_TAG_FILE_TYPE;
}
for(i = 0; i < TAG_NUM_OF_ITEM_TYPES; i++) {
if(0 == strcasecmp(str, mpdTagItemKeys[i])) return i;
}
return -1;
}
LocateTagItem * newLocateTagItem(char * typeStr, char * needle) {
LocateTagItem * ret = malloc(sizeof(LocateTagItem));
ret->tagType = getLocateTagItemType(typeStr);
if(ret->tagType < 0) {
free(ret);
return NULL;
}
ret->needle = strdup(needle);
return ret;
}
void freeLocateTagItem(LocateTagItem * item) {
free(item->needle);
free(item);
}
int countSongsInDirectory(FILE * fp, Directory * directory, void * data) {
int * count = (int *)data;
*count+=directory->songs->numberOfNodes;
return 0;
}
int printDirectoryInDirectory(FILE * fp, Directory * directory, void * data) {
if(directory->utf8name) {
myfprintf(fp,"directory: %s\n",directory->utf8name);
}
return 0;
}
int printSongInDirectory(FILE * fp, Song * song, void * data) {
myfprintf(fp,"file: %s\n",song->utf8url);
return 0;
}
static inline int strstrSearchTag(Song * song, int type, char * str) {
int i;
char * dup;
int ret = 0;
if(type == LOCATE_TAG_FILE_TYPE) {
dup = strDupToUpper(song->utf8url);
if(strstr(dup, str)) ret = 1;
free(dup);
return ret;
}
if(!song->tag) return 0;
for(i = 0; i < song->tag->numOfItems && !ret; i++) {
if(song->tag->items[i].type != type) continue;
dup = strDupToUpper(song->tag->items[i].value);
if(strstr(dup, str)) ret = 1;
free(dup);
}
return ret;
}
int searchInDirectory(FILE * fp, Song * song, void * item) {
if(strstrSearchTag(song, ((LocateTagItem *)item)->tagType,
((LocateTagItem *)item)->needle)) {
printSongInfo(fp, song);
}
return 0;
}
int searchForSongsIn(FILE * fp, char * name, LocateTagItem * item) {
char * originalNeedle = item->needle;
int ret = -1;
item->needle = strDupToUpper(originalNeedle);
ret = traverseAllIn(fp,name,searchInDirectory, NULL,
(void *)item);
free(item->needle);
item->needle = originalNeedle;
return ret;
}
static inline int tagItemFoundAndMatches(Song * song, int type, char * str) {
int i;
if(type == LOCATE_TAG_FILE_TYPE) {
if(0 == strcmp(str, song->utf8url)) return 1;
}
if(!song->tag) return 0;
for(i = 0; i < song->tag->numOfItems; i++) {
if(song->tag->items[i].type != type) continue;
if(0 == strcmp(str, song->tag->items[i].value)) return 1;
}
return 0;
}
int findInDirectory(FILE * fp, Song * song, void * item) {
if(tagItemFoundAndMatches(song, ((LocateTagItem *)item)->tagType,
((LocateTagItem *)item)->needle)) {
printSongInfo(fp, song);
}
return 0;
}
int findSongsIn(FILE * fp, char * name, LocateTagItem * item) {
return traverseAllIn(fp, name, findInDirectory, NULL,
(void *)item);
}
int printAllIn(FILE * fp, char * name) {
return traverseAllIn(fp,name,printSongInDirectory,
printDirectoryInDirectory,NULL);
}
int directoryAddSongToPlaylist(FILE * fp, Song * song, void * data) {
return addSongToPlaylist(fp, song, 0);
}
int addAllIn(FILE * fp, char * name) {
return traverseAllIn(fp,name,directoryAddSongToPlaylist,NULL,NULL);
}
int directoryPrintSongInfo(FILE * fp, Song * song, void * data) {
return printSongInfo(fp,song);
}
int sumSongTime(FILE * fp, Song * song, void * data) {
unsigned long * time = (unsigned long *)data;
if(song->tag && song->tag->time>=0) *time+=song->tag->time;
return 0;
}
int printInfoForAllIn(FILE * fp, char * name) {
return traverseAllIn(fp,name,directoryPrintSongInfo,printDirectoryInDirectory,NULL);
}
int countSongsIn(FILE * fp, char * name) {
int count = 0;
void * ptr = (void *)&count;
traverseAllIn(fp,name,NULL,countSongsInDirectory,ptr);
return count;
}
unsigned long sumSongTimesIn(FILE * fp, char * name) {
unsigned long dbPlayTime = 0;
void * ptr = (void *)&dbPlayTime;
traverseAllIn(fp,name,sumSongTime,NULL,ptr);
return dbPlayTime;
}
ListCommandItem * newListCommandItem(int tagType, int numConditionals,
LocateTagItem * conditionals)
{
ListCommandItem * item = malloc(sizeof(ListCommandItem));
item->tagType = tagType;
item->numConditionals = numConditionals;
item->conditionals = conditionals;
return item;
}
void freeListCommandItem(ListCommandItem * item) {
free(item);
}
void printUnvisitedTags(FILE * fp, Song * song, int tagType) {
int i;
MpdTag * tag = song->tag;
if(tagType == LOCATE_TAG_FILE_TYPE) {
myfprintf(fp, "file: %s\n", song->utf8url);
return;
}
if(!tag) return;
for(i = 0; i < tag->numOfItems; i++) {
if(tag->items[i].type == tagType &&
!wasVisitedInTagTracker(tagType, tag->items[i].value))
{
myfprintf(fp, "%s: %s\n", mpdTagItemKeys[tagType],
tag->items[i].value);
}
}
}
int listUniqueTagsInDirectory(FILE * fp, Song * song, void * data) {
ListCommandItem * item = data;
int i;
for(i = 0; i < item->numConditionals; i++) {
if(!tagItemFoundAndMatches(song, item->conditionals[i].tagType,
item->conditionals[i].needle))
{
return 0;
}
}
printUnvisitedTags(fp, song, item->tagType);
return 0;
}
int listAllUniqueTags(FILE * fp, int type, int numConditionals,
LocateTagItem * conditionals)
{
int ret;
ListCommandItem * item = newListCommandItem(type, numConditionals,
conditionals);
if(type >= 0 && type <= TAG_NUM_OF_ITEM_TYPES) {
resetVisitedFlagsInTagTracker(type);
}
ret = traverseAllIn(fp, NULL, listUniqueTagsInDirectory, NULL,
(void *)item);
freeListCommandItem(item);
return ret;
}

42
src/dbUtils.h Normal file
View File

@ -0,0 +1,42 @@
#ifndef DB_UTILS_H
#define DB_UTILS_H
#include <stdio.h>
#include "tag.h"
#define LOCATE_TAG_FILE_TYPE TAG_NUM_OF_ITEM_TYPES+10
#define LOCATE_TAG_FILE_KEY "filename"
/* struct used for search, find, list queries */
typedef struct _LocateTagItem {
mpd_sint8 tagType;
/* what we are looking for */
char * needle;
} LocateTagItem;
/* returns NULL if not a known type */
LocateTagItem * newLocateTagItem(char * typeString, char * needle);
int getLocateTagItemType(char * str);
void freeLocateTagItem(LocateTagItem * item);
int printAllIn(FILE * fp, char * name);
int addAllIn(FILE * fp, char * name);
int printInfoForAllIn(FILE * fp, char * name);
int searchForSongsIn(FILE * fp, char * name, LocateTagItem * item);
int findSongsIn(FILE * fp, char * name, LocateTagItem * item);
int countSongsIn(FILE * fp, char * name);
unsigned long sumSongTimesIn(FILE * fp, char * name);
int listAllUniqueTags(FILE * fp, int type, int numConditiionals,
LocateTagItem * conditionals);
#endif

View File

@ -158,10 +158,6 @@ int waitOnDecode(PlayerControl * pc, DecoderControl * dc, OutputBuffer * cb,
}
if((tag = metadataChunkToMpdTagDup(&(pc->fileMetadataChunk)))) {
/* lets put the filename in the title if no tag info */
if(!tag->title && !tag->artist && !tag->album) {
tag->title = strdup(pc->currentUrl);
}
sendMetadataToAudioDevice(tag);
freeMpdTag(tag);
}

View File

@ -32,6 +32,9 @@
#include "mpd_types.h"
#include "sig_handlers.h"
#include "player.h"
#include "tagTracker.h"
#include "list.h"
#include "dbUtils.h"
#include <string.h>
#include <sys/types.h>
@ -54,11 +57,6 @@
#define DIRECTORY_MPD_VERSION "mpd_version: "
#define DIRECTORY_FS_CHARSET "fs_charset: "
#define DIRECTORY_SEARCH_ALBUM "album"
#define DIRECTORY_SEARCH_ARTIST "artist"
#define DIRECTORY_SEARCH_TITLE "title"
#define DIRECTORY_SEARCH_FILENAME "filename"
#define DIRECTORY_UPDATE_EXIT_NOUPDATE 0
#define DIRECTORY_UPDATE_EXIT_UPDATE 1
#define DIRECTORY_UPDATE_EXIT_ERROR 2
@ -67,21 +65,6 @@
#define DIRECTORY_RETURN_UPDATE 1
#define DIRECTORY_RETURN_ERROR -1
typedef List DirectoryList;
typedef struct _DirectoryStat {
ino_t inode;
dev_t device;
} DirectoryStat;
typedef struct _Directory {
char * utf8name;
DirectoryList * subDirectories;
SongList * songs;
struct _Directory * parent;
DirectoryStat * stat;
} Directory;
Directory * mp3rootDirectory = NULL;
char * directory_db;
@ -1000,6 +983,8 @@ int writeDirectoryDB() {
while(fclose(fp) && errno==EINTR);
sortTagTrackerInfo();
return 0;
}
@ -1088,6 +1073,8 @@ int readDirectoryDB() {
if(stat(directory_db,&st)==0) directory_dbModTime = st.st_mtime;
sortTagTrackerInfo();
return 0;
}
@ -1168,159 +1155,6 @@ int traverseAllIn(FILE * fp, char * name,
data);
}
int countSongsInDirectory(FILE * fp, Directory * directory, void * data) {
int * count = (int *)data;
*count+=directory->songs->numberOfNodes;
return 0;
}
int printDirectoryInDirectory(FILE * fp, Directory * directory, void * data) {
if(directory->utf8name) {
myfprintf(fp,"directory: %s\n",directory->utf8name);
}
return 0;
}
int printSongInDirectory(FILE * fp, Song * song, void * data) {
myfprintf(fp,"file: %s\n",song->utf8url);
return 0;
}
int searchForAlbumInDirectory(FILE * fp, Song * song, void * string) {
if(song->tag && song->tag->album) {
char * dup = strDupToUpper(song->tag->album);
if(strstr(dup,(char *)string)) printSongInfo(fp,song);
free(dup);
}
return 0;
}
int searchForArtistInDirectory(FILE * fp, Song * song, void * string) {
if(song->tag && song->tag->artist) {
char * dup = strDupToUpper(song->tag->artist);
if(strstr(dup,(char *)string)) printSongInfo(fp,song);
free(dup);
}
return 0;
}
int searchForTitleInDirectory(FILE * fp, Song * song, void * string) {
if(song->tag && song->tag->title) {
char * dup = strDupToUpper(song->tag->title);
if(strstr(dup,(char *)string)) printSongInfo(fp,song);
free(dup);
}
return 0;
}
int searchForFilenameInDirectory(FILE * fp, Song * song, void * string) {
char * dup = strDupToUpper(song->utf8url);
if(strstr(dup,(char *)string)) printSongInfo(fp,song);
free(dup);
return 0;
}
int searchForSongsIn(FILE * fp, char * name, char * item, char * string) {
char * dup = strDupToUpper(string);
int ret = -1;
if(strcmp(item,DIRECTORY_SEARCH_ALBUM)==0) {
ret = traverseAllIn(fp,name,searchForAlbumInDirectory,NULL,
(void *)dup);
}
else if(strcmp(item,DIRECTORY_SEARCH_ARTIST)==0) {
ret = traverseAllIn(fp,name,searchForArtistInDirectory,NULL,
(void *)dup);
}
else if(strcmp(item,DIRECTORY_SEARCH_TITLE)==0) {
ret = traverseAllIn(fp,name,searchForTitleInDirectory,NULL,
(void *)dup);
}
else if(strcmp(item,DIRECTORY_SEARCH_FILENAME)==0) {
ret = traverseAllIn(fp,name,searchForFilenameInDirectory,NULL,
(void *)dup);
}
else commandError(fp, ACK_ERROR_ARG, "unknown table", NULL);
free(dup);
return ret;
}
int findAlbumInDirectory(FILE * fp, Song * song, void * string) {
if(song->tag && song->tag->album &&
strcmp((char *)string,song->tag->album)==0)
{
printSongInfo(fp,song);
}
return 0;
}
int findArtistInDirectory(FILE * fp, Song * song, void * string) {
if(song->tag && song->tag->artist &&
strcmp((char *)string,song->tag->artist)==0)
{
printSongInfo(fp,song);
}
return 0;
}
int findSongsIn(FILE * fp, char * name, char * item, char * string) {
if(strcmp(item,DIRECTORY_SEARCH_ALBUM)==0) {
return traverseAllIn(fp,name,findAlbumInDirectory,NULL,
(void *)string);
}
else if(strcmp(item,DIRECTORY_SEARCH_ARTIST)==0) {
return traverseAllIn(fp,name,findArtistInDirectory,NULL,
(void *)string);
}
commandError(fp, ACK_ERROR_ARG, "unknown table", NULL);
return -1;
}
int printAllIn(FILE * fp, char * name) {
return traverseAllIn(fp,name,printSongInDirectory,
printDirectoryInDirectory,NULL);
}
int directoryAddSongToPlaylist(FILE * fp, Song * song, void * data) {
return addSongToPlaylist(fp, song, 0);
}
int addAllIn(FILE * fp, char * name) {
return traverseAllIn(fp,name,directoryAddSongToPlaylist,NULL,NULL);
}
int directoryPrintSongInfo(FILE * fp, Song * song, void * data) {
return printSongInfo(fp,song);
}
int sumSongTime(FILE * fp, Song * song, void * data) {
unsigned long * time = (unsigned long *)data;
if(song->tag && song->tag->time>=0) *time+=song->tag->time;
return 0;
}
int printInfoForAllIn(FILE * fp, char * name) {
return traverseAllIn(fp,name,directoryPrintSongInfo,printDirectoryInDirectory,NULL);
}
int countSongsIn(FILE * fp, char * name) {
int count = 0;
void * ptr = (void *)&count;
traverseAllIn(fp,name,NULL,countSongsInDirectory,ptr);
return count;
}
void freeAllDirectoryStats(Directory * directory) {
ListNode * node = directory->subDirectories->firstNode;
@ -1332,15 +1166,6 @@ void freeAllDirectoryStats(Directory * directory) {
freeDirectoryStatFromDirectory(directory);
}
unsigned long sumSongTimesIn(FILE * fp, char * name) {
unsigned long dbPlayTime = 0;
void * ptr = (void *)&dbPlayTime;
traverseAllIn(fp,name,sumSongTime,NULL,ptr);
return dbPlayTime;
}
void initMp3Directory() {
struct stat st;

View File

@ -27,6 +27,21 @@
#include <stdio.h>
#include <sys/param.h>
typedef List DirectoryList;
typedef struct _DirectoryStat {
ino_t inode;
dev_t device;
} DirectoryStat;
typedef struct _Directory {
char * utf8name;
DirectoryList * subDirectories;
SongList * songs;
struct _Directory * parent;
DirectoryStat * stat;
} Directory;
extern char * directory_db;
void readDirectoryDBIfUpdateIsFinished();
@ -51,22 +66,12 @@ int readDirectoryDB();
void updateMp3Directory();
int printAllIn(FILE * fp, char * name);
int addAllIn(FILE * fp, char * name);
int printInfoForAllIn(FILE * fp, char * name);
int searchForSongsIn(FILE * fp, char * name, char * item, char * string);
int findSongsIn(FILE * fp, char * name, char * item, char * string);
int countSongsIn(FILE * fp, char * name);
unsigned long sumSongTimesIn(FILE * fp, char * name);
Song * getSongFromDB(char * file);
time_t getDbModTime();
int traverseAllIn(FILE * fp, char * name,
int (*forEachSong)(FILE *, Song *, void *),
int (*forEachDir)(FILE *, Directory *, void *),
void * data);
#endif

View File

@ -450,12 +450,73 @@ FLAC__StreamDecoderWriteStatus flacWrite(const FLAC__SeekableStreamDecoder *dec,
return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
}
static int commentMatchesAddToTag(
char * str,
FLAC__StreamMetadata_VorbisComment_Entry * entry,
int itemType,
MpdTag ** tag)
{
int slen = strlen(str);
int vlen = entry->length - slen;
if( vlen <= 0 ) return 0;
if( 0 == strncasecmp(str, entry->entry, slen) ) {
if(*tag == NULL) *tag = newMpdTag();
addItemToMpdTagWithLen(*tag, itemType,
entry->entry+slen, vlen);
return 1;
}
return 0;
}
static MpdTag * copyVorbisCommentBlockToMpdTag(FLAC__StreamMetadata * block,
MpdTag * tag)
{
int i;
for(i = 0; i < block->data.vorbis_comment.num_comments; i++) {
if(commentMatchesAddToTag(
"artist=",
block->data.vorbis_comment.comments+i,
TAG_ITEM_ARTIST,
&tag));
else if(commentMatchesAddToTag(
"title=",
block->data.vorbis_comment.comments+i,
TAG_ITEM_TITLE,
&tag));
else if(commentMatchesAddToTag(
"album=",
block->data.vorbis_comment.comments+i,
TAG_ITEM_ALBUM,
&tag));
else if(commentMatchesAddToTag(
"tracknumber=",
block->data.vorbis_comment.comments+i,
TAG_ITEM_TRACK,
&tag));
else if(commentMatchesAddToTag(
"genre=",
block->data.vorbis_comment.comments+i,
TAG_ITEM_GENRE,
&tag));
else if(commentMatchesAddToTag(
"date=",
block->data.vorbis_comment.comments+i,
TAG_ITEM_DATE,
&tag));
}
return tag;
}
MpdTag * flacMetadataDup(char * file, int * vorbisCommentFound) {
MpdTag * ret = NULL;
FLAC__Metadata_SimpleIterator * it;
FLAC__StreamMetadata * block = NULL;
int offset;
int len, pos;
*vorbisCommentFound = 0;
@ -469,60 +530,9 @@ MpdTag * flacMetadataDup(char * file, int * vorbisCommentFound) {
block = FLAC__metadata_simple_iterator_get_block(it);
if(!block) break;
if(block->type == FLAC__METADATA_TYPE_VORBIS_COMMENT) {
char * dup;
ret = copyVorbisCommentBlockToMpdTag(block, ret);
offset = FLAC__metadata_object_vorbiscomment_find_entry_from(block,0,"artist");
if(offset>=0) {
*vorbisCommentFound = 1;
if(!ret) ret = newMpdTag();
pos = strlen("artist=");
len = block->data.vorbis_comment.comments[offset].length-pos;
if(len>0) {
dup = malloc(len+1);
memcpy(dup,&(block->data.vorbis_comment.comments[offset].entry[pos]),len);
dup[len] = '\0';
ret->artist = dup;
}
}
offset = FLAC__metadata_object_vorbiscomment_find_entry_from(block,0,"album");
if(offset>=0) {
*vorbisCommentFound = 1;
if(!ret) ret = newMpdTag();
pos = strlen("album=");
len = block->data.vorbis_comment.comments[offset].length-pos;
if(len>0) {
dup = malloc(len+1);
memcpy(dup,&(block->data.vorbis_comment.comments[offset].entry[pos]),len);
dup[len] = '\0';
ret->album = dup;
}
}
offset = FLAC__metadata_object_vorbiscomment_find_entry_from(block,0,"title");
if(offset>=0) {
*vorbisCommentFound = 1;
if(!ret) ret = newMpdTag();
pos = strlen("title=");
len = block->data.vorbis_comment.comments[offset].length-pos;
if(len>0) {
dup = malloc(len+1);
memcpy(dup,&(block->data.vorbis_comment.comments[offset].entry[pos]),len);
dup[len] = '\0';
ret->title = dup;
}
}
offset = FLAC__metadata_object_vorbiscomment_find_entry_from(block,0,"tracknumber");
if(offset>=0) {
*vorbisCommentFound = 1;
if(!ret) ret = newMpdTag();
pos = strlen("tracknumber=");
len = block->data.vorbis_comment.comments[offset].length-pos;
if(len>0) {
dup = malloc(len+1);
memcpy(dup,&(block->data.vorbis_comment.comments[offset].entry[pos]),len);
dup[len] = '\0';
ret->track = dup;
}
}
if(ret) *vorbisCommentFound = 1;
}
else if(block->type == FLAC__METADATA_TYPE_STREAMINFO) {
if(!ret) ret = newMpdTag();

View File

@ -212,6 +212,7 @@ int mod_decode(OutputBuffer * cb, DecoderControl * dc, char * path) {
MpdTag * modTagDup(char * file) {
MpdTag * ret = NULL;
MODULE * moduleHandle;
char * title;
if(mod_initMikMod() < 0) return NULL;
@ -222,7 +223,8 @@ MpdTag * modTagDup(char * file) {
ret = newMpdTag();
ret->time = 0;
ret->title = strdup(Player_LoadTitle(file));
title = strdup(Player_LoadTitle(file));
if(title) mpdItemToMpdTag(ret, TAG_ITEM_TITLE, title);
fail:
MikMod_Exit();

View File

@ -549,9 +549,12 @@ int mp3Read(mp3DecodeData * data, OutputBuffer * cb, DecoderControl * dc) {
if(data->inStream->metaTitle) {
MpdTag * tag = newMpdTag();
if(data->inStream->metaName) {
tag->name = strdup(data->inStream->metaName);
addItemToMpdTag(tag,
TAG_ITEM_NAME,
data->inStream->metaName);
}
tag->title = strdup(data->inStream->metaTitle);
addItemToMpdTag(tag, TAG_ITEM_TITLE,
data->inStream->metaTitle);
free(data->inStream->metaTitle);
data->inStream->metaTitle = NULL;
copyMpdTagToOutputBuffer(cb, tag);
@ -676,19 +679,21 @@ int mp3_decode(OutputBuffer * cb, DecoderControl * dc, InputStream * inStream) {
if(inStream->metaTitle) {
if(tag) freeMpdTag(tag);
tag = newMpdTag();
tag->title = strdup(inStream->metaTitle);
addItemToMpdTag(tag, TAG_ITEM_TITLE, inStream->metaTitle);
free(inStream->metaTitle);
inStream->metaTitle = NULL;
if(inStream->metaName) {
tag->name = strdup(inStream->metaName);
addItemToMpdTag(tag, TAG_ITEM_NAME,
inStream->metaName);
}
copyMpdTagToOutputBuffer(cb, tag);
freeMpdTag(tag);
}
else if(tag) {
if(inStream->metaName) {
if(tag->name) free(tag->name);
tag->name = strdup(inStream->metaName);
clearItemsFromMpdTag(tag, TAG_ITEM_NAME);
addItemToMpdTag(tag, TAG_ITEM_NAME,
inStream->metaName);
}
copyMpdTagToOutputBuffer(cb, tag);
freeMpdTag(tag);
@ -696,7 +701,8 @@ int mp3_decode(OutputBuffer * cb, DecoderControl * dc, InputStream * inStream) {
else if(inStream->metaName) {
tag = newMpdTag();
if(inStream->metaName) {
tag->name = strdup(inStream->metaName);
addItemToMpdTag(tag, TAG_ITEM_NAME,
inStream->metaName);
}
copyMpdTagToOutputBuffer(cb, tag);
freeMpdTag(tag);

View File

@ -322,6 +322,7 @@ MpdTag * mp4DataDup(char * file, int * mp4MetadataFound) {
int32_t track;
int32_t time;
int32_t scale;
int i;
*mp4MetadataFound = 0;
@ -359,20 +360,39 @@ MpdTag * mp4DataDup(char * file, int * mp4MetadataFound) {
}
ret->time = ((float)time)/scale+0.5;
if(!mp4ff_meta_get_artist(mp4fh,&ret->artist)) {
*mp4MetadataFound = 1;
}
for(i = 0; i < mp4ff_meta_get_num_items(mp4fh); i++) {
char * item;
char * value;
if(!mp4ff_meta_get_album(mp4fh,&ret->album)) {
*mp4MetadataFound = 1;
}
mp4ff_meta_get_by_index(mp4fh, i, &item, &value);
if(!mp4ff_meta_get_title(mp4fh,&ret->title)) {
*mp4MetadataFound = 1;
}
if(0 == strcasecmp("artist", item)) {
addItemToMpdTag(ret, TAG_ITEM_ARTIST, value);
*mp4MetadataFound = 1;
}
else if(0 == strcasecmp("title", item)) {
addItemToMpdTag(ret, TAG_ITEM_TITLE, value);
*mp4MetadataFound = 1;
}
else if(0 == strcasecmp("album", item)) {
addItemToMpdTag(ret, TAG_ITEM_ALBUM, value);
*mp4MetadataFound = 1;
}
else if(0 == strcasecmp("track", item)) {
addItemToMpdTag(ret, TAG_ITEM_TRACK, value);
*mp4MetadataFound = 1;
}
else if(0 == strcasecmp("genre", item)) {
addItemToMpdTag(ret, TAG_ITEM_GENRE, value);
*mp4MetadataFound = 1;
}
else if(0 == strcasecmp("date", item)) {
addItemToMpdTag(ret, TAG_ITEM_DATE, value);
*mp4MetadataFound = 1;
}
if(!mp4ff_meta_get_track(mp4fh,&ret->track)) {
*mp4MetadataFound = 1;
free(item);
free(value);
}
mp4ff_close(mp4fh);

View File

@ -162,27 +162,27 @@ MpdTag * oggCommentsParse(char ** comments) {
while(*comments) {
if((temp = ogg_parseComment(*comments,"artist"))) {
if(!ret) ret = newMpdTag();
if(!ret->artist) {
ret->artist = strdup(temp);
}
addItemToMpdTag(ret, TAG_ITEM_ARTIST, temp);
}
else if((temp = ogg_parseComment(*comments,"title"))) {
if(!ret) ret = newMpdTag();
if(!ret->title) {
ret->title = strdup(temp);
}
addItemToMpdTag(ret, TAG_ITEM_TITLE, temp);
}
else if((temp = ogg_parseComment(*comments,"album"))) {
if(!ret) ret = newMpdTag();
if(!ret->album) {
ret->album = strdup(temp);
}
addItemToMpdTag(ret, TAG_ITEM_ALBUM, temp);
}
else if((temp = ogg_parseComment(*comments,"tracknumber"))) {
if(!ret) ret = newMpdTag();
if(!ret->track) {
ret->track = strdup(temp);
}
addItemToMpdTag(ret, TAG_ITEM_TRACK, temp);
}
else if((temp = ogg_parseComment(*comments,"genre"))) {
if(!ret) ret = newMpdTag();
addItemToMpdTag(ret, TAG_ITEM_GENRE, temp);
}
else if((temp = ogg_parseComment(*comments,"date"))) {
if(!ret) ret = newMpdTag();
addItemToMpdTag(ret, TAG_ITEM_DATE, temp);
}
comments++;
@ -208,8 +208,8 @@ void putOggCommentsIntoOutputBuffer(OutputBuffer * cb, char * streamName,
if(tag->title) printf("Title: %s\n", tag->title);*/
if(streamName) {
if(tag->name) free(tag->name);
tag->name = strdup(streamName);
clearItemsFromMpdTag(tag, TAG_ITEM_NAME);
addItemToMpdTag(tag, TAG_ITEM_NAME, streamName);
}
copyMpdTagToOutputBuffer(cb, tag);

View File

@ -104,7 +104,7 @@ int insertInListBeforeNode(List * list, ListNode * beforeNode, char * key,
return 1;
}
int insertInList(List * list,char * key,void * data) {
ListNode * insertInList(List * list,char * key,void * data) {
ListNode * node;
assert(list!=NULL);
@ -137,7 +137,7 @@ int insertInList(List * list,char * key,void * data) {
list->numberOfNodes++;
return 1;
return node;
}
int insertInListWithoutKey(List * list, void * data) {
@ -173,7 +173,7 @@ int insertInListWithoutKey(List * list, void * data) {
return 1;
}
int findInList(List * list,char * key,void ** data) {
ListNode * findNodeInList(List * list, char * key) {
static long high;
static long low;
static long cur;
@ -191,10 +191,7 @@ int findInList(List * list,char * key,void ** data) {
cur = (high+low)/2;
tmpNode = list->nodesArray[cur];
cmp = strcmp(tmpNode->key,key);
if(cmp==0) {
if(data) *data = tmpNode->data;
return 1;
}
if(cmp==0) return tmpNode;
else if(cmp>0) high = cur;
else {
if(low==cur) break;
@ -205,10 +202,7 @@ int findInList(List * list,char * key,void ** data) {
cur = high;
if(cur>=0) {
tmpNode = list->nodesArray[cur];
if(strcmp(tmpNode->key,key)==0) {
(*data) = tmpNode->data;
return 1;
}
if(strcmp(tmpNode->key,key)==0) return tmpNode;
}
}
else {
@ -218,10 +212,18 @@ int findInList(List * list,char * key,void ** data) {
tmpNode = tmpNode->nextNode;
}
if(tmpNode!=NULL) {
(*data) = tmpNode->data;
return 1;
}
return tmpNode;
}
return NULL;
}
int findInList(List * list, char * key, void ** data) {
ListNode * node = findNodeInList(list, key);
if(node) {
if(data) *data = node->data;
return 1;
}
return 0;

View File

@ -67,7 +67,7 @@ List * makeList(ListFreeDataFunc * freeDataFunc);
* _data_ -> data to be inserted in list
* returns 1 if successful, 0 otherwise
*/
int insertInList(List * list,char * key,void * data);
ListNode * insertInList(List * list,char * key,void * data);
int insertInListBeforeNode(List * list, ListNode * beforeNode, char * key,
void * data);
@ -93,6 +93,8 @@ void deleteNodeFromList(List * list,ListNode * node);
*/
int findInList(List * list, char * key, void ** data);
ListNode * findNodeInList(List * list, char * key);
/* frees memory malloc'd for list and its nodes
* _list_ -> List to be free'd
*/

View File

@ -20,7 +20,6 @@
#include "command.h"
#include "playlist.h"
#include "directory.h"
#include "tables.h"
#include "player.h"
#include "listen.h"
#include "conf.h"
@ -35,6 +34,8 @@
#include "replayGain.h"
#include "inputPlugin.h"
#include "inputStream.h"
#include "tag.h"
#include "tagTracker.h"
#include "../config.h"
#include <stdio.h>
@ -403,6 +404,7 @@ int main(int argc, char * argv[]) {
parseOptions(argc, argv, &options);
initStats();
initTagConfig();
initLog();
establishListen(&options);
@ -415,7 +417,6 @@ int main(int argc, char * argv[]) {
initPermissions();
initReplayGainState();
initTables();
initPlaylist();
initInputPlugins();
@ -427,8 +428,10 @@ int main(int argc, char * argv[]) {
initAudioDriver();
initVolume();
initInterfaces();
initInputStream();
initInputStream();
printMemorySavedByTagTracker();
daemonize(&options);
setupLogOutput(&options, out, err);
@ -450,7 +453,6 @@ int main(int argc, char * argv[]) {
freeAllInterfaces();
closeAllListenSockets();
closeMp3Directory();
closeTables();
finishPlaylist();
freePlayerData();
finishAudioDriver();

View File

@ -29,9 +29,9 @@ void initMetadataChunk(MetadataChunk * chunk) {
chunk->title = -1;
}
#define dupElementToTag(string, element) { \
#define dupElementToTag(item, element) { \
if(element >= 0 && element < METADATA_BUFFER_LENGTH) { \
string = strdup(chunk->buffer+element); \
addItemToMpdTag(ret, item, chunk->buffer+element); \
} \
}
@ -40,10 +40,10 @@ MpdTag * metadataChunkToMpdTagDup(MetadataChunk * chunk) {
chunk->buffer[METADATA_BUFFER_LENGTH-1] = '\0';
dupElementToTag(ret->name, chunk->name);
dupElementToTag(ret->title, chunk->title);
dupElementToTag(ret->artist, chunk->artist);
dupElementToTag(ret->album, chunk->album);
dupElementToTag(TAG_ITEM_NAME, chunk->name);
dupElementToTag(TAG_ITEM_TITLE, chunk->title);
dupElementToTag(TAG_ITEM_ARTIST, chunk->artist);
dupElementToTag(TAG_ITEM_ALBUM, chunk->album);
return ret;
}
@ -67,8 +67,16 @@ void copyMpdTagToMetadataChunk(MpdTag * tag, MetadataChunk * chunk) {
if(!tag) return;
copyStringToChunk(tag->name, chunk->name);
copyStringToChunk(tag->title, chunk->title);
copyStringToChunk(tag->artist, chunk->artist);
copyStringToChunk(tag->album, chunk->album);
copyStringToChunk(
getNextItemFromMpdTag(tag, TAG_ITEM_NAME, NULL),
chunk->name);
copyStringToChunk(
getNextItemFromMpdTag(tag, TAG_ITEM_TITLE, NULL),
chunk->title);
copyStringToChunk(
getNextItemFromMpdTag(tag, TAG_ITEM_ARTIST, NULL),
chunk->title);
copyStringToChunk(
getNextItemFromMpdTag(tag, TAG_ITEM_ALBUM, NULL),
chunk->album);
}

View File

@ -25,7 +25,6 @@
#include "listen.h"
#include "log.h"
#include "utils.h"
#include "tables.h"
#include "directory.h"
#include "volume.h"
#include "playerData.h"
@ -116,7 +115,6 @@ int playerInit() {
freeAllInterfaces();
closeMp3Directory();
finishPlaylist();
closeTables();
finishPermissions();
finishCommands();
finishVolume();
@ -480,7 +478,6 @@ Song * playerCurrentDecodeSong() {
song = newNullSong();
song->utf8url = strdup(pc->currentUrl);
song->tag = metadataChunkToMpdTagDup(prev);
validateUtf8Tag(song->tag);
ret = song;
resetPlayerMetadata();
}

View File

@ -19,22 +19,15 @@
#include "song.h"
#include "ls.h"
#include "directory.h"
#include "tables.h"
#include "utils.h"
#include "tag.h"
#include "log.h"
#include "path.h"
#include "playlist.h"
#include "tables.h"
#include "inputPlugin.h"
#define SONG_KEY "key: "
#define SONG_FILE "file: "
#define SONG_ARTIST "Artist: "
#define SONG_ALBUM "Album: "
#define SONG_TRACK "Track: "
#define SONG_TITLE "Title: "
#define SONG_NAME "Name: "
#define SONG_TIME "Time: "
#define SONG_MTIME "mtime: "
@ -66,13 +59,11 @@ Song * newSong(char * utf8url, SONG_TYPE type) {
if((plugin = isMusic(utf8url,&(song->mtime)))) {
song->tag = plugin->tagDupFunc(
rmp2amp(utf8ToFsCharset(utf8url)));
if(song->tag) validateUtf8Tag(song->tag);
}
if(!song->tag || song->tag->time<0) {
freeSong(song);
song = NULL;
}
else addSongToTables(song);
}
return song;
@ -80,7 +71,6 @@ Song * newSong(char * utf8url, SONG_TYPE type) {
void freeSong(Song * song) {
deleteASongFromPlaylist(song);
if(song->type == SONG_TYPE_FILE) removeASongFromTables(song);
free(song->utf8url);
if(song->tag) freeMpdTag(song->tag);
free(song);
@ -172,27 +162,38 @@ void insertSongIntoList(SongList * list, ListNode ** nextSongNode, char * key,
if(!(*nextSongNode)) {
insertInList(list,key,(void *)song);
addSongToTables(song);
}
else if(cmpRet == 0) {
Song * tempSong = (Song *)((*nextSongNode)->data);
if(tempSong->mtime != song->mtime) {
removeASongFromTables(tempSong);
freeMpdTag(tempSong->tag);
tempSong->tag = song->tag;
tempSong->mtime = song->mtime;
song->tag = NULL;
addSongToTables(tempSong);
}
freeJustSong(song);
*nextSongNode = (*nextSongNode)->nextNode;
}
else {
addSongToTables(song);
insertInListBeforeNode(list,*nextSongNode,key,(void *)song);
}
}
static int matchesAnMpdTagItemKey(char * buffer, int * itemType) {
int i;
for(i = 0; i < TAG_NUM_OF_ITEM_TYPES; i++) {
if( 0 == strncmp(mpdTagItemKeys[i], buffer,
strlen(mpdTagItemKeys[i])))
{
*itemType = i;
return 1;
}
}
return 0;
}
void readSongInfoIntoList(FILE * fp, SongList * list) {
char buffer[MAXPATHLEN+1024];
int bufferSize = MAXPATHLEN+1024;
@ -200,6 +201,7 @@ void readSongInfoIntoList(FILE * fp, SongList * list) {
char * key = NULL;
ListNode * nextSongNode = list->firstNode;
ListNode * nodeTemp;
int itemType;
while(myFgets(buffer,bufferSize,fp) && 0!=strcmp(SONG_END,buffer)) {
if(0==strncmp(SONG_KEY,buffer,strlen(SONG_KEY))) {
@ -220,32 +222,17 @@ void readSongInfoIntoList(FILE * fp, SongList * list) {
}
song->utf8url = strdup(&(buffer[strlen(SONG_FILE)]));
}
else if(0==strncmp(SONG_ARTIST,buffer,strlen(SONG_ARTIST))) {
else if(matchesAnMpdTagItemKey(buffer, &itemType)) {
if(!song->tag) song->tag = newMpdTag();
song->tag->artist = strdup(&(buffer[strlen(SONG_ARTIST)]));
}
else if(0==strncmp(SONG_ALBUM,buffer,strlen(SONG_ALBUM))) {
if(!song->tag) song->tag = newMpdTag();
song->tag->album = strdup(&(buffer[strlen(SONG_ALBUM)]));
}
else if(0==strncmp(SONG_TRACK,buffer,strlen(SONG_TRACK))) {
if(!song->tag) song->tag = newMpdTag();
song->tag->track = strdup(&(buffer[strlen(SONG_TRACK)]));
}
else if(0==strncmp(SONG_TITLE,buffer,strlen(SONG_TITLE))) {
if(!song->tag) song->tag = newMpdTag();
song->tag->title = strdup(&(buffer[strlen(SONG_TITLE)]));
}
else if(0==strncmp(SONG_NAME,buffer,strlen(SONG_NAME))) {
if(!song->tag) song->tag = newMpdTag();
song->tag->name = strdup(&(buffer[strlen(SONG_NAME)]));
addItemToMpdTag(song->tag, itemType,
&(buffer[strlen(mpdTagItemKeys[itemType])+2]));
}
else if(0==strncmp(SONG_TIME,buffer,strlen(SONG_TIME))) {
if(!song->tag) song->tag = newMpdTag();
song->tag->time = atoi(&(buffer[strlen(SONG_TIME)]));
}
else if(0==strncmp(SONG_MTIME,buffer,strlen(SONG_MTIME))) {
song->mtime = atoi(&(buffer[strlen(SONG_TITLE)]));
song->mtime = atoi(&(buffer[strlen(SONG_MTIME)]));
}
else {
ERROR("songinfo: unknown line in db: %s\n",buffer);
@ -272,7 +259,6 @@ int updateSongInfo(Song * song) {
if(song->type == SONG_TYPE_FILE) {
InputPlugin * plugin;
removeASongFromTables(song);
if(song->tag) freeMpdTag(song->tag);
song->tag = NULL;
@ -280,10 +266,8 @@ int updateSongInfo(Song * song) {
if((plugin = isMusic(utf8url,&(song->mtime)))) {
song->tag = plugin->tagDupFunc(
rmp2amp(utf8ToFsCharset(utf8url)));
if(song->tag) validateUtf8Tag(song->tag);
}
if(!song->tag || song->tag->time<0) return -1;
else addSongToTables(song);
}
return 0;

View File

@ -18,10 +18,11 @@
#include "stats.h"
#include "tables.h"
#include "directory.h"
#include "myfprintf.h"
#include "player.h"
#include "tag.h"
#include "tagTracker.h"
#include <time.h>
@ -35,8 +36,8 @@ void initStats() {
}
int printStats(FILE * fp) {
myfprintf(fp,"artists: %li\n",numberOfArtists());
myfprintf(fp,"albums: %li\n",numberOfAlbums());
myfprintf(fp,"artists: %li\n", getNumberOfTagItems(TAG_ITEM_ARTIST));
myfprintf(fp,"albums: %li\n", getNumberOfTagItems(TAG_ITEM_ALBUM));
myfprintf(fp,"songs: %i\n",stats.numberOfSongs);
myfprintf(fp,"uptime: %li\n",time(NULL)-stats.daemonStart);
myfprintf(fp,"playtime: %li\n",(long)(getPlayerTotalPlayTime()+0.5));

View File

@ -1,200 +0,0 @@
/* the Music Player Daemon (MPD)
* (c)2003-2004 by Warren Dukes (shank@mercury.chem.pitt.edu)
* This project's homepage is: http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "tables.h"
#include "list.h"
#include "command.h"
#include "utils.h"
#include "myfprintf.h"
#include <string.h>
#define TABLES_ARTIST "artist"
#define TABLES_ALBUM "album"
List * albumTable;
List * artistTable;
typedef struct _ArtistData {
int songs;
List * albums;
} ArtistData;
ArtistData * newArtistData() {
ArtistData * ad = malloc(sizeof(ArtistData));
ad->songs = 0;
ad->albums = makeList(free);
return ad;
}
void freeArtistData(ArtistData * ad) {
freeList(ad->albums);
}
void initTables() {
albumTable = makeList(free);
artistTable = makeList((ListFreeDataFunc *)freeArtistData);
}
void closeTables() {
freeList(albumTable);
freeList(artistTable);
}
void addSongToSomeAlbumTable(List * table, Song * song) {
void * songs;
if(!song->tag) return;
if(!song->tag->album || !strlen(song->tag->album)) return;
if(!findInList(table,song->tag->album,&songs)) {
songs = malloc(sizeof(int));
*((int *)songs) = 0;
insertInList(table,song->tag->album,songs);
}
(*((int *)songs))++;
}
void addSongToAlbumTable(Song * song) {
addSongToSomeAlbumTable(albumTable,song);
}
void addSongToArtistTable(Song * song) {
void * artist;
if(!song->tag) return;
if(!song->tag->artist || !strlen(song->tag->artist)) return;
if(!findInList(artistTable,song->tag->artist,&artist)) {
artist = newArtistData();
insertInList(artistTable,song->tag->artist,artist);
}
((ArtistData *)artist)->songs++;
addSongToSomeAlbumTable(((ArtistData *)artist)->albums,song);
}
void addSongToTables(Song * song) {
addSongToAlbumTable(song);
addSongToArtistTable(song);
}
void removeSongFromSomeAlbumTable(List * table, Song * song) {
void * songs;
if(!song->tag) return;
if(!song->tag->album || !strlen(song->tag->album)) return;
if(findInList(table,song->tag->album,&songs)) {
(*((int *)songs))--;
if(*((int *)songs)<=0) {
deleteFromList(table,song->tag->album);
}
}
}
void removeSongFromAlbumTable(Song * song) {
removeSongFromSomeAlbumTable(albumTable,song);
}
void removeSongFromArtistTable(Song * song) {
void * artist;
if(!song->tag) return;
if(!song->tag->artist || !strlen(song->tag->artist)) return;
if(findInList(artistTable,song->tag->artist,&artist)) {
removeSongFromSomeAlbumTable(((ArtistData *)artist)->albums,
song);
((ArtistData*)artist)->songs--;
if(((ArtistData *)artist)->songs<=0) {
deleteFromList(artistTable,song->tag->artist);
}
}
}
void removeASongFromTables(Song * song) {
removeSongFromAlbumTable(song);
removeSongFromArtistTable(song);
}
unsigned long numberOfSongs() {
return 0;
}
unsigned long numberOfArtists() {
return artistTable->numberOfNodes;
}
unsigned long numberOfAlbums() {
return albumTable->numberOfNodes;
}
int printAllArtists(FILE * fp) {
ListNode * node = artistTable->firstNode;
while(node) {
myfprintf(fp,"Artist: %s\n",node->key);
node = node->nextNode;
}
return 0;
}
int printAllAlbums(FILE * fp, char * artist) {
if(artist==NULL) {
ListNode * node = albumTable->firstNode;
while(node) {
myfprintf(fp,"Album: %s\n",node->key);
node = node->nextNode;
}
}
else {
void * ad;
if(findInList(artistTable,artist,&ad)) {
ListNode * node = ((ArtistData *)ad)->albums->firstNode;
while(node) {
myfprintf(fp,"Album: %s\n",node->key);
node = node->nextNode;
}
}
else {
commandError(fp, ACK_ERROR_NO_EXIST,
"artist \"%s\" not found", artist);
return -1;
}
}
return 0;
}
int printAllKeysOfTable(FILE * fp, char * table, char * arg1) {
if(strcmp(table,TABLES_ARTIST)==0) {
if(arg1!=NULL) {
commandError(fp, ACK_ERROR_ARG,
"%s table takes no args", table);
return -1;
}
return printAllArtists(fp);
}
else if(strcmp(table,TABLES_ALBUM)==0) {
return printAllAlbums(fp,arg1);
}
else {
commandError(fp, ACK_ERROR_ARG, "unknown table", table);
return -1;
}
}

View File

@ -1,43 +0,0 @@
/* the Music Player Daemon (MPD)
* (c)2003-2004 by Warren Dukes (shank@mercury.chem.pitt.edu)
* This project's homepage is: http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef TABLES_H
#define TABLES_H
#include "../config.h"
#include "song.h"
#include <stdio.h>
void initTables();
void closeTables();
void addSongToTables(Song * song);
void removeASongFromTables(Song * song);
unsigned long numberOfSongs();
unsigned long numberOfArtists();
unsigned long numberOfAlbums();
int printAllKeysOfTable(FILE * fp, char * table, char * arg1);
#endif

305
src/tag.c
View File

@ -25,6 +25,8 @@
#include "inputStream.h"
#include "conf.h"
#include "charConv.h"
#include "tagTracker.h"
#include "mpd_types.h"
#include <sys/stat.h>
#include <stdlib.h>
@ -40,91 +42,120 @@
#include <FLAC/metadata.h>
#endif
char * mpdTagItemKeys[TAG_NUM_OF_ITEM_TYPES] =
{
"Artist",
"Album",
"Title",
"Track",
"Name",
"Genre",
"Date"
};
static mpd_sint8 ignoreTagItems[TAG_NUM_OF_ITEM_TYPES];
void initTagConfig() {
int quit = 0;
char * temp;
char * s;
char * c;
ConfigParam * param;
int i;
memset(ignoreTagItems, 0, TAG_NUM_OF_ITEM_TYPES);
param = getConfigParam(CONF_METADATA_TO_USE);
if(!param) return;
memset(ignoreTagItems, 1, TAG_NUM_OF_ITEM_TYPES);
if(0 == strcasecmp(param->value, "none")) return;
temp = c = s = strdup(param->value);
while(!quit) {
if(*s == ',' || *s == '\0') {
if(*s == '\0') quit = 1;
*s = '\0';
for(i = 0; i < TAG_NUM_OF_ITEM_TYPES; i++) {
if(strcasecmp(c, mpdTagItemKeys[i]) == 0) {
ignoreTagItems[i] = 0;
break;
}
}
if(strlen(c) && i == TAG_NUM_OF_ITEM_TYPES) {
ERROR("error parsing metadata item \"%s\" at "
"line %i\n", c, param->line);
exit(EXIT_FAILURE);
}
s++;
c = s;
}
s++;
}
free(temp);
}
void printMpdTag(FILE * fp, MpdTag * tag) {
if(tag->artist) myfprintf(fp,"Artist: %s\n",tag->artist);
if(tag->album) myfprintf(fp,"Album: %s\n",tag->album);
if(tag->track) myfprintf(fp,"Track: %s\n",tag->track);
if(tag->title) myfprintf(fp,"Title: %s\n",tag->title);
if(tag->name) myfprintf(fp,"Name: %s\n",tag->name);
int i;
if(tag->time>=0) myfprintf(fp,"Time: %i\n",tag->time);
}
#define fixUtf8(str) { \
if(str && !validUtf8String(str)) { \
char * temp; \
DEBUG("not valid utf8 in tag: %s\n",str); \
temp = latin1StrToUtf8Dup(str); \
free(str); \
str = temp; \
} \
}
void validateUtf8Tag(MpdTag * tag) {
fixUtf8(tag->artist);
stripReturnChar(tag->artist);
fixUtf8(tag->album);
stripReturnChar(tag->album);
fixUtf8(tag->track);
stripReturnChar(tag->track);
fixUtf8(tag->title);
stripReturnChar(tag->title);
fixUtf8(tag->name);
stripReturnChar(tag->name);
for(i = 0; i < tag->numOfItems; i++) {
myfprintf(fp, "%s: %s\n", mpdTagItemKeys[tag->items[i].type],
tag->items[i].value);
}
}
#ifdef HAVE_ID3TAG
char * getID3Info(struct id3_tag * tag, char * id) {
MpdTag * getID3Info(struct id3_tag * tag, char * id, int type, MpdTag * mpdTag)
{
struct id3_frame const * frame;
id3_ucs4_t const * ucs4;
id3_utf8_t * utf8;
union id3_field const * field;
unsigned int nstrings;
int i;
frame = id3_tag_findframe(tag, id, 0);
if(!frame) return NULL;
if(!frame) return mpdTag;
field = &frame->fields[1];
nstrings = id3_field_getnstrings(field);
if(nstrings<1) return NULL;
ucs4 = id3_field_getstrings(field,0);
assert(ucs4);
for(i = 0; i < nstrings; i++) {
ucs4 = id3_field_getstrings(field, i);
assert(ucs4);
utf8 = id3_ucs4_utf8duplicate(ucs4);
if(!utf8) return NULL;
if(type == TAG_ITEM_GENRE) {
ucs4 = id3_genre_name(ucs4);
}
return utf8;
utf8 = id3_ucs4_utf8duplicate(ucs4);
if(!utf8) continue;
if( NULL == mpdTag ) mpdTag = newMpdTag();
addItemToMpdTag(mpdTag, type, utf8);
free(utf8);
}
return mpdTag;
}
#endif
#ifdef HAVE_ID3TAG
MpdTag * parseId3Tag(struct id3_tag * tag) {
MpdTag * ret = NULL;
char * str;
str = getID3Info(tag,ID3_FRAME_ARTIST);
if(str) {
if(!ret) ret = newMpdTag();
ret->artist = str;
}
str = getID3Info(tag,ID3_FRAME_TITLE);
if(str) {
if(!ret) ret = newMpdTag();
ret->title = str;
}
str = getID3Info(tag,ID3_FRAME_ALBUM);
if(str) {
if(!ret) ret = newMpdTag();
ret->album = str;
}
str = getID3Info(tag,ID3_FRAME_TRACK);
if(str) {
if(!ret) ret = newMpdTag();
ret->track = str;
}
ret = getID3Info(tag, ID3_FRAME_ARTIST, TAG_ITEM_ARTIST, ret);
ret = getID3Info(tag, ID3_FRAME_TITLE, TAG_ITEM_TITLE, ret);
ret = getID3Info(tag, ID3_FRAME_ALBUM, TAG_ITEM_ALBUM, ret);
ret = getID3Info(tag, ID3_FRAME_TRACK, TAG_ITEM_TRACK, ret);
ret = getID3Info(tag, ID3_FRAME_YEAR, TAG_ITEM_DATE, ret);
ret = getID3Info(tag, ID3_FRAME_GENRE, TAG_ITEM_GENRE, ret);
return ret;
}
@ -158,21 +189,61 @@ MpdTag * id3Dup(char * file) {
MpdTag * newMpdTag() {
MpdTag * ret = malloc(sizeof(MpdTag));
ret->album = NULL;
ret->artist = NULL;
ret->title = NULL;
ret->track = NULL;
ret->name = NULL;
ret->items = NULL;
ret->time = -1;
ret->numOfItems = 0;
return ret;
}
static void deleteItem(MpdTag * tag, int index) {
tag->numOfItems--;
assert(index < tag->numOfItems);
removeTagItemString(tag->items[index].type, tag->items[index].value);
//free(tag->items[index].value);
if(tag->numOfItems-index > 0) {
memmove(tag->items+index, tag->items+index+1,
tag->numOfItems-index);
}
if(tag->numOfItems > 0) {
tag->items = realloc(tag->items,
tag->numOfItems*sizeof(MpdTagItem));
}
else {
free(tag->items);
tag->items = NULL;
}
}
void clearItemsFromMpdTag(MpdTag * tag, int type) {
int i = 0;
for(i = 0; i < tag->numOfItems; i++) {
if(tag->items[i].type == type) {
deleteItem(tag, i);
/* decrement since when just deleted this node */
i--;
}
}
}
void clearMpdTag(MpdTag * tag) {
if(tag->artist) free(tag->artist);
if(tag->album) free(tag->album);
if(tag->title) free(tag->title);
if(tag->name) free(tag->name);
if(tag->track) free(tag->track);
int i;
for(i = 0; i < tag->numOfItems; i++) {
removeTagItemString(tag->items[i].type, tag->items[i].value);
//free(tag->items[i].value);
}
if(tag->items) free(tag->items);
tag->items = NULL;
tag->numOfItems = 0;
tag->time = -1;
}
void freeMpdTag(MpdTag * tag) {
@ -182,40 +253,92 @@ void freeMpdTag(MpdTag * tag) {
MpdTag * mpdTagDup(MpdTag * tag) {
MpdTag * ret = NULL;
int i;
if(tag) {
ret = newMpdTag();
if(tag->artist) ret->artist = strdup(tag->artist);
if(tag->album) ret->album = strdup(tag->album);
if(tag->title) ret->title = strdup(tag->title);
if(tag->track) ret->track = strdup(tag->track);
if(tag->name) ret->name = strdup(tag->name);
ret->time = tag->time;
if(!tag) return NULL;
ret = newMpdTag();
ret->time = tag->time;
for(i = 0; i < tag->numOfItems; i++) {
addItemToMpdTag(ret, tag->items[i].type, tag->items[i].value);
}
return ret;
}
int mpdTagStringsAreEqual(char * s1, char * s2) {
if(s1 && s2) {
if(strcmp(s1, s2)) return 0;
}
else if(s1 || s2) return 0;
return 1;
}
int mpdTagsAreEqual(MpdTag * tag1, MpdTag * tag2) {
int i;
if(tag1 == NULL && tag2 == NULL) return 1;
else if(!tag1 || !tag2) return 0;
if(tag1->time != tag2->time) return 0;
if(!mpdTagStringsAreEqual(tag1->artist, tag2->artist)) return 0;
if(!mpdTagStringsAreEqual(tag1->album, tag2->album)) return 0;
if(!mpdTagStringsAreEqual(tag1->track, tag2->track)) return 0;
if(!mpdTagStringsAreEqual(tag1->title, tag2->title)) return 0;
if(!mpdTagStringsAreEqual(tag1->name, tag2->name)) return 0;
if(tag1->numOfItems != tag2->numOfItems) return 0;
for(i = 0; i < tag1->numOfItems; i++) {
if(tag1->items[i].type != tag2->items[i].type) return 0;
if(strcmp(tag1->items[i].value, tag2->items[i].value)) {
return 0;
}
}
return 1;
}
#define fixUtf8(str) { \
if(str && !validUtf8String(str)) { \
char * temp; \
DEBUG("not valid utf8 in tag: %s\n",str); \
temp = latin1StrToUtf8Dup(str); \
free(str); \
str = temp; \
} \
}
inline static void appendToTagItems(MpdTag * tag, int type, char * value,
int len)
{
int i = tag->numOfItems;
char * dup;
dup = malloc(len+1);
strncpy(dup, value, len);
dup[len] = '\0';
fixUtf8(dup);
tag->numOfItems++;
tag->items = realloc(tag->items, tag->numOfItems*sizeof(MpdTagItem));
tag->items[i].type = type;
tag->items[i].value = getTagItemString(type, dup);
//tag->items[i].value = strdup(dup);
free(dup);
}
void addItemToMpdTagWithLen(MpdTag * tag, int itemType, char * value, int len) {
if(ignoreTagItems[itemType]) return;
if(!value || !len) return;
appendToTagItems(tag, itemType, value, len);
}
char * getNextItemFromMpdTag(MpdTag * tag, int itemType, int * last) {
int i = 0;
if(last && *last >=0) i = *last+1;
for(i = 0; i < tag->numOfItems; i++) {
if(itemType == tag->items[i].type) {
if(last) *last = i;
return tag->items[i].value;
}
i++;
}
return NULL;
}

View File

@ -21,6 +21,10 @@
#include "../config.h"
#include "mpd_types.h"
#include <string.h>
#include <stdio.h>
#ifdef HAVE_ID3TAG
#ifdef USE_MPD_ID3TAG
@ -30,13 +34,27 @@
#endif
#endif
#define TAG_ITEM_ARTIST 0
#define TAG_ITEM_ALBUM 1
#define TAG_ITEM_TITLE 2
#define TAG_ITEM_TRACK 3
#define TAG_ITEM_NAME 4
#define TAG_ITEM_GENRE 5
#define TAG_ITEM_DATE 6
#define TAG_NUM_OF_ITEM_TYPES 7
extern char * mpdTagItemKeys[];
typedef struct _MpdTagItem {
mpd_sint8 type;
char * value;
} MpdTagItem;
typedef struct _MpdTag {
char * artist;
char * album;
char * track;
char * title;
char * name;
int time;
MpdTagItem * items;
mpd_uint8 numOfItems;
} MpdTag;
#ifdef HAVE_ID3TAG
@ -47,16 +65,26 @@ MpdTag * id3Dup(char * file);
MpdTag * newMpdTag();
void initTagConfig();
void clearItemsFromMpdTag(MpdTag * tag, int itemType);
void clearMpdTag(MpdTag * tag);
void freeMpdTag(MpdTag * tag);
void addItemToMpdTagWithLen(MpdTag * tag, int itemType, char * value, int len);
#define addItemToMpdTag(tag, itemType, value) \
addItemToMpdTagWithLen(tag, itemType, value, strlen(value))
void printMpdTag(FILE * fp, MpdTag * tag);
MpdTag * mpdTagDup(MpdTag * tag);
void validateUtf8Tag(MpdTag * tag);
int mpdTagsAreEqual(MpdTag * tag1, MpdTag * tag2);
/* *last shoudl be initialzed to -1 before calling this function */
char * getNextItemFromMpdTag(MpdTag * tag, int itemType, int * last);
#endif

142
src/tagTracker.c Normal file
View File

@ -0,0 +1,142 @@
#include "tagTracker.h"
#include "list.h"
#include "log.h"
#include <assert.h>
static List * tagLists[TAG_NUM_OF_ITEM_TYPES] =
{
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL
};
typedef struct tagTrackerItem {
int count;
mpd_sint8 visited;
} TagTrackerItem;
char * getTagItemString(int type, char * string) {
ListNode * node;
if(type == TAG_ITEM_TITLE) return strdup(string);
if(tagLists[type] == NULL) {
tagLists[type] = makeList(free);
}
if((node = findNodeInList(tagLists[type], string))) {
((TagTrackerItem *)node->data)->count++;
}
else {
TagTrackerItem * item = malloc(sizeof(TagTrackerItem));
item->count = 1;
item->visited = 0;
node = insertInList(tagLists[type], string, item);
}
return node->key;
}
void removeTagItemString(int type, char * string) {
ListNode * node;
assert(string);
if(type == TAG_ITEM_TITLE) {
free(string);
return;
}
assert(tagLists[type]);
if(tagLists[type] == NULL) return;
node = findNodeInList(tagLists[type], string);
assert(node);
if(node) {
TagTrackerItem * item = node->data;
item->count--;
if(item->count <= 0) deleteNodeFromList(tagLists[type], node);
}
if(tagLists[type]->numberOfNodes == 0) {
freeList(tagLists[type]);
tagLists[type] = NULL;
}
}
int getNumberOfTagItems(int type) {
if(tagLists[type] == NULL) return 0;
return tagLists[type]->numberOfNodes;
}
void printMemorySavedByTagTracker() {
int i;
ListNode * node;
size_t sum = 0;
for(i = 0; i < TAG_NUM_OF_ITEM_TYPES; i++) {
if(!tagLists[i]) continue;
sum -= sizeof(List);
node = tagLists[i]->firstNode;
while(node != NULL) {
sum -= sizeof(ListNode);
sum -= sizeof(TagTrackerItem);
sum -= sizeof(node->key);
sum += (strlen(node->key)+1)*(*((int *)node->data));
node = node->nextNode;
}
}
DEBUG("saved memory: %li\n", (long)sum);
}
void sortTagTrackerInfo() {
int i;
for(i = 0; i < TAG_NUM_OF_ITEM_TYPES; i++) {
if(!tagLists[i]) continue;
sortList(tagLists[i]);
}
}
void resetVisitedFlagsInTagTracker(int type) {
ListNode * node;
if(!tagLists[type]) return;
node = tagLists[type]->firstNode;
while(node) {
((TagTrackerItem *)node->data)->visited = 0;
node = node->nextNode;
}
}
int wasVisitedInTagTracker(int type, char * str) {
int ret;
ListNode * node;
TagTrackerItem * item;
if(!tagLists[type]) return 0;
node = findNodeInList(tagLists[type], str);
if(!node) return 0;
item = node->data;
ret = item->visited;
item->visited = 1;
return ret;
}

20
src/tagTracker.h Normal file
View File

@ -0,0 +1,20 @@
#ifndef TAG_TRACKER_H
#define TAG_TRACKER_H
#include "tag.h"
char * getTagItemString(int type, char * string);
void removeTagItemString(int type, char * string);
int getNumberOfTagItems(int type);
void printMemorySavedByTagTracker();
void sortTagTrackerInfo();
void resetVisitedFlagsInTagTracker(int type);
int wasVisitedInTagTracker(int type, char * str);
#endif