From c5b0f668b530042974696ba5650fd61c6ad01a65 Mon Sep 17 00:00:00 2001
From: Jakub Ambrus <50302308+kubaam@users.noreply.github.com>
Date: Thu, 7 Aug 2025 05:31:28 +0200
Subject: [PATCH 1/9] refactor settings panel toggles
---
css/style.css | 12 +++-
js/settingsPanel.js | 131 ++++++++++++++++++--------------------------
2 files changed, 65 insertions(+), 78 deletions(-)
diff --git a/css/style.css b/css/style.css
index 0fddac2..fcafe02 100644
--- a/css/style.css
+++ b/css/style.css
@@ -346,13 +346,23 @@ tbody .fullTd {
}
.keydorp-plus-change-language {
+ display: inline-block;
+ height: 34px;
+ cursor: pointer;
+ filter: opacity(0.5);
transition: 0.25s;
}
-.keydorp-plus-change-language:hover {
+.keydorp-plus-change-language:hover,
+.keydorp-plus-change-language.active {
filter: opacity(1) !important;
}
+.keydorp-plus-change-language.active {
+ border: 1px solid gold;
+ border-radius: 4px;
+}
+
div.hidden.overflow-hidden.md\:block.bg-navy-700 {
height: 76px;
}
diff --git a/js/settingsPanel.js b/js/settingsPanel.js
index 2666db6..64c7ca6 100644
--- a/js/settingsPanel.js
+++ b/js/settingsPanel.js
@@ -5,97 +5,72 @@ $( document ).ready(async() => {
const server = await getServerData();
if(!server) return;
await createSettingsPanel(config, language, server);
+ const attachToggle = (key, selector, { onInit, onChange } = {}) => {
+ if(config?.[key]) $(selector)?.prop('checked', true);
+ if(onInit) onInit(!!config?.[key]);
+ $(selector)?.on('change', function(e) {
+ const checked = e?.target?.checked;
+ config[key] = checked;
+ try { chrome.storage.sync.set({ config: config }); } catch(e) {};
+ if(onChange) onChange(checked);
+ });
+ };
if(window?.location?.href?.includes('/#keydrop_plus'))
$('div#keydrop-plus-modal')?.addClass('is-open');
$('#keydrop-plus-modal').click(function(e) {
if(e?.target?.id == 'close-keydrop-plus-modal' || e?.target?.id == "keydrop-plus-modal")
- $('#keydrop-plus-modal')
- .removeClass('is-open');
- });
-
- if(config?.toastSoundEnable_error)
- $('#toastSoundEnable_error')?.prop('checked', true);
- $('#toastSoundEnable_error')?.on('change', function(e) {
- config.toastSoundEnable_error = e?.target?.checked;
- try { chrome.storage.sync.set({ config: config }); } catch(e) {};
- });
-
- if(config?.toastSoundEnable_info)
- $('#toastSoundEnable_info')?.prop('checked', true);
- $('#toastSoundEnable_info')?.on('change', function(e) {
- config.toastSoundEnable_info = e?.target?.checked;
- try { chrome.storage.sync.set({ config: config }); } catch(e) {};
- });
-
- if(config?.toastSoundEnable_success)
- $('#toastSoundEnable_success')?.prop('checked', true);
- $('#toastSoundEnable_success')?.on('change', function(e) {
- config.toastSoundEnable_success = e?.target?.checked;
- try { chrome.storage.sync.set({ config: config }); } catch(e) {};
+ $('#keydrop-plus-modal').removeClass('is-open');
});
- if(config?.toastSoundEnable_warning)
- $('#toastSoundEnable_warning')?.prop('checked', true);
- $('#toastSoundEnable_warning')?.on('change', function(e) {
- config.toastSoundEnable_warning = e?.target?.checked;
- try { chrome.storage.sync.set({ config: config }); } catch(e) {};
+ ['error','info','success','warning'].forEach(type => {
+ attachToggle(`toastSoundEnable_${type}`, `#toastSoundEnable_${type}`);
});
- if(config?.toastAutoHide)
- $('#hideToast')?.prop('checked', true);
- $('#hideToast')?.on('change', function(e) {
- config.toastAutoHide = e?.target?.checked;
- try { chrome.storage.sync.set({ config: config }); } catch(e) {};
- });
+ attachToggle('toastAutoHide', '#hideToast');
- if(config?.showAllYoutuberCases)
- $('#showAllYoutuberCases')?.prop('checked', true);
- $('#showAllYoutuberCases')?.on('change', function(e) {
- $('.keydrop-plus-ytcases').css('display', e?.target?.checked ? 'block' : 'none');
- $('[case-orginal="true"').css('display', e?.target?.checked ? 'none' : 'block');
- config.showAllYoutuberCases = e?.target?.checked;
- try { chrome.storage.sync.set({ config: config }); } catch(e) {};
+ attachToggle('showAllYoutuberCases', '#showAllYoutuberCases', {
+ onChange: (checked) => {
+ $('.keydrop-plus-ytcases').css('display', checked ? 'block' : 'none');
+ $('[case-orginal="true"]').css('display', checked ? 'none' : 'block');
+ }
});
- if(config?.hideLiveDrop) {
- $('#hideLiveDrop')?.prop('checked', true);
- waitForElm('div.flex.flex-col.overflow-hidden.bg-navy-900.lg\\:flex-row').then(() => {
- if(config?.hideLiveDrop)
- $('div.flex.flex-col.overflow-hidden.bg-navy-900.lg\\:flex-row')?.eq(0)?.css('display', 'none');
- });
- }
- $('#hideLiveDrop')?.on('change', function(e) {
- config.hideLiveDrop = e?.target?.checked;
- try { chrome.storage.sync.set({ config: config }); } catch(e) {};
- $('div.flex.flex-col.overflow-hidden.bg-navy-900.lg\\:flex-row')?.eq(0)?.css('display', e?.target?.checked ? 'none' : 'flex');
+ attachToggle('hideLiveDrop', '#hideLiveDrop', {
+ onInit: (checked) => {
+ if(checked)
+ waitForElm('div.flex.flex-col.overflow-hidden.bg-navy-900.lg\\:flex-row').then(() => {
+ $('div.flex.flex-col.overflow-hidden.bg-navy-900.lg\\:flex-row')?.eq(0)?.css('display', 'none');
+ });
+ },
+ onChange: (checked) => {
+ $('div.flex.flex-col.overflow-hidden.bg-navy-900.lg\\:flex-row')?.eq(0)?.css('display', checked ? 'none' : 'flex');
+ }
});
- if(config?.hideCaseBattle) {
- $('#hideCaseBattle')?.prop('checked', true);
- waitForElm('[data-testid="single-bttl-rounds-counter"]').then(() => {
- if(!config?.hideCaseBattle)
- return;
- $('div#caseList-root div.container.mb-8')?.eq(0)?.css('display', 'none');
- $('div#caseList-root div.mx-auto.max-w-screen-2xl.2xl\\:px-5')?.eq(0)?.css('margin-top', '50px');
- });
- }
- $('#hideCaseBattle')?.on('change', function(e) {
- config.hideCaseBattle = e?.target?.checked;
- try { chrome.storage.sync.set({ config: config }); } catch(e) {};
- $('div#caseList-root div.container.mb-8')?.eq(0)?.css('display', e?.target?.checked ? 'none' : 'block');
- $('div#caseList-root div.mx-auto.max-w-screen-2xl.2xl\\:px-5')?.eq(0)?.css('margin-top', e?.target?.checked ? '50px' : '0px');
+ attachToggle('hideCaseBattle', '#hideCaseBattle', {
+ onInit: (checked) => {
+ waitForElm('[data-testid="single-bttl-rounds-counter"]').then(() => {
+ if(checked) {
+ $('div#caseList-root div.container.mb-8')?.eq(0)?.css('display', 'none');
+ $('div#caseList-root div.mx-auto.max-w-screen-2xl.2xl\\:px-5')?.eq(0)?.css('margin-top', '50px');
+ }
+ });
+ },
+ onChange: (checked) => {
+ $('div#caseList-root div.container.mb-8')?.eq(0)?.css('display', checked ? 'none' : 'block');
+ $('div#caseList-root div.mx-auto.max-w-screen-2xl.2xl\\:px-5')?.eq(0)?.css('margin-top', checked ? '50px' : '0px');
+ }
});
- if(config?.hideFavourite) {
- $('#hideFavourite')?.prop('checked', true);
- $('section#favorite')?.css('display', 'none');
- }
- $('#hideFavourite')?.on('change', function(e) {
- config.hideFavourite = e?.target?.checked;
- try { chrome.storage.sync.set({ config: config }); } catch(e) {};
- $('section#favorite')?.css('display', e?.target?.checked ? 'none' : 'block');
+ attachToggle('hideFavourite', '#hideFavourite', {
+ onInit: (checked) => {
+ if(checked) $('section#favorite')?.css('display', 'none');
+ },
+ onChange: (checked) => {
+ $('section#favorite')?.css('display', checked ? 'none' : 'block');
+ }
});
$('#keydrop-plus-remove-data')?.on('click', function(e) {
@@ -120,13 +95,15 @@ $( document ).ready(async() => {
try { chrome.storage.sync.set({ config: config }); refreshOdds(config, cases); } catch(e) {};
});
- $(`.keydorp-plus-change-language[data-lang="${config?.lang}"]`)
- ?.css('filter', 'opacity(0.8)');
+ const langSelector = `.keydorp-plus-change-language[data-lang="${config?.lang}"]`;
+ $(langSelector).addClass('active');
$('.keydorp-plus-change-language')?.click(function() {
const lnagData = $(this)?.attr('data-lang');
config.lang = lnagData;
try{ chrome.storage.sync.set({ config: config }) } catch(e) {};
+ $('.keydorp-plus-change-language').removeClass('active');
+ $(this).addClass('active');
window?.location?.reload();
});
});
@@ -169,7 +146,7 @@ const createSettingsPanel = async(config, language, server) => {
server?.languages?.forEach(el => {
$("#keydrop-plus-remove-data").before($(document.createElement('div'))
.css({ display: "inline-table", width: "65px" })
- .html(`
${el?.langBy != null ? `${languageText?.by} ${el?.langBy}` : ""}
`) + .html(`${el?.langBy != null ? `${languageText?.by} ${el?.langBy}` : ""}
`) ); }); }; \ No newline at end of file From cabb8f32fc8fa3cc5f7c6cfdefabf49628501ba2 Mon Sep 17 00:00:00 2001 From: Jakub Ambrus <50302308+kubaam@users.noreply.github.com> Date: Thu, 7 Aug 2025 05:31:52 +0200 Subject: [PATCH 2/9] refactor settings panel toggles --- css/style.css | 12 +++- js/settingsPanel.js | 131 ++++++++++++++++++-------------------------- 2 files changed, 65 insertions(+), 78 deletions(-) diff --git a/css/style.css b/css/style.css index 0fddac2..fcafe02 100644 --- a/css/style.css +++ b/css/style.css @@ -346,13 +346,23 @@ tbody .fullTd { } .keydorp-plus-change-language { + display: inline-block; + height: 34px; + cursor: pointer; + filter: opacity(0.5); transition: 0.25s; } -.keydorp-plus-change-language:hover { +.keydorp-plus-change-language:hover, +.keydorp-plus-change-language.active { filter: opacity(1) !important; } +.keydorp-plus-change-language.active { + border: 1px solid gold; + border-radius: 4px; +} + div.hidden.overflow-hidden.md\:block.bg-navy-700 { height: 76px; } diff --git a/js/settingsPanel.js b/js/settingsPanel.js index 2666db6..64c7ca6 100644 --- a/js/settingsPanel.js +++ b/js/settingsPanel.js @@ -5,97 +5,72 @@ $( document ).ready(async() => { const server = await getServerData(); if(!server) return; await createSettingsPanel(config, language, server); + const attachToggle = (key, selector, { onInit, onChange } = {}) => { + if(config?.[key]) $(selector)?.prop('checked', true); + if(onInit) onInit(!!config?.[key]); + $(selector)?.on('change', function(e) { + const checked = e?.target?.checked; + config[key] = checked; + try { chrome.storage.sync.set({ config: config }); } catch(e) {}; + if(onChange) onChange(checked); + }); + }; if(window?.location?.href?.includes('/#keydrop_plus')) $('div#keydrop-plus-modal')?.addClass('is-open'); $('#keydrop-plus-modal').click(function(e) { if(e?.target?.id == 'close-keydrop-plus-modal' || e?.target?.id == "keydrop-plus-modal") - $('#keydrop-plus-modal') - .removeClass('is-open'); - }); - - if(config?.toastSoundEnable_error) - $('#toastSoundEnable_error')?.prop('checked', true); - $('#toastSoundEnable_error')?.on('change', function(e) { - config.toastSoundEnable_error = e?.target?.checked; - try { chrome.storage.sync.set({ config: config }); } catch(e) {}; - }); - - if(config?.toastSoundEnable_info) - $('#toastSoundEnable_info')?.prop('checked', true); - $('#toastSoundEnable_info')?.on('change', function(e) { - config.toastSoundEnable_info = e?.target?.checked; - try { chrome.storage.sync.set({ config: config }); } catch(e) {}; - }); - - if(config?.toastSoundEnable_success) - $('#toastSoundEnable_success')?.prop('checked', true); - $('#toastSoundEnable_success')?.on('change', function(e) { - config.toastSoundEnable_success = e?.target?.checked; - try { chrome.storage.sync.set({ config: config }); } catch(e) {}; + $('#keydrop-plus-modal').removeClass('is-open'); }); - if(config?.toastSoundEnable_warning) - $('#toastSoundEnable_warning')?.prop('checked', true); - $('#toastSoundEnable_warning')?.on('change', function(e) { - config.toastSoundEnable_warning = e?.target?.checked; - try { chrome.storage.sync.set({ config: config }); } catch(e) {}; + ['error','info','success','warning'].forEach(type => { + attachToggle(`toastSoundEnable_${type}`, `#toastSoundEnable_${type}`); }); - if(config?.toastAutoHide) - $('#hideToast')?.prop('checked', true); - $('#hideToast')?.on('change', function(e) { - config.toastAutoHide = e?.target?.checked; - try { chrome.storage.sync.set({ config: config }); } catch(e) {}; - }); + attachToggle('toastAutoHide', '#hideToast'); - if(config?.showAllYoutuberCases) - $('#showAllYoutuberCases')?.prop('checked', true); - $('#showAllYoutuberCases')?.on('change', function(e) { - $('.keydrop-plus-ytcases').css('display', e?.target?.checked ? 'block' : 'none'); - $('[case-orginal="true"').css('display', e?.target?.checked ? 'none' : 'block'); - config.showAllYoutuberCases = e?.target?.checked; - try { chrome.storage.sync.set({ config: config }); } catch(e) {}; + attachToggle('showAllYoutuberCases', '#showAllYoutuberCases', { + onChange: (checked) => { + $('.keydrop-plus-ytcases').css('display', checked ? 'block' : 'none'); + $('[case-orginal="true"]').css('display', checked ? 'none' : 'block'); + } }); - if(config?.hideLiveDrop) { - $('#hideLiveDrop')?.prop('checked', true); - waitForElm('div.flex.flex-col.overflow-hidden.bg-navy-900.lg\\:flex-row').then(() => { - if(config?.hideLiveDrop) - $('div.flex.flex-col.overflow-hidden.bg-navy-900.lg\\:flex-row')?.eq(0)?.css('display', 'none'); - }); - } - $('#hideLiveDrop')?.on('change', function(e) { - config.hideLiveDrop = e?.target?.checked; - try { chrome.storage.sync.set({ config: config }); } catch(e) {}; - $('div.flex.flex-col.overflow-hidden.bg-navy-900.lg\\:flex-row')?.eq(0)?.css('display', e?.target?.checked ? 'none' : 'flex'); + attachToggle('hideLiveDrop', '#hideLiveDrop', { + onInit: (checked) => { + if(checked) + waitForElm('div.flex.flex-col.overflow-hidden.bg-navy-900.lg\\:flex-row').then(() => { + $('div.flex.flex-col.overflow-hidden.bg-navy-900.lg\\:flex-row')?.eq(0)?.css('display', 'none'); + }); + }, + onChange: (checked) => { + $('div.flex.flex-col.overflow-hidden.bg-navy-900.lg\\:flex-row')?.eq(0)?.css('display', checked ? 'none' : 'flex'); + } }); - if(config?.hideCaseBattle) { - $('#hideCaseBattle')?.prop('checked', true); - waitForElm('[data-testid="single-bttl-rounds-counter"]').then(() => { - if(!config?.hideCaseBattle) - return; - $('div#caseList-root div.container.mb-8')?.eq(0)?.css('display', 'none'); - $('div#caseList-root div.mx-auto.max-w-screen-2xl.2xl\\:px-5')?.eq(0)?.css('margin-top', '50px'); - }); - } - $('#hideCaseBattle')?.on('change', function(e) { - config.hideCaseBattle = e?.target?.checked; - try { chrome.storage.sync.set({ config: config }); } catch(e) {}; - $('div#caseList-root div.container.mb-8')?.eq(0)?.css('display', e?.target?.checked ? 'none' : 'block'); - $('div#caseList-root div.mx-auto.max-w-screen-2xl.2xl\\:px-5')?.eq(0)?.css('margin-top', e?.target?.checked ? '50px' : '0px'); + attachToggle('hideCaseBattle', '#hideCaseBattle', { + onInit: (checked) => { + waitForElm('[data-testid="single-bttl-rounds-counter"]').then(() => { + if(checked) { + $('div#caseList-root div.container.mb-8')?.eq(0)?.css('display', 'none'); + $('div#caseList-root div.mx-auto.max-w-screen-2xl.2xl\\:px-5')?.eq(0)?.css('margin-top', '50px'); + } + }); + }, + onChange: (checked) => { + $('div#caseList-root div.container.mb-8')?.eq(0)?.css('display', checked ? 'none' : 'block'); + $('div#caseList-root div.mx-auto.max-w-screen-2xl.2xl\\:px-5')?.eq(0)?.css('margin-top', checked ? '50px' : '0px'); + } }); - if(config?.hideFavourite) { - $('#hideFavourite')?.prop('checked', true); - $('section#favorite')?.css('display', 'none'); - } - $('#hideFavourite')?.on('change', function(e) { - config.hideFavourite = e?.target?.checked; - try { chrome.storage.sync.set({ config: config }); } catch(e) {}; - $('section#favorite')?.css('display', e?.target?.checked ? 'none' : 'block'); + attachToggle('hideFavourite', '#hideFavourite', { + onInit: (checked) => { + if(checked) $('section#favorite')?.css('display', 'none'); + }, + onChange: (checked) => { + $('section#favorite')?.css('display', checked ? 'none' : 'block'); + } }); $('#keydrop-plus-remove-data')?.on('click', function(e) { @@ -120,13 +95,15 @@ $( document ).ready(async() => { try { chrome.storage.sync.set({ config: config }); refreshOdds(config, cases); } catch(e) {}; }); - $(`.keydorp-plus-change-language[data-lang="${config?.lang}"]`) - ?.css('filter', 'opacity(0.8)'); + const langSelector = `.keydorp-plus-change-language[data-lang="${config?.lang}"]`; + $(langSelector).addClass('active'); $('.keydorp-plus-change-language')?.click(function() { const lnagData = $(this)?.attr('data-lang'); config.lang = lnagData; try{ chrome.storage.sync.set({ config: config }) } catch(e) {}; + $('.keydorp-plus-change-language').removeClass('active'); + $(this).addClass('active'); window?.location?.reload(); }); }); @@ -169,7 +146,7 @@ const createSettingsPanel = async(config, language, server) => { server?.languages?.forEach(el => { $("#keydrop-plus-remove-data").before($(document.createElement('div')) .css({ display: "inline-table", width: "65px" }) - .html(`${el?.langBy != null ? `${languageText?.by} ${el?.langBy}` : ""}
`) + .html(`${el?.langBy != null ? `${languageText?.by} ${el?.langBy}` : ""}
`) ); }); }; \ No newline at end of file From 61bb485db2152a1b4314f1e656f34a9cff45aff9 Mon Sep 17 00:00:00 2001 From: Jakub Ambrus <50302308+kubaam@users.noreply.github.com> Date: Thu, 7 Aug 2025 13:45:56 +0200 Subject: [PATCH 3/9] feat: add advanced giveaway search options --- data/lang/english.json | 2 ++ data/lang/polish.json | 2 ++ data/lang/portuguese.json | 2 ++ js/giveawaysList.js | 31 ++++++++++++++++++------------- js/joinGiveaway.js | 16 +++++++++++----- js/main.js | 7 ++++++- 6 files changed, 41 insertions(+), 19 deletions(-) diff --git a/data/lang/english.json b/data/lang/english.json index 7cff24a..3bea35b 100644 --- a/data/lang/english.json +++ b/data/lang/english.json @@ -22,6 +22,8 @@ "autogiveaway_settings_a2": "You can only join up to 20 giveaways per day", "autogiveaway_settings_p5": "Minimum Amount", "autogiveaway_settings_a5": "Minimum amount of the giveaway", + "autogiveaway_settings_p6": "Search pages", + "autogiveaway_settings_a6": "Number of pages to scan for giveaways", "autogiveaway_settings_p3": "Won Giveaways", "autogiveaway_settings_a3": "Counted won giveaways", "autogiveaway_settings_p4": "Earnings from Giveaways", diff --git a/data/lang/polish.json b/data/lang/polish.json index f94073e..45ea971 100644 --- a/data/lang/polish.json +++ b/data/lang/polish.json @@ -22,6 +22,8 @@ "autogiveaway_settings_a2": "Codziennie można dołączyć tylko do 20 konkursów", "autogiveaway_settings_p5": "Minimalna kwota", "autogiveaway_settings_a5": "Minimalna kwota konkursu", + "autogiveaway_settings_p6": "Liczba stron", + "autogiveaway_settings_a6": "Ilość stron do przeszukania konkursów", "autogiveaway_settings_p3": "Wygrane konkursy", "autogiveaway_settings_a3": "Zliczone wygrane konkursy", "autogiveaway_settings_p4": "Zarobek z konkursów", diff --git a/data/lang/portuguese.json b/data/lang/portuguese.json index e5b4ca7..1c8f6e8 100644 --- a/data/lang/portuguese.json +++ b/data/lang/portuguese.json @@ -22,6 +22,8 @@ "autogiveaway_settings_a2": "Você só pode participar de até 20 sorteios por dia", "autogiveaway_settings_p5": "Quantidade mínima", "autogiveaway_settings_a5": "Quantidade mínima do sorteio", + "autogiveaway_settings_p6": "Páginas de busca", + "autogiveaway_settings_a6": "Número de páginas para procurar sorteios", "autogiveaway_settings_p3": "Sorteios Ganhos", "autogiveaway_settings_a3": "Número de sorteios ganhos", "autogiveaway_settings_p4": "Ganhos com sorteios", diff --git a/js/giveawaysList.js b/js/giveawaysList.js index 0439311..e515c63 100644 --- a/js/giveawaysList.js +++ b/js/giveawaysList.js @@ -57,11 +57,13 @@ const createGiveawayListPanel = async() => { endDate: language?.autogiveaway_endDate, }; - $('#main-view div.min-h-screen.pb-16 div.container').eq(2) - .after($(document.createElement('div')) - .addClass('container giveaway-keydropPlus-info') - .html(`${panelText?.settings_p1}
${panelText?.settings_a1}${panelText?.settings_p5}: PLN
${panelText?.settings_a5}${panelText?.settings_p3}: N/A
${panelText?.settings_a3}${panelText?.settings_p4}: N/A
${panelText?.settings_a4}${panelText?.settings_desc}${panelText?.settings_p1}
${panelText?.settings_a1}${panelText?.settings_p5}: PLN
${panelText?.settings_a5}${panelText?.settings_p3}: N/A
${panelText?.settings_a3}${panelText?.settings_p4}: N/A
${panelText?.settings_a4}${panelText?.settings_desc}${panelText?.settings_p6}:
${panelText?.settings_a6}`); if(autoGiveawayConfig?.winNotification) $('#notificationSwitch').prop('checked', true); @@ -77,10 +79,12 @@ const createGiveawayListPanel = async() => { try { chrome.storage.sync.set({ autoGiveawayConfig: autoGiveawayConfigData }); } catch(e) {}; }); - if(autoGiveawayConfig?.minPrice) - $('#giveawayMinPrice').val(autoGiveawayConfig?.minPrice); + if(autoGiveawayConfig?.minPrice) + $('#giveawayMinPrice').val(autoGiveawayConfig?.minPrice); + if(autoGiveawayConfig?.pagesToCheck) + $('#giveawayPages').val(autoGiveawayConfig?.pagesToCheck); - $('#autoGiveawayButton').on('click', async() => { + $('#autoGiveawayButton').on('click', async() => { const autoGiveawayConfigData = await getAutoGiveawayConfigData(); const checked = autoGiveawayConfigData?.active; $('#autoGiveawayButton').removeClass(checked ? 'button-primary' : 'button-light-green'); @@ -88,11 +92,12 @@ const createGiveawayListPanel = async() => { $('#autoGiveawayButton').text(checked ? panelText?.start : panelText?.disable); $('#giveawaySearch').css('display', checked ? 'none' : 'block'); $('#main-view div.grid-stack.relative.grid.overflow-hidden').eq(4).css('display', checked ? 'block' : 'none') - autoGiveawayConfigData.active = !autoGiveawayConfigData?.active; - autoGiveawayConfigData.minPrice = $('#giveawayMinPrice')?.val(); - try { chrome.storage.sync.set({ autoGiveawayConfig: autoGiveawayConfigData }); } catch(e) {}; - createToast('info', checked ? 'autogiveaway_deactivate' : 'autogiveaway_active'); - }); + autoGiveawayConfigData.active = !autoGiveawayConfigData?.active; + autoGiveawayConfigData.minPrice = $('#giveawayMinPrice')?.val(); + autoGiveawayConfigData.pagesToCheck = $('#giveawayPages')?.val(); + try { chrome.storage.sync.set({ autoGiveawayConfig: autoGiveawayConfigData }); } catch(e) {}; + createToast('info', checked ? 'autogiveaway_deactivate' : 'autogiveaway_active'); + }); refreshGiveawaysPanel(panelText); }; diff --git a/js/joinGiveaway.js b/js/joinGiveaway.js index e2ce43c..37c8619 100644 --- a/js/joinGiveaway.js +++ b/js/joinGiveaway.js @@ -1,5 +1,6 @@ let giveawayInterval = null; -const refreshGiveawayTime = 45 * 1000; +const refreshGiveawayTime = 45 * 1000; +const getRefreshDelay = () => refreshGiveawayTime + Math.floor(Math.random() * 10 * 1000); const giveawayStart = async(isFirst) => { const config = await getConfigData(); @@ -37,7 +38,7 @@ const runAutoGiveaway = async(language, port, currentRate, isFirst) => { //const waitingTime = (autoGiveawayConfig?.currentGiveaway?.deadlineTimestamp - new Date().getTime()) + Math.floor(Math.random() * 60000) + 60000; setTimeout(async() => { return runAutoGiveaway(language, port, currentRate); - }, refreshGiveawayTime);// waitingTime > 0 ? waitingTime : (15 * 60 * 1000)); + }, getRefreshDelay());// waitingTime > 0 ? waitingTime : (15 * 60 * 1000)); }; const getGiveawayData = async(language, gConfig, port, token) => { @@ -81,10 +82,15 @@ const getGiveawayData = async(language, gConfig, port, token) => { }; const findNewGiveaway = async(gConfig, port, token) => { - const fetch = JSON.parse(JSON.stringify(await fetchUrl('GET', `https://wss-${port || 2061}.key-drop.com/v1/giveaway//list?type=active&page=0&perPage=5&status=active&sort=latest`, token))); - if(!fetch || !fetch?.data) return createToast('error', 'error_fetch'); + const pages = gConfig?.pagesToCheck || 1; + let amateurGiveaways = null; + + for(let page = 0; page < pages && !amateurGiveaways; page++) { + const fetch = JSON.parse(JSON.stringify(await fetchUrl('GET', `https://wss-${port || 2061}.key-drop.com/v1/giveaway//list?type=active&page=${page}&perPage=5&status=active&sort=latest`, token))); + if(!fetch || !fetch?.data) continue; + amateurGiveaways = fetch?.data?.find(el => el?.frequency == 'amateur'); + } - const amateurGiveaways = fetch?.data?.find(el => el?.frequency == 'amateur'); if(!amateurGiveaways) return createToast('error', 'error_fetch'); gConfig.currentGiveaway.id = amateurGiveaways?.id; diff --git a/js/main.js b/js/main.js index f6b92e7..a4f902a 100644 --- a/js/main.js +++ b/js/main.js @@ -153,10 +153,15 @@ const getCurrency = async() => { const getAutoGiveawayConfigData = async() => { const storageData = await getStorageData(1, 'autoGiveawayConfig'); - if(storageData) return storageData; + if(storageData) { + if(!storageData?.pagesToCheck) + storageData.pagesToCheck = 1; + return storageData; + } const autoGiveawayConfigData = { active: false, winNotification: false, + pagesToCheck: 1, currentGiveaway: { id: null, deadlineTimestamp: null, From c9ee204cf46b264260349ebde038c23698c20425 Mon Sep 17 00:00:00 2001 From: Jakub Ambrus <50302308+kubaam@users.noreply.github.com> Date: Thu, 7 Aug 2025 14:16:18 +0200 Subject: [PATCH 4/9] refactor: enhance utility functions --- js/caseInfo.js | 2 +- js/caseOdds.js | 2 +- js/dailyCaseTimer.js | 2 +- js/giveawaysList.js | 8 ++-- js/joinCaseBattle.js | 2 +- js/joinGiveaway.js | 8 ++-- js/main.js | 87 ++++++++++++++++++++++++----------------- js/settingsPanel.js | 13 +++--- js/skinChanger.js | 4 +- js/ticketInfo.js | 2 +- js/websites/skinport.js | 2 +- js/websites/steam.js | 2 +- 12 files changed, 76 insertions(+), 58 deletions(-) diff --git a/js/caseInfo.js b/js/caseInfo.js index 04b3645..ebb245b 100644 --- a/js/caseInfo.js +++ b/js/caseInfo.js @@ -295,7 +295,7 @@ const caseDataCombine = async(caseJSON, languageText) => { const casesFetch = await fetchUrl('GET', `${githubUrl}/cases.json`) if(!casesFetch) return; - const cases = JSON.parse(`{"cases": ${casesFetch}}`)?.cases; + const cases = Array.isArray(casesFetch) ? casesFetch : casesFetch?.cases; if(!cases?.length) return; const goldenCases = cases?.filter(el => el?.goldProfit !== undefined); diff --git a/js/caseOdds.js b/js/caseOdds.js index 864e9a9..b08b521 100644 --- a/js/caseOdds.js +++ b/js/caseOdds.js @@ -2,7 +2,7 @@ $( document ).ready(async() => { const config = await getConfigData(); const casesFetch = await fetchUrl('GET', `${githubUrl}/cases.json`) if(!casesFetch || !config) return; - const cases = JSON.parse(`{"cases": ${casesFetch}}`)?.cases; + const cases = Array.isArray(casesFetch) ? casesFetch : casesFetch?.cases; if(!cases?.length) return; waitForElm('section#gold-area').then(async() => { diff --git a/js/dailyCaseTimer.js b/js/dailyCaseTimer.js index 55d6ac9..535471c 100644 --- a/js/dailyCaseTimer.js +++ b/js/dailyCaseTimer.js @@ -61,7 +61,7 @@ const createSkinsValueDiv = async() => { const fetch = await fetchUrl("GET", "https://key-drop.com/en/panel/profil/eq_value"); if(!fetch) return; - const data = JSON.parse(fetch); + const data = fetch; const skinsValue = `${(data?.fullPrice).toFixed(2).toString().replace('.',',')} ${data?.currency}`; $('div[data-testid="balance"]') diff --git a/js/giveawaysList.js b/js/giveawaysList.js index e515c63..d594de3 100644 --- a/js/giveawaysList.js +++ b/js/giveawaysList.js @@ -76,7 +76,7 @@ const createGiveawayListPanel = async() => { const autoGiveawayConfigData = await getAutoGiveawayConfigData(); if(!autoGiveawayConfigData) return; autoGiveawayConfigData.winNotification = e?.target?.checked; - try { chrome.storage.sync.set({ autoGiveawayConfig: autoGiveawayConfigData }); } catch(e) {}; + setStorageData('sync', { autoGiveawayConfig: autoGiveawayConfigData }); }); if(autoGiveawayConfig?.minPrice) @@ -95,7 +95,7 @@ const createGiveawayListPanel = async() => { autoGiveawayConfigData.active = !autoGiveawayConfigData?.active; autoGiveawayConfigData.minPrice = $('#giveawayMinPrice')?.val(); autoGiveawayConfigData.pagesToCheck = $('#giveawayPages')?.val(); - try { chrome.storage.sync.set({ autoGiveawayConfig: autoGiveawayConfigData }); } catch(e) {}; + setStorageData('sync', { autoGiveawayConfig: autoGiveawayConfigData }); createToast('info', checked ? 'autogiveaway_deactivate' : 'autogiveaway_active'); }); refreshGiveawaysPanel(panelText); @@ -127,7 +127,7 @@ const refreshGiveawaysPanel = async(panelText) => { if(giveawaysHistory?.length >= 100) { giveawaysHistory = giveawaysHistory?.slice(1, 100); - try { chrome.storage.local.set({ giveawaysHistory: giveawaysHistory }); } catch(e) {}; + setStorageData('local', { giveawaysHistory: giveawaysHistory }); } // let joinsCount = 20; @@ -166,7 +166,7 @@ const refreshGiveawaysPanel = async(panelText) => { $('#autoGiveawayButton').text(panelText?.start); $('#giveawaySearch').css('display', 'none'); $('#main-view div.grid-stack.relative.grid.overflow-hidden').eq(4).css('display', 'block'); - try { chrome.storage.sync.set({ autoGiveawayConfig: autoGiveawayConfig }); } catch(e) {}; + setStorageData('sync', { autoGiveawayConfig: autoGiveawayConfig }); }*/ if(autoGiveawayConfig?.active) { diff --git a/js/joinCaseBattle.js b/js/joinCaseBattle.js index 952658f..657d5f4 100644 --- a/js/joinCaseBattle.js +++ b/js/joinCaseBattle.js @@ -155,7 +155,7 @@ function autoJoinCaseBattle() { return createToast('error', 'autoJoinFreeCaseBattle_noPlayers'); if(fastCaseBattleConfig?.casesName?.length <= 0) return createToast('error', 'autoJoinFreeCaseBattle_noCaseName'); - try { chrome.storage.sync.set({ fastCaseBattleConfig: fastCaseBattleConfig }) } catch(e) {}; + setStorageData('sync', { fastCaseBattleConfig: fastCaseBattleConfig }); fastCaseBattleData = fastCaseBattleConfig; autoJoinActive = !autoJoinActive; diff --git a/js/joinGiveaway.js b/js/joinGiveaway.js index 37c8619..ee23474 100644 --- a/js/joinGiveaway.js +++ b/js/joinGiveaway.js @@ -72,12 +72,12 @@ const getGiveawayData = async(language, gConfig, port, token) => { gConfig.currentGiveaway.haveIJoined = false; gConfig.currentGiveaway.captcha = false; gConfig.currentGiveaway.maxPrice = null; - try { chrome.storage.sync.set({ autoGiveawayConfig: gConfig }); } catch(e) {}; + setStorageData('sync', { autoGiveawayConfig: gConfig }); const giveawaysHistory = await getStorageData('local', 'giveawaysHistory') || []; giveawaysHistory.push(giveaway); - try { chrome.storage.local.set({ giveawaysHistory: giveawaysHistory }); } catch(e) {}; + setStorageData('local', { giveawaysHistory: giveawaysHistory }); return gConfig; }; @@ -97,7 +97,7 @@ const findNewGiveaway = async(gConfig, port, token) => { gConfig.currentGiveaway.deadlineTimestamp = amateurGiveaways?.deadlineTimestamp; gConfig.currentGiveaway.haveIJoined = amateurGiveaways?.haveIJoined; gConfig.currentGiveaway.maxPrice = amateurGiveaways?.prizes[0]?.price; - try { chrome.storage.sync.set({ autoGiveawayConfig: gConfig }); } catch(e) {}; + setStorageData('sync', { autoGiveawayConfig: gConfig }); return gConfig; }; @@ -117,7 +117,7 @@ const joinGiveaway = async(language, gConfig, token) => { } else createToast('error', null, idText, giveawayUrl, `${language?.autogiveaway_error} ${fetch?.message}`); - try { chrome.storage.sync.set({ autoGiveawayConfig: gConfig }); } catch(e) {}; + setStorageData('sync', { autoGiveawayConfig: gConfig }); return gConfig; }; diff --git a/js/main.js b/js/main.js index a4f902a..dc46b93 100644 --- a/js/main.js +++ b/js/main.js @@ -14,37 +14,55 @@ $('body').append($(document.createElement('div')) const fetchUrl = async(type, url, token, noTime, data) => { try { - const result = await $.ajax({ - type: type, - url: `${url}${noTime ? '' : `?t=${new Date().getTime()}`}`, - data: data ? JSON.stringify(data) : '', - beforeSend: async (xhr) => { - if(token) - xhr.setRequestHeader('authorization', `Bearer ${token}`); + const controller = new AbortController(); + const timer = setTimeout(() => controller.abort(), 15 * 1000); + const response = await fetch(`${url}${noTime ? '' : `?t=${Date.now()}`}`, { + method: type, + headers: { + 'Content-Type': data ? 'application/json' : undefined, + ...(token ? { authorization: `Bearer ${token}` } : {}) }, - success: function (response, textStatus, jqXHR) { - if(!response) - return createToast('error', 'error_fetch'); - return JSON.parse(JSON.stringify(response)) || undefined; - }, - error: function(error) { - return; - } + body: data ? JSON.stringify(data) : undefined, + signal: controller.signal }); - return result; - } catch(e) { if(e?.status == 403) return window?.location?.reload(); }; + clearTimeout(timer); + if(response.status === 403) { + return window?.location?.reload(); + } + const contentType = response.headers.get('content-type'); + if(contentType && contentType.includes('application/json')) + return await response.json(); + return await response.text(); + } catch(e) { + return null; + } }; const getStorageData = async(type, name) => { try { - const storageData = - (type === 'local' || type === 0) ? await chrome.storage.local.get([name]).then((result) => { return result[name]; }) - : await chrome.storage.sync.get([name]).then((result) => { return result[name] }); - return storageData; + const storage = (type === 'local' || type === 0) ? chrome.storage.local : chrome.storage.sync; + const result = await storage.get([name]); + return result[name]; } catch(e) { - return;// console.log(e); - }; -} + return; + } +}; + +const setStorageData = async(type, data) => { + try { + const storage = (type === 'local' || type === 0) ? chrome.storage.local : chrome.storage.sync; + await storage.set(data); + return true; + } catch(e) { return false; } +}; + +const clearStorageData = async(type) => { + try { + const storage = (type === 'local' || type === 0) ? chrome.storage.local : chrome.storage.sync; + await storage.clear(); + return true; + } catch(e) { return false; } +}; const getIndexData = async() => { const storageData = await getStorageData(1, 'index'); @@ -59,7 +77,7 @@ const getIndexData = async() => { currency: fetch?.currency, currencyRates: fetch?.rates || [{id: 'EUR', rate: 1}, {id: 'PLN', rate: 5}, {id: 'USD', rate: 1}, {id: 'UAH', rate: 36.5}, {id: 'BRL', rate: 5.13}, {id: 'ARS', rate: 175}, {id: 'GBP', rate: 0.89}, {id: 'CZK', rate: 25.5}] }; - try { chrome.storage.sync.set({ index: indexData }); } catch(e) {}; + try { await setStorageData('sync', { index: indexData }); } catch(e) {}; return indexData; }; @@ -89,7 +107,7 @@ const getConfigData = async() => { if(refreshedConfigData?.tokenExp && refreshedConfigData?.tokenExp > (new Date().getTime() + tokenExpiresTime)) { refreshedConfigData.token = null; refreshedConfigData.tokenExp = null; - try { chrome.storage.sync.set({ config: refreshedConfigData }); } catch(e) {}; + try { await setStorageData('sync', { config: refreshedConfigData }); } catch(e) {}; createToast('warning', 'warning_dateManipulated'); } return refreshedConfigData; @@ -103,13 +121,13 @@ const checkToken = async(config) => { config.token = fetch; config.tokenExp = timestamp + tokenExpiresTime; } - try { chrome.storage.sync.set({ config: config }); } catch(e) {}; + try { await setStorageData('sync', { config: config }); } catch(e) {}; return config; }; const getServerData = async() => { - const fetch = JSON.parse(await fetchUrl('GET', `${githubUrl}/serverData.json`)); + const fetch = await fetchUrl('GET', `${githubUrl}/serverData.json`); if(!fetch || !fetch?.current_versions) return; return fetch; }; @@ -127,9 +145,8 @@ const getLanguageData = async(lang) => { } const fetch = await fetchUrl('GET', `${githubUrl}/lang/${lang}.json`); - if(!fetch || fetch?.length <= 0) return; - const json = JSON.parse(fetch); - return json; + if(!fetch) return; + return fetch; }; const getCookieValue = (cookieName) => { @@ -146,7 +163,7 @@ const getCurrency = async() => { let currency = getCookieValue('currency'); if (currency == null) { fetch = await fetchUrl('GET', 'https://key-drop.com/en/balance?skinsValue=true'); - currency = JSON.parse(fetch)?.currency; + currency = fetch?.currency; } return currency || 'USD'; } @@ -169,7 +186,7 @@ const getAutoGiveawayConfigData = async() => { captcha: false }, } - try { chrome.storage.sync.set({ autoGiveawayConfig: autoGiveawayConfigData }); } catch(e) {}; + try { await setStorageData('sync', { autoGiveawayConfig: autoGiveawayConfigData }); } catch(e) {}; return autoGiveawayConfigData; }; @@ -180,7 +197,7 @@ const getUserSkinsData = async(token) => { const totalMaxSkins = 999; do { - const fetch = JSON.parse(await fetchUrl('GET', `https://key-drop.com/en/panel/profil/my_winner_list?type=all&sort=newest&state=all&per_page=${totalMaxSkins}¤t_page=${currentPage}?t=${new Date().getTime()}`, token)); + const fetch = await fetchUrl('GET', `https://key-drop.com/en/panel/profil/my_winner_list?type=all&sort=newest&state=all&per_page=${totalMaxSkins}¤t_page=${currentPage}?t=${new Date().getTime()}`, token); if(!fetch || !fetch?.total || fetch?.data?.length <= 0) return; totalUserSkins = fetch?.total || 1; if(currentPage == 1) userSkinsArray = fetch?.data; @@ -364,7 +381,7 @@ const verifyUser = async() => { const configData = await getConfigData(); configData.active = true; - chrome.storage.sync.set({ config: configData }); + setStorageData('sync', { config: configData }); return; }; verifyUser(); diff --git a/js/settingsPanel.js b/js/settingsPanel.js index 64c7ca6..7a7330f 100644 --- a/js/settingsPanel.js +++ b/js/settingsPanel.js @@ -11,7 +11,7 @@ $( document ).ready(async() => { $(selector)?.on('change', function(e) { const checked = e?.target?.checked; config[key] = checked; - try { chrome.storage.sync.set({ config: config }); } catch(e) {}; + setStorageData('sync', { config: config }); if(onChange) onChange(checked); }); }; @@ -74,9 +74,9 @@ $( document ).ready(async() => { }); $('#keydrop-plus-remove-data')?.on('click', function(e) { - try { chrome.storage.sync.clear(); } catch(e) {}; + clearStorageData('sync'); setTimeout(async() => { - try { chrome.storage.local.clear(); } catch(e) {}; + clearStorageData('local'); window?.location?.reload(); }, 200); }); @@ -88,11 +88,12 @@ $( document ).ready(async() => { const config = await getConfigData(); const casesFetch = await fetchUrl('GET', `${githubUrl}/cases.json`) if(!casesFetch || !config) return; - const cases = JSON.parse(`{"cases": ${casesFetch}}`)?.cases; + const cases = Array.isArray(casesFetch) ? casesFetch : casesFetch?.cases; if(!cases?.length) return; config.showJokerOdds = e?.target?.checked; - try { chrome.storage.sync.set({ config: config }); refreshOdds(config, cases); } catch(e) {}; + setStorageData('sync', { config: config }); + refreshOdds(config, cases); }); const langSelector = `.keydorp-plus-change-language[data-lang="${config?.lang}"]`; @@ -101,7 +102,7 @@ $( document ).ready(async() => { $('.keydorp-plus-change-language')?.click(function() { const lnagData = $(this)?.attr('data-lang'); config.lang = lnagData; - try{ chrome.storage.sync.set({ config: config }) } catch(e) {}; + setStorageData('sync', { config: config }); $('.keydorp-plus-change-language').removeClass('active'); $(this).addClass('active'); window?.location?.reload(); diff --git a/js/skinChanger.js b/js/skinChanger.js index 5c79cde..20319fd 100644 --- a/js/skinChanger.js +++ b/js/skinChanger.js @@ -209,7 +209,7 @@ const createMenu = async(language) => { try { const config = await getConfigData(); config.skinportPrice = e?.target?.checked; - await chrome.storage.sync.set({ config: config }); + await setStorageData('sync', { config: config }); refreshPrices(); } catch(e) {}; }); @@ -225,7 +225,7 @@ const createMenu = async(language) => { try { const config = await getConfigData(); config.steamPrice = e?.target?.checked; - await chrome.storage.sync.set({ config: config }); + await setStorageData('sync', { config: config }); refreshPrices(); } catch(e) {}; }); diff --git a/js/ticketInfo.js b/js/ticketInfo.js index d82b0be..484f307 100644 --- a/js/ticketInfo.js +++ b/js/ticketInfo.js @@ -9,7 +9,7 @@ $( document ).ready(async() => { const createTicketsInfo = async() => { const fetch = await fetchUrl('GET', 'https://key-drop.com/en/balance?battleTickets=1'); - const data = JSON.parse(fetch); + const data = fetch; const tickets = data?.caseBattleTickets; $('div a[href="#gold-area"]').after($(document.createElement('a')) diff --git a/js/websites/skinport.js b/js/websites/skinport.js index c3eb3c8..88af2b6 100644 --- a/js/websites/skinport.js +++ b/js/websites/skinport.js @@ -42,7 +42,7 @@ const getSkins = async() => { marketJSON.currency = currency; marketJSON.updateTime = `${new Date().getTime()}`; - try { chrome.storage.local.set({skinportMarketJSON: marketJSON }); } catch(e) {}; + setStorageData('local', {skinportMarketJSON: marketJSON }); setTimeout(function() { try { open(`https://key-drop.com/skin-changer`, '_self'); diff --git a/js/websites/steam.js b/js/websites/steam.js index 8b15e46..bba81d2 100644 --- a/js/websites/steam.js +++ b/js/websites/steam.js @@ -57,7 +57,7 @@ const loadSteamSkins = (langText) => { loadSteamSkins(langText); } else { marketJSON.updateTime = `${new Date().getTime()}`; - try { chrome.storage.local.set({steamMarketJSON: marketJSON}); } catch(e) {}; + setStorageData('local', {steamMarketJSON: marketJSON}); setTimeout(() => { try { open(`https://key-drop.com/skin-changer`, '_self'); From 0d0ac3bf880c1d95a7362078840ff8f315d86b2f Mon Sep 17 00:00:00 2001 From: Jakub Ambrus <50302308+kubaam@users.noreply.github.com> Date: Thu, 7 Aug 2025 14:24:41 +0200 Subject: [PATCH 5/9] refactor: enhance utilities and fetch accuracy --- js/giveawaysList.js | 2 +- js/main.js | 92 ++++++++++++++++++++++++++++++++++++++------- 2 files changed, 80 insertions(+), 14 deletions(-) diff --git a/js/giveawaysList.js b/js/giveawaysList.js index d594de3..63bea15 100644 --- a/js/giveawaysList.js +++ b/js/giveawaysList.js @@ -106,7 +106,7 @@ const refreshGiveawaysPanel = async(panelText) => { if(!config?.active) return; const index = await getIndexData(); - let giveawaysHistory = await getStorageData('local', 'giveawaysHistory'); + let giveawaysHistory = await getStorageData('local', 'giveawaysHistory', []); const userSkins = await getUserSkinsData(config?.token); const giveawayWinnersTab = userSkins?.length !== 0 ? userSkins?.filter(el => el?.sourceType == 'giveaway') : []; diff --git a/js/main.js b/js/main.js index dc46b93..aae9de5 100644 --- a/js/main.js +++ b/js/main.js @@ -12,15 +12,33 @@ $('body').append($(document.createElement('div')) .css({ position: 'fixed', right: 0, 'margin-right': '10px', 'margin-bottom': '11px', bottom: 0, 'z-index': 999 }) ); -const fetchUrl = async(type, url, token, noTime, data) => { +const defaultFetchTimeout = 15 * 1000; + +/** + * Perform a network request with optional authorization and body data. + * Automatically appends a timestamp to bust caches unless `noTime` is true. + * + * @param {string} type HTTP method + * @param {string} url Target URL + * @param {string|false} token Optional bearer token + * @param {boolean} noTime Skip timestamp parameter + * @param {Object} [data] JSON body payload + * @param {Object} [options] Additional options (timeout, headers) + * @returns {Promise<*>} Parsed JSON/text response or null on error + */ +const fetchUrl = async(type, url, token, noTime, data, options = {}) => { + const { timeout = defaultFetchTimeout, headers = {} } = options; try { const controller = new AbortController(); - const timer = setTimeout(() => controller.abort(), 15 * 1000); - const response = await fetch(`${url}${noTime ? '' : `?t=${Date.now()}`}`, { + const timer = setTimeout(() => controller.abort(), timeout); + const requestUrl = new URL(url); + if(!noTime) requestUrl.searchParams.set('t', Date.now()); + const response = await fetch(requestUrl.toString(), { method: type, headers: { - 'Content-Type': data ? 'application/json' : undefined, - ...(token ? { authorization: `Bearer ${token}` } : {}) + ...(data ? { 'Content-Type': 'application/json' } : {}), + ...(token ? { authorization: `Bearer ${token}` } : {}), + ...headers }, body: data ? JSON.stringify(data) : undefined, signal: controller.signal @@ -29,25 +47,39 @@ const fetchUrl = async(type, url, token, noTime, data) => { if(response.status === 403) { return window?.location?.reload(); } - const contentType = response.headers.get('content-type'); - if(contentType && contentType.includes('application/json')) - return await response.json(); - return await response.text(); + if(!response.ok) return null; + const contentType = response.headers.get('content-type') || ''; + return contentType.includes('application/json') ? await response.json() : await response.text(); } catch(e) { return null; } }; -const getStorageData = async(type, name) => { +/** + * Retrieve a value from browser storage. + * + * @param {'local'|'sync'|0|1} type Storage type + * @param {string} name Key name + * @param {*} [defaultValue] Value to return if key does not exist + * @returns {Promise<*>} Stored value or defaultValue + */ +const getStorageData = async(type, name, defaultValue) => { try { const storage = (type === 'local' || type === 0) ? chrome.storage.local : chrome.storage.sync; const result = await storage.get([name]); - return result[name]; + return result[name] ?? defaultValue; } catch(e) { - return; + return defaultValue; } }; +/** + * Save data to browser storage. + * + * @param {'local'|'sync'|0|1} type Storage type + * @param {Object} data Data to store + * @returns {Promise