This script should not be not be installed directly. It is a library for other scripts to include with the meta directive // @require https://update.greasyfork.org/scripts/519877/1507987/UserScript%20Compatibility%20Library.js
- // ==UserScript==
- // @name UserScript Compatibility Library
- // @name:en UserScript Compatibility Library
- // @name:zh-CN UserScript 兼容库
- // @name:ru Библиотека совместимости для пользовательских скриптов
- // @name:vi Thư viện tương thích cho userscript
- // @namespace https://greasyfork.org/vi/users/1195312-renji-yuusei
- // @version 2024.12.23.1
- // @description A library to ensure compatibility between different userscript managers
- // @description:en A library to ensure compatibility between different userscript managers
- // @description:zh-CN 确保不同用户脚本管理器之间兼容性的库
- // @description:vi Thư viện đảm bảo tương thích giữa các trình quản lý userscript khác nhau
- // @description:ru Библиотека для обеспечения совместимости между различными менеджерами пользовательских скриптов
- // @author Yuusei
- // @license GPL-3.0-only
- // @grant unsafeWindow
- // @grant GM_info
- // @grant GM.info
- // @grant GM_getValue
- // @grant GM.getValue
- // @grant GM_setValue
- // @grant GM.setValue
- // @grant GM_deleteValue
- // @grant GM.deleteValue
- // @grant GM_listValues
- // @grant GM.listValues
- // @grant GM_xmlhttpRequest
- // @grant GM.xmlHttpRequest
- // @grant GM_download
- // @grant GM.download
- // @grant GM_notification
- // @grant GM.notification
- // @grant GM_addStyle
- // @grant GM.addStyle
- // @grant GM_registerMenuCommand
- // @grant GM.registerMenuCommand
- // @grant GM_unregisterMenuCommand
- // @grant GM.unregisterMenuCommand
- // @grant GM_setClipboard
- // @grant GM.setClipboard
- // @grant GM_getResourceText
- // @grant GM.getResourceText
- // @grant GM_getResourceURL
- // @grant GM.getResourceURL
- // @grant GM_openInTab
- // @grant GM.openInTab
- // @grant GM_addElement
- // @grant GM.addElement
- // @grant GM_addValueChangeListener
- // @grant GM.addValueChangeListener
- // @grant GM_removeValueChangeListener
- // @grant GM.removeValueChangeListener
- // @grant GM_log
- // @grant GM.log
- // @grant GM_getTab
- // @grant GM.getTab
- // @grant GM_saveTab
- // @grant GM.saveTab
- // @grant GM_getTabs
- // @grant GM.getTabs
- // @grant GM_cookie
- // @grant GM.cookie
- // @grant GM_webRequest
- // @grant GM.webRequest
- // @grant GM_fetch
- // @grant GM.fetch
- // @grant window.close
- // @grant window.focus
- // @grant window.onurlchange
- // @grant GM_addValueChangeListener
- // @grant GM_removeValueChangeListener
- // @grant GM_getResourceURL
- // @grant GM_notification
- // @grant GM_xmlhttpRequest
- // @grant GM_openInTab
- // @grant GM_registerMenuCommand
- // @grant GM_unregisterMenuCommand
- // @grant GM_setClipboard
- // @grant GM_getResourceText
- // @grant GM_addStyle
- // @grant GM_download
- // @grant GM_cookie.get
- // @grant GM_cookie.set
- // @grant GM_cookie.delete
- // @grant GM_webRequest.listen
- // @grant GM_webRequest.onBeforeRequest
- // @grant GM_addElement.byTag
- // @grant GM_addElement.byId
- // @grant GM_addElement.byClass
- // @grant GM_addElement.byXPath
- // @grant GM_addElement.bySelector
- // @grant GM_removeElement
- // @grant GM_removeElements
- // @grant GM_getElement
- // @grant GM_getElements
- // @grant GM_addScript
- // @grant GM_removeScript
- // @grant GM_addLink
- // @grant GM_removeLink
- // @grant GM_addMeta
- // @grant GM_removeMeta
- // @grant GM_addIframe
- // @grant GM_removeIframe
- // @grant GM_addImage
- // @grant GM_removeImage
- // @grant GM_addVideo
- // @grant GM_removeVideo
- // @grant GM_addAudio
- // @grant GM_removeAudio
- // @grant GM_addCanvas
- // @grant GM_removeCanvas
- // @grant GM_addSvg
- // @grant GM_removeSvg
- // @grant GM_addObject
- // @grant GM_removeObject
- // @grant GM_addEmbed
- // @grant GM_removeEmbed
- // @grant GM_addApplet
- // @grant GM_removeApplet
- // @run-at document-start
- // @license GPL-3.0-only
- // @grant GM_addValueChangeListener.remove
- // @grant GM_getResourceURL.blob
- // @grant GM_notification.close
- // @grant GM_openInTab.focus
- // @grant GM_setClipboard.format
- // @grant GM_xmlhttpRequest.abort
- // @grant GM_download.progress
- // @grant GM_cookie.list
- // @grant GM_cookie.deleteAll
- // @grant GM_webRequest.filter
- // @grant GM_addElement.create
- // @grant GM_removeElement.all
- // @grant GM_getElement.all
- // @grant GM_addScript.remote
- // @grant GM_addLink.stylesheet
- // @grant GM_addMeta.viewport
- // @grant GM_addIframe.sandbox
- // @grant GM_addImage.lazy
- // @grant GM_addVideo.controls
- // @grant GM_addAudio.autoplay
- // @grant GM_addCanvas.context
- // @grant GM_addSvg.namespace
- // @grant GM_addObject.data
- // @grant GM_addEmbed.type
- // @grant GM_addApplet.code
- // ==/UserScript==
- (function () {
- 'use strict';
- const utils = {
- isFunction: function (fn) {
- return typeof fn === 'function';
- },
- isUndefined: function (value) {
- return typeof value === 'undefined';
- },
- isObject: function (value) {
- return value !== null && typeof value === 'object';
- },
- sleep: function (ms) {
- return new Promise(resolve => setTimeout(resolve, ms));
- },
- retry: async function (fn, attempts = 3, delay = 1000) {
- let lastError;
- for (let i = 0; i < attempts; i++) {
- try {
- return await fn();
- } catch (error) {
- lastError = error;
- if (i === attempts - 1) break;
- await this.sleep(delay * Math.pow(2, i));
- }
- }
- throw lastError;
- },
- debounce: function (fn, wait) {
- let timeout;
- return function (...args) {
- clearTimeout(timeout);
- timeout = setTimeout(() => fn.apply(this, args), wait);
- };
- },
- throttle: function (fn, limit) {
- let timeout;
- let inThrottle;
- return function (...args) {
- if (!inThrottle) {
- fn.apply(this, args);
- inThrottle = true;
- clearTimeout(timeout);
- timeout = setTimeout(() => (inThrottle = false), limit);
- }
- };
- },
- // Thêm các tiện ích mới
- isArray: function (arr) {
- return Array.isArray(arr);
- },
- isString: function (str) {
- return typeof str === 'string';
- },
- isNumber: function (num) {
- return typeof num === 'number' && !isNaN(num);
- },
- isBoolean: function (bool) {
- return typeof bool === 'boolean';
- },
- isNull: function (value) {
- return value === null;
- },
- isEmpty: function (value) {
- if (this.isArray(value)) return value.length === 0;
- if (this.isObject(value)) return Object.keys(value).length === 0;
- if (this.isString(value)) return value.trim().length === 0;
- return false;
- },
- };
- const GMCompat = {
- info: (function () {
- if (!utils.isUndefined(GM_info)) return GM_info;
- if (!utils.isUndefined(GM) && GM.info) return GM.info;
- return {};
- })(),
- storageCache: new Map(),
- cacheTimestamps: new Map(),
- cacheExpiry: 3600000, // 1 hour
- getValue: async function (key, defaultValue) {
- try {
- if (this.storageCache.has(key)) {
- const timestamp = this.cacheTimestamps.get(key);
- if (Date.now() - timestamp < this.cacheExpiry) {
- return this.storageCache.get(key);
- }
- }
- let value;
- if (!utils.isUndefined(GM_getValue)) {
- value = GM_getValue(key, defaultValue);
- } else if (!utils.isUndefined(GM) && GM.getValue) {
- value = await GM.getValue(key, defaultValue);
- } else {
- value = defaultValue;
- }
- this.storageCache.set(key, value);
- this.cacheTimestamps.set(key, Date.now());
- return value;
- } catch (error) {
- console.error('getValue error:', error);
- return defaultValue;
- }
- },
- setValue: async function (key, value) {
- try {
- this.storageCache.set(key, value);
- this.cacheTimestamps.set(key, Date.now());
- if (!utils.isUndefined(GM_setValue)) {
- return GM_setValue(key, value);
- }
- if (!utils.isUndefined(GM) && GM.setValue) {
- return await GM.setValue(key, value);
- }
- } catch (error) {
- this.storageCache.delete(key);
- this.cacheTimestamps.delete(key);
- throw new Error('Failed to set value: ' + error.message);
- }
- },
- deleteValue: async function (key) {
- try {
- this.storageCache.delete(key);
- this.cacheTimestamps.delete(key);
- if (!utils.isUndefined(GM_deleteValue)) {
- return GM_deleteValue(key);
- }
- if (!utils.isUndefined(GM) && GM.deleteValue) {
- return await GM.deleteValue(key);
- }
- } catch (error) {
- throw new Error('Failed to delete value: ' + error.message);
- }
- },
- requestQueue: [],
- processingRequest: false,
- maxRetries: 3,
- retryDelay: 1000,
- xmlHttpRequest: async function (details) {
- const makeRequest = () => {
- return new Promise((resolve, reject) => {
- try {
- const callbacks = {
- onload: resolve,
- onerror: reject,
- ontimeout: reject,
- onprogress: details.onprogress,
- onreadystatechange: details.onreadystatechange,
- };
- const finalDetails = {
- timeout: 30000,
- ...details,
- ...callbacks,
- };
- if (!utils.isUndefined(GM_xmlhttpRequest)) {
- GM_xmlhttpRequest(finalDetails);
- } else if (!utils.isUndefined(GM) && GM.xmlHttpRequest) {
- GM.xmlHttpRequest(finalDetails);
- } else if (!utils.isUndefined(GM_fetch)) {
- GM_fetch(finalDetails.url, finalDetails);
- } else if (!utils.isUndefined(GM) && GM.fetch) {
- GM.fetch(finalDetails.url, finalDetails);
- } else {
- reject(new Error('XMLHttpRequest API not available'));
- }
- } catch (error) {
- reject(error);
- }
- });
- };
- return utils.retry(makeRequest, this.maxRetries, this.retryDelay);
- },
- download: async function (details) {
- try {
- const downloadWithProgress = {
- ...details,
- onprogress: details.onprogress,
- onerror: details.onerror,
- onload: details.onload,
- };
- if (!utils.isUndefined(GM_download)) {
- return new Promise((resolve, reject) => {
- GM_download({
- ...downloadWithProgress,
- onload: resolve,
- onerror: reject,
- });
- });
- }
- if (!utils.isUndefined(GM) && GM.download) {
- return await GM.download(downloadWithProgress);
- }
- throw new Error('Download API not available');
- } catch (error) {
- throw new Error('Download failed: ' + error.message);
- }
- },
- notification: function (details) {
- return new Promise((resolve, reject) => {
- try {
- const defaultOptions = {
- timeout: 5000,
- highlight: false,
- silent: false,
- requireInteraction: false,
- priority: 0,
- };
- const callbacks = {
- onclick: utils.debounce((...args) => {
- if (details.onclick) details.onclick(...args);
- resolve('clicked');
- }, 300),
- ondone: (...args) => {
- if (details.ondone) details.ondone(...args);
- resolve('closed');
- },
- onerror: (...args) => {
- if (details.onerror) details.onerror(...args);
- reject('error');
- },
- };
- const finalDetails = { ...defaultOptions, ...details, ...callbacks };
- if (!utils.isUndefined(GM_notification)) {
- GM_notification(finalDetails);
- } else if (!utils.isUndefined(GM) && GM.notification) {
- GM.notification(finalDetails);
- } else {
- if ('Notification' in window) {
- Notification.requestPermission().then(permission => {
- if (permission === 'granted') {
- const notification = new Notification(finalDetails.title, {
- body: finalDetails.text,
- silent: finalDetails.silent,
- icon: finalDetails.image,
- tag: finalDetails.tag,
- requireInteraction: finalDetails.requireInteraction,
- badge: finalDetails.badge,
- vibrate: finalDetails.vibrate,
- });
- notification.onclick = callbacks.onclick;
- notification.onerror = callbacks.onerror;
- if (finalDetails.timeout > 0) {
- setTimeout(() => {
- notification.close();
- callbacks.ondone();
- }, finalDetails.timeout);
- }
- } else {
- reject(new Error('Notification permission denied'));
- }
- });
- } else {
- reject(new Error('Notification API not available'));
- }
- }
- } catch (error) {
- reject(error);
- }
- });
- },
- addStyle: function (css) {
- try {
- const testStyle = document.createElement('style');
- testStyle.textContent = css;
- if (testStyle.sheet === null) {
- throw new Error('Invalid CSS');
- }
- if (!utils.isUndefined(GM_addStyle)) {
- return GM_addStyle(css);
- }
- if (!utils.isUndefined(GM) && GM.addStyle) {
- return GM.addStyle(css);
- }
- const style = document.createElement('style');
- style.textContent = css;
- style.type = 'text/css';
- document.head.appendChild(style);
- return style;
- } catch (error) {
- throw new Error('Failed to add style: ' + error.message);
- }
- },
- registerMenuCommand: function (name, fn, accessKey) {
- try {
- if (!utils.isFunction(fn)) {
- throw new Error('Command callback must be a function');
- }
- if (!utils.isUndefined(GM_registerMenuCommand)) {
- return GM_registerMenuCommand(name, fn, accessKey);
- }
- if (!utils.isUndefined(GM) && GM.registerMenuCommand) {
- return GM.registerMenuCommand(name, fn, accessKey);
- }
- } catch (error) {
- throw new Error('Failed to register menu command: ' + error.message);
- }
- },
- setClipboard: function (text, info) {
- try {
- if (!utils.isUndefined(GM_setClipboard)) {
- return GM_setClipboard(text, info);
- }
- if (!utils.isUndefined(GM) && GM.setClipboard) {
- return GM.setClipboard(text, info);
- }
- return navigator.clipboard.writeText(text);
- } catch (error) {
- throw new Error('Failed to set clipboard: ' + error.message);
- }
- },
- getResourceText: async function (name) {
- try {
- if (!utils.isUndefined(GM_getResourceText)) {
- return GM_getResourceText(name);
- }
- if (!utils.isUndefined(GM) && GM.getResourceText) {
- return await GM.getResourceText(name);
- }
- throw new Error('Resource API not available');
- } catch (error) {
- throw new Error('Failed to get resource text: ' + error.message);
- }
- },
- getResourceURL: async function (name) {
- try {
- if (!utils.isUndefined(GM_getResourceURL)) {
- return GM_getResourceURL(name);
- }
- if (!utils.isUndefined(GM) && GM.getResourceURL) {
- return await GM.getResourceURL(name);
- }
- throw new Error('Resource URL API not available');
- } catch (error) {
- throw new Error('Failed to get resource URL: ' + error.message);
- }
- },
- openInTab: function (url, options = {}) {
- try {
- const defaultOptions = {
- active: true,
- insert: true,
- setParent: true,
- };
- const finalOptions = { ...defaultOptions, ...options };
- if (!utils.isUndefined(GM_openInTab)) {
- return GM_openInTab(url, finalOptions);
- }
- if (!utils.isUndefined(GM) && GM.openInTab) {
- return GM.openInTab(url, finalOptions);
- }
- return window.open(url, '_blank');
- } catch (error) {
- throw new Error('Failed to open tab: ' + error.message);
- }
- },
- cookie: {
- get: async function (details) {
- try {
- if (!utils.isUndefined(GM_cookie) && GM_cookie.get) {
- return await GM_cookie.get(details);
- }
- if (!utils.isUndefined(GM) && GM.cookie && GM.cookie.get) {
- return await GM.cookie.get(details);
- }
- return document.cookie;
- } catch (error) {
- throw new Error('Failed to get cookie: ' + error.message);
- }
- },
- set: async function (details) {
- try {
- if (!utils.isUndefined(GM_cookie) && GM_cookie.set) {
- return await GM_cookie.set(details);
- }
- if (!utils.isUndefined(GM) && GM.cookie && GM.cookie.set) {
- return await GM.cookie.set(details);
- }
- document.cookie = details;
- } catch (error) {
- throw new Error('Failed to set cookie: ' + error.message);
- }
- },
- delete: async function (details) {
- try {
- if (!utils.isUndefined(GM_cookie) && GM_cookie.delete) {
- return await GM_cookie.delete(details);
- }
- if (!utils.isUndefined(GM) && GM.cookie && GM.cookie.delete) {
- return await GM.cookie.delete(details);
- }
- } catch (error) {
- throw new Error('Failed to delete cookie: ' + error.message);
- }
- },
- },
- webRequest: {
- listen: function (filter, callback) {
- try {
- if (!utils.isUndefined(GM_webRequest) && GM_webRequest.listen) {
- return GM_webRequest.listen(filter, callback);
- }
- if (!utils.isUndefined(GM) && GM.webRequest && GM.webRequest.listen) {
- return GM.webRequest.listen(filter, callback);
- }
- } catch (error) {
- throw new Error('Failed to listen to web request: ' + error.message);
- }
- },
- onBeforeRequest: function (filter, callback) {
- try {
- if (!utils.isUndefined(GM_webRequest) && GM_webRequest.onBeforeRequest) {
- return GM_webRequest.onBeforeRequest(filter, callback);
- }
- if (!utils.isUndefined(GM) && GM.webRequest && GM.webRequest.onBeforeRequest) {
- return GM.webRequest.onBeforeRequest(filter, callback);
- }
- } catch (error) {
- throw new Error('Failed to handle onBeforeRequest: ' + error.message);
- }
- },
- },
- dom: {
- addElement: function (tag, attributes = {}, parent = document.body) {
- try {
- const element = document.createElement(tag);
- Object.entries(attributes).forEach(([key, value]) => {
- element.setAttribute(key, value);
- });
- parent.appendChild(element);
- return element;
- } catch (error) {
- throw new Error('Failed to add element: ' + error.message);
- }
- },
- removeElement: function (element) {
- try {
- if (element && element.parentNode) {
- element.parentNode.removeChild(element);
- }
- } catch (error) {
- throw new Error('Failed to remove element: ' + error.message);
- }
- },
- getElement: function (selector) {
- try {
- return document.querySelector(selector);
- } catch (error) {
- throw new Error('Failed to get element: ' + error.message);
- }
- },
- getElements: function (selector) {
- try {
- return Array.from(document.querySelectorAll(selector));
- } catch (error) {
- throw new Error('Failed to get elements: ' + error.message);
- }
- },
- },
- storage: {
- setObject: async function (key, obj) {
- try {
- const jsonStr = JSON.stringify(obj);
- return await GMCompat.setValue(key, jsonStr);
- } catch (error) {
- utils.logger.error('setObject failed:', error);
- throw error;
- }
- },
- getObject: async function (key, defaultValue = null) {
- try {
- const jsonStr = await GMCompat.getValue(key, null);
- return jsonStr ? JSON.parse(jsonStr) : defaultValue;
- } catch (error) {
- utils.logger.error('getObject failed:', error);
- return defaultValue;
- }
- },
- appendToArray: async function (key, value) {
- try {
- const arr = await this.getObject(key, []);
- arr.push(value);
- await this.setObject(key, arr);
- return arr;
- } catch (error) {
- utils.logger.error('appendToArray failed:', error);
- throw error;
- }
- },
- removeFromArray: async function (key, predicate) {
- try {
- const arr = await this.getObject(key, []);
- const filtered = arr.filter(item => !predicate(item));
- await this.setObject(key, filtered);
- return filtered;
- } catch (error) {
- utils.logger.error('removeFromArray failed:', error);
- throw error;
- }
- },
- },
- request: {
- downloadWithProgress: async function (url, filename, onProgress) {
- try {
- return await GMCompat.download({
- url: url,
- name: filename,
- onprogress: onProgress,
- saveAs: true,
- });
- } catch (error) {
- utils.logger.error('downloadWithProgress failed:', error);
- throw error;
- }
- },
- fetchWithRetry: async function (url, options = {}) {
- const finalOptions = {
- method: 'GET',
- timeout: 10000,
- retry: 3,
- retryDelay: 1000,
- ...options,
- };
-
- return await utils.retry(
- async () => {
- return await GMCompat.xmlHttpRequest({
- url: url,
- ...finalOptions,
- });
- },
- finalOptions.retry,
- finalOptions.retryDelay
- );
- },
- },
- ui: {
- createMenuCommand: function (name, callback, options = {}) {
- const defaultOptions = {
- accessKey: null,
- autoClose: true,
- };
- const finalOptions = { ...defaultOptions, ...options };
-
- return GMCompat.registerMenuCommand(
- name,
- async (...args) => {
- try {
- await callback(...args);
- if (finalOptions.autoClose) {
- window.close();
- }
- } catch (error) {
- utils.logger.error('Menu command failed:', error);
- GMCompat.notification({
- title: 'Lỗi',
- text: `Lỗi thực thi lệnh: ${error.message}`,
- type: 'error',
- });
- }
- },
- finalOptions.accessKey
- );
- },
- toast: function (message, type = 'info', duration = 3000) {
- return GMCompat.notification({
- title: type.charAt(0).toUpperCase() + type.slice(1),
- text: message,
- timeout: duration,
- onclick: () => {},
- silent: true,
- highlight: false,
- });
- },
- },
- clipboard: {
- copyFormatted: async function (text, format = 'text/plain') {
- try {
- await GMCompat.setClipboard(text, format);
- return true;
- } catch (error) {
- utils.logger.error('copyFormatted failed:', error);
- return false;
- }
- },
- copyHTML: async function (html) {
- return await this.copyFormatted(html, 'text/html');
- },
- },
- cookies: {
- getAll: async function (domain) {
- try {
- return await GMCompat.cookie.get({ domain: domain });
- } catch (error) {
- utils.logger.error('getAll cookies failed:', error);
- return [];
- }
- },
- setCookie: async function (name, value, options = {}) {
- try {
- const defaultOptions = {
- path: '/',
- secure: true,
- sameSite: 'Lax',
- expirationDate: Math.floor(Date.now() / 1000) + 86400, // 1 day
- };
-
- await GMCompat.cookie.set({
- name: name,
- value: value,
- ...defaultOptions,
- ...options,
- });
- } catch (error) {
- utils.logger.error('setCookie failed:', error);
- throw error;
- }
- },
- },
- valueChangeListener: {
- listeners: new Map(),
-
- add: function (name, callback) {
- try {
- if (typeof GM_addValueChangeListener !== 'undefined') {
- const listenerId = GM_addValueChangeListener(name, callback);
- this.listeners.set(name, listenerId);
- return listenerId;
- }
- return null;
- } catch (error) {
- utils.logger.error('Failed to add value change listener:', error);
- return null;
- }
- },
-
- remove: function (name) {
- try {
- const listenerId = this.listeners.get(name);
- if (listenerId && typeof GM_removeValueChangeListener !== 'undefined') {
- GM_removeValueChangeListener(listenerId);
- this.listeners.delete(name);
- return true;
- }
- return false;
- } catch (error) {
- utils.logger.error('Failed to remove value change listener:', error);
- return false;
- }
- },
- },
- resource: {
- getBlob: async function (name) {
- try {
- const url = await GMCompat.getResourceURL(name);
- const response = await fetch(url);
- return await response.blob();
- } catch (error) {
- utils.logger.error('Failed to get resource blob:', error);
- throw error;
- }
- },
-
- getText: async function (name, defaultValue = '') {
- try {
- return (await GMCompat.getResourceText(name)) || defaultValue;
- } catch (error) {
- utils.logger.error('Failed to get resource text:', error);
- return defaultValue;
- }
- },
- },
- tab: {
- open: function (url, options = {}) {
- const defaultOptions = {
- active: true,
- insert: true,
- setParent: true,
- incognito: false,
- };
-
- try {
- return GMCompat.openInTab(url, { ...defaultOptions, ...options });
- } catch (error) {
- utils.logger.error('Failed to open tab:', error);
- return null;
- }
- },
-
- focus: function (tab) {
- try {
- if (tab && tab.focus) {
- tab.focus();
- return true;
- }
- return false;
- } catch (error) {
- utils.logger.error('Failed to focus tab:', error);
- return false;
- }
- },
- },
- notification: {
- create: function (details) {
- const defaultDetails = {
- title: '',
- text: '',
- image: '',
- timeout: 5000,
- onclick: null,
- ondone: null,
- silent: false,
- };
-
- try {
- return GMCompat.notification({ ...defaultDetails, ...details });
- } catch (error) {
- utils.logger.error('Failed to create notification:', error);
- return null;
- }
- },
-
- close: function (id) {
- try {
- if (typeof GM_notification !== 'undefined' && GM_notification.close) {
- GM_notification.close(id);
- return true;
- }
- return false;
- } catch (error) {
- utils.logger.error('Failed to close notification:', error);
- return false;
- }
- },
- },
- request: {
- abort: function (requestId) {
- try {
- if (typeof GM_xmlhttpRequest !== 'undefined' && GM_xmlhttpRequest.abort) {
- GM_xmlhttpRequest.abort(requestId);
- return true;
- }
- return false;
- } catch (error) {
- utils.logger.error('Failed to abort request:', error);
- return false;
- }
- },
- },
- cookie: {
- list: async function (details = {}) {
- try {
- if (typeof GM_cookie !== 'undefined' && GM_cookie.list) {
- return await GM_cookie.list(details);
- }
- return [];
- } catch (error) {
- utils.logger.error('Failed to list cookies:', error);
- return [];
- }
- },
-
- deleteAll: async function (details = {}) {
- try {
- if (typeof GM_cookie !== 'undefined' && GM_cookie.deleteAll) {
- return await GM_cookie.deleteAll(details);
- }
- return false;
- } catch (error) {
- utils.logger.error('Failed to delete all cookies:', error);
- return false;
- }
- },
- },
- };
- const exportGMCompat = function () {
- try {
- const target = !utils.isUndefined(unsafeWindow) ? unsafeWindow : window;
- Object.defineProperty(target, 'GMCompat', {
- value: GMCompat,
- writable: false,
- configurable: false,
- enumerable: true,
- });
- if (window.onurlchange !== undefined) {
- window.addEventListener('urlchange', () => {});
- }
- } catch (error) {
- console.error('Failed to export GMCompat:', error);
- }
- };
- exportGMCompat();
- })();