Skip to content

Commit

Permalink
Fixed bug with grid.getTileByAsin not returning null if no match.
Browse files Browse the repository at this point in the history
Fixed remote storing of hidden items storing item hidden by keywords.

Pinned list now store remotely

New API protocol for handling remote storage of hidden/pinned items
  • Loading branch information
FMaz008 committed Jul 3, 2024
1 parent 43bc45a commit 67f350c
Show file tree
Hide file tree
Showing 7 changed files with 258 additions and 33 deletions.
2 changes: 1 addition & 1 deletion popup/homepage.html
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ <h1>
<input type="checkbox" name="hiddenTab.active" value="1" />
</label>
<label for="hiddenTab.remote" style="margin-left: 10px"
>Store Hidden Items Remotely.
>Store Hidden/Pinned Items Remotely.
<a
href="#"
target="_blank"
Expand Down
19 changes: 12 additions & 7 deletions scripts/HiddenListMgr.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@ class HiddenListMgr {

if (ev.data.type == "hideItem") {
showRuntime("Broadcast received: hide item " + ev.data.asin);
HiddenList.addItem(ev.data.asin, false, false);
this.addItem(ev.data.asin, false, false);
}
if (ev.data.type == "showItem") {
showRuntime("Broadcast received: show item " + ev.data.asin);
HiddenList.removeItem(ev.data.asin, false, false);
this.removeItem(ev.data.asin, false, false);
}
};
}
Expand Down Expand Up @@ -116,8 +116,11 @@ class HiddenListMgr {
}

isChange(asin) {
for (const id in this.arrChanges) if (this.arrChanges[id].asin == asin) return id;

for (const id in this.arrChanges) {
if (this.arrChanges[id].asin == asin) {
return id;
}
}
return false;
}

Expand All @@ -129,23 +132,25 @@ class HiddenListMgr {

/**
* Send new items on the server to be added or removed from the hidden list.
* @param [{"asin": "abc", "hidden": true}, ...] arr
*/
notifyServerOfHiddenItem() {
let arrJSON = {
api_version: 4,
country: vineCountry,
action: "save_hidden_list",
uuid: appSettings.general.uuid,
arr: this.arrChanges,
};
let jsonArrURL = JSON.stringify(arrJSON);

showRuntime("Saving hidden item(s) remotely...");

//Post an AJAX request to the 3rd party server, passing along the JSON array of all the products on the page
let url = "https://www.vinehelper.ovh/vinehelper.php" + "?data=" + jsonArrURL;
fetch(url);
fetch(url, {
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body: JSON.stringify(this.arrChanges),
});
}

async garbageCollection() {
Expand Down
120 changes: 120 additions & 0 deletions scripts/ListMgr.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
class ListMgr {
constructor() {
this.mapItem = new Map();
this.arrChanges = [];
this.listLoaded = false;
this.broadcast = new BroadcastChannel("vine_helper");
}

processLocalStorageData(jsonItems) {
if (jsonItems) {
try {
// Try parsing the stored string as JSON
this.mapItem = this.deserialize(jsonItems);
} catch (error) {
// If JSON parsing fails assume legacy format and convert to new format
// Once the migration period is over delete this section of code
showRuntime("Failed to parse hiddenItems as JSON, treating as array:");
if (Array.isArray(jsonItems)) {
this.mapItem = jsonItems.reduce((map, product) => {
map.set(product.asin, new Date(product.date));
return map;
}, new Map());
} else {
showRuntime("Invalid data format for hidden items. Creating new map.");
this.mapItem = new Map(); // Initialize with an empty map if data is malformed
}
}
} else {
// No data found or empty hiddenItems, initialize an empty Map
this.mapItem = new Map();
}
this.listLoaded = true;
}

async removeItem(asin, save = true, broadcastData = null) {
if (save) await this.loadFromLocalStorage(); //Load the list in case it was altered in a different tab

this.mapItem.delete(asin);

//The server may not be in sync with the local list, and will deal with duplicate.
this.updateArrChange({ asin: asin, onList: false });

if (save) this.saveList();

//Broadcast the change to other tabs
this.broadcastChange(broadcastData);
}

async addItem(asin, save = true, broadcastData = null) {
if (save) await this.loadFromLocalStorage(); //Load the list in case it was altered in a different tab

if (!this.mapItem.has(asin)) {
this.mapItem.set(asin, new Date());
}

//The server may not be in sync with the local list, and will deal with duplicate.
this.updateArrChange({ asin: asin, onList: true });

if (save) this.saveList();

//Broadcast the change to other tabs
this.broadcastChange(broadcastData);
}

broadcastChange(broadcastData = null) {
if (broadcastData !== null) {
this.broadcast.postMessage(broadcastData);
}
}

isChange(asin) {
for (const id in this.arrChanges) {
if (this.arrChanges[id].asin == asin) {
return id;
}
}
return false;
}

updateArrChange(obj) {
let itemId = this.isChange(obj.asin);
if (itemId == false) this.arrChanges.push(obj);
else this.arrChanges[itemId] = obj;
}

/**
* Send new items on the server to be added or removed from the hidden list.
*
*/
notifyServerOfItemChanges(actionName) {
let arrJSON = {
api_version: 4,
country: vineCountry,
action: actionName,
uuid: appSettings.general.uuid,
arr: this.arrChanges,
};
let jsonArrURL = JSON.stringify(arrJSON);

showRuntime("Saving " + actionName + " item(s) remotely...");

//Post an AJAX request to the 3rd party server, passing along the JSON array of all the products on the page
let url = "https://www.vinehelper.ovh/vinehelper.php" + "?data=" + jsonArrURL;
fetch(url);
}

serialize(map) {
//truncate ms to store as unix timestamp
const objToStore = Object.fromEntries(
Array.from(map.entries()).map(([key, value]) => [key, Math.floor(value.getTime() / 1000)])
);
return JSON.stringify(objToStore);
}

deserialize(jsonString) {
//multiply by 1000 to convert from unix timestamp to js Date
const retrievedObj = JSON.parse(jsonString);
return new Map(Object.entries(retrievedObj).map(([key, value]) => [key, new Date(value * 1000)]));
}
}
95 changes: 87 additions & 8 deletions scripts/PinnedListMgr.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ class PinnedListMgr {
constructor() {
this.mapPin = new Map();
this.listLoaded = false;

this.arrChanges = [];
this.broadcast = new BroadcastChannel("vine_helper");

showRuntime("PINNEDMGR: Loading list");
Expand All @@ -16,25 +16,41 @@ class PinnedListMgr {

if (ev.data.type == "pinnedItem") {
showRuntime("Broadcast received: pinned item " + ev.data.asin);
PinnedList.addItem(ev.data.asin, ev.data.title, ev.data.thumbnail, false, false);
this.addItem(ev.data.asin, ev.data.title, ev.data.thumbnail, false, false);
}
if (ev.data.type == "unpinnedItem") {
showRuntime("Broadcast received: unpinned item " + ev.data.asin);
PinnedList.removeItem(ev.data.asin, false, false);
this.removeItem(ev.data.asin, false, false);
}
};
}

async loadFromLocalStorage() {
const data = await browser.storage.local.get("pinnedItems");

//Load pinned items
if (Object.keys(data).length === 0) {
let storableVal = JSON.stringify(Array.from(this.mapPin.entries()));
await browser.storage.local.set({ pinnedItems: storableVal });
if (data.pinnedItems) {
try {
// Try parsing the stored string as JSON
this.mapPin = new Map(JSON.parse(data.pinnedItems));
} catch (error) {
// If JSON parsing fails assume legacy format and convert to new format
// Once the migration period is over delete this section of code
showRuntime("Failed to parse pinnedItems as JSON, treating as array:");
if (Array.isArray(data.pinnedItems)) {
this.mapPin = data.pinnedItems.reduce((map, product) => {
map.set(product.asin, { title: product.title, thumbnail: product.thumbnail });
return map;
}, new Map());
} else {
showRuntime("Invalid data format for pinned items. Creating new map.");
this.mapPin = new Map(); // Initialize with an empty map if data is malformed
}
}
} else {
this.mapPin = new Map(JSON.parse(data.pinnedItems));
// No data found or empty pinnedItems, initialize an empty Map
this.mapPin = new Map();
}

this.listLoaded = true;
showRuntime("PINNEDMGR: List loaded.");
}
Expand All @@ -44,6 +60,9 @@ class PinnedListMgr {

this.mapPin.delete(asin);

//The server may not be in sync with the local list, and will deal with duplicate.
this.updateArrChange({ asin: asin, pinned: false });

if (save) this.saveList();

//Broadcast the change to other tabs
Expand All @@ -57,6 +76,9 @@ class PinnedListMgr {

this.mapPin.set(asin, { title: title, thumbnail: thumbnail });

//The server may not be in sync with the local list, and will deal with duplicate.
this.updateArrChange({ asin: asin, pinned: true, title: title, thumbnail: thumbnail });

if (save) this.saveList();

//Broadcast the change to other tabs
Expand All @@ -81,6 +103,34 @@ class PinnedListMgr {
}
}
});

if (appSettings.hiddenTab.remote) {
this.notifyServerOfChangedItem();
this.arrChanges = [];
}
}

/**
* Send new items on the server to be added or removed from the changed list.
*/
notifyServerOfChangedItem() {
let arrJSON = {
api_version: 4,
country: vineCountry,
action: "save_pinned_list",
uuid: appSettings.general.uuid,
};
let jsonArrURL = JSON.stringify(arrJSON);

showRuntime("Saving pinned item(s) remotely...");

//Post an AJAX request to the 3rd party server, passing along the JSON array of all the products on the page
let url = "https://www.vinehelper.ovh/vinehelper.php" + "?data=" + jsonArrURL;
fetch(url, {
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body: JSON.stringify(this.arrChanges),
});
}

isPinned(asin) {
Expand All @@ -89,7 +139,36 @@ class PinnedListMgr {
return this.mapPin.has(asin);
}

isChange(asin) {
for (const id in this.arrChanges) {
if (this.arrChanges[id].asin == asin) {
return id;
}
}
return false;
}

updateArrChange(obj) {
let itemId = this.isChange(obj.asin);
if (itemId == false) this.arrChanges.push(obj);
else this.arrChanges[itemId] = obj;
}

getList() {
return this.mapPin;
}

serialize(map) {
//truncate ms to store as unix timestamp
const objToStore = Object.fromEntries(
Array.from(map.entries()).map(([key, value]) => [key, Math.floor(value.getTime() / 1000)])
);
return JSON.stringify(objToStore);
}

deserialize(jsonString) {
//multiply by 1000 to convert from unix timestamp to js Date
const retrievedObj = JSON.parse(jsonString);
return new Map(Object.entries(retrievedObj).map(([key, value]) => [key, value]));
}
}
27 changes: 24 additions & 3 deletions scripts/bootloader.js
Original file line number Diff line number Diff line change
Expand Up @@ -515,9 +515,11 @@ async function serverProductsResponse(data) {
return false;
}

showRuntime("FETCH: Waiting on hidden items list to be loaded...");
while (!HiddenList.listLoaded) {
await new Promise((r) => setTimeout(r, 10));
if (appSettings.hiddenTab.active) {
showRuntime("FETCH: Waiting on hidden items list to be loaded...");
while (!HiddenList.listLoaded) {
await new Promise((r) => setTimeout(r, 10));
}
}

timenow = data["current_time"];
Expand Down Expand Up @@ -602,6 +604,25 @@ async function serverProductsResponse(data) {
}
tile.initiateTile();
});

if (appSettings.pinnedTab.active) {
if (data["pinned_products"] != undefined) {
showRuntime("DRAW: Loading remote pinned products");
for (let i = 0; i < data["pinned_products"].length; i++) {
PinnedList.addItem(
data["pinned_products"][i]["asin"],
data["pinned_products"][i]["title"],
data["pinned_products"][i]["thumbnail"]
);
await addPinnedTile(
data["pinned_products"][i]["asin"],
data["pinned_products"][i]["title"],
data["pinned_products"][i]["thumbnail"]
); //grid.js
}
}
}

updateTileCounts();
showRuntime("Done updating products");
}
Expand Down
14 changes: 6 additions & 8 deletions scripts/grid.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,15 +48,13 @@ class Grid {
else return this.pArrTile.length;
}

getTileId(asin) {
var r = null;
$.each(this.pArrTile, function (key, value) {
if (value != undefined && value.getAsin() == asin) {
r = value;
return false; //Stop the loop
getTileByASIN(asin) {
for (let i = 0; i < this.pArrTile.length; i++) {
if (this.pArrTile[i].getAsin() == asin) {
return this.pArrTile[i];
}
});
return r;
}
return null;
}

getArrTile() {
Expand Down
Loading

0 comments on commit 67f350c

Please sign in to comment.