Persistent Storage

Useful library for dealing with the storage.

此脚本不应直接安装,它是一个供其他脚本使用的外部库。如果您需要使用该库,请在脚本元属性加入:// @require https://update.cn-greasyfork.org/scripts/476018/1255634/Persistent%20Storage.js

  1. // ==UserScript==
  2. // @name Persistent Storage
  3. // @namespace https://rafaelgssa.gitlab.io/monkey-scripts
  4. // @version 3.0.2
  5. // @author rafaelgssa
  6. // @description Useful library for dealing with the storage.
  7. // @match *://*/*
  8. // @require https://greasemonkey.github.io/gm4-polyfill/gm4-polyfill.js
  9. // @require https://greasyfork.org/scripts/405813-monkey-utils/code/Monkey%20Utils.js
  10. // @grant GM_setValue
  11. // @grant GM_getValue
  12. // @grant GM_deleteValue
  13. // @grant GM_setValue
  14. // @grant GM_getValue
  15. // @grant GM_deleteValue
  16. // ==/UserScript==
  17. /* global Utils */
  18. /**
  19. * @typedef {Record<string, unknown> & StorageValuesBase} StorageValues
  20. *
  21. * @typedef {Object} StorageValuesBase
  22. * @property {Record<string, unknown>} settings
  23. */
  24. // eslint-disable-next-line
  25. const PersistentStorage = (() => {
  26. let _id = '';
  27. const _defaultValues = /** @type {StorageValues} */ ({
  28. settings: {},
  29. });
  30. const _cache = /** @type {StorageValues} */ ({
  31. settings: {},
  32. });
  33. /**
  34. * Initializes the storage.
  35. * @param {string} id The ID to use for the local storage.
  36. * @param {Partial<StorageValues>} [defaultValues] Any default values to set.
  37. * @returns {Promise<void>}
  38. */
  39. const init = (id, defaultValues) => {
  40. _id = id;
  41. if (defaultValues) {
  42. for (const [key, value] of Object.entries(defaultValues)) {
  43. setDefaultValue(key, value);
  44. }
  45. }
  46. return _updateCache('settings');
  47. };
  48. /**
  49. * Sets a default value.
  50. * @param {string} key The key of the default value to set.
  51. * @param {unknown} value The default value to set.
  52. */
  53. const setDefaultValue = (key, value) => {
  54. _defaultValues[key] = value;
  55. };
  56. /**
  57. * Sets a value in the storage.
  58. * @param {string} key The key of the value to set.
  59. * @param {unknown} value The value to set.
  60. * @returns {Promise<void>}
  61. */
  62. const setValue = (key, value) => {
  63. const stringifiedValue = JSON.stringify(value);
  64. GM_setValue(key, stringifiedValue);
  65. _cache[key] = value;
  66. };
  67. /**
  68. * Gets a value from the cache.
  69. * @param {string} key The key of the value to get.
  70. * @param {boolean} [updateCache] Whether to update the cache with the storage or not.
  71. * @returns {Promise<unknown>} The value.
  72. */
  73. const getValue = (key, updateCache = false) => {
  74. if (!Utils.isSet(_cache[key]) || updateCache) {
  75. _updateCache(key);
  76. }
  77. return _cache[key];
  78. };
  79. /**
  80. * Updates a value in the cache with the storage.
  81. * @param {string} key The key of the value to update.
  82. * @returns {Promise<void>}
  83. */
  84. const _updateCache = (key) => {
  85. let value = GM_getValue(key);
  86. if (typeof value === 'string') {
  87. try {
  88. value = JSON.parse(value);
  89. } catch (err) {
  90. // Value is already parsed, just ignore.
  91. }
  92. }
  93. _cache[key] = Utils.isSet(value) ? value : _defaultValues[key];
  94. };
  95. /**
  96. * Deletes a value from the storage.
  97. * @param {string} key The key of the value to delete.
  98. * @returns {Promise<void>}
  99. */
  100. const deleteValue = (key) => {
  101. GM_deleteValue(key);
  102. delete _cache[key];
  103. };
  104. /**
  105. * Sets a value in the local storage.
  106. * @param {string} key The key of the value to set.
  107. * @param {unknown} value The value to set.
  108. */
  109. const setLocalValue = (key, value) => {
  110. const stringifiedValue = JSON.stringify(value);
  111. window.localStorage.setItem(`${_id}_${key}`, stringifiedValue);
  112. _cache[key] = value;
  113. };
  114. /**
  115. * Gets a value from the cache.
  116. * @param {string} key The key of the value to get.
  117. * @param {boolean} [updateCache] Whether to update the cache with the local storage or not.
  118. * @returns {unknown} The value.
  119. */
  120. const getLocalValue = (key, updateCache = false) => {
  121. if (!Utils.isSet(_cache[key]) || updateCache) {
  122. _updateLocalCache(key);
  123. }
  124. return _cache[key];
  125. };
  126. /**
  127. * Updates a value in the cache with the local storage.
  128. * @param {string} key The key of the value to update.
  129. */
  130. const _updateLocalCache = (key) => {
  131. let value = window.localStorage.getItem(`${_id}_${key}`);
  132. if (typeof value === 'string') {
  133. try {
  134. value = JSON.parse(value);
  135. } catch (err) {
  136. // Value is already parsed, just ignore.
  137. }
  138. }
  139. _cache[key] = Utils.isSet(value) ? value : _defaultValues[key];
  140. };
  141. /**
  142. * Deletes a value from the local storage.
  143. * @param {string} key The key of the value to delete.
  144. */
  145. const deleteLocalValue = (key) => {
  146. window.localStorage.removeItem(`${_id}_${key}`);
  147. delete _cache[key];
  148. };
  149. /**
  150. * Sets a default setting.
  151. * @param {string} key The key of the default setting to set.
  152. * @param {unknown} setting The default setting to set.
  153. */
  154. const setDefaultSetting = (key, setting) => {
  155. _defaultValues.settings[key] = setting;
  156. };
  157. /**
  158. * Sets a setting in the cache.
  159. * @param {string} key The key of the setting to set.
  160. * @param {unknown} setting The setting to set.
  161. */
  162. const setSetting = (key, setting) => {
  163. _cache.settings[key] = setting;
  164. };
  165. /**
  166. * Gets a setting from the cache.
  167. * @param {string} key The key of the setting to get.
  168. * @param {boolean} [updateCache] Whether to update the settings cache with the storage or not.
  169. * @returns {Promise<unknown>} The setting.
  170. */
  171. const getSetting = (key, updateCache = false) => {
  172. if (isSettingsEmpty() || !Utils.isSet(_cache.settings[key]) || updateCache) {
  173. _updateCache('settings');
  174. }
  175. return _cache.settings[key];
  176. };
  177. /**
  178. * Deletes a setting from the cache.
  179. * @param {string} key The key of the setting to delete.
  180. */
  181. const deleteSetting = (key) => {
  182. delete _cache.settings[key];
  183. };
  184. /**
  185. * Saves the settings from the cache.
  186. * @returns {Promise<void>}
  187. */
  188. const saveSettings = () => {
  189. return setValue('settings', _cache.settings);
  190. };
  191. /**
  192. * Checks if the settings cache is empty.
  193. * @returns {boolean} Whether the settings cache is empty or not.
  194. */
  195. const isSettingsEmpty = () => {
  196. return Object.keys(_cache.settings).length === 0;
  197. };
  198. return {
  199. init,
  200. setDefaultValue,
  201. setValue,
  202. getValue,
  203. deleteValue,
  204. setLocalValue,
  205. getLocalValue,
  206. deleteLocalValue,
  207. setDefaultSetting,
  208. setSetting,
  209. getSetting,
  210. deleteSetting,
  211. saveSettings,
  212. isSettingsEmpty,
  213. };
  214. })();