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:
parent
86cf70dcb2
commit
c5d27d8eaa
23
TODO
23
TODO
@ -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
|
||||
|
@ -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,)
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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
267
src/dbUtils.c
Normal 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
42
src/dbUtils.h
Normal 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
|
@ -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);
|
||||
}
|
||||
|
189
src/directory.c
189
src/directory.c
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
32
src/list.c
32
src/list.c
@ -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;
|
||||
|
@ -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
|
||||
*/
|
||||
|
10
src/main.c
10
src/main.c
@ -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();
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
56
src/song.c
56
src/song.c
@ -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;
|
||||
|
@ -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));
|
||||
|
200
src/tables.c
200
src/tables.c
@ -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;
|
||||
}
|
||||
}
|
43
src/tables.h
43
src/tables.h
@ -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
305
src/tag.c
@ -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;
|
||||
}
|
||||
|
42
src/tag.h
42
src/tag.h
@ -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
142
src/tagTracker.c
Normal 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
20
src/tagTracker.h
Normal 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
|
Loading…
Reference in New Issue
Block a user