From 6fa3c2e4637a68717f52262c45fe48c530ceebcc Mon Sep 17 00:00:00 2001 From: Razzmatazz Date: Sat, 13 Jul 2024 10:29:18 -0500 Subject: [PATCH 1/4] fix preset image refresh --- src/tarkov-data-manager/index.mjs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/tarkov-data-manager/index.mjs b/src/tarkov-data-manager/index.mjs index 6019621a..d3086e5d 100644 --- a/src/tarkov-data-manager/index.mjs +++ b/src/tarkov-data-manager/index.mjs @@ -402,7 +402,10 @@ app.post('/items/refresh-images/:id', async (req, res) => { } let newImage; if (item.types.includes('preset')) { - newImage = await webSocketServer.getJsonImage(item.properties.items); + newImage = await webSocketServer.getJsonImage({ + id: item.id, + items: item.properties.items, + }); } else { const results = await webSocketServer.getImages(item.id); newImage = results[item.id]; From a2b243187466ad693021f23066b5c28f1c41e291 Mon Sep 17 00:00:00 2001 From: Razzmatazz Date: Tue, 16 Jul 2024 14:31:26 -0500 Subject: [PATCH 2/4] fix archive-prices job --- src/tarkov-data-manager/jobs/archive-prices.mjs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/tarkov-data-manager/jobs/archive-prices.mjs b/src/tarkov-data-manager/jobs/archive-prices.mjs index b2559f77..de6c17e8 100644 --- a/src/tarkov-data-manager/jobs/archive-prices.mjs +++ b/src/tarkov-data-manager/jobs/archive-prices.mjs @@ -68,7 +68,7 @@ class ArchivePricesJob extends DataJob { this.logger.log(`Inserted ${Object.keys(itemPrices).length} ${gameModeName} archived prices in ${new Date() - insertStart}ms`); // delete the prices we just archived - await this.deletePricesThrough(archiveDate); + await this.deletePricesThrough(archiveDate, gameMode); } } } @@ -90,13 +90,13 @@ class ArchivePricesJob extends DataJob { DELETE FROM price_data WHERE timestamp < ? + INTERVAL 1 DAY AND game_mode = ? LIMIT ? - `, [mysqlDateCutoff, gameMode, batchSize]); + `, [mysqlDateCutoff, gameMode.value, batchSize]); deletedCount += deleteResult.affectedRows; if (deleteResult.affectedRows < batchSize) { break; } } - this.logger.log(`Deleted ${deletedCount} individual prices in ${new Date() - deleteStart}ms`); + this.logger.log(`Deleted ${deletedCount} individual ${gameMode.name} prices in ${new Date() - deleteStart}ms`); } } From 65bb9a5095a0524bc9d2239d6e242083af3a065c Mon Sep 17 00:00:00 2001 From: Razzmatazz Date: Tue, 16 Jul 2024 14:44:09 -0500 Subject: [PATCH 3/4] improve job --- .../jobs/archive-prices.mjs | 54 +++++++++---------- 1 file changed, 25 insertions(+), 29 deletions(-) diff --git a/src/tarkov-data-manager/jobs/archive-prices.mjs b/src/tarkov-data-manager/jobs/archive-prices.mjs index de6c17e8..9739a462 100644 --- a/src/tarkov-data-manager/jobs/archive-prices.mjs +++ b/src/tarkov-data-manager/jobs/archive-prices.mjs @@ -1,6 +1,6 @@ import DataJob from '../modules/data-job.mjs'; -const max_days_per_run = 1; +const max_days_per_run = 2; class ArchivePricesJob extends DataJob { constructor(options) { @@ -24,7 +24,6 @@ class ArchivePricesJob extends DataJob { // archive max_days_per_run number of days for (let i = 0; i < max_days_per_run; i++) { for (const gameMode of this.gameModes) { - const gameModeName = gameMode.name; // get the price with the oldest timestamp const oldestPrice = await this.query(` SELECT * FROM price_data @@ -33,13 +32,16 @@ class ArchivePricesJob extends DataJob { LIMIT 1 `, [cutoff, gameMode.value]); if (oldestPrice.length === 0) { - this.logger.success(`No ${gameModeName} prices found before ${cutoff}`); - return; + // we don't have any prices before the cutoff + // this means archiving is current, so nothing to do + this.logger.success(`No ${gameMode.name} prices found before ${cutoff}`); + continue; } // convert oldest price date to YYYY-MM-dd + // removes hours, mins, etc. to break at the start of the day const archiveDate = this.getMysqlDate(oldestPrice[0].timestamp); - this.logger.log(`Archiving ${gameModeName} prices for ${archiveDate}`); + this.logger.log(`Archiving ${gameMode.name} prices for ${archiveDate}`); // get minimum and average prices per item during day const itemPrices = await this.query(` @@ -65,10 +67,25 @@ class ArchivePricesJob extends DataJob { ON DUPLICATE KEY UPDATE price_min=VALUES(price_min), price_avg=VALUES(price_avg) `, insertValues); - this.logger.log(`Inserted ${Object.keys(itemPrices).length} ${gameModeName} archived prices in ${new Date() - insertStart}ms`); + this.logger.log(`Inserted ${Object.keys(itemPrices).length} ${gameMode.name} archived prices in ${new Date() - insertStart}ms`); - // delete the prices we just archived - await this.deletePricesThrough(archiveDate, gameMode); + // delete the prices we just archived from main price table + // can only delete 100k at a time, so need to loop + const batchSize = this.maxQueryRows; + let deletedCount = 0; + const deleteStart = new Date(); + while (true) { + const deleteResult = await this.query(` + DELETE FROM price_data + WHERE timestamp < ? + INTERVAL 1 DAY AND game_mode = ? + LIMIT ? + `, [archiveDate, gameMode.value, batchSize]); + deletedCount += deleteResult.affectedRows; + if (deleteResult.affectedRows < batchSize) { + break; + } + } + this.logger.log(`Deleted ${deletedCount} individual ${gameMode.name} prices in ${new Date() - deleteStart}ms`); } } } @@ -77,27 +94,6 @@ class ArchivePricesJob extends DataJob { getMysqlDate = (jsDate) => { return jsDate.toISOString().slice(0, 10); } - - // deletes all prices through the given YYY-MM-dd date - deletePricesThrough = async (mysqlDateCutoff, gameMode) => { - // delete archived prices from main price table - // can only delete 100k at a time, so need to loop - const batchSize = this.maxQueryRows; - let deletedCount = 0; - const deleteStart = new Date(); - while (true) { - const deleteResult = await this.query(` - DELETE FROM price_data - WHERE timestamp < ? + INTERVAL 1 DAY AND game_mode = ? - LIMIT ? - `, [mysqlDateCutoff, gameMode.value, batchSize]); - deletedCount += deleteResult.affectedRows; - if (deleteResult.affectedRows < batchSize) { - break; - } - } - this.logger.log(`Deleted ${deletedCount} individual ${gameMode.name} prices in ${new Date() - deleteStart}ms`); - } } export default ArchivePricesJob; From 8ccbb170cd95dc3d03e2fae8f1209ffba6363ecd Mon Sep 17 00:00:00 2001 From: Razzmatazz Date: Tue, 16 Jul 2024 16:55:30 -0500 Subject: [PATCH 4/4] improve handling of preset images --- src/tarkov-data-manager/index.mjs | 35 ++++++++- .../modules/remote-data.mjs | 4 + src/tarkov-data-manager/public/presets.js | 77 ++++++++++++++++++- 3 files changed, 111 insertions(+), 5 deletions(-) diff --git a/src/tarkov-data-manager/index.mjs b/src/tarkov-data-manager/index.mjs index d3086e5d..8231e61b 100644 --- a/src/tarkov-data-manager/index.mjs +++ b/src/tarkov-data-manager/index.mjs @@ -1873,6 +1873,9 @@ app.get('/presets', async (req, res) => { name + + images + @@ -1916,9 +1919,10 @@ app.get('/presets', async (req, res) => { }); app.get('/presets/get', async (req, res) => { - const [presets, en] = await Promise.all([ + const [presets, en, items] = await Promise.all([ query('SELECT * FROM manual_preset'), tarkovData.locale('en'), + remoteData.get(), ]); for (const preset of presets) { const baseItemId = preset.items[0]._tpl; @@ -1932,6 +1936,12 @@ app.get('/presets/get', async (req, res) => { shortName: en[`${item._tpl} ShortName`], }; }); + preset.image_8x_link = items.get(preset.id)?.image_8x_link; + preset.image_512_link = items.get(preset.id)?.image_512_link; + preset.image_link = items.get(preset.id)?.image_link; + preset.base_image_link = items.get(preset.id)?.base_image_link; + preset.grid_image_link = items.get(preset.id)?.grid_image_link; + preset.icon_link = items.get(preset.id)?.icon_link; } res.json(presets); }); @@ -1939,8 +1949,27 @@ app.get('/presets/get', async (req, res) => { app.put('/presets/:id', async (req, res) => { const response = {message: 'No changes made.', errors: []}; try { - await query('UPDATE manual_preset SET append_name = ? WHERE id = ?', [req.body.append_name, req.params.id]); - response.message = 'Preset updated'; + const preset = await query('SELECT * FROM manual_preset WHERE id = ?', [req.params.id]).then(results => results[0]); + if (preset.append_name !== req.body.append_name) { + await query('UPDATE manual_preset SET append_name = ? WHERE id = ?', [req.body.append_name, req.params.id]); + const [en, items] = await Promise.all([tarkovData.locale('en'), remoteData.get()]); + const baseItem = items.get(preset.items[0]._tpl); + await remoteData.setProperties(req.params.id, { + name: `${baseItem.name} ${en[req.body.append_name]}`, + short_name: `${baseItem.short_name} ${en[req.body.append_name]}`, + }); + response.message = 'Preset updated'; + try { + await regenerateFromExisting(req.params.id); + } catch (error) { + console.log(error); + if (Array.isArray(error)) { + response.errors = error.map(err => err.message || err); + } else { + response.errors.push(error.message || error); + } + } + } } catch (error) { response.errors.push(error.message); } diff --git a/src/tarkov-data-manager/modules/remote-data.mjs b/src/tarkov-data-manager/modules/remote-data.mjs index 1092c55a..e025f93e 100644 --- a/src/tarkov-data-manager/modules/remote-data.mjs +++ b/src/tarkov-data-manager/modules/remote-data.mjs @@ -1,5 +1,6 @@ import midmean from 'compute-midmean'; +import normalizeName from './normalize-name.js'; import timer from './console-timer.js'; import { query, maxQueryRows } from './db-connection.mjs'; import gameModes from './game-modes.mjs'; @@ -330,6 +331,9 @@ const methods = { } if (currentValue !== value) { changeValues[property] = value; + if (property === 'name' && !properties.normalized_name) { + changeValues.normalized_name = normalizeName(value); + } } } if (Object.keys(changeValues).length === 0) { diff --git a/src/tarkov-data-manager/public/presets.js b/src/tarkov-data-manager/public/presets.js index 29dc71ee..6ee18044 100644 --- a/src/tarkov-data-manager/public/presets.js +++ b/src/tarkov-data-manager/public/presets.js @@ -1,5 +1,16 @@ let table = false; +const existingImageElement = (itemId, imageType, url) => { + const tooltipId = `${itemId}-${imageType}-tooltip-content`; + return ` + ✔️ + + `; +}; + $(document).ready( function () { //$('.tooltipped').tooltip(); //$('.modal').modal(); @@ -26,7 +37,38 @@ $(document).ready( function () { render: (data, type, wipe) => { return data; } - } + }, + { + data: 'image_link', + render: (data, type, item) => { + if (type === 'display') { + let imageLink = item.image_512_link; + if (!imageLink) { + imageLink = item.base_image_link || item.grid_image_link || item.icon_link; + } + return ` +
+ ${imageLink ? `
`: ''} +
+
+ ${item.image_8x_link ? existingImageElement(item.id, '8x', item.image_8x_link): missingImageElement('8x')} + ${item.image_512_link ? existingImageElement(item.id, '512', item.image_512_link): missingImageElement('512')} + ${data ? existingImageElement(item.id, 'inspect', data): missingImageElement('inspect')} + ${item.base_image_link ? existingImageElement(item.id, 'base', item.base_image_link): missingImageElement('base')} + ${item.grid_image_link ? existingImageElement(item.id, 'grid', item.grid_image_link): missingImageElement('grid')} + ${item.icon_link ? existingImageElement(item.id, 'icon', item.icon_link) : missingImageElement('icon')} +
+
+ ${item.image_8x_link || item.base_image_link ? `refresh` : ''} + sync +
+ `; + } + return data; + }, + className: 'image-column', + width: '10%', + }, ]; table = $('table.main').DataTable({ @@ -91,6 +133,38 @@ $(document).ready( function () { $('#modal-delete-confirm .delete-confirm').data('id', target.data('id')); M.Modal.getInstance(document.getElementById('modal-delete-confirm')).open(); }); + + $('.btn-small.regenerate').off('click'); + $('.btn-small.regenerate').click(event => { + let target = event.target; + if (target.nodeName !== 'A') { + target = target.parentElement; + } + $(target).addClass('disabled'); + fetch(`/items/regenerate-images/${$(target).data('id')}`, {method: 'POST'}).then(response => response.json()).then(data => { + $(target).removeClass('disabled'); + M.toast({text: data.message}); + for (const error of data.errors) { + M.toast({text: error}); + } + }); + }); + + $('.btn-small.refresh-images').off('click'); + $('.btn-small.refresh-images').click(event => { + let target = event.target; + if (target.nodeName !== 'A') { + target = target.parentElement; + } + $(target).addClass('disabled'); + fetch(`/items/refresh-images/${$(target).data('id')}`, {method: 'POST'}).then(response => response.json()).then(data => { + $(target).removeClass('disabled'); + M.toast({text: data.message}); + for (const error of data.errors) { + M.toast({text: error}); + } + }); + }); } }); @@ -129,7 +203,6 @@ $(document).ready( function () { $('#modal-edit-preset .edit-preset-save').click(function(event) { const form = $('#modal-edit-preset').find('form').first(); const formData = form.serialize(); - console.log(formData) $.ajax({ method: form.attr('method'), url: form.attr('action'),