mirror of
https://github.com/jellyfin/jellyfin-web
synced 2025-03-30 19:56:21 +00:00
Merge 256c2412e0
into 7d84185d0e
This commit is contained in:
commit
cb740ee5f4
6 changed files with 192 additions and 12 deletions
|
@ -88,6 +88,7 @@ Jellyfin Web is the frontend used for most of the clients available for end user
|
|||
├── components # Higher order visual components and React components
|
||||
├── constants # Common constant values
|
||||
├── controllers # Legacy page views and controllers 🧹 ❌
|
||||
├── crashReporter # Script to send crash report logs to a connected server
|
||||
├── elements # Basic webcomponents and React equivalents 🧹
|
||||
├── hooks # Custom React hooks
|
||||
├── lib # Reusable libraries
|
||||
|
|
75
src/crashReporter/index.ts
Normal file
75
src/crashReporter/index.ts
Normal file
|
@ -0,0 +1,75 @@
|
|||
import { getClientLogApi } from '@jellyfin/sdk/lib/utils/api/client-log-api';
|
||||
|
||||
import ServerConnections from 'components/ServerConnections';
|
||||
import { getSDK, toApi } from 'utils/jellyfin-apiclient/compat';
|
||||
|
||||
import { buildLogTemplate } from './template';
|
||||
|
||||
/** Firefox supports additional properties on the Error object */
|
||||
interface NonstandardError extends Error {
|
||||
fileName?: string
|
||||
columnNumber?: number
|
||||
lineNumber?: number
|
||||
}
|
||||
|
||||
interface OnUnhandledRejectionHandler {
|
||||
(this: WindowEventHandlers, ev: PromiseRejectionEvent): void
|
||||
}
|
||||
|
||||
const initialTime = Date.now();
|
||||
|
||||
const reporter: OnErrorEventHandler = (
|
||||
event,
|
||||
source,
|
||||
lineno,
|
||||
colno,
|
||||
error
|
||||
) => {
|
||||
const apiClient = window.ApiClient ?? ServerConnections.currentApiClient();
|
||||
|
||||
if (!apiClient) {
|
||||
console.warn('[crash reporter] no api client; unable to report crash', {
|
||||
event,
|
||||
source,
|
||||
lineno,
|
||||
colno,
|
||||
error
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const jellyfin = getSDK(apiClient);
|
||||
|
||||
const log = buildLogTemplate(jellyfin, {
|
||||
initialTime
|
||||
}, {
|
||||
event,
|
||||
source,
|
||||
lineno,
|
||||
colno,
|
||||
error
|
||||
});
|
||||
|
||||
if (__WEBPACK_SERVE__) {
|
||||
console.error('[crash reporter] crash report not submitted in dev server', log);
|
||||
return;
|
||||
}
|
||||
|
||||
console.debug('[crash reporter] submitting crash report', log);
|
||||
getClientLogApi(toApi(apiClient))
|
||||
.logFile({
|
||||
body: log
|
||||
})
|
||||
.catch(err => {
|
||||
console.error('[crash reporter] failed to submit crash log', err, log);
|
||||
});
|
||||
};
|
||||
|
||||
const rejectionReporter: OnUnhandledRejectionHandler = (event) => {
|
||||
const error = event.reason as NonstandardError;
|
||||
const message = event.reason as string;
|
||||
reporter(error.message ?? message, error.fileName, error.lineNumber, error.columnNumber, error);
|
||||
};
|
||||
|
||||
window.onerror = reporter;
|
||||
window.onunhandledrejection = rejectionReporter;
|
87
src/crashReporter/template.ts
Normal file
87
src/crashReporter/template.ts
Normal file
|
@ -0,0 +1,87 @@
|
|||
import type { Jellyfin } from '@jellyfin/sdk';
|
||||
|
||||
import browser from 'scripts/browser';
|
||||
|
||||
import pkg from '../../package.json';
|
||||
|
||||
interface CrashContext {
|
||||
initialTime: number
|
||||
}
|
||||
|
||||
interface CrashDetails {
|
||||
event: Event | string,
|
||||
source?: string,
|
||||
lineno?: number,
|
||||
colno?: number,
|
||||
error?: Error
|
||||
}
|
||||
|
||||
const buildDetailsTemplate = (
|
||||
message: string,
|
||||
details: CrashDetails
|
||||
) => {
|
||||
const templates: string[] = [];
|
||||
if (details.error?.name) templates.push(`***Name***: \`${details.error.name}\``);
|
||||
templates.push(`***Message***: \`${message}\``);
|
||||
if (details.source) templates.push(`***Source***: \`${details.source}\``);
|
||||
if (details.lineno) templates.push(`***Line number***: \`${details.lineno}\``);
|
||||
if (details.colno) templates.push(`***Column number***: \`${details.colno}\``);
|
||||
|
||||
return templates.join('\n');
|
||||
};
|
||||
|
||||
export const buildLogTemplate = (
|
||||
jellyfin: Jellyfin,
|
||||
context: CrashContext,
|
||||
details: CrashDetails
|
||||
) => {
|
||||
const event = details.event as Event;
|
||||
const message = (details.event as string) ?? details.error?.message;
|
||||
const startTime = new Date(context.initialTime);
|
||||
const crashTime = event?.timeStamp ? new Date(context.initialTime + event.timeStamp) : new Date();
|
||||
|
||||
return `---
|
||||
client: ${pkg.name}
|
||||
client_version: ${pkg.version}
|
||||
client_repository: ${pkg.repository}
|
||||
type: crash_report
|
||||
format: markdown
|
||||
---
|
||||
|
||||
### Logs
|
||||
|
||||
${buildDetailsTemplate(message, details)}
|
||||
***Stack Trace***:
|
||||
\`\`\`log
|
||||
${details.error?.stack}
|
||||
\`\`\`
|
||||
|
||||
### App information
|
||||
|
||||
***App name***: \`${jellyfin.clientInfo.name}\`
|
||||
***App version***: \`${jellyfin.clientInfo.version}\`
|
||||
***Package name***: \`${pkg.name}\`
|
||||
***Package config***:
|
||||
\`\`\`json
|
||||
${JSON.stringify(pkg)}
|
||||
\`\`\`
|
||||
***Build options****:
|
||||
| Option | Value |
|
||||
|----------------------|-------------------------|
|
||||
| __USE_SYSTEM_FONTS__ | ${__USE_SYSTEM_FONTS__} |
|
||||
| __WEBPACK_SERVE__ | ${__WEBPACK_SERVE__} |
|
||||
|
||||
### Device information
|
||||
|
||||
***Device name***: \`${jellyfin.deviceInfo.name}\`
|
||||
***Browser information***:
|
||||
\`\`\`json
|
||||
${JSON.stringify(browser)}
|
||||
\`\`\`
|
||||
|
||||
### Crash information
|
||||
|
||||
***Start time***: \`${startTime.toISOString()}\`
|
||||
***Crash time***: \`${crashTime.toISOString()}\`
|
||||
`;
|
||||
};
|
4
src/global.d.ts
vendored
4
src/global.d.ts
vendored
|
@ -1,6 +1,10 @@
|
|||
export declare global {
|
||||
import { ApiClient, Events } from 'jellyfin-apiclient';
|
||||
|
||||
// Globals declared in webpack
|
||||
declare const __USE_SYSTEM_FONTS__: boolean;
|
||||
declare const __WEBPACK_SERVE__: boolean;
|
||||
|
||||
interface Window {
|
||||
ApiClient: ApiClient;
|
||||
Events: Events;
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
import { Api, Jellyfin } from '@jellyfin/sdk';
|
||||
import { ApiClient } from 'jellyfin-apiclient';
|
||||
import type { Api } from '@jellyfin/sdk';
|
||||
import { Jellyfin } from '@jellyfin/sdk/lib/jellyfin';
|
||||
import { type ApiClient } from 'jellyfin-apiclient';
|
||||
|
||||
/**
|
||||
* Returns an SDK Api instance using the same parameters as the provided ApiClient.
|
||||
* Returns an SDK instance from the configuration of an ApiClient instance.
|
||||
* @param {ApiClient} apiClient The (legacy) ApiClient.
|
||||
* @returns {Api} An equivalent SDK Api instance.
|
||||
* @returns {Jellyfin} An instance of the Jellyfin SDK.
|
||||
*/
|
||||
export const toApi = (apiClient: ApiClient): Api => {
|
||||
return (new Jellyfin({
|
||||
export const getSDK = (apiClient: ApiClient): Jellyfin => (
|
||||
new Jellyfin({
|
||||
clientInfo: {
|
||||
name: apiClient.appName(),
|
||||
version: apiClient.appVersion()
|
||||
|
@ -16,8 +17,18 @@ export const toApi = (apiClient: ApiClient): Api => {
|
|||
name: apiClient.deviceName(),
|
||||
id: apiClient.deviceId()
|
||||
}
|
||||
})).createApi(
|
||||
apiClient.serverAddress(),
|
||||
apiClient.accessToken()
|
||||
);
|
||||
})
|
||||
);
|
||||
|
||||
/**
|
||||
* Returns an SDK Api instance using the same parameters as the provided ApiClient.
|
||||
* @param {ApiClient} apiClient The (legacy) ApiClient.
|
||||
* @returns {Api} An equivalent SDK Api instance.
|
||||
*/
|
||||
export const toApi = (apiClient: ApiClient): Api => {
|
||||
return getSDK(apiClient)
|
||||
.createApi(
|
||||
apiClient.serverAddress(),
|
||||
apiClient.accessToken()
|
||||
);
|
||||
};
|
||||
|
|
|
@ -45,7 +45,8 @@ const config = {
|
|||
target: 'browserslist',
|
||||
entry: {
|
||||
'main.jellyfin': './index.jsx',
|
||||
...THEMES_BY_ID
|
||||
...THEMES_BY_ID,
|
||||
'crashReporter': './crashReporter/index.ts'
|
||||
},
|
||||
resolve: {
|
||||
extensions: ['.tsx', '.ts', '.js'],
|
||||
|
@ -74,7 +75,8 @@ const config = {
|
|||
hash: true,
|
||||
chunks: [
|
||||
'main.jellyfin',
|
||||
'serviceworker'
|
||||
'serviceworker',
|
||||
'crashReporter'
|
||||
]
|
||||
}),
|
||||
new CopyPlugin({
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue