/** * ======================== legal notice ====================== * * File: FilesystemScanner.cc * Created: 2. Juli 2012, 13:58 * Author: Geronimo * Project: libfsScan: mediatypes and filesystem scanning * * CMP - compound media player * * is a client/server mediaplayer intended to play any media from any workstation * without the need to export or mount shares. cmps is an easy to use backend * with a (ready to use) HTML-interface. Additionally the backend supports * authentication via HTTP-digest authorization. * cmpc is a client with vdr-like osd-menues. * * Copyright (c) 2012 Reinhard Mantey, some rights reserved! * published under Creative Commons by-sa * For details see http://creativecommons.org/licenses/by-sa/3.0/ * * The cmp project's homepage is at http://projects.vdr-developer.org/projects/cmp * * -------------------------------------------------------------- */ #include #include #include #include #include #include #include #include #include #include #include #include void freeMediaCallback(void *elem) { delete (cAbstractMedia *)elem; } cFilesystemScanner::cFilesystemScanner() : baseDirectory(NULL) , fileBufSize(512) , dirEntryBuf(NULL) , pool(freeMediaCallback) , mediaFactory(NULL) { } cFilesystemScanner::~cFilesystemScanner() { FREE(dirEntryBuf); FREE(baseDirectory); pool.clear(); if (mediaFactory) delete mediaFactory; } void cFilesystemScanner::SetBaseDirectory(const char* dir) { FREE(baseDirectory); baseDirectory = strdup(dir); if (mediaFactory) mediaFactory->SetBaseDirectory(dir); } void cFilesystemScanner::SetMediaFactory(cMediaFactory* factory) { if ((mediaFactory = factory)) { FREE(baseDirectory); baseDirectory = strdup(mediaFactory->BaseDirectory()); } } // return true if a should be ordered before b bool defaultMediaSortOrder(void *a, void *b) { if (a == b) return false; if (!a) return false; if (!b) return true; cAbstractMedia *m0 = (cAbstractMedia *)a; cAbstractMedia *m1 = (cAbstractMedia *)b; bool rv = false; if (m0->MediaType() == m1->MediaType()) rv = strcasecmp(m0->Name(), m1->Name()) < 0; else rv = (m0->MediaType() - m1->MediaType()) < 0; return rv; } void cFilesystemScanner::Refresh() { if (!mediaFactory) return; pool.clear(); categories.clear(); dirEntryBuf = (struct dirent *)malloc(sizeof(struct dirent)); if (!dirEntryBuf) { esyslog("ERROR: out of memory!"); return; } parseDir(baseDirectory, pool); FREE(dirEntryBuf); cAbstractMedia::SupportedMediaType ot = cAbstractMedia::Invalid; cAbstractMedia *m; pool.sort(defaultMediaSortOrder); for (size_t i=0; i < pool.size(); ++i) { m = (cAbstractMedia *) pool[i]; if (m->MediaType() != ot) { ot = m->MediaType(); categories[ot] = i; } } } void cFilesystemScanner::parseDir(const char* dirName, cManagedVector &result) { if (!mediaFactory) return; DIR *dir = opendir(dirName); cAbstractMedia *media; char *pathBuf = (char *)malloc(fileBufSize); struct dirent *dirEntry; struct stat statBuf; if (!dir) return; if (!pathBuf) { closedir(dir); return; } if (fileBufSize < strlen(dirName) + 128) { fileBufSize += 256; pathBuf = (char *)realloc(pathBuf, fileBufSize); } while (!readdir_r(dir, dirEntryBuf, &dirEntry) && dirEntry) { if (*dirEntry->d_name == '.') continue; // don't bother with hidden stuff strcpy(pathBuf, dirName); strcat(pathBuf, "/"); strcat(pathBuf, dirEntry->d_name); if (stat(pathBuf, &statBuf) < 0) return; if ((media = mediaFactory->CreateMedia(pathBuf, &statBuf))) { result.push_back(media); isyslog("found media %s - %s", media->MimeType(), media->LogicalPath()); continue; } if ((statBuf.st_mode & S_IFMT) == S_IFDIR) parseDir(pathBuf, result); } closedir(dir); FREE(pathBuf); } cAbstractMedia *cFilesystemScanner::FindMedia(const char* LogicalPath) { cAbstractMedia *rv = NULL, *tmp; for (size_t i=0; i < pool.size(); ++i) { tmp = (cAbstractMedia *) pool[i]; if (!strcmp(tmp->LogicalPath(), LogicalPath)) { rv = tmp; break; } } return rv; }