7
7
Copyright (C) 2005 Gena Batyan <bgeradz@mediatomb.cc>,
8
8
Sergey 'Jin' Bostandzhyan <jin@mediatomb.cc>
10
Copyright (C) 2006-2007 Gena Batyan <bgeradz@mediatomb.cc>,
10
Copyright (C) 2006-2008 Gena Batyan <bgeradz@mediatomb.cc>,
11
11
Sergey 'Jin' Bostandzhyan <jin@mediatomb.cc>,
12
12
Leonhard Wimmer <leo@mediatomb.cc>
24
24
version 2 along with MediaTomb; if not, write to the Free Software
25
25
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
27
$Id: content_manager.cc 1388 2007-07-11 17:08:40Z jin_eld $
27
$Id: content_manager.cc 1698 2008-02-23 20:48:30Z lww $
30
30
/// \file content_manager.cc
107
121
extension_mimetype_map =
108
122
cm->getDictionaryOption(CFG_IMPORT_MAPPINGS_EXTENSION_TO_MIMETYPE_LIST);
110
String optIgnoreUnknown =
111
cm->getOption(CFG_IMPORT_MAPPINGS_IGNORE_UNKNOWN_EXTENSIONS);
112
if (optIgnoreUnknown != nil && optIgnoreUnknown == "yes")
113
ignore_unknown_extensions = 1;
124
ignore_unknown_extensions = cm->getBoolOption(CFG_IMPORT_MAPPINGS_IGNORE_UNKNOWN_EXTENSIONS);
115
126
if (ignore_unknown_extensions && (extension_mimetype_map->size() == 0))
117
128
log_warning("Ignore unknown extensions set, but no mappings specified\n");
118
129
log_warning("Please review your configuration!\n");
119
ignore_unknown_extensions = 0;
130
ignore_unknown_extensions = false;
133
extension_map_case_sensitive = cm->getBoolOption(CFG_IMPORT_MAPPINGS_EXTENSION_TO_MIMETYPE_CASE_SENSITIVE);
122
135
mimetype_upnpclass_map =
123
136
cm->getDictionaryOption(CFG_IMPORT_MAPPINGS_MIMETYPE_TO_UPNP_CLASS_LIST);
125
138
Ref<AutoscanList> config_timed_list =
126
139
cm->getAutoscanListOption(CFG_IMPORT_AUTOSCAN_TIMED_LIST);
128
for (int i = 0; i < config_timed_list->size(); i++)
141
for (i = 0; i < config_timed_list->size(); i++)
130
143
Ref<AutoscanDirectory> dir = config_timed_list->get(i);
143
156
autoscan_timed = storage->getAutoscanList(TimedScanMode);
145
158
#ifdef HAVE_INOTIFY
146
Ref<AutoscanList> config_inotify_list =
147
cm->getAutoscanListOption(CFG_IMPORT_AUTOSCAN_INOTIFY_LIST);
149
for (int i = 0; i < config_inotify_list->size(); i++)
159
if (cm->getBoolOption(CFG_IMPORT_AUTOSCAN_USE_INOTIFY))
151
Ref<AutoscanDirectory> dir = config_inotify_list->get(i);
161
Ref<AutoscanList> config_inotify_list =
162
cm->getAutoscanListOption(CFG_IMPORT_AUTOSCAN_INOTIFY_LIST);
164
for (i = 0; i < config_inotify_list->size(); i++)
154
String path = dir->getLocation();
155
if (check_path(path, true))
166
Ref<AutoscanDirectory> dir = config_inotify_list->get(i);
157
dir->setObjectID(ensurePathExistence(path));
169
String path = dir->getLocation();
170
if (check_path(path, true))
172
dir->setObjectID(ensurePathExistence(path));
177
storage->updateAutoscanPersistentList(InotifyScanMode,
178
config_inotify_list);
179
autoscan_inotify = storage->getAutoscanList(InotifyScanMode);
162
storage->updateAutoscanPersistentList(InotifyScanMode, config_inotify_list);
163
autoscan_inotify = storage->getAutoscanList(InotifyScanMode);
182
// make an empty list so we do not have to do extra checks on shutdown
183
autoscan_inotify = Ref<AutoscanList>(new AutoscanList());
165
185
/* init filemagic */
166
186
#ifdef HAVE_MAGIC
190
210
cm->getOption(CFG_IMPORT_SCRIPTING_VIRTUAL_LAYOUT_TYPE);
191
211
if ((layout_type == "builtin") || (layout_type == "js"))
192
212
layout_enabled = true;
214
#ifdef ONLINE_SERVICES
215
online_services = Ref<OnlineServiceList>(new OnlineServiceList());
217
if (cm->getBoolOption(CFG_ONLINE_CONTENT_YOUTUBE_ENABLED))
221
Ref<OnlineService> yt((OnlineService *)new YouTubeService());
223
i = cm->getIntOption(CFG_ONLINE_CONTENT_YOUTUBE_REFRESH);
224
yt->setRefreshInterval(i);
226
i = cm->getIntOption(CFG_ONLINE_CONTENT_YOUTUBE_PURGE_AFTER);
227
yt->setItemPurgeInterval(i);
229
if (cm->getBoolOption(CFG_ONLINE_CONTENT_YOUTUBE_UPDATE_AT_START))
230
i = CFG_DEFAULT_UPDATE_AT_START;
232
Ref<TimerParameter> yt_param(new TimerParameter(TimerParameter::IDOnlineContent, OS_YouTube));
233
yt->setTimerParameter(RefCast(yt_param, Object));
234
online_services->registerService(yt);
238
Timer::getInstance()->addTimerSubscriber(AS_TIMER_SUBSCRIBER_SINGLETON(this), i, yt->getTimerParameter(), true);
243
log_error("Could not setup YouTube: %s\n",
244
ex.getMessage().c_str());
250
if (cm->getBoolOption(CFG_ONLINE_CONTENT_SOPCAST_ENABLED))
254
Ref<OnlineService> sc((OnlineService *)new SopCastService());
256
i = cm->getIntOption(CFG_ONLINE_CONTENT_SOPCAST_REFRESH);
257
sc->setRefreshInterval(i);
259
i = cm->getIntOption(CFG_ONLINE_CONTENT_SOPCAST_PURGE_AFTER);
260
sc->setItemPurgeInterval(i);
262
if (cm->getBoolOption(CFG_ONLINE_CONTENT_SOPCAST_UPDATE_AT_START))
263
i = CFG_DEFAULT_UPDATE_AT_START;
265
Ref<TimerParameter> sc_param(new TimerParameter(TimerParameter::IDOnlineContent, OS_SopCast));
266
sc->setTimerParameter(RefCast(sc_param, Object));
267
online_services->registerService(sc);
270
Timer::getInstance()->addTimerSubscriber(AS_TIMER_SUBSCRIBER_SINGLETON(this), i, sc->getTimerParameter(), true);
275
log_error("Could not setup SopCast: %s\n",
276
ex.getMessage().c_str());
282
#endif //ONLINE_SERVICES
195
285
ContentManager::~ContentManager()
233
323
autoscan_timed->notifyAll(AS_TIMER_SUBSCRIBER_SINGLETON(this));
235
325
#ifdef HAVE_INOTIFY
236
inotify = Ref<AutoscanInotify>(new AutoscanInotify());
237
/// \todo change this for 0.9.1 (we need a new autoscan architecture)
238
for (int i = 0; i < autoscan_inotify->size(); i++)
240
Ref<AutoscanDirectory> dir = autoscan_inotify->get(i);
242
inotify->monitor(dir);
248
void ContentManager::timerNotify(int id)
250
Ref<AutoscanDirectory> dir = autoscan_timed->get(id);
254
int objectID = dir->getObjectID();
255
rescanDirectory(objectID, dir->getScanID(), dir->getScanMode());
326
if (ConfigManager::getInstance()->getBoolOption(CFG_IMPORT_AUTOSCAN_USE_INOTIFY))
328
inotify = Ref<AutoscanInotify>(new AutoscanInotify());
329
/// \todo change this (we need a new autoscan architecture)
330
for (int i = 0; i < autoscan_inotify->size(); i++)
332
Ref<AutoscanDirectory> dir = autoscan_inotify->get(i);
334
inotify->monitor(dir);
339
#ifdef EXTERNAL_TRANSCODING
340
process_list = Ref<Array<Executor> >(new Array<Executor>());
344
#if defined(EXTERNAL_TRANSCODING) || defined(SOPCAST)
345
void ContentManager::registerExecutor(Ref<Executor> exec)
348
process_list->append(exec);
351
void ContentManager::unregisterExecutor(Ref<Executor> exec)
353
// when shutting down we will kill the transcoding processes,
354
// which if given enough time will get a close in the io handler and
355
// will try to unregister themselves - this would mess up the
356
// transcoding_processes list
357
// since we are anyway shutting down we can ignore the unregister call
358
// and go through the list, ensuring that no zombie stays alive :>
363
for (int i = 0; i < process_list->size(); i++)
365
if (process_list->get(i) == exec)
366
process_list->remove(i);
371
void ContentManager::timerNotify(Ref<Object> parameter)
373
if (parameter == nil)
376
Ref<TimerParameter> tp = RefCast(parameter, TimerParameter);
377
if (tp->whoami() == TimerParameter::IDAutoscan)
379
Ref<AutoscanDirectory> dir = autoscan_timed->get(tp->getID());
383
int objectID = dir->getObjectID();
384
rescanDirectory(objectID, dir->getScanID(), dir->getScanMode());
386
#ifdef ONLINE_SERVICES
387
else if (tp->whoami() == TimerParameter::IDOnlineContent)
389
fetchOnlineContent((service_type_t)(tp->getID()));
258
394
void ContentManager::shutdown()
1326
1478
_loadAccounting();
1329
int ContentManager::addFile(zmm::String path, bool recursive, bool async, bool hidden, bool lowPriority, bool cancellable)
1482
int ContentManager::addFile(zmm::String path, bool recursive, bool async,
1483
bool hidden, bool lowPriority, bool cancellable)
1331
1485
return addFileInternal(path, recursive, async, hidden, lowPriority, 0, cancellable);
1334
int ContentManager::addFileInternal(zmm::String path, bool recursive, bool async,
1335
bool hidden, bool lowPriority, unsigned int parentTaskID, bool cancellable)
1488
int ContentManager::addFileInternal(zmm::String path, bool recursive,
1489
bool async, bool hidden, bool lowPriority,
1490
unsigned int parentTaskID,
1507
#ifdef ONLINE_SERVICES
1508
void ContentManager::fetchOnlineContent(service_type_t service,
1509
bool lowPriority, bool cancellable)
1511
Ref<OnlineService> os = online_services->getService(service);
1514
log_debug("No surch service! %d\n", service);
1515
throw _Exception(_("Service not found!"));
1517
fetchOnlineContentInternal(os, lowPriority, cancellable);
1520
void ContentManager::fetchOnlineContentInternal(Ref<OnlineService> service,
1521
bool lowPriority, bool cancellable,
1522
unsigned int parentTaskID)
1524
Ref<CMTask> task(new CMFetchOnlineContentTask(service, cancellable));
1525
task->setDescription(_("Updating content from ") +
1526
service->getServiceName());
1527
task->setParentID(parentTaskID);
1528
service->incTaskCount();
1529
addTask(task, lowPriority);
1532
void ContentManager::_fetchOnlineContent(Ref<OnlineService> service,
1533
unsigned int parentTaskID)
1535
log_debug("Fetching online content!\n");
1539
if (service->refreshServiceData(layout) && (!shutdownFlag))
1541
log_debug("Scheduling another task for online service: %s\n",
1542
service->getServiceName().c_str());
1544
if (service->getRefreshInterval() > 0)
1545
fetchOnlineContentInternal(service, true, true, parentTaskID);
1549
log_debug("Finished fetch cycle for service: %s\n",
1550
service->getServiceName().c_str());
1552
if (service->getItemPurgeInterval() > 0)
1554
Ref<Storage> storage = Storage::getInstance();
1555
Ref<IntArray> ids = storage->getServiceObjectIDs(service->getStoragePrefix());
1557
struct timespec current, last;
1558
getTimespecNow(¤t);
1562
for (int i = 0; i < ids->size(); i++)
1564
int object_id = ids->get(i);
1565
Ref<CdsObject> obj = storage->loadObject(object_id);
1569
temp = obj->getAuxData(_(ONLINE_SERVICE_LAST_UPDATE));
1570
if (!string_ok(temp))
1573
last.tv_sec = temp.toLong();
1575
if ((service->getItemPurgeInterval() > 0) &&
1576
((current.tv_sec - last.tv_sec) > service->getItemPurgeInterval()))
1578
log_debug("Purging old online service object %s\n",
1579
obj->getTitle().c_str());
1580
removeObject(object_id, false);
1351
1588
void ContentManager::invalidateAddTask(Ref<CMTask> t, String path)
1353
1590
if (t->getType() == AddFile)
1439
1676
Ref<AutoscanList> rm_list = autoscan_timed->removeIfSubdir(path);
1440
1677
for (i = 0; i < rm_list->size(); i++)
1442
Timer::getInstance()->removeTimerSubscriber(AS_TIMER_SUBSCRIBER_SINGLETON(this), rm_list->get(i)->getScanID(), true);
1679
Timer::getInstance()->removeTimerSubscriber(AS_TIMER_SUBSCRIBER_SINGLETON(this), rm_list->get(i)->getTimerParameter(), true);
1444
1681
#ifdef HAVE_INOTIFY
1445
rm_list = autoscan_inotify->removeIfSubdir(path);
1446
for (i = 0; i < rm_list->size(); i++)
1682
if (ConfigManager::getInstance()->getBoolOption(CFG_IMPORT_AUTOSCAN_USE_INOTIFY))
1448
Ref<AutoscanDirectory> dir = rm_list->get(i);
1449
inotify->unmonitor(dir);
1684
rm_list = autoscan_inotify->removeIfSubdir(path);
1685
for (i = 0; i < rm_list->size(); i++)
1687
Ref<AutoscanDirectory> dir = rm_list->get(i);
1688
inotify->unmonitor(dir);
1576
1816
SessionManager::getInstance()->containerChangedUI(adir->getObjectID());
1578
1818
// if 3rd parameter is true: won't fail if scanID doesn't exist
1579
Timer::getInstance()->removeTimerSubscriber(AS_TIMER_SUBSCRIBER_SINGLETON(this), scanID, true);
1819
Timer::getInstance()->removeTimerSubscriber(AS_TIMER_SUBSCRIBER_SINGLETON(this), adir->getTimerParameter(), true);
1582
1822
#ifdef HAVE_INOTIFY
1583
else if (scanMode == InotifyScanMode)
1823
if (ConfigManager::getInstance()->getBoolOption(CFG_IMPORT_AUTOSCAN_USE_INOTIFY))
1585
Ref<Storage> storage = Storage::getInstance();
1586
Ref<AutoscanDirectory> adir = autoscan_inotify->get(scanID);
1588
throw _Exception(_("can not remove autoscan directory - was not an autoscan"));
1589
autoscan_inotify->remove(scanID);
1590
storage->removeAutoscanDirectory(adir->getStorageID());
1591
SessionManager::getInstance()->containerChangedUI(adir->getObjectID());
1592
inotify->unmonitor(adir);
1825
if (scanMode == InotifyScanMode)
1827
Ref<Storage> storage = Storage::getInstance();
1828
Ref<AutoscanDirectory> adir = autoscan_inotify->get(scanID);
1830
throw _Exception(_("can not remove autoscan directory - was not an autoscan"));
1831
autoscan_inotify->remove(scanID);
1832
storage->removeAutoscanDirectory(adir->getStorageID());
1833
SessionManager::getInstance()->containerChangedUI(adir->getObjectID());
1834
inotify->unmonitor(adir);
1605
1848
if (adir->getScanMode() == TimedScanMode)
1607
int scanID = autoscan_timed->remove(adir->getLocation());
1850
autoscan_timed->remove(adir->getLocation());
1608
1851
storage->removeAutoscanDirectoryByObjectID(objectID);
1609
1852
SessionManager::getInstance()->containerChangedUI(objectID);
1610
Timer::getInstance()->removeTimerSubscriber(AS_TIMER_SUBSCRIBER_SINGLETON(this), scanID, true);
1853
Timer::getInstance()->removeTimerSubscriber(AS_TIMER_SUBSCRIBER_SINGLETON(this), adir->getTimerParameter(), true);
1612
1855
#ifdef HAVE_INOTIFY
1613
else if (adir->getScanMode() == InotifyScanMode)
1856
if (ConfigManager::getInstance()->getBoolOption(CFG_IMPORT_AUTOSCAN_USE_INOTIFY))
1615
autoscan_inotify->remove(adir->getLocation());
1616
storage->removeAutoscanDirectoryByObjectID(objectID);
1617
SessionManager::getInstance()->containerChangedUI(objectID);
1618
inotify->unmonitor(adir);
1858
if (adir->getScanMode() == InotifyScanMode)
1860
autoscan_inotify->remove(adir->getLocation());
1861
storage->removeAutoscanDirectoryByObjectID(objectID);
1862
SessionManager::getInstance()->containerChangedUI(objectID);
1863
inotify->unmonitor(adir);
1695
1947
if (dir->getScanMode() == TimedScanMode)
1697
1949
scanID = autoscan_timed->add(dir);
1698
timerNotify(scanID);
1950
timerNotify(dir->getTimerParameter());
1700
1952
#ifdef HAVE_INOTIFY
1701
else if (dir->getScanMode() == InotifyScanMode)
1953
if (ConfigManager::getInstance()->getBoolOption(CFG_IMPORT_AUTOSCAN_USE_INOTIFY))
1703
autoscan_inotify->add(dir);
1704
inotify->monitor(dir);
1955
if (dir->getScanMode() == InotifyScanMode)
1957
autoscan_inotify->add(dir);
1958
inotify->monitor(dir);
1707
1962
SessionManager::getInstance()->containerChangedUI(dir->getObjectID());
1711
1966
if (original->getScanMode() == TimedScanMode)
1712
Timer::getInstance()->removeTimerSubscriber(AS_TIMER_SUBSCRIBER_SINGLETON(this), original->getScanID(), true);
1967
Timer::getInstance()->removeTimerSubscriber(AS_TIMER_SUBSCRIBER_SINGLETON(this), original->getTimerParameter(), true);
1713
1968
#ifdef HAVE_INOTIFY
1714
else if (original->getScanMode() == InotifyScanMode)
1969
if (ConfigManager::getInstance()->getBoolOption(CFG_IMPORT_AUTOSCAN_USE_INOTIFY))
1716
inotify->unmonitor(original);
1971
if (original->getScanMode() == InotifyScanMode)
1973
inotify->unmonitor(original);
1754
2015
if (dir->getScanMode() == TimedScanMode)
1756
2017
scanID = autoscan_timed->add(copy);
1757
timerNotify(scanID);
2018
timerNotify(copy->getTimerParameter());
1759
2020
#ifdef HAVE_INOTIFY
1760
else if (dir->getScanMode() == InotifyScanMode)
2021
if (ConfigManager::getInstance()->getBoolOption(CFG_IMPORT_AUTOSCAN_USE_INOTIFY))
1762
autoscan_inotify->add(copy);
1763
inotify->monitor(copy);
2023
if (dir->getScanMode() == InotifyScanMode)
2025
autoscan_inotify->add(copy);
2026
inotify->monitor(copy);
1842
2106
dir->updateLMT();
1843
2107
if (dir->getScanMode() == TimedScanMode)
1844
Timer::getInstance()->addTimerSubscriber(AS_TIMER_SUBSCRIBER_SINGLETON_FROM_REF(cm), dir->getInterval(), dir->getScanID(), true);
2108
Timer::getInstance()->addTimerSubscriber(AS_TIMER_SUBSCRIBER_SINGLETON_FROM_REF(cm), dir->getInterval(), dir->getTimerParameter(), true);
2112
#ifdef ONLINE_SERVICES
2113
CMFetchOnlineContentTask::CMFetchOnlineContentTask(Ref<OnlineService> service,
2116
this->service = service;
2117
this->taskType = FetchOnlineContent;
2118
this->cancellable = cancellable;
2121
void CMFetchOnlineContentTask::run(Ref<ContentManager> cm)
2123
if (this->service == nil)
2125
log_debug("Received invalid service!\n");
2128
cm->_fetchOnlineContent(service, getParentID());
2129
service->decTaskCount();
2130
if (service->getTaskCount() == 0)
2132
Timer::getInstance()->addTimerSubscriber(AS_TIMER_SUBSCRIBER_SINGLETON_FROM_REF(cm),
2133
service->getRefreshInterval(),
2134
service->getTimerParameter(), true);
1848
2139
CMLoadAccountingTask::CMLoadAccountingTask() : CMTask()