Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions src/backend/common/infrastructure/config/source/jellyfin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,13 @@ export interface JellyApiData extends CommonSourceData {
* @default false
*/
allowUnknown?: boolean

/**
* HOST:PORT of the Jellyfin server that your browser will be able to access from the frontend (and thus load images and links from)
* If unspecified it will use the normal server HOST and PORT from the `url`
* Necessary if you are using a reverse proxy or other network configuration that prevents the frontend from accessing the server directly
* */
frontendUrlOverride?: string
}

export interface JellyApiOptions extends CommonSourceOptions {
Expand Down
16 changes: 16 additions & 0 deletions src/backend/sources/JellyfinApiSource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,14 @@ export default class JellyfinApiSource extends MemoryPositionalSource {
if(AlbumId !== undefined && AlbumPrimaryImageTag !== undefined) {
const existingArt = play.meta?.art || {};
existingArt.album = this.imageApi.getItemImageUrlById(AlbumId, undefined, {maxHeight: 500});
if(
this.config.data.frontendUrlOverride !== undefined &&
this.config.data.frontendUrlOverride.length > 0 &&
existingArt.album !== undefined &&
existingArt.album.length > 0
) {
existingArt.album = existingArt.album.replace(this.config.data.url, this.config.data.frontendUrlOverride);
Comment thread
wolffshots marked this conversation as resolved.
Outdated
}
Comment thread
wolffshots marked this conversation as resolved.
Outdated
play.meta.art = existingArt;
}
if(ParentId !== undefined) {
Expand All @@ -388,6 +396,14 @@ export default class JellyfinApiSource extends MemoryPositionalSource {
...(play.meta?.url || {}),
web: u.toString().replace('%23', '#')
}
if(
this.config.data.frontendUrlOverride !== undefined &&
this.config.data.frontendUrlOverride.length > 0 &&
play.meta.url.web !== undefined &&
play.meta.url.web.length > 0
) {
play.meta.url.web = play.meta.url.web.replace(this.config.data.url, this.config.data.frontendUrlOverride);
Comment thread
wolffshots marked this conversation as resolved.
Outdated
}
}

return play;
Expand Down
40 changes: 40 additions & 0 deletions src/backend/tests/jellyfin/jellyfin.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import {
// @ts-expect-error weird typings?
SessionInfo,
} from "@jellyfin/sdk/lib/generated-client/index.js";
// @ts-expect-error weird typings?
import { getImageApi } from "@jellyfin/sdk/lib/utils/api/index.js";
import { PlayerStateDataMaybePlay } from "../../common/infrastructure/Atomic.js";

const dataAsFixture = (data: any): TestFixture => {
Expand Down Expand Up @@ -132,6 +134,44 @@ describe("Jellyfin API Source", function() {
});
});

describe('Parses and replaces frontendUrlOverride correctly if set', function () {

const item = {
AlbumId: 123,
AlbumPrimaryImageTag: 'Primary',
ParentId: 456,
ServerId: 789,
};
const sourceUrl = 'http://192.168.10.11:8096';
const frontendUrlOverride = 'https://myjellyfin.com';

it('Should use default url if frontendUrlOverride unset', async function () {
const jf = createJfApi({...defaultJfApiCreds, url: sourceUrl});
await jf.buildInitData();
jf.address = sourceUrl;
jf.api = jf.client.createApi(jf.address);
jf.imageApi = getImageApi(jf.api);

expect(jf.formatPlayObjAware(item).meta.art.album).to.be.eql(`${sourceUrl}/Items/123/Images/Primary?maxHeight=500`);
expect(jf.formatPlayObjAware(item).meta.url.web).to.be.eql(`${sourceUrl}/web/#/details?id=456&serviceId=789`);

await jf.destroy();
});

it('Should parse and replace frontendUrlOverride correctly', async function () {
const jf = createJfApi({...defaultJfApiCreds, frontendUrlOverride: frontendUrlOverride, url: sourceUrl});
await jf.buildInitData();
jf.address = sourceUrl;
jf.api = jf.client.createApi(jf.address);
jf.imageApi = getImageApi(jf.api);

expect(jf.formatPlayObjAware(item).meta.art.album).to.be.eql(`${frontendUrlOverride}/Items/123/Images/Primary?maxHeight=500`);
expect(jf.formatPlayObjAware(item).meta.url.web).to.be.eql(`${frontendUrlOverride}/web/#/details?id=456&serviceId=789`);

await jf.destroy();
});
});

describe('Correctly detects activity as valid/invalid', function() {

describe('Filters from Configuration', function() {
Expand Down