add more robust logging
This commit is contained in:
parent
7cb2d1aa9c
commit
0cca83ff07
2 changed files with 237 additions and 37 deletions
|
|
@ -10,6 +10,108 @@ import { serviceFactory } from "./services/ServiceFactory";
|
||||||
import Settings from "./ui/pages/Settings";
|
import Settings from "./ui/pages/Settings";
|
||||||
import patchSidebar from "./sidebar";
|
import patchSidebar from "./sidebar";
|
||||||
|
|
||||||
|
(function installUnhandledRejectionHandler() {
|
||||||
|
try {
|
||||||
|
const g = typeof globalThis !== "undefined" ? (globalThis as any) : {};
|
||||||
|
|
||||||
|
// Avoid installing multiple times
|
||||||
|
if (g && !g.__scrobble_unhandled_rejection_installed) {
|
||||||
|
const handler = (ev: any) => {
|
||||||
|
try {
|
||||||
|
// ev may be an event or a reason object depending on the runtime
|
||||||
|
const reason = ev && (ev.reason ?? ev) ? (ev.reason ?? ev) : ev;
|
||||||
|
console.error("[Scrobble Plugin] Unhandled rejection:", reason);
|
||||||
|
} catch (inner) {
|
||||||
|
// Defensive: if formatting the event fails, still log something
|
||||||
|
console.error("[Scrobble Plugin] Unhandled rejection (unknown format)", ev);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Prefer globalThis.addEventListener
|
||||||
|
if (g && typeof g.addEventListener === "function") {
|
||||||
|
try {
|
||||||
|
g.addEventListener("unhandledrejection", handler);
|
||||||
|
g.__scrobble_unhandled_rejection_installed = true;
|
||||||
|
return;
|
||||||
|
} catch (e) {
|
||||||
|
// continue to other fallbacks
|
||||||
|
console.error("[Scrobble Plugin] Failed to register via globalThis.addEventListener:", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If window exists and supports addEventListener, use it
|
||||||
|
if (typeof (globalThis as any).window !== "undefined") {
|
||||||
|
const w = (globalThis as any).window;
|
||||||
|
if (w && typeof w.addEventListener === "function") {
|
||||||
|
try {
|
||||||
|
w.addEventListener("unhandledrejection", handler);
|
||||||
|
g.__scrobble_unhandled_rejection_installed = true;
|
||||||
|
return;
|
||||||
|
} catch (e) {
|
||||||
|
console.error("[Scrobble Plugin] Failed to register via window.addEventListener:", e);
|
||||||
|
}
|
||||||
|
} else if (w) {
|
||||||
|
// fallback to assigning onunhandledrejection if available and not a function call
|
||||||
|
try {
|
||||||
|
if (typeof w.onunhandledrejection === "undefined") {
|
||||||
|
w.onunhandledrejection = (ev: any) => handler(ev);
|
||||||
|
g.__scrobble_unhandled_rejection_installed = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error("[Scrobble Plugin] Failed to assign window.onunhandledrejection:", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// As a last resort, try process.on (Node-style). Guard existence and function type.
|
||||||
|
try {
|
||||||
|
const proc = (globalThis as any).process;
|
||||||
|
if (proc && typeof proc.on === "function") {
|
||||||
|
proc.on("unhandledRejection", (reason: any) => handler({ reason }));
|
||||||
|
g.__scrobble_unhandled_rejection_installed = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
|
||||||
|
// If none of the above worked, set a marker so we don't keep trying on repeated loads
|
||||||
|
g.__scrobble_unhandled_rejection_installed = true;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
// Most defensive: don't let any error here block plugin loading
|
||||||
|
try {
|
||||||
|
console.error("[Scrobble Plugin] Error while installing unhandled rejection handler:", e);
|
||||||
|
} catch {
|
||||||
|
/* swallow */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
|
||||||
|
// Heartbeat helpers
|
||||||
|
let __scrobbleHeartbeat: any;
|
||||||
|
function startHeartbeat() {
|
||||||
|
if (__scrobbleHeartbeat) return;
|
||||||
|
try {
|
||||||
|
__scrobbleHeartbeat = setInterval(() => {
|
||||||
|
console.log("[Scrobble Plugin] Heartbeat (alive)");
|
||||||
|
}, 60_000);
|
||||||
|
} catch (e) {
|
||||||
|
console.error("[Scrobble Plugin] Failed to start heartbeat:", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function stopHeartbeat() {
|
||||||
|
if (!__scrobbleHeartbeat) return;
|
||||||
|
try {
|
||||||
|
clearInterval(__scrobbleHeartbeat);
|
||||||
|
} catch (e) {
|
||||||
|
console.error("[Scrobble Plugin] Failed to clear heartbeat:", e);
|
||||||
|
} finally {
|
||||||
|
__scrobbleHeartbeat = undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export const pluginState = {
|
export const pluginState = {
|
||||||
pluginStopped: false,
|
pluginStopped: false,
|
||||||
lastActivity: undefined,
|
lastActivity: undefined,
|
||||||
|
|
@ -28,18 +130,29 @@ let sidebarUnpatch: (() => void) | undefined;
|
||||||
// Set up default plugin settings
|
// Set up default plugin settings
|
||||||
const defaultSettings: LFMSettings = Constants.DEFAULT_SETTINGS;
|
const defaultSettings: LFMSettings = Constants.DEFAULT_SETTINGS;
|
||||||
for (const key of Object.keys(defaultSettings)) {
|
for (const key of Object.keys(defaultSettings)) {
|
||||||
plugin.storage[key] =
|
// Defensive: plugin.storage may not accept arbitrary keys in some environments,
|
||||||
plugin.storage[key] ?? defaultSettings[key as keyof typeof defaultSettings];
|
// but assignment should generally be fine in Vendetta.
|
||||||
|
try {
|
||||||
|
plugin.storage[key] =
|
||||||
|
plugin.storage[key] ?? defaultSettings[key as keyof typeof defaultSettings];
|
||||||
|
} catch (e) {
|
||||||
|
console.error("[Scrobble Plugin] Failed to initialize default setting", key, e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
plugin.storage.addToSidebar ??= false;
|
try {
|
||||||
|
// safe default for addToSidebar
|
||||||
|
plugin.storage.addToSidebar ??= false;
|
||||||
|
} catch (e) {
|
||||||
|
// ignore if storage access fails
|
||||||
|
}
|
||||||
|
|
||||||
export const currentSettings = new Proxy(plugin.storage, {
|
export const currentSettings = new Proxy(plugin.storage, {
|
||||||
get(target, prop) {
|
get(target, prop) {
|
||||||
return target[prop];
|
return (target as any)[prop];
|
||||||
},
|
},
|
||||||
set(target, prop, value) {
|
set(target, prop, value) {
|
||||||
target[prop] = value;
|
(target as any)[prop] = value;
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
@ -50,8 +163,7 @@ const MAX_CONNECTION_ATTEMPTS = 3;
|
||||||
const RECONNECT_DELAY = 5000;
|
const RECONNECT_DELAY = 5000;
|
||||||
|
|
||||||
const log = (...args: any[]) => console.log("[Scrobble Plugin]", ...args);
|
const log = (...args: any[]) => console.log("[Scrobble Plugin]", ...args);
|
||||||
const logError = (...args: any[]) =>
|
const logError = (...args: any[]) => console.error("[Scrobble Plugin] Error:", ...args);
|
||||||
console.error("[Scrobble Plugin] Error:", ...args);
|
|
||||||
|
|
||||||
async function tryInitialize() {
|
async function tryInitialize() {
|
||||||
try {
|
try {
|
||||||
|
|
@ -63,9 +175,7 @@ async function tryInitialize() {
|
||||||
connectionAttempts++;
|
connectionAttempts++;
|
||||||
|
|
||||||
if (connectionAttempts < MAX_CONNECTION_ATTEMPTS) {
|
if (connectionAttempts < MAX_CONNECTION_ATTEMPTS) {
|
||||||
log(
|
log(`Retrying connection (${connectionAttempts}/${MAX_CONNECTION_ATTEMPTS})...`);
|
||||||
`Retrying connection (${connectionAttempts}/${MAX_CONNECTION_ATTEMPTS})...`,
|
|
||||||
);
|
|
||||||
setTimeout(tryInitialize, RECONNECT_DELAY);
|
setTimeout(tryInitialize, RECONNECT_DELAY);
|
||||||
} else {
|
} else {
|
||||||
logError(`Failed to connect after ${MAX_CONNECTION_ATTEMPTS} attempts`);
|
logError(`Failed to connect after ${MAX_CONNECTION_ATTEMPTS} attempts`);
|
||||||
|
|
@ -80,7 +190,12 @@ async function validateAndInitialize() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const serviceName = serviceFactory.getCurrentService().getServiceName();
|
let serviceName = "Unknown";
|
||||||
|
try {
|
||||||
|
serviceName = serviceFactory.getCurrentService().getServiceName();
|
||||||
|
} catch (e) {
|
||||||
|
logError("Failed to determine current service name:", e);
|
||||||
|
}
|
||||||
|
|
||||||
// Make sure we have credentials for whatever service is selected
|
// Make sure we have credentials for whatever service is selected
|
||||||
const service = currentSettings.service;
|
const service = currentSettings.service;
|
||||||
|
|
@ -91,9 +206,7 @@ async function validateAndInitialize() {
|
||||||
hasCredentials = !!(currentSettings.username && currentSettings.apiKey);
|
hasCredentials = !!(currentSettings.username && currentSettings.apiKey);
|
||||||
break;
|
break;
|
||||||
case "librefm":
|
case "librefm":
|
||||||
hasCredentials = !!(
|
hasCredentials = !!(currentSettings.librefmUsername && currentSettings.librefmApiKey);
|
||||||
currentSettings.librefmUsername && currentSettings.librefmApiKey
|
|
||||||
);
|
|
||||||
break;
|
break;
|
||||||
case "listenbrainz":
|
case "listenbrainz":
|
||||||
hasCredentials = !!currentSettings.listenbrainzUsername;
|
hasCredentials = !!currentSettings.listenbrainzUsername;
|
||||||
|
|
@ -101,9 +214,7 @@ async function validateAndInitialize() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!hasCredentials) {
|
if (!hasCredentials) {
|
||||||
logError(
|
logError(`Missing credentials for ${serviceName}. Please configure in plugin settings.`);
|
||||||
`Missing credentials for ${serviceName}. Please configure in plugin settings.`,
|
|
||||||
);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -115,14 +226,22 @@ async function validateAndInitialize() {
|
||||||
} else {
|
} else {
|
||||||
log("Waiting for Discord connection...");
|
log("Waiting for Discord connection...");
|
||||||
const waitForUser = () => {
|
const waitForUser = () => {
|
||||||
if (UserStore.getCurrentUser()) {
|
try {
|
||||||
log("Discord connection established");
|
if (UserStore.getCurrentUser()) {
|
||||||
tryInitialize();
|
log("Discord connection established");
|
||||||
FluxDispatcher.unsubscribe("CONNECTION_OPEN", waitForUser);
|
tryInitialize();
|
||||||
|
FluxDispatcher.unsubscribe("CONNECTION_OPEN", waitForUser);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
logError("Error while waiting for Discord connection:", e);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
FluxDispatcher.subscribe("CONNECTION_OPEN", waitForUser);
|
try {
|
||||||
|
FluxDispatcher.subscribe("CONNECTION_OPEN", waitForUser);
|
||||||
|
} catch (e) {
|
||||||
|
logError("Failed to subscribe to CONNECTION_OPEN:", e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -131,15 +250,27 @@ export default {
|
||||||
log("Plugin loading...");
|
log("Plugin loading...");
|
||||||
pluginState.pluginStopped = false;
|
pluginState.pluginStopped = false;
|
||||||
|
|
||||||
|
// Start heartbeat so we can confirm plugin process is alive
|
||||||
|
try {
|
||||||
|
startHeartbeat();
|
||||||
|
log("Heartbeat started");
|
||||||
|
} catch (e) {
|
||||||
|
logError("Failed to start heartbeat:", e);
|
||||||
|
}
|
||||||
|
|
||||||
// Check if service is configured
|
// Check if service is configured
|
||||||
if (!currentSettings.service) {
|
if (!currentSettings.service) {
|
||||||
log("No service configured. Please select a service in plugin settings.");
|
log("No service configured. Please select a service in plugin settings.");
|
||||||
} else {
|
} else {
|
||||||
// Show what we're starting with
|
// Show what we're starting with
|
||||||
const serviceName = serviceFactory.getCurrentService().getServiceName();
|
try {
|
||||||
log(
|
const serviceName = serviceFactory.getCurrentService().getServiceName();
|
||||||
`Configuration: Service=${serviceName}, Update Interval=${currentSettings.timeInterval}s, Verbose=${currentSettings.verboseLogging}`,
|
log(
|
||||||
);
|
`Configuration: Service=${serviceName}, Update Interval=${currentSettings.timeInterval}s, Verbose=${currentSettings.verboseLogging}`,
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
logError("Failed to read service configuration:", e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add to sidebar if user wants it
|
// Add to sidebar if user wants it
|
||||||
|
|
@ -147,7 +278,11 @@ export default {
|
||||||
sidebarUnpatch = patchSidebar();
|
sidebarUnpatch = patchSidebar();
|
||||||
cleanupFunctions.push(() => {
|
cleanupFunctions.push(() => {
|
||||||
if (sidebarUnpatch) {
|
if (sidebarUnpatch) {
|
||||||
sidebarUnpatch();
|
try {
|
||||||
|
sidebarUnpatch();
|
||||||
|
} catch (e) {
|
||||||
|
// ignore individual cleanup errors
|
||||||
|
}
|
||||||
sidebarUnpatch = undefined;
|
sidebarUnpatch = undefined;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -155,13 +290,26 @@ export default {
|
||||||
log("Sidebar setup failed:", error);
|
log("Sidebar setup failed:", error);
|
||||||
}
|
}
|
||||||
|
|
||||||
validateAndInitialize();
|
try {
|
||||||
|
validateAndInitialize();
|
||||||
|
log("onLoad complete - validateAndInitialize triggered");
|
||||||
|
} catch (e) {
|
||||||
|
logError("validateAndInitialize threw an error:", e);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
onUnload() {
|
onUnload() {
|
||||||
log("Plugin unloading...");
|
log("Plugin unloading...");
|
||||||
pluginState.pluginStopped = true;
|
pluginState.pluginStopped = true;
|
||||||
|
|
||||||
|
// Stop heartbeat first to avoid stray logs after unload
|
||||||
|
try {
|
||||||
|
stopHeartbeat();
|
||||||
|
log("Heartbeat stopped");
|
||||||
|
} catch (e) {
|
||||||
|
logError("Failed to stop heartbeat:", e);
|
||||||
|
}
|
||||||
|
|
||||||
// Run all cleanup functions
|
// Run all cleanup functions
|
||||||
cleanupFunctions.forEach((cleanup) => {
|
cleanupFunctions.forEach((cleanup) => {
|
||||||
try {
|
try {
|
||||||
|
|
@ -172,7 +320,11 @@ export default {
|
||||||
});
|
});
|
||||||
cleanupFunctions.length = 0;
|
cleanupFunctions.length = 0;
|
||||||
|
|
||||||
stop();
|
try {
|
||||||
|
stop();
|
||||||
|
} catch (e) {
|
||||||
|
logError("Error while stopping plugin manager:", e);
|
||||||
|
}
|
||||||
log("Plugin unloaded");
|
log("Plugin unloaded");
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
@ -184,9 +336,13 @@ export default {
|
||||||
const newSidebar = newSettings.addToSidebar;
|
const newSidebar = newSettings.addToSidebar;
|
||||||
|
|
||||||
// Apply the new settings
|
// Apply the new settings
|
||||||
Object.assign(currentSettings, newSettings);
|
try {
|
||||||
|
Object.assign(currentSettings, newSettings);
|
||||||
|
} catch (e) {
|
||||||
|
logError("Failed to apply new settings:", e);
|
||||||
|
}
|
||||||
|
|
||||||
log("Settings updated:", Object.keys(newSettings));
|
log("Settings updated:", Object.keys(newSettings || {}));
|
||||||
|
|
||||||
// Check if sidebar setting changed
|
// Check if sidebar setting changed
|
||||||
if (oldSidebar !== newSidebar) {
|
if (oldSidebar !== newSidebar) {
|
||||||
|
|
@ -199,7 +355,11 @@ export default {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (sidebarUnpatch) {
|
if (sidebarUnpatch) {
|
||||||
sidebarUnpatch();
|
try {
|
||||||
|
sidebarUnpatch();
|
||||||
|
} catch (e) {
|
||||||
|
logError("Failed to unpatch sidebar:", e);
|
||||||
|
}
|
||||||
sidebarUnpatch = undefined;
|
sidebarUnpatch = undefined;
|
||||||
log("Sidebar disabled");
|
log("Sidebar disabled");
|
||||||
}
|
}
|
||||||
|
|
@ -209,7 +369,11 @@ export default {
|
||||||
// Switch services if needed
|
// Switch services if needed
|
||||||
if (oldService !== newService && newService) {
|
if (oldService !== newService && newService) {
|
||||||
log(`Service changed from ${oldService || "none"} to ${newService}`);
|
log(`Service changed from ${oldService || "none"} to ${newService}`);
|
||||||
await switchService(newService);
|
try {
|
||||||
|
await switchService(newService);
|
||||||
|
} catch (e) {
|
||||||
|
logError("Failed to switch service:", e);
|
||||||
|
}
|
||||||
} else if (!pluginState.pluginStopped && currentSettings.service) {
|
} else if (!pluginState.pluginStopped && currentSettings.service) {
|
||||||
// Just restart with the updated settings (only if service is selected)
|
// Just restart with the updated settings (only if service is selected)
|
||||||
log("Restarting with updated settings...");
|
log("Restarting with updated settings...");
|
||||||
|
|
@ -217,7 +381,11 @@ export default {
|
||||||
} else if (!currentSettings.service) {
|
} else if (!currentSettings.service) {
|
||||||
// Service was unselected, stop the plugin
|
// Service was unselected, stop the plugin
|
||||||
log("Service unselected, stopping plugin...");
|
log("Service unselected, stopping plugin...");
|
||||||
stop();
|
try {
|
||||||
|
stop();
|
||||||
|
} catch (e) {
|
||||||
|
logError("Error while stopping due to service unselected:", e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -53,8 +53,14 @@ class PluginManager {
|
||||||
// Check for new tracks and update Discord status when something changes
|
// Check for new tracks and update Discord status when something changes
|
||||||
private async updateActivity() {
|
private async updateActivity() {
|
||||||
if (pluginState.pluginStopped) {
|
if (pluginState.pluginStopped) {
|
||||||
|
log("Plugin is stopped; skipping activity updates and clearing timers");
|
||||||
logVerbose("Plugin is stopped, skipping update");
|
logVerbose("Plugin is stopped, skipping update");
|
||||||
this.stopUpdates();
|
try {
|
||||||
|
this.stopUpdates();
|
||||||
|
logVerbose("Update timers cleared due to stopped plugin");
|
||||||
|
} catch (e) {
|
||||||
|
logError("Error while stopping updates for stopped plugin:", e);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -75,10 +81,16 @@ class PluginManager {
|
||||||
});
|
});
|
||||||
|
|
||||||
if (ignoredActivity) {
|
if (ignoredActivity) {
|
||||||
|
log(`Ignored app (${ignoredActivity.name}) is currently active; clearing activity and skipping updates`);
|
||||||
logVerbose(
|
logVerbose(
|
||||||
`Ignored app (${ignoredActivity.name}) is currently playing, clearing activity`,
|
`Ignored app (${ignoredActivity.name}) is currently playing, clearing activity`,
|
||||||
);
|
);
|
||||||
// Remove these setDebugInfo calls that cause TypeScript errors
|
try {
|
||||||
|
// Provide a little debug context so we can see why updates are skipped
|
||||||
|
setDebugInfo("ignoredActivity", ignoredActivity.name);
|
||||||
|
} catch (e) {
|
||||||
|
logVerbose("Failed to set debug info for ignored activity:", e);
|
||||||
|
}
|
||||||
clearActivity();
|
clearActivity();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -91,13 +103,20 @@ class PluginManager {
|
||||||
setDebugInfo("lastTrack", lastTrack);
|
setDebugInfo("lastTrack", lastTrack);
|
||||||
|
|
||||||
if (!lastTrack.nowPlaying) {
|
if (!lastTrack.nowPlaying) {
|
||||||
|
log("No currently playing track reported by service; clearing activity and skipping RPC update");
|
||||||
logVerbose("Track is not currently playing");
|
logVerbose("Track is not currently playing");
|
||||||
|
try {
|
||||||
|
setDebugInfo("lastTrack_nowPlaying", false);
|
||||||
|
} catch (e) {
|
||||||
|
logVerbose("Failed to set debug info for nowPlaying:", e);
|
||||||
|
}
|
||||||
clearActivity();
|
clearActivity();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// use simple URL comparison like Last.fm plugin
|
// use simple URL comparison like Last.fm plugin
|
||||||
if (pluginState.lastTrackUrl === lastTrack.url) {
|
if (pluginState.lastTrackUrl === lastTrack.url) {
|
||||||
|
log("Track unchanged; skipping Discord RPC update");
|
||||||
logVerbose("Track hasn't changed");
|
logVerbose("Track hasn't changed");
|
||||||
recordSuccessfulUpdate();
|
recordSuccessfulUpdate();
|
||||||
this.consecutiveFailures = 0;
|
this.consecutiveFailures = 0;
|
||||||
|
|
@ -255,7 +274,20 @@ class PluginManager {
|
||||||
);
|
);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logError("Update failed:", error);
|
logError("Update failed:", error);
|
||||||
recordServiceError(currentSettings.service, (error as Error).message);
|
try {
|
||||||
|
recordServiceError(currentSettings.service, (error as Error).message);
|
||||||
|
} catch (e) {
|
||||||
|
logError("Failed to record service error:", e);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
setDebugInfo("lastUpdateError", {
|
||||||
|
message: (error as Error).message,
|
||||||
|
service: currentSettings.service,
|
||||||
|
lastTrackUrl: pluginState.lastTrackUrl,
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
logVerbose("Failed to set debug info for last update error:", e);
|
||||||
|
}
|
||||||
this.handleError(error as Error);
|
this.handleError(error as Error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue