Hallo zusammen,
ich habe mein Script nochmal aktualisiert. Es werden in Alexa nun automatisch alle Duplikate sofort wieder gelöscht. Außerdem wird nun erzwungen, dass Artikel mit einem Großbuchstaben beginnen.
Viel Spaß damit und gerne wieder testen
Kleiner Nachtrag: wenn ich über Alexa Dinge hinzufüge und dann in Bring als erledigt markiere, dann werden diese bei mir in Alexa nicht mehr gelöscht. Das muss ich mir nochmal ansehen - könnte an den Zeitstempeln liegen.
Nachtrag 2: ging doch - mein Adapter war nur offline
const bringBaseId = 'bring.0.0f0c420c-3298-4911-91f5-7ed0fbbfd36e';
const alexa2BaseId = 'alexa2.0.Lists.SHOPPING_LIST';
const bringListId = bringBaseId + '.content';
const bringListCompletedId = bringBaseId + '.recentContent';
const bringAddToList = bringBaseId + '.saveItem';
const bringCompleteItem = bringBaseId + '.moveToRecentContent';
const alexaAddToList = alexa2BaseId + '.#New';
const alexaListId = alexa2BaseId + '.json';
//switch off to silence:
const printDebug = true;
function debug(msg) {
if (printDebug) {
log(msg)
}
}
const TodoItemStatus = {
NeedsAction: 'needs_action',
Completed: 'completed',
};
/**
* @typedef bringItem
* @type {object}
* @property {string} specification
* @property {string} name
* @property {string} status
* @property {boolean} [found] - keep track if found or not.
*/
/**
* @typedef alexaItem
* @type {object}
* @property {string} value
* @property {string} id
* @property {boolean} completed
* @property {number} updatedDateTime
* @property {boolean} [found] - keep track if found or not.
*/
/**
* Compare alexaItem complete and bringItem status -> returns true if same status.
* @param {Array<alexaItem>} alexaList
* @param {Array<bringItem>} list
* @returns {boolean} true if same status.
*/
function compareCompleted(alexaItem, bringItem) {
if (alexaItem.completed && bringItem.status !== TodoItemStatus.Completed) {
return false;
}
if (!alexaItem.completed && bringItem.status !== TodoItemStatus.NeedsAction) {
return false;
}
return true;
}
function ListCleaner(Eintrag='') {
const arr = Eintrag.split(' ');
for (let i = 0; i < arr.length; i++) {
arr[i] = arr[i].charAt(0).toUpperCase() + arr[i].slice(1);
}
return arr.join(' ');
}
/**
* sync lists
* @param {Array<alexaItem>} alexaList
* @param {Array<bringItem>} list
* @param {number} timestampBring
* @param {string} msource
* @param {Array<bringItem>} recentList
* @returns {Array<bringItem>} new bring List
*/
function syncLists(alexaList, list, timestampBring, msource, recentList) {
const newBringList = [];
var empty = true;
for (const alexaItem of alexaList) {
for (const bringItem of list) {
empty = false;
if (bringItem.name === alexaItem.value) {
alexaItem.found = true;
bringItem.found = true;
//found item. Update completed state from 'newer' list:
bringItem.status = TodoItemStatus.NeedsAction;
if (alexaItem.updatedDateTime > timestampBring) {
if (alexaItem.value !== bringItem.name || !compareCompleted(alexaItem, bringItem)) {
if (msource === 'Alexa') {
debug('Updating Bring item: ' + bringItem.name + ' from Alexa');
setState(bringCompleteItem, ListCleaner(bringItem.name));
}
}
} else {
//keep bring:
//update alexa:
if (!compareCompleted(alexaItem, bringItem)) {
if (msource === 'Bring') {
bringItem.status = TodoItemStatus.Completed;
debug('Update Alexa item: ' + alexaItem.value + ' to ' + (bringItem.status === TodoItemStatus.Completed ? 'done' : 'undone') + ' from Bring.');
setState(`${alexa2BaseId}.items.${alexaItem.id}.completed`, bringItem.status === TodoItemStatus.Completed);
}
}
}
}
}
for (const bringItemCompleted of recentList) {
if (bringItemCompleted.name === alexaItem.value) {
alexaItem.found = true;
bringItemCompleted.found = true;
//found item. Update completed state from 'newer' list:
bringItemCompleted.status = TodoItemStatus.Completed;
if (alexaItem.updatedDateTime > timestampBring) {
if (alexaItem.value !== bringItemCompleted.name || !compareCompleted(alexaItem, bringItemCompleted)) {
if (msource === 'Alexa') {
debug('Adding Bring item: ' + bringItemCompleted.name + ' from Alexa');
setState(bringAddToList, ListCleaner(bringItemCompleted.name));
}
}
} else {
//keep bring:
//update alexa:
if (!compareCompleted(alexaItem, bringItemCompleted)) {
bringItemCompleted.status = TodoItemStatus.Completed;
if (msource === 'Bring') {
debug('Delete Alexa item: ' + alexaItem.value + ' from Bring.');
//setState(`${alexa2BaseId}.items.${alexaItem.id}.completed`, bringItemCompleted.status === TodoItemStatus.Completed);
setState(`${alexa2BaseId}.items.${alexaItem.id}.#delete`, true);
}
}
}
}
}
if (!alexaItem.found) {
//alexa item not found:
if (alexaItem.completed) {
debug('Delete ' + alexaItem.value + ' because done and not in Bring list.');
setState(`${alexa2BaseId}.items.${alexaItem.id}.#delete`, true);
} else {
if (msource === 'Alexa') {
debug('Adding ' + alexaItem.value + ' to Bring list');
setState(bringAddToList, ListCleaner(alexaItem.value));
}
}
}
if (empty === true) {
if (alexaItem.updatedDateTime < timestampBring) {
debug('Delete ' + alexaItem.value + ' from Alexa list because Bring list is all done.');
setState(`${alexa2BaseId}.items.${alexaItem.id}.#delete`, true);
}
}
}
for (const bringItem of list) {
if (!bringItem.found) {
if (bringItem.status === TodoItemStatus.Completed) {
//debug('Remove from bring item: ' + bringItem.name + ' because done and not on alexa list');
//Not executed since I want to keep the recent items inside bring app
} else {
if (msource === 'Bring') {
debug('Adding ' + bringItem.name + ' to Alexa list.');
setState(alexaAddToList, ListCleaner(bringItem.name));
}
}
}
}
return newBringList;
}
function doSync(source) {
eliminateDuplicated();
const alexaList = JSON.parse(getState(alexaListId).val);
const state = getState(bringListId);
const bringList = JSON.parse(state.val);
const state2 = getState(bringListCompletedId);
const bringListCompleted = JSON.parse(state2.val);
syncLists(alexaList, bringList, state.ts, source, bringListCompleted);
}
function eliminateDuplicated() {
var myAlexaList = JSON.parse(getState(alexaListId).val);
var arrayWithDuplicates = [];
for(var alexaItem of myAlexaList) {
var obj = {};
obj["value"] = ListCleaner(alexaItem.value);
obj["id"] = alexaItem.id;
arrayWithDuplicates.push(obj);
}
const lookup = arrayWithDuplicates.reduce((a, e) => {
a[e.value] = ++a[e.value] || 0;
return a;
}, {});
const
getKey = o => keys.map(k => o[k]).join('|'),
keys = ['value'],
myarray = arrayWithDuplicates.filter(e => lookup[e.value]),
hash = Object.create(null),
duplicates = myarray.filter(o =>
(k => (hash[k] = (hash[k] || 0) + 1) > 1)
(getKey(o))
);
for(var item of duplicates) {
debug('Delete Alexa item: ' + item.value + ' because duplicated.');
setState(`${alexa2BaseId}.items.${item.id}.#delete`, true);
}
}
on({id: bringListId, change: 'any'}, e => {
debug('Update triggered from Bring');
doSync('Bring');
});
on({id: alexaListId, change: 'any'}, e => {
debug('Update triggered from Alexa');
doSync('Alexa');
});
doSync();