25 const Cc = Components.classes;
26 const Ci = Components.interfaces;
27 const Cr = Components.results;
28 const Ce = Components.Exception;
30 Components.utils.import(
"resource://gre/modules/XPCOMUtils.jsm");
31 Components.utils.import(
"resource://app/jsmodules/sbProperties.jsm");
32 Components.utils.import(
"resource://app/jsmodules/sbLibraryUtils.jsm");
33 Components.utils.import(
"resource://app/jsmodules/StringUtils.jsm");
42 var obs =
Cc[
"@mozilla.org/observer-service;1"]
43 .getService(
Ci.nsIObserverService);
44 obs.addObserver(
this,
'songbird-library-manager-ready',
false);
51 classID : Components.ID(
"{35af253e-c7b0-40d6-a1a2-c747de924639}"),
52 contractID :
"@songbirdnest.com/Songbird/SmartMediaListsUpdater;1",
58 _updatedProperties : {},
64 _updateVideoQueue : {},
70 _updateInitialDelay : 1000,
74 _maxInitialDelay : 5000,
78 _timerInitTime :
null,
81 _causeMoreChecks :
false,
84 _updateSubsequentDelay : 500,
90 _dirtyPropertiesTable :
"smartplupd_dirty_properties",
91 _dirtyListsTable :
"smartplupd_dirty_lists",
92 _updateVideoListsTable :
"smartplupd_update_video_lists",
99 var obs =
Cc[
"@mozilla.org/observer-service;1"]
100 .getService(
Ci.nsIObserverService);
102 if (topic ==
"songbird-library-manager-ready") {
106 obs.removeObserver(
this,
"songbird-library-manager-ready");
107 obs.addObserver(
this,
"final-ui-startup",
false);
108 }
else if (topic ==
"final-ui-startup") {
111 obs.removeObserver(
this,
"final-ui-startup");
112 obs.addObserver(
this,
"songbird-library-manager-before-shutdown",
false);
114 }
else if (topic ==
"songbird-library-manager-before-shutdown") {
115 obs.removeObserver(
this,
"songbird-library-manager-before-shutdown");
128 Ci.sbIMediaList.LISTENER_FLAGS_ITEMADDED |
129 Ci.sbIMediaList.LISTENER_FLAGS_AFTERITEMREMOVED |
130 Ci.sbIMediaList.LISTENER_FLAGS_ITEMUPDATED |
131 Ci.sbIMediaList.LISTENER_FLAGS_BATCHBEGIN |
132 Ci.sbIMediaList.LISTENER_FLAGS_BATCHEND |
133 Ci.sbIMediaList.LISTENER_FLAGS_LISTCLEARED,
138 this._dbQuery =
Cc[
"@songbirdnest.com/Songbird/DatabaseQuery;1"]
139 .createInstance(
Ci.sbIDatabaseQuery);
140 this._dbQuery.setAsyncQuery(
false);
141 this._dbQuery.setDatabaseGUID(
"songbird");
144 this._dbQuery.resetQuery();
145 this._dbQuery.addQuery(
"CREATE TABLE IF NOT EXISTS " +
146 this._dirtyPropertiesTable +
147 " (propertyid TEXT UNIQUE NOT NULL)");
148 this._dbQuery.execute();
151 this._dbQuery.resetQuery();
152 this._dbQuery.addQuery(
"CREATE TABLE IF NOT EXISTS " +
153 this._dirtyListsTable +
154 " (listguid TEXT UNIQUE NOT NULL)");
155 this._dbQuery.execute();
158 this._dbQuery.resetQuery();
159 this._dbQuery.addQuery(
"CREATE TABLE IF NOT EXISTS " +
160 this._updateVideoListsTable +
161 " (listguid TEXT UNIQUE NOT NULL)");
162 this._dbQuery.execute();
165 var query = this._dbQuery;
166 function applyOnTableValues(aTableId, aFunction) {
168 query.addQuery(
"SELECT * FROM " + aTableId);
170 var result = query.getResultObject();
171 if (result && result.getRowCount() > 0) {
172 for (var
i = 0;
i < result.getRowCount();
i++) {
173 var
value = result.getRowCell(
i, 0);
184 function addToUpdateQueue(aListGuid) {
186 var mediaList =
LibraryUtils.mainLibrary.getMediaItem(aListGuid);
187 if (mediaList instanceof
Ci.sbIMediaList &&
188 mediaList.type ==
"smart") {
189 that._updateQueue[aListGuid] = mediaList;
192 applyOnTableValues(this._dirtyListsTable, addToUpdateQueue);
196 function addToModifiedProperties(aPropertyID) {
197 that._updatedProperties[aPropertyID] =
true;
199 applyOnTableValues(this._dirtyPropertiesTable, addToModifiedProperties);
204 function addToUpdateVideoQueue(aListGuid) {
206 var mediaList =
LibraryUtils.mainLibrary.getMediaItem(aListGuid);
207 if (mediaList instanceof
Ci.sbIMediaList &&
208 mediaList.type ==
"smart") {
209 that._updateVideoQueue[aListGuid] = mediaList;
213 applyOnTableValues(this._updateVideoListsTable, addToUpdateVideoQueue);
217 this.updateListConditions();
218 this.resetUpdateVideoListsTable();
224 this.delayedUpdateCheck();
233 this._secondaryTimer =
null;
235 this._monitor.shutdown();
236 this._monitor =
null;
255 onBatchBegin:
function(aMediaList) {
262 onBatchEnd:
function(aMediaList) {
264 if (--this._batchCount == 0) {
265 this.delayedUpdateCheck();
273 onItemAdded:
function(aMediaList, aMediaItem, aIndex) {
275 aMediaList instanceof
Ci.sbILibrary) {
276 if (aMediaItem instanceof
Ci.sbIMediaList) {
281 this.recordUpdateProperty(
'*');
284 this.recordUpdateProperty(aMediaList.guid);
288 if (this._batchCount > 0)
291 this.delayedUpdateCheck();
298 onAfterItemRemoved:
function(aMediaList, aMediaItem, aIndex) {
300 aMediaList instanceof
Ci.sbILibrary) {
301 if (aMediaItem instanceof
Ci.sbIMediaList) {
306 this.recordUpdateProperty(
'*');
309 this.recordUpdateProperty(aMediaList.guid);
313 if (this._batchCount > 0)
316 this.delayedUpdateCheck();
323 onItemUpdated:
function(aMediaList, aMediaItem, aProperties) {
325 if (aMediaItem instanceof
Ci.sbIMediaList)
333 if (this._batchCount > 0 && this._updatedProperties[
"*"]) {
338 for (var
i=0;
i<aProperties.length;
i++) {
339 var
property = aProperties.getPropertyAt(
i);
341 this.recordUpdateProperty(property.id);
347 if (this._batchCount > 0)
350 this.delayedUpdateCheck();
357 onListCleared:
function(list, excludeLists) {
359 this.recordUpdateProperty(list.guid);
360 if (this._batchCount > 0)
363 this.delayedUpdateCheck();
370 onBeforeListCleared:
function(list, excludeLists) {},
371 onBeforeItemRemoved:
function(list, item, index) {},
372 onItemMoved:
function(list, item, index) {},
377 recordUpdateProperty:
function(aPropertyID) {
379 if (!(aPropertyID in this._updatedProperties)) {
381 this._updatedProperties[aPropertyID] =
true;
386 this.addPropertyToDirtyTable(aPropertyID);
393 updateListConditions:
function() {
394 var propertyManager =
395 Cc[
"@songbirdnest.com/Songbird/Properties/PropertyManager;1"]
396 .getService(
Ci.sbIPropertyManager);
397 var typePI = propertyManager.getPropertyInfo(SBProperties.contentType);
400 property : SBProperties.contentType,
401 operator : typePI.getOperator(typePI.OPERATOR_NOTEQUALS),
406 var defaultSmartPlaylists = [
407 SBString(
"smart.defaultlist.highestrated",
"Highest Rated"),
408 SBString(
"smart.defaultlist.mostplayed",
"Most Played"),
409 SBString(
"smart.defaultlist.recentlyadded",
"Recently Added"),
410 SBString(
"smart.defaultlist.recentlyplayed",
"Recently Played")
414 function objectConverter(a) {
416 for (var
i = 0;
i < a.length; ++
i) {
422 for (var guid in this._updateVideoQueue) {
423 list = this._updateVideoQueue[guid];
425 if (list.name in objectConverter(defaultSmartPlaylists)) {
426 list.appendCondition(condition.property,
429 condition.rightValue,
430 condition.displayUnit);
442 getSmartPlaylists:
function() {
445 onEnumerationBegin:
function(aMediaList) { },
446 onEnumerationEnd:
function(aMediaList) { },
447 onEnumeratedItem:
function(aMediaList, aMediaItem) {
449 if (aMediaItem.type ==
'smart') {
450 this.items.push(aMediaItem);
453 return Ci.sbIMediaListEnumerationListener.CONTINUE;
456 XPCOMUtils.generateQI([
Ci.sbIMediaListEnumerationListener])
461 var pa =
Cc[
"@songbirdnest.com/Songbird/Properties/MutablePropertyArray;1"]
462 .createInstance(
Ci.sbIMutablePropertyArray);
463 pa.appendProperty(SBProperties.isList,
"1");
464 pa.appendProperty(SBProperties.hidden,
"0");
468 enumerateItemsByProperties(pa,
470 Ci.sbIMediaList.ENUMERATIONTYPE_LOCKING);
473 return enumListener.items;
479 delayedUpdateCheck:
function() {
483 if (this._updating) {
484 this._causeMoreChecks =
true;
489 this.
_timer =
Cc[
"@mozilla.org/timer;1"].createInstance(
Ci.nsITimer);
498 var
now =
new Date().getTime();
499 if (!this._timerInitTime) this._timerInitTime =
now;
501 if (this._batchCount == 0 &&
502 now - this._timerInitTime > this._maxInitialDelay) {
506 this.
_timer.initWithCallback(
this,
507 this._updateInitialDelay,
508 Ci.nsITimer.TYPE_ONE_SHOT);
515 notify:
function(aTimer) {
518 if (this._batchCount == 0) {
519 if (aTimer == this.
_timer) {
521 this._timerInitTime =
null;
526 }
else if (aTimer == this._secondaryTimer) {
528 this.performUpdates();
532 this.delayedUpdateCheck();
550 if (!this.emptyOfProperties(this._updatedProperties)) {
552 var lists = this.getSmartPlaylists();
554 for each (var list
in lists) {
557 if (list.guid in
this._updateQueue)
560 list.QueryInterface(
Ci.sbILocalDatabaseSmartMediaList);
562 if (!list.autoUpdate)
567 if (list.limit !=
Ci.sbILocalDatabaseSmartMediaList.LIMIT_TYPE_NONE &&
568 (
"*" in
this._updatedProperties ||
569 list.selectPropertyID in
this._updatedProperties)) {
570 this._updateQueue[list.guid] = list;
571 this.addListToDirtyTable(list);
574 for (var c=0; c<list.conditionCount; c++) {
576 var condition = list.getConditionAt(c);
579 if (
"*" in this._updatedProperties ||
580 condition.propertyID in
this._updatedProperties ||
581 this.isPlaylistConditionMatch(condition.propertyID, condition.leftValue,
this._updatedProperties)) {
582 this._updateQueue[list.guid] = list;
583 this.addListToDirtyTable(list);
596 this._updatedProperties = {};
601 this.resetDirtyPropertiesTable();
604 if (!this._updating &&
605 !this.emptyOfProperties(this._updateQueue)) {
608 this.performUpdates();
615 isPlaylistConditionMatch:
function(prop,
value, dirtyprops) {
616 if (prop !=
"http://songbirdnest.com/dummy/smartmedialists/1.0#playlist")
618 return (value in dirtyprops);
624 performUpdates:
function() {
629 for (var v in this._updateQueue) {
631 list = this._updateQueue[v];
633 remaining[v] = this._updateQueue[v];
635 this._updateQueue = remaining;
642 this._updating =
false;
644 this.resetDirtylistsTable();
654 this._updating =
true;
659 list.addSmartMediaListListener(
this);
668 onRebuild:
function(aSmartMediaList) {
670 aSmartMediaList.removeSmartMediaListListener(
this);
675 this.removeListFromDirtyTable(aSmartMediaList);
679 if (!this.emptyOfProperties(this._updateQueue)) {
680 if (!this._secondaryTimer)
681 this._secondaryTimer =
682 Cc[
"@mozilla.org/timer;1"].createInstance(
Ci.nsITimer);
684 this._secondaryTimer.initWithCallback(
this,
685 this._updateSubsequentDelay,
686 Ci.nsITimer.TYPE_ONE_SHOT);
689 this._updating =
false;
692 this.resetDirtyListsTable();
694 if (this._causeMoreChecks) {
695 this._causeMoreChecks =
false;
696 this.delayedUpdateCheck();
699 this._currentListUpdate =
null;
705 emptyOfProperties:
function(obj) {
706 var hasItems =
false;
707 for each (var v
in obj) {
717 addListToDirtyTable:
function(aMediaList) {
718 this._dbQuery.resetQuery();
719 this._dbQuery.addQuery(
"INSERT OR REPLACE INTO " +
720 this._dirtyListsTable +
724 this._dbQuery.execute();
730 addPropertyToDirtyTable:
function(aPropertyID) {
731 this._dbQuery.resetQuery();
732 this._dbQuery.addQuery(
"INSERT OR REPLACE INTO " +
733 this._dirtyPropertiesTable +
737 this._dbQuery.execute();
743 removeListFromDirtyTable:
function(aMediaList) {
744 this._dbQuery.resetQuery();
745 this._dbQuery.addQuery(
"DELETE FROM " +
746 this._dirtyListsTable +
747 " WHERE listguid = \"" +
750 this._dbQuery.execute();
756 resetDirtyListsTable:
function() {
757 this._dbQuery.resetQuery();
758 this._dbQuery.addQuery(
"DELETE FROM " + this._dirtyListsTable);
759 this._dbQuery.execute();
765 resetDirtyPropertiesTable:
function() {
766 this._dbQuery.resetQuery();
767 this._dbQuery.addQuery(
"DELETE FROM " + this._dirtyPropertiesTable);
768 this._dbQuery.execute();
774 resetUpdateVideoListsTable:
function() {
775 this._dbQuery.resetQuery();
776 this._dbQuery.addQuery(
"DELETE FROM " + this._updateVideoListsTable);
777 this._dbQuery.execute();
784 XPCOMUtils.generateQI([
Ci.sbIMediaListListener,
786 Ci.sbILocalDatabaseSmartMediaListListener])
795 XPCOMUtils.categoryManager
796 .addCategoryEntry(
'app-startup',
797 'smartplaylists-updater',
798 'service,@songbirdnest.com/Songbird/SmartMediaListsUpdater;1',
function checkForUpdates()
sbDeviceFirmwareAutoCheckForUpdate prototype contractID
sbOSDControlService prototype QueryInterface
sbDeviceFirmwareAutoCheckForUpdate prototype classDescription
sbDownloadDeviceServicePaneModule prototype shutdown
function SBString(aKey, aDefault, aStringBundle)
sbDeviceFirmwareAutoCheckForUpdate prototype _timer
TimerLoop prototype notify
DataRemote prototype constructor
sbDeviceFirmwareAutoCheckForUpdate prototype classID
Javascript wrappers for common library tasks.
_getSelectedPageStyle s i
sbDeviceFirmwareAutoCheckForUpdate prototype observe