config.ts 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. import { ConfigManager, type ConfigMigrationsDict } from "@sv443-network/userutils";
  2. import { featInfo } from "./features/index";
  3. import { info, log } from "./utils";
  4. import { emitSiteEvent } from "./siteEvents";
  5. import type { FeatureConfig } from "./types";
  6. /** If this number is incremented, the features object data will be migrated to the new format */
  7. export const formatVersion = 4;
  8. /** Config data format migration dictionary */
  9. export const migrations: ConfigMigrationsDict = {
  10. // 1 -> 2
  11. 2: (oldData: Record<string, unknown>) => {
  12. const queueBtnsEnabled = Boolean(oldData.queueButtons);
  13. delete oldData.queueButtons;
  14. return {
  15. ...oldData,
  16. deleteFromQueueButton: queueBtnsEnabled,
  17. lyricsQueueButton: queueBtnsEnabled,
  18. };
  19. },
  20. // 2 -> 3
  21. 3: (oldData: Record<string, unknown>) => ({
  22. ...oldData,
  23. removeShareTrackingParam: getFeatureDefault("removeShareTrackingParam"),
  24. numKeysSkipToTime: getFeatureDefault("numKeysSkipToTime"),
  25. fixSpacing: getFeatureDefault("fixSpacing"),
  26. scrollToActiveSongBtn: getFeatureDefault("scrollToActiveSongBtn"),
  27. logLevel: getFeatureDefault("logLevel"),
  28. }),
  29. // 3 -> 4
  30. 4: (oldData: Record<string, unknown>) => {
  31. const oldSwitchSitesHotkey = oldData.switchSitesHotkey as Record<string, unknown>;
  32. return {
  33. ...oldData,
  34. rememberSongTime: getFeatureDefault("rememberSongTime"),
  35. rememberSongTimeSites: getFeatureDefault("rememberSongTimeSites"),
  36. arrowKeySkipBy: 10,
  37. switchSitesHotkey: {
  38. code: oldSwitchSitesHotkey.key ?? "F9",
  39. shift: Boolean(oldSwitchSitesHotkey.shift ?? false),
  40. ctrl: Boolean(oldSwitchSitesHotkey.ctrl ?? false),
  41. alt: Boolean(oldSwitchSitesHotkey.meta ?? false),
  42. },
  43. listButtonsPlacement: "queueOnly",
  44. volumeSliderScrollStep: getFeatureDefault("volumeSliderScrollStep"),
  45. locale: getFeatureDefault("locale"),
  46. versionCheck: getFeatureDefault("versionCheck"),
  47. };
  48. },
  49. };
  50. function getFeatureDefault<TKey extends keyof typeof featInfo>(key: TKey): typeof featInfo[TKey]["default"] {
  51. return featInfo[key].default;
  52. }
  53. export const defaultConfig = (Object.keys(featInfo) as (keyof typeof featInfo)[])
  54. .reduce<Partial<FeatureConfig>>((acc, key) => {
  55. acc[key] = featInfo[key].default as unknown as undefined;
  56. return acc;
  57. }, {}) as FeatureConfig;
  58. const cfgMgr = new ConfigManager({
  59. id: "bytm-config",
  60. formatVersion,
  61. defaultConfig,
  62. migrations,
  63. });
  64. /** Initializes the ConfigManager instance and loads persistent data into memory */
  65. export async function initConfig() {
  66. const oldFmtVer = Number(await GM.getValue(`_uucfgver-${cfgMgr.id}`, NaN));
  67. const data = await cfgMgr.loadData();
  68. log(`Initialized ConfigManager (format version = ${cfgMgr.formatVersion})`);
  69. if(isNaN(oldFmtVer))
  70. info("Config data initialized with default values");
  71. else if(oldFmtVer !== cfgMgr.formatVersion)
  72. info(`Config data migrated from version ${oldFmtVer} to ${cfgMgr.formatVersion}`);
  73. return data;
  74. }
  75. /** Returns the current feature config from the in-memory cache */
  76. export function getFeatures() {
  77. return cfgMgr.getData();
  78. }
  79. /** Saves the feature config synchronously to the in-memory cache and asynchronously to the persistent storage */
  80. export function saveFeatures(featureConf: FeatureConfig) {
  81. const res = cfgMgr.setData(featureConf);
  82. emitSiteEvent("configChanged", cfgMgr.getData());
  83. info("Saved new feature config:", featureConf);
  84. return res;
  85. }
  86. /** Saves the default feature config synchronously to the in-memory cache and asynchronously to persistent storage */
  87. export function setDefaultFeatures() {
  88. const res = cfgMgr.saveDefaultData();
  89. emitSiteEvent("configChanged", cfgMgr.getData());
  90. info("Reset feature config to its default values");
  91. return res;
  92. }
  93. /** Clears the feature config from the persistent storage - since the cache will be out of whack, this should only be run before a site re-/unload */
  94. export async function clearConfig() {
  95. await cfgMgr.deleteConfig();
  96. info("Deleted config from persistent storage");
  97. }