musiccatalog.cpp
字号:
Error MusicCatalog::Remove(const char *url)
{
assert(url);
if (!m_database->Working())
return kError_DatabaseNotWorking;
char *data = m_database->Value(url);
if (!data)
return kError_ItemNotFound;
Error retvalue = kError_YouScrewedUp;
if (!strncmp("P", data, 1))
retvalue = RemovePlaylist(url);
else if (!strncmp("M", data, 1))
retvalue = RemoveSong(url);
else if (!strncmp("S", data, 1))
retvalue = RemoveStream(url);
delete [] data;
return retvalue;
}
Error MusicCatalog::Add(const char *url)
{
assert(url);
if (!m_database->Working())
return kError_DatabaseNotWorking;
char *data = m_database->Value(url);
if (!data)
return kError_ItemNotFound;
Error retvalue = kError_YouScrewedUp;
if (!strncmp("P", data, 1))
retvalue = AddPlaylist(url);
else if (!strncmp("M", data, 1))
retvalue = AddSong(url);
else if (!strncmp("S", data, 1))
retvalue = AddStream(url);
delete [] data;
return retvalue;
}
void MusicCatalog::ClearCatalog()
{
m_catMutex->Acquire();
delete m_artistList;
delete m_unsorted;
delete m_playlists;
delete m_streams;
m_artistList = new vector<ArtistList *>;
m_unsorted = new vector<PlaylistItem *>;
m_playlists = new vector<string>;
m_streams = new vector<PlaylistItem *>;
m_catMutex->Release();
m_context->target->AcceptEvent(new Event(INFO_MusicCatalogCleared));
}
Error MusicCatalog::RePopulateFromDatabase()
{
if (!m_database->Working())
return kError_DatabaseNotWorking;
ClearCatalog();
char *key = m_database->NextKey(NULL);
Error err = kError_NoErr;
while (key) {
err = Add(key);
if (IsError(err)) {
m_context->target->AcceptEvent(new ErrorMessageEvent("There was an internal error during generation of the Music Catalog"));
return kError_YouScrewedUp;
}
key = m_database->NextKey(key);
}
return kError_NoErr;
}
void MusicCatalog::SetDatabase(const char *path)
{
if (m_database)
delete m_database;
m_database = new Database(path, METADATABASE_VERSION);
if (!m_database->Working()) {
delete m_database;
m_database = NULL;
}
PruneDatabase();
if (m_database) {
RePopulateFromDatabase();
Sort();
}
}
void MusicCatalog::PruneDatabase(void)
{
char *key = m_database->NextKey(NULL);
struct stat st;
while (key) {
if (!strncmp("file://", key, 7)) {
uint32 length = strlen(key) + 1;
char *filename = new char[length];
if (IsntError(URLToFilePath(key, filename, &length)))
if (-1 == stat(filename, &st)) {
m_database->Remove(key);
key = NULL;
}
delete [] filename;
}
key = m_database->NextKey(key);
}
}
typedef struct MusicSearchThreadStruct {
MusicCatalog *mc;
vector<string> pathList;
Thread *thread;
} MusicSearchThreadStruct;
void MusicCatalog::SearchMusic(vector<string> &pathList)
{
if (!m_database->Working())
return;
Thread *thread = Thread::CreateThread();
if (thread) {
MusicSearchThreadStruct *mst = new MusicSearchThreadStruct;
mst->mc = this;
mst->pathList = pathList;
mst->thread = thread;
thread->Create(musicsearch_thread_function, mst);
}
}
void MusicCatalog::StopSearchMusic(void)
{
m_exit = true;
}
void MusicCatalog::musicsearch_thread_function(void *arg)
{
MusicSearchThreadStruct *mst = (MusicSearchThreadStruct *)arg;
mst->mc->m_mutex->Acquire();
mst->mc->m_exit = false;
mst->mc->DoSearchPaths(mst->pathList);
mst->mc->AcceptEvent(new Event(INFO_SearchMusicDone));
mst->mc->m_mutex->Release();
delete mst->thread;
delete mst;
}
void MusicCatalog::DoSearchPaths(vector<string> &pathList)
{
vector<string>::iterator i;
m_acceptItemChanged = true;
m_itemWaitCount = 0;
for(i = pathList.begin(); i != pathList.end(); i++)
DoSearchMusic((char *)(*i).c_str());
while (m_itemWaitCount > 0)
usleep(5);
m_acceptItemChanged = false;
}
void MusicCatalog::DoSearchMusic(char *path)
{
vector<PlaylistItem *> *metalist = new vector<PlaylistItem *>;
WIN32_FIND_DATA find;
HANDLE handle;
string search = path;
#ifndef WIN32
if (!strcmp(path, "/dev") || !strcmp(path, "/proc"))
return;
#endif
string *info = new string("Searching: ");
(*info) += path;
m_context->player->AcceptEvent(new BrowserMessageEvent(info->c_str()));
delete info;
if (search[search.size() - 1] != DIR_MARKER)
search.append(DIR_MARKER_STR);
search.append("*");
#ifdef WIN32
search.append(".*");
#endif
handle = FindFirstFile((char *)search.c_str(), &find);
if (handle != INVALID_HANDLE_VALUE)
{
do
{
char *fileExt;
#ifndef WIN32
if (find.dwFileAttributes == FILE_ATTRIBUTE_SYMLINK)
continue;
#endif
if (find.dwFileAttributes == FILE_ATTRIBUTE_DIRECTORY)
{
if (!(!strcmp("." , find.cFileName) || !strcmp("..", find.cFileName)))
{
string newDir = path;
if (path[strlen(path) - 1] != DIR_MARKER)
newDir.append(DIR_MARKER_STR);
newDir.append(find.cFileName);
DoSearchMusic((char *)newDir.c_str());
}
}
else if ((fileExt = m_context->player->GetExtension(find.cFileName)))
{
if (m_plm->IsSupportedPlaylistFormat(fileExt) &&
strcmp("currentlist.m3u", find.cFileName))
{
string file = path;
file.append(DIR_MARKER_STR);
file.append(find.cFileName);
uint32 urlLength = strlen(file.c_str()) + 10;
char *url = new char[urlLength];
if (IsntError(FilePathToURL(file.c_str(), url, &urlLength)))
m_database->Insert(url, "P");
delete [] url;
}
else if (m_context->player->IsSupportedExtension(fileExt))
{
string file = path;
file.append(DIR_MARKER_STR);
file.append(find.cFileName);
char *tempurl = new char[file.length() + 10];
uint32 length = file.length() + 10;
if (IsError(FilePathToURL(file.c_str(), tempurl, &length)))
{
continue;
}
PlaylistItem *plist = new PlaylistItem(tempurl);
metalist->push_back(plist);
m_itemWaitCount++;
delete [] tempurl;
}
delete fileExt;
}
}
while (FindNextFile(handle, &find) && !m_exit);
FindClose(handle);
if (metalist->size() > 0)
m_plm->RetrieveMetaData(metalist);
else
delete metalist;
}
}
void MusicCatalog::WriteMetaDataToDatabase(const char *url,
const MetaData metadata,
MetadataStorageType type)
{
if (!m_database->Working())
return;
ostringstream ost;
char num[256];
const char *kDatabaseDelimiter = " ";
if (type == kTypeStream)
ost << "S" << kDatabaseDelimiter;
else
ost << "M" << kDatabaseDelimiter;
ost << 9 << kDatabaseDelimiter;
ost << metadata.Artist().size() << kDatabaseDelimiter;
ost << metadata.Album().size() << kDatabaseDelimiter;
ost << metadata.Title().size() << kDatabaseDelimiter;
ost << metadata.Comment().size() << kDatabaseDelimiter;
ost << metadata.Genre().size() << kDatabaseDelimiter;
sprintf(num, "%ld", (long int)metadata.Year());
ost << strlen(num) << kDatabaseDelimiter;
sprintf(num, "%ld", (long int)metadata.Track());
ost << strlen(num) << kDatabaseDelimiter;
sprintf(num, "%ld", (long int)metadata.Time());
ost << strlen(num) << kDatabaseDelimiter;
sprintf(num, "%ld", (long int)metadata.Size());
ost << strlen(num) << kDatabaseDelimiter;
ost << metadata.Artist();
ost << metadata.Album();
ost << metadata.Title();
ost << metadata.Comment();
ost << metadata.Genre();
ost << metadata.Year();
ost << metadata.Track();
ost << metadata.Time();
ost << metadata.Size();
ost << '\0';
#ifdef WIN32
m_database->Insert(url, (char *)ost.str().c_str());
#else
m_database->Insert(url, (char *)ost.str());
#endif
}
MetaData *MusicCatalog::ReadMetaDataFromDatabase(const char *url)
{
if (!m_database->Working())
return NULL;
char *dbasedata = m_database->Value(url);
if (!dbasedata)
return NULL;
MetaData *metadata = new MetaData();
char *value = dbasedata + 2;
uint32 numFields = 0;
int offset = 0;
sscanf(value, "%lu%n", (long unsigned int *)&numFields, &offset);
uint32* fieldLength = new uint32[numFields];
for(uint32 i = 0; i < numFields; i++)
{
int temp;
sscanf(value + offset, " %lu %n", (long unsigned int *)&fieldLength[i],
&temp);
if (i == numFields - 1) {
char intholder[10];
sprintf(intholder, "%lu", (long unsigned int)fieldLength[i]);
offset += strlen(intholder) + 1;
}
else
offset += temp;
}
string data = value;
data.erase(0, offset);
uint32 count = 0;
for(uint32 j = 0; j < numFields; j++)
{
if (fieldLength[j] == 0)
continue;
switch(j)
{
case 0:
metadata->SetArtist(data.substr(count, fieldLength[j]).c_str());
break;
case 1:
metadata->SetAlbum(data.substr(count, fieldLength[j]).c_str());
break;
case 2:
metadata->SetTitle(data.substr(count, fieldLength[j]).c_str());
break;
case 3:
metadata->SetComment(data.substr(count, fieldLength[j]).c_str());
break;
case 4:
metadata->SetGenre(data.substr(count, fieldLength[j]).c_str());
break;
case 5:
metadata->SetYear(atoi(data.substr(count, fieldLength[j]).c_str()));
break;
case 6:
metadata->SetTrack(atoi(data.substr(count, fieldLength[j]).c_str()));
break;
case 7:
metadata->SetTime(atoi(data.substr(count, fieldLength[j]).c_str()));
break;
case 8:
metadata->SetSize(atoi(data.substr(count, fieldLength[j]).c_str()));
break;
default:
break;
}
count += fieldLength[j];
}
delete [] fieldLength;
delete [] dbasedata;
return metadata;
}
int32 MusicCatalog::AcceptEvent(Event *e)
{
switch (e->Type()) {
case INFO_MusicCatalogTrackRemoved: {
if (m_inUpdateSong) {
MusicCatalogTrackRemovedEvent *mctr =
(MusicCatalogTrackRemovedEvent *)e;
m_oldItem = (PlaylistItem *)mctr->Item();
m_oldArtist = (ArtistList *)mctr->Artist();
m_oldAlbum = (AlbumList *)mctr->Album();
delete e;
}
else
m_context->target->AcceptEvent(e);
break; }
case INFO_MusicCatalogTrackAdded: {
if (m_inUpdateSong) {
MusicCatalogTrackAddedEvent *mcta =
(MusicCatalogTrackAddedEvent *)e;
m_newItem = (PlaylistItem *)mcta->Item();
m_newArtist = (ArtistList *)mcta->Artist();
m_newAlbum = (AlbumList *)mcta->Album();
delete e;
}
else
m_context->target->AcceptEvent(e);
break; }
case INFO_PlaylistItemUpdated: {
if (m_acceptItemChanged) {
PlaylistItemUpdatedEvent *piu = (PlaylistItemUpdatedEvent *)e;
WriteMetaDataToDatabase(piu->Item()->URL().c_str(),
(MetaData)piu->Item()->GetMetaData());
delete piu->Item();
m_itemWaitCount--;
}
break; }
case INFO_SearchMusicDone: {
m_database->Sync();
string info = "Pruning the Music Catalog Database...";
m_context->target->AcceptEvent(new BrowserMessageEvent(info.c_str()));
PruneDatabase();
info = "Regenerating the Music Catalog Database...";
m_context->target->AcceptEvent(new BrowserMessageEvent(info.c_str()));
RePopulateFromDatabase();
info = "Sorting the Music Catalog Database...";
m_context->target->AcceptEvent(new BrowserMessageEvent(info.c_str()));
Sort();
m_context->target->AcceptEvent(new Event(INFO_SearchMusicDone));
delete e;
break;
}
}
return 0;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -