config.ts 2.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768
  1. import { featInfo } from "./features/index";
  2. import { FeatureConfig } from "./types";
  3. import { log } from "./utils";
  4. /** If this number is incremented, the features object needs to be migrated (TODO: migration not implemented yet) */
  5. const formatVersion = 1;
  6. export const defaultFeatures = (Object.keys(featInfo) as (keyof typeof featInfo)[])
  7. .reduce<Partial<FeatureConfig>>((acc, key) => {
  8. acc[key] = featInfo[key].default as unknown as undefined;
  9. return acc;
  10. }, {}) as FeatureConfig;
  11. /** In-memory features object to save on a little bit of I/O */
  12. let featuresCache: FeatureConfig | undefined;
  13. /**
  14. * Returns the current FeatureConfig in memory or reads it from GM storage
  15. * Automatically applies defaults for non-existant keys
  16. * @param forceRead Set to true to force reading the config from GM storage
  17. */
  18. export async function getFeatures(forceRead = false) {
  19. if(featuresCache === undefined || forceRead)
  20. await saveFeatureConf(featuresCache = { ...defaultFeatures, ...await loadFeatureConf() }); // look at this sexy one liner
  21. return featuresCache;
  22. }
  23. /** Loads a feature configuration saved persistently, returns an empty object if no feature configuration was saved */
  24. export async function loadFeatureConf(): Promise<FeatureConfig> {
  25. const defConf = { ...defaultFeatures };
  26. try {
  27. const featureConf = await GM.getValue("betterytm-config") as string;
  28. if(typeof featureConf !== "string") {
  29. await setDefaultFeatConf();
  30. return featuresCache = defConf;
  31. }
  32. return featuresCache = Object.freeze(featureConf ? JSON.parse(featureConf) as FeatureConfig : defConf);
  33. }
  34. catch(err) {
  35. await setDefaultFeatConf();
  36. return featuresCache = defConf;
  37. }
  38. }
  39. /**
  40. * Saves the passed feature configuration persistently in GM storage and in the in-memory cache
  41. * @param featureConf
  42. */
  43. export function saveFeatureConf(featureConf: FeatureConfig) {
  44. if(!featureConf || typeof featureConf != "object")
  45. throw new TypeError("Feature config not provided or invalid");
  46. log("Saving new feature config:", featureConf);
  47. featuresCache = { ...featureConf };
  48. GM.setValue("betterytm-config-ver", formatVersion);
  49. return GM.setValue("betterytm-config", JSON.stringify(featureConf));
  50. }
  51. /** Resets the featuresCache synchronously and the persistent features storage asynchronously to its default values */
  52. export function setDefaultFeatConf() {
  53. featuresCache = { ...defaultFeatures };
  54. GM.setValue("betterytm-config-ver", formatVersion);
  55. return GM.setValue("betterytm-config", JSON.stringify(defaultFeatures));
  56. }