// ==UserScript==
// @name Dreadcast Script Manager
// @namespace Dreadcast
// @match https://www.dreadcast.net/Main
// @match https://www.dreadcast.net/Forum
// @match https://www.dreadcast.net/Forum/*
// @match https://www.dreadcast.net/EDC
// @match https://www.dreadcast.net/EDC/*
// @version 1.3.3
// @author Pelagia/Isilin
// @description Centralize all dreadcast scripts in one single source, integrated to the game.
// @license https://github.com/Isilin/dreadcast-scripts?tab=GPL-3.0-1-ov-file
// @require https://update.greasyfork.icu/scripts/507382/Dreadcast%20Development%20Kit.user.js?version=1533476
// @grant GM_setValue
// @grant GM_getValue
// @grant GM_deleteValue
// @grant GM_listValues
// @grant GM_xmlhttpRequest
// @grant GM_addStyle
// @connect update.greasyfork.org
// @connect docs.google.com
// @connect googleusercontent.com
// @connect sheets.googleapis.com
// @connect raw.githubusercontent.com
// @downloadURL none
// ==/UserScript==
// TODO remplacer petit à petit les scripts par les versions locales nettoyées.
// TODO use a recent jquery with noConflict
// TODO Reset button in Com'Back reset all the settings from DCSM (including scripts then).
$(() => {
// To check if a script is used in a DSM context.
Util.isDSM = () => true;
const LIST_TAG = 'dcsm_list';
const ALL_DISABLED_TAG = 'dcsm_all_disabled';
const INTRO_TAG = 'dcsm_intro_disabled';
const DEV_MODE_TAG = 'dcsm_dev_mode';
let settings, allDisabled, introDisabled, devMode;
let newSettings, newAllDisabled, newDevMode;
// ===== CORE =====
const initPersistence = () => {
// Init persistent memory if needed.
DC.LocalMemory.init(LIST_TAG, {});
DC.LocalMemory.init(ALL_DISABLED_TAG, false);
DC.LocalMemory.init(INTRO_TAG, false);
DC.LocalMemory.init(DEV_MODE_TAG, false);
// TODO to delete at next major version.
if (DC.LocalMemory.get('dcm_list') !== undefined) {
DC.LocalMemory.set(LIST_TAG, DC.LocalMemory.get('dcm_list'));
DC.LocalMemory.delete('dcm_list');
}
if (DC.LocalMemory.get('dcm_all_disabled') !== undefined) {
DC.LocalMemory.set(
ALL_DISABLED_TAG,
DC.LocalMemory.get('dcm_all_disabled'),
);
DC.LocalMemory.delete('dcm_all_disabled');
}
// Load the current settings.
settings = DC.LocalMemory.get(LIST_TAG);
allDisabled = DC.LocalMemory.get(ALL_DISABLED_TAG);
introDisabled = DC.LocalMemory.get(INTRO_TAG);
devMode = DC.LocalMemory.get(DEV_MODE_TAG);
};
const synchronizeSettings = (settings, scripts) => {
let tmp = settings;
scripts.forEach((script) => {
if (!Object.hasOwn(tmp, script.id)) {
// Update the settings, if there is new scripts.
tmp[script.id] = false;
}
});
// Remove in settings, scripts that doesn't exist anymore.
tmp = Object.keys(tmp)
.filter(
(key) => scripts.find((script) => script.id === key) !== undefined,
)
.reduce((obj, key) => {
obj[key] = tmp[key];
return obj;
}, {});
// Save the new settings in persistent memory.
DC.LocalMemory.set(LIST_TAG, tmp);
return tmp;
};
const createScriptLine = (script, index) => {
const line = $(`
${index}
${
script.icon && script.icon !== ''
? ` `
: ' '
}
${
script.experimental ? '[DEV] ' : ''
} ${script.name || ''}
${
script.authors || ''
}
${
script.description || ''
}
`);
$('.enabled_cell', line).append(
DC.UI.Tooltip(
'Activer/Désactiver le script ne perdra pas sa configuration.',
DC.UI.Checkbox(
`${script.id}_check`,
newSettings[script.id],
() => (newSettings[script.id] = !newSettings[script.id]),
),
),
);
if (script.settings) {
$('.setting_cell', line).append(
DC.UI.Tooltip(
'Settings',
DC.UI.Button(
`${script.id}_setting`,
' ',
() => {},
),
),
);
}
if (script.doc && script.doc !== '') {
$('.doc_cell', line).append(
DC.UI.Tooltip(
'Documentation',
DC.UI.Button(`${script.id}_doc`, ' ', () =>
window.open(script.doc, '_blank'),
),
),
);
}
if (script.rp && script.rp !== '') {
$('.rp_cell', line).append(
DC.UI.Tooltip(
'Topic RP',
DC.UI.Button(
`${script.id}_rp`,
'RP
',
() => window.open(script.doc, '_blank'),
),
),
);
}
if (script.contact && script.contact !== '') {
$('.contact_cell', line).append(
DC.UI.Tooltip(
'Contact',
DC.UI.Button(
`${script.id}_rp`,
' ',
() => nav.getMessagerie().newMessage(script.contact),
),
),
);
}
return line;
};
const createIntro = () => {
if (Util.isGame() && !introDisabled) {
introDisabled = true;
DC.LocalMemory.set(INTRO_TAG, introDisabled);
DC.UI.PopUp(
'dcsm_intro',
'Bienvenue sur le Dreadcast Script Manager !',
$(`
Merci d'avoir installé le DreaCast Script Manager (DCSM).
Cet utilitaire va vous permettre de gérer vos scripts directement en jeu. Pensez à désactiver/désinstaller dans votre GreaseMonkey/TamperMonkey (ou équivalent), les scripts que vous activerez dans le DCSM, pour éviter des doublons.
La suite se passe dans Paramètres > Scripts & Skins.
Vous pourrez obtenir des réponses à vos questions sur le wiki , sur le forum, ou en me contactant directement par Com' HRP : (JD Pelagia ).
Bon jeu ! (Vous ne verrez plus cette fenêtre d'information par la suite).
`),
);
}
};
const createUI = (scripts, settings) => {
DC.UI.addSubMenuTo(
'Paramètres ▾',
DC.UI.SubMenu(
'Scripts & Skins',
() => {
// On récupère une config temporaire qu'on appliquera uniquement si sauvegardée.
newSettings = settings;
newAllDisabled = allDisabled;
newDevMode = devMode;
const sections = [
{ id: 'all', label: 'Tous' },
{ id: 'game', label: 'Jeu' },
{ id: 'forum', label: 'Forum' },
{ id: 'edc', label: 'EDC' },
];
const categories = [
{ id: 'all', label: 'Tous' },
{ id: 'mailing', label: 'Messagerie' },
{ id: 'chat', label: 'Chat' },
{ id: 'silhouette', label: 'Silhouette' },
{ id: 'ui', label: 'UI' },
{ id: 'mech', label: 'Mécaniques' },
{ id: 'fix', label: 'Correctifs' },
{ id: 'misc', label: 'Autres' },
];
const content = $(`
Filtrer :
${sections
.map(
(section, index) => `
${section.label}
`,
)
.join('')}
Filtrer :
${categories
.map(
(category, index) => `
${
category.label
}
`,
)
.join('')}
`);
$(document).on('change', "input[name='category']", (e) => {
const category = e.target.value;
const section = $("input[name='section']:checked").val();
const search = $("input[name='search_script']").val().toLowerCase();
// Empty the table
$('tbody', content).empty();
// Add filtered lines
scripts
.filter(
(script) =>
(script.section.includes(section) || section === 'all') &&
(script.category.includes(category) || category === 'all') &&
(script.name.toLowerCase().includes(search) ||
script.description.toLowerCase().includes(search)),
)
.forEach((script, index) => {
const line = createScriptLine(script, index);
$('tbody', content).append(line);
});
});
$(document).on('change', "input[name='section']", (e) => {
const section = e.target.value;
const category = $("input[name='category']:checked").val();
const search = $("input[name='search_script']").val().toLowerCase();
// Empty the table
$('tbody', content).empty();
// Add filtered lines
scripts
.filter(
(script) =>
(script.section.includes(section) || section === 'all') &&
(script.category.includes(category) || category === 'all') &&
(script.name.toLowerCase().includes(search) ||
script.description.toLowerCase().includes(search)),
)
.forEach((script, index) => {
const line = createScriptLine(script, index);
$('tbody', content).append(line);
});
});
$(document).on('input', "input[name='search_script']", (e) => {
const search = e.target.value.toLowerCase();
const category = $("input[name='category']:checked").val();
const section = $("input[name='section']:checked").val();
// Empty the table
$('tbody', content).empty();
// Add filtered lines
scripts
.filter(
(script) =>
(script.section.includes(section) || section === 'all') &&
(script.category.includes(category) || category === 'all') &&
(script.name.toLowerCase().includes(search) ||
script.description.toLowerCase().includes(search)),
)
.forEach((script, index) => {
const line = createScriptLine(script, index);
$('tbody', content).append(line);
});
});
// Sauvegarder les paramètres.
content.append(
DC.UI.TextButton('scripts_refresh', 'Sauvegarder', () => {
settings = newSettings;
allDisabled = newAllDisabled;
devMode = newDevMode;
DC.LocalMemory.set(LIST_TAG, settings);
DC.LocalMemory.set(ALL_DISABLED_TAG, allDisabled);
DC.LocalMemory.set(DEV_MODE_TAG, devMode);
location.replace('https://www.dreadcast.net/Main'); // Better than reload() with Chrome.
}),
);
content.append(
$(
`⚠ Sauvegarder votre configuration va raffraichir la page.
Pensez à sauvegarder votre travail en cours avant.
`,
),
);
const resetConfig = () => {
const list = DC.LocalMemory.list();
list.forEach((key) => {
DC.LocalMemory.delete(key);
});
};
// Import/Export
content.append(
$(
'
',
),
);
$('#config_buttons', content).append(
DC.UI.TextButton(
'config_reset',
' Réinitialiser',
() => {
resetConfig();
location.replace('https://www.dreadcast.net/Main');
},
),
);
$('#config_buttons', content).append(
DC.UI.TextButton(
'config_import',
' Importer la configuration',
() => {
resetConfig();
const anchor = document.createElement('input');
anchor.style.display = 'none';
anchor.type = 'file';
anchor.accept = 'application.json';
anchor.onchange = (e) => {
var reader = new FileReader();
reader.onload = (e) => {
const data = JSON.parse(e.target.result);
Object.keys(data).forEach((key) => {
DC.LocalMemory.set(key, data[key]);
});
};
reader.readAsText(e.target.files[0]);
document.body.removeChild(anchor);
location.replace('https://www.dreadcast.net/Main');
};
document.body.appendChild(anchor);
anchor.click();
},
),
);
$('#config_buttons', content).append(
DC.UI.TextButton(
'config_export',
' Exporter la configuration',
function () {
const list = DC.LocalMemory.list();
let data = {};
list.forEach((key) => {
data[key] = DC.LocalMemory.get(key);
});
const anchor = document.createElement('a');
anchor.style.display = 'none';
anchor.href = URL.createObjectURL(
new Blob([JSON.stringify(data)], {
type: 'application/json',
}),
);
anchor.download = 'dcsm_config.json';
document.body.appendChild(anchor);
anchor.click();
document.body.removeChild(anchor);
},
),
);
// Switch button pour désactiver tous les scripts.
$('#scripts_all_switch', content).append(
DC.UI.Checkbox(
'scripts_all_check',
newAllDisabled,
() => (newAllDisabled = !newAllDisabled),
),
);
// Switch button pour le développeur mode.
$('#developper_mode_switch', content).append(
DC.UI.Tooltip(
'Attention, ces scripts sont encore en développement !',
DC.UI.Checkbox(
'developper_mode_check',
newDevMode,
() => (newDevMode = !newDevMode),
),
),
);
scripts
.filter((script) => devMode || !script.experimental)
.forEach((script, index) => {
const line = createScriptLine(script, index);
$('tbody', content).append(line);
});
return DC.UI.PopUp('scripts_modal', 'Scripts & Skins', content);
},
true,
),
5,
);
};
// ===============
$(document).ready(() => {
initPersistence();
createIntro();
// Load list of scripts
DC.Network.loadJson(
'https://raw.githubusercontent.com/Isilin/dreadcast-scripts/main/data/scripts.json',
)
.then((scripts) => {
settings = synchronizeSettings(settings, scripts);
// Create the interface.
if (Util.isGame()) {
createUI(scripts, settings);
}
// Load the scripts
if (!allDisabled) {
const context = Util.getContext();
scripts
.filter((script) => script.section.includes(context))
.filter((script) => devMode || !script.experimental)
.forEach((script) => {
if (settings[script.id]) {
DC.Network.loadScript(script.url)
.then(() => {
console.info(
`DCSM - '${script.name}' script has been loaded successfully.`,
);
})
.catch((err) => {
console.error(
`DCSM - Error loading '${script.name}' script: ` + err,
);
});
}
});
}
})
.catch((err) => {
console.error('DCSM - Error loading the list of scripts :' + err);
});
});
});