refactor: Restructure server directory

* Rename to backend to better reflect what it is
* Move server functionality out of entry file and into own server subdirectory
* Rename 'apis' folder to 'vendor' to reflect usage and move into common
* Rename 'clients' folder to 'scrobblers' reflect usage and prevent ambiguity with client CRA folder
This commit is contained in:
FoxxMD 2023-08-24 11:12:27 -04:00
parent 4cccdeeff0
commit 04ffc0a589
105 changed files with 172 additions and 423 deletions

View file

@ -17,5 +17,6 @@ flatpak/generated-sources.json
flatpak/.flatpak-builder
docsite/build
docsite/node_modules
docsite/.docusaurus
docsite/.cache-loader
build
yarn.lock

View file

@ -2,16 +2,16 @@
"extends": "@istanbuljs/nyc-config-typescript",
"exclude": [
"node_modules/",
"**/src/server/common/schema/**",
"**/src/server/tests/**",
"**/src/backend/common/schema/**",
"**/src/backend/tests/**",
"register.js",
"**/src/server/**/*.d.ts",
"**/src/client/**"
],
"include": [
"**/src/server/**/*.ts",
"**/src/**/server/*.js",
"**/src/**/server/*.js.map"
"**/src/backend/**/*.ts",
"**/src/**/backend/*.js",
"**/src/**/backend/*.js.map"
],
"extension": [
".ts"

14
package-lock.json generated
View file

@ -27,7 +27,6 @@
"concat-stream": "^2.0.0",
"dayjs": "^1.10.4",
"dbus-next": "0.10.2",
"ejs": "^3.1.6",
"es6-error": "^4.1.1",
"express": "^4.17.1",
"express-session": "^1.17.2",
@ -8830,6 +8829,7 @@
"version": "3.1.9",
"resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.9.tgz",
"integrity": "sha512-rC+QVNMJWv+MtPgkt0y+0rVEIdbtxVADApW9JXrUVlzHetgcyczP/E7DJmWJ4fJCZF2cPcBk0laWO9ZHMG3DmQ==",
"dev": true,
"dependencies": {
"jake": "^10.8.5"
},
@ -10295,6 +10295,7 @@
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz",
"integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==",
"dev": true,
"dependencies": {
"minimatch": "^5.0.1"
}
@ -10303,6 +10304,7 @@
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
"dev": true,
"dependencies": {
"balanced-match": "^1.0.0"
}
@ -10311,6 +10313,7 @@
"version": "5.1.6",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz",
"integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==",
"dev": true,
"dependencies": {
"brace-expansion": "^2.0.1"
},
@ -12722,6 +12725,7 @@
"version": "10.8.7",
"resolved": "https://registry.npmjs.org/jake/-/jake-10.8.7.tgz",
"integrity": "sha512-ZDi3aP+fG/LchyBzUM804VjddnwfSfsdeYkwt8NcbKRvo4rFkjhs456iLFn3k2ZUWvNe4i48WACDbza8fhq2+w==",
"dev": true,
"dependencies": {
"async": "^3.2.3",
"chalk": "^4.0.2",
@ -12739,6 +12743,7 @@
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"dev": true,
"dependencies": {
"color-convert": "^2.0.1"
},
@ -12753,6 +12758,7 @@
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
"dev": true,
"dependencies": {
"ansi-styles": "^4.1.0",
"supports-color": "^7.1.0"
@ -12768,6 +12774,7 @@
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"dev": true,
"dependencies": {
"color-name": "~1.1.4"
},
@ -12778,12 +12785,14 @@
"node_modules/jake/node_modules/color-name": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
"dev": true
},
"node_modules/jake/node_modules/has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
"dev": true,
"engines": {
"node": ">=8"
}
@ -12792,6 +12801,7 @@
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
"dev": true,
"dependencies": {
"has-flag": "^4.0.0"
},

View file

@ -22,7 +22,7 @@
"build:client": "react-scripts build",
"build:server": "webpack --config webpack.config.server.js",
"start": "node build/server.js",
"fileEndings": "jscodeshift --transformFrom js --transformTo none --importTypes relative --extensions=ts --parser tsx --transform codeshift/transform.ts src/server"
"fileEndings": "jscodeshift --transformFrom js --transformTo none --importTypes relative --extensions=ts --parser tsx --transform codeshift/transform.ts src/backend"
},
"exports": {
".": {
@ -64,7 +64,6 @@
"concat-stream": "^2.0.0",
"dayjs": "^1.10.4",
"dbus-next": "0.10.2",
"ejs": "^3.1.6",
"es6-error": "^4.1.1",
"express": "^4.17.1",
"express-session": "^1.17.2",

View file

@ -5,10 +5,10 @@
const tsNode = require('ts-node');
const tsConfigPaths = require('tsconfig-paths');
const mainTSConfig = require('./src/server/tsconfig.json');
const mainTSConfig = require('./src/backend/tsconfig.json');
tsConfigPaths.register({
baseUrl: './src/server/tests',
baseUrl: './src/backend/tests',
paths: {
...mainTSConfig.compilerOptions.paths,
}
@ -17,5 +17,5 @@ tsConfigPaths.register({
tsNode.register({
files: true,
transpileOnly: true,
project: './src/server/tsconfig.json'
project: './src/backend/tsconfig.json'
});

View file

@ -1,8 +1,8 @@
import { capitalize, mergeArr } from "../utils";
import { capitalize, mergeArr } from "../../utils";
import {Logger} from '@foxxmd/winston';
import { FormatPlayObjectOptions } from "../common/infrastructure/Atomic";
import { FormatPlayObjectOptions } from "../infrastructure/Atomic";
import winston from '@foxxmd/winston';
import { PlayObject } from "../../core/Atomic";
import { PlayObject } from "../../../core/Atomic";
export default abstract class AbstractApiClient {
name: string;

View file

@ -1,5 +1,5 @@
import AbstractApiClient from "./AbstractApiClient";
import {JRiverData} from "../common/infrastructure/config/source/jriver";
import AbstractApiClient from "./AbstractApiClient.js";
import {JRiverData} from "../infrastructure/config/source/jriver.js";
import request, {Request, Response} from 'superagent';
import xml2js from 'xml2js';
import {ErrorWithCause} from "pony-cause";

View file

@ -1,13 +1,13 @@
import AbstractApiClient from "./AbstractApiClient";
import {ErrorWithCause} from "pony-cause";
import { KodiData } from "../common/infrastructure/config/source/kodi";
import { KodiData } from "../infrastructure/config/source/kodi";
import { KodiClient } from 'kodi-api'
import normalizeUrl from "normalize-url";
import {URL} from "url";
import { RecentlyPlayedOptions } from "../sources/AbstractSource";
import { FormatPlayObjectOptions } from "../common/infrastructure/Atomic";
import { RecentlyPlayedOptions } from "../../sources/AbstractSource";
import { FormatPlayObjectOptions } from "../infrastructure/Atomic";
import dayjs from "dayjs";
import { PlayObject } from "../../core/Atomic";
import { PlayObject } from "../../../core/Atomic";
interface KodiDuration {
hours: number

View file

@ -1,10 +1,10 @@
import LastFm, {AuthGetSessionResponse, TrackObject, UserGetInfoResponse} from "lastfm-node-client";
import AbstractApiClient from "./AbstractApiClient";
import dayjs from "dayjs";
import { readJson, sleep, writeFile } from "../utils";
import { FormatPlayObjectOptions } from "../common/infrastructure/Atomic";
import { LastfmData } from "../common/infrastructure/config/client/lastfm";
import { PlayObject } from "../../core/Atomic";
import { readJson, sleep, writeFile } from "../../utils";
import { FormatPlayObjectOptions } from "../infrastructure/Atomic";
import { LastfmData } from "../infrastructure/config/client/lastfm";
import { PlayObject } from "../../../core/Atomic";
const badErrors = [
'api key suspended',

View file

@ -1,20 +1,22 @@
import AbstractApiClient from "./AbstractApiClient";
import request, {Request} from 'superagent';
import { ListenBrainzClientData } from "../common/infrastructure/config/client/listenbrainz";
import {DELIMITERS, FormatPlayObjectOptions} from "../common/infrastructure/Atomic";
import { ListenBrainzClientData } from "../infrastructure/config/client/listenbrainz";
import { DELIMITERS, FormatPlayObjectOptions } from "../infrastructure/Atomic";
import dayjs from "dayjs";
import { stringSameness } from '@foxxmd/string-sameness';
import {
containsDelimiters,
findDelimiters,
normalizeStr, parseArtistCredits,
normalizeStr,
parseArtistCredits,
parseCredits,
parseStringList, parseTrackCredits,
parseStringList,
parseTrackCredits,
unique,
uniqueNormalizedStrArr,
} from "../utils";
import { PlayObject } from "../../core/Atomic";
import {slice} from "../../core/StringUtils";
} from "../../utils";
import { PlayObject } from "../../../core/Atomic";
import { slice } from "../../../core/StringUtils";
export interface ArtistMBIDMapping {

View file

@ -1,6 +1,3 @@
import {addAsync, Router} from '@awaitjs/express';
import express from 'express';
import bodyParser from 'body-parser';
import {Logger} from '@foxxmd/winston';
import dayjs from 'dayjs';
import utc from 'dayjs/plugin/utc.js';
@ -8,10 +5,7 @@ import isBetween from 'dayjs/plugin/isBetween.js';
import relativeTime from 'dayjs/plugin/relativeTime.js';
import duration from 'dayjs/plugin/duration.js';
import timezone from 'dayjs/plugin/timezone.js';
import passport from 'passport';
import session from 'express-session';
import {
getAddress,
parseBool,
readJson,
sleep
@ -22,11 +16,8 @@ import SpotifySource from "./sources/SpotifySource";
import { AIOConfig } from "./common/infrastructure/config/aioConfig";
import { getRoot } from "./ioc";
import {getLogger} from "./common/logging";
import { setupApi } from "./api/api";
import {LogInfo} from "../core/Atomic";
import {stripIndents} from "common-tags";
const buildDir = path.join(process.cwd() + "/build");
import {initServer} from "./server/index";
dayjs.extend(utc)
@ -35,32 +26,8 @@ dayjs.extend(relativeTime);
dayjs.extend(duration);
dayjs.extend(timezone);
const app = addAsync(express());
const router = Router();
const isProd = process.env.NODE_ENV !== undefined && (process.env.NODE_ENV === 'production' || process.env.NODE_ENV === 'prod');
const apiPort = process.env.API_PORT ?? 9079;
const mainPort = process.env.PORT ?? 3000;
let envPort = isProd ? mainPort : apiPort;
(async function () {
app.use(router);
app.use(bodyParser.json());
app.use(
bodyParser.urlencoded({
extended: true,
})
);
app.use(express.static(buildDir));
app.use(session({secret: 'keyboard cat', resave: false, saveUninitialized: false}));
app.use(passport.initialize());
app.use(passport.session());
let output: LogInfo[] = []
const initLogger = getLogger({file: false}, 'init');
@ -86,7 +53,7 @@ const configDir = process.env.CONFIG_DIR || path.resolve(projectDir, `./config`)
const {
webhooks = [],
port = envPort,
port,
logging = {},
debugMode,
} = (config || {}) as AIOConfig;
@ -100,12 +67,11 @@ const configDir = process.env.CONFIG_DIR || path.resolve(projectDir, `./config`)
process.env.DEBUG_MODE = b.toString();
}
app.listen(port);
const root = getRoot(port);
logger = getLogger(logging, 'app');
setupApi(app, logger, output);
initServer(logger, output);
if(process.env.IS_LOCAL === 'true') {
logger.info('multi-scrobbler can be run as a background service! See: https://github.com/FoxxMD/multi-scrobbler/blob/develop/docs/service.md');
@ -116,8 +82,6 @@ const configDir = process.env.CONFIG_DIR || path.resolve(projectDir, `./config`)
logger.warn(appConfigFail);
}
const localUrl = root.get('localUrl');
const notifiers = root.get('notifiers');
await notifiers.buildWebhooks(webhooks);
@ -168,50 +132,9 @@ const configDir = process.env.CONFIG_DIR || path.resolve(projectDir, `./config`)
}
}
if (anyNotReady) {
logger.info(`Some sources are not ready, open ${localUrl} to continue`);
logger.info(`Some sources are not ready, open the dashboard to continue`);
}
app.get("/*", function (req, res) {
if(!isProd) {
logger.warn(`In development environment this path (on port ${apiPort}) does nothing. You most likely want port ${mainPort}`)
}
res.sendFile(path.join(buildDir, "index.html"));
});
app.set('views', path.resolve(projectDir, 'src/views'));
app.set('view engine', 'ejs');
const addy = getAddress();
const addresses: string[] = [];
let dockerHint = '';
if(parseBool(process.env.IS_DOCKER) && addy.v4 !== undefined && addy.v4.includes('172')) {
dockerHint = stripIndents`
--- HINT ---
MS is likely being run in a container with BRIDGE networking which means the above addresses are not accessible from outside this container.
To ensure the container is accessible make sure you have mapped the *container* port ${port} to a *host* port. https://foxxmd.github.io/multi-scrobbler/docs/installation#networking
The container will then be accessible at http://HOST_MACHINE_IP:HOST_PORT
--- HINT ---
`;
}
for(const [k, v] of Object.entries(addy)) {
if(v !== undefined) {
switch(k) {
case 'host':
case 'v4':
addresses.push(`---> ${k === 'host' ? 'Local'.padEnd(14, ' ') : 'Network'.padEnd(14, ' ')} http://${v}:${port}`);
break;
case 'v6':
addresses.push(`---> Network (IPv6) http://[${v}]:${port}`);
}
}
}
const start = stripIndents`\n
${isProd ? 'Server' : 'API Backend'} started:
${addresses.join('\n')}${dockerHint !== '' ? `\n${dockerHint}` : ''}`
logger.info(start);
} catch (e) {
logger.error('Exited with uncaught error');
logger.error(e);

View file

@ -1,7 +1,7 @@
import {createContainer} from "iti";
import path from "path";
import {projectDir} from "./common/index";
import ScrobbleClients from "./clients/ScrobbleClients";
import ScrobbleClients from "./scrobblers/ScrobbleClients";
import ScrobbleSources from "./sources/ScrobbleSources";
import {Notifiers} from "./notifier/Notifiers";
import {EventEmitter} from "events";
@ -20,12 +20,15 @@ if(typeof process.env.CONFIG_DIR === 'string') {
let root: ReturnType<typeof createRoot>;
const createRoot = (port: number | string) => {
const createRoot = (port: number | string | undefined) => {
return createContainer().add({
configDir: configDir,
logDir: logPath,
localUrl: `http://localhost:${port}`,
isProd: process.env.NODE_ENV !== undefined && (process.env.NODE_ENV === 'production' || process.env.NODE_ENV === 'prod'),
configPort: port,
apiPort: process.env.API_PORT ?? 9079,
mainPort: process.env.PORT ?? 3000,
clientEmitter: () => new WildcardEmitter(),
sourceEmitter: () => new WildcardEmitter(),
notifierEmitter: () => new EventEmitter(),
@ -33,6 +36,12 @@ const createRoot = (port: number | string) => {
clients: () => new ScrobbleClients(items.clientEmitter, items.sourceEmitter, items.configDir),
sources: () => new ScrobbleSources(items.sourceEmitter, items.localUrl, items.configDir),
notifiers: () => new Notifiers(items.notifierEmitter, items.clientEmitter, items.sourceEmitter),
port: () => {
if(items.configPort !== undefined) {
return items.configPort;
}
return items.isProd ? items.mainPort : items.apiPort;
}
}));
}

View file

@ -9,7 +9,7 @@ import {
sleep,
sortByOldestPlayDate,
} from "../utils";
import LastfmApiClient from "../apis/LastfmApiClient";
import LastfmApiClient from "../common/vendor/LastfmApiClient";
import { FormatPlayObjectOptions, INITIALIZING, ScrobbledPlayObject } from "../common/infrastructure/Atomic";
import { LastfmClientConfig } from "../common/infrastructure/config/client/lastfm";
import {TrackScrobbleResponse, UserGetRecentTracksResponse} from "lastfm-node-client";

View file

@ -9,12 +9,12 @@ import {
sleep,
sortByOldestPlayDate,
} from "../utils";
import LastfmApiClient from "../apis/LastfmApiClient";
import LastfmApiClient from "../common/vendor/LastfmApiClient";
import { FormatPlayObjectOptions, INITIALIZING } from "../common/infrastructure/Atomic";
import { Notifiers } from "../notifier/Notifiers";
import {Logger} from '@foxxmd/winston';
import { ListenBrainzClientConfig } from "../common/infrastructure/config/client/listenbrainz";
import { ListenbrainzApiClient } from "../apis/ListenbrainzApiClient";
import { ListenbrainzApiClient } from "../common/vendor/ListenbrainzApiClient";
import { PlayObject, TrackStringOptions } from "../../core/Atomic";
import { buildTrackString } from "../../core/StringUtils";
import EventEmitter from "events";

View file

@ -20,7 +20,7 @@ import {
MalojaScrobbleRequestData,
MalojaScrobbleV2RequestData,
MalojaScrobbleV3RequestData, MalojaScrobbleV3ResponseData, MalojaV2ScrobbleData, MalojaV3ScrobbleData
} from "../apis/maloja/interfaces";
} from "../common/vendor/maloja/interfaces";
import { PlayObject, TrackStringOptions } from "../../core/Atomic";
import { buildTrackString } from "../../core/StringUtils";
import EventEmitter from "events";

View file

@ -12,7 +12,7 @@ import {
SourceStatusData,
} from "../../core/Atomic";
import {Logger} from "@foxxmd/winston";
import {formatLogToHtml, isLogLineMinLevel} from "../common/logging";
import {formatLogToHtml, getLogger, isLogLineMinLevel} from "../common/logging";
import {MESSAGE} from "triple-beam";
import {Transform} from "stream";
import {createSession} from "better-sse";
@ -21,12 +21,8 @@ import {setupPlexRoutes} from "./plexRoutes";
import {setupJellyfinRoutes} from "./jellyfinRoutes";
import {setupDeezerRoutes} from "./deezerRoutes";
import {setupAuthRoutes} from "./auth";
import path from "path";
import {source} from "common-tags";
import { ExpressHandler } from "../common/infrastructure/Atomic";
const buildDir = path.join(process.cwd() + "/build");
let output: LogInfo[] = []
const availableLevels = ['error', 'warn', 'info', 'verbose', 'debug'];
@ -56,7 +52,8 @@ export const setupApi = (app: ExpressWithAsync, logger: Logger, initialLogOutput
console.log(e);
}
logger.stream().on('log', (log: LogInfo) => {
const appLogger = getLogger({}, 'app');
appLogger.stream().on('log', (log: LogInfo) => {
output.unshift(log);
output = output.slice(0, 501);
if(isLogLineMinLevel(log, logConfig.level)) {

View file

@ -3,8 +3,8 @@ import {Logger} from "@foxxmd/winston";
import ScrobbleSources from "../sources/ScrobbleSources";
import passport from "passport";
import { ExpressHandler } from "../common/infrastructure/Atomic";
import ScrobbleClients from "../clients/ScrobbleClients";
import LastfmScrobbler from "../clients/LastfmScrobbler";
import ScrobbleClients from "../scrobblers/ScrobbleClients";
import LastfmScrobbler from "../scrobblers/LastfmScrobbler";
import LastfmSource from "../sources/LastfmSource";
import SpotifySource from "../sources/SpotifySource";

View file

@ -0,0 +1,89 @@
import {addAsync, Router} from '@awaitjs/express';
import express from 'express';
import bodyParser from 'body-parser';
import passport from 'passport';
import session from 'express-session';
import path from "path";
import { getRoot } from "../ioc";
import {Logger} from "@foxxmd/winston";
import { LogInfo } from "../../core/Atomic";
import { setupApi } from "./api";
import { getAddress, mergeArr, parseBool } from "../utils";
import {stripIndents} from "common-tags";
import {ErrorWithCause} from "pony-cause";
const buildDir = path.join(process.cwd() + "/build");
const app = addAsync(express());
const router = Router();
export const initServer = async (parentLogger: Logger, initialOutput: LogInfo[] = []) => {
const logger = parentLogger.child({labels: ['API']}, mergeArr);
try {
app.use(router);
app.use(bodyParser.json());
app.use(
bodyParser.urlencoded({
extended: true,
})
);
app.use(express.static(buildDir));
app.use(session({secret: 'keyboard cat', resave: false, saveUninitialized: false}));
app.use(passport.initialize());
app.use(passport.session());
const root = getRoot();
const isProd = root.get('isProd');
const apiPort = root.get('apiPort');
const mainPort = root.get('mainPort');
const port = root.get('port');
setupApi(app, logger, initialOutput);
app.get("/*", function (req, res) {
if (!isProd) {
logger.warn(`In development environment this path (on port ${apiPort}) does nothing. You most likely want port ${mainPort}`)
}
res.sendFile(path.join(buildDir, "index.html"));
});
app.listen(port);
const addy = getAddress();
const addresses: string[] = [];
let dockerHint = '';
if (parseBool(process.env.IS_DOCKER) && addy.v4 !== undefined && addy.v4.includes('172')) {
dockerHint = stripIndents`
--- HINT ---
MS is likely being run in a container with BRIDGE networking which means the above addresses are not accessible from outside this container.
To ensure the container is accessible make sure you have mapped the *container* port ${port} to a *host* port. https://foxxmd.github.io/multi-scrobbler/docs/installation#networking
The container will then be accessible at http://HOST_MACHINE_IP:HOST_PORT
--- HINT ---
`;
}
for (const [k, v] of Object.entries(addy)) {
if (v !== undefined) {
switch (k) {
case 'host':
case 'v4':
addresses.push(`---> ${k === 'host' ? 'Local'.padEnd(14, ' ') : 'Network'.padEnd(14, ' ')} http://${v}:${port}`);
break;
case 'v6':
addresses.push(`---> Network (IPv6) http://[${v}]:${port}`);
}
}
}
const start = stripIndents`\n
${isProd ? 'Server' : 'API Backend'} started:
${addresses.join('\n')}${dockerHint !== '' ? `\n${dockerHint}` : ''}`
logger.info(start);
} catch (e) {
logger.error(new ErrorWithCause('Server crashed with uncaught exception', {cause: e}));
}
}

View file

@ -6,7 +6,7 @@ import normalizeUrl from 'normalize-url';
import {EventEmitter} from "events";
import { RecentlyPlayedOptions } from "./AbstractSource";
import { JRiverSourceConfig } from "../common/infrastructure/config/source/jriver";
import { Info, JRiverApiClient, PLAYER_STATE } from "../apis/JRiverApiClient";
import { Info, JRiverApiClient, PLAYER_STATE } from "../common/vendor/JRiverApiClient";
import { PlayObject } from "../../core/Atomic";
export class JRiverSource extends MemorySource {

View file

@ -3,7 +3,7 @@ import { FormatPlayObjectOptions, InternalConfig } from "../common/infrastructur
import {EventEmitter} from "events";
import { RecentlyPlayedOptions } from "./AbstractSource";
import { KodiSourceConfig } from "../common/infrastructure/config/source/kodi";
import { KodiApiClient } from "../apis/KodiApiClient";
import { KodiApiClient } from "../common/vendor/KodiApiClient";
import { PlayObject } from "../../core/Atomic";
export class KodiSource extends MemorySource {

View file

@ -1,5 +1,5 @@
import AbstractSource, { RecentlyPlayedOptions } from "./AbstractSource";
import LastfmApiClient from "../apis/LastfmApiClient";
import LastfmApiClient from "../common/vendor/LastfmApiClient";
import { sortByOldestPlayDate } from "../utils";
import { LastfmClientConfig } from "../common/infrastructure/config/client/lastfm";
import { FormatPlayObjectOptions, InternalConfig } from "../common/infrastructure/Atomic";

View file

@ -2,7 +2,7 @@ import AbstractSource, { RecentlyPlayedOptions } from "./AbstractSource";
import { FormatPlayObjectOptions, INITIALIZING, InternalConfig } from "../common/infrastructure/Atomic";
import EventEmitter from "events";
import { ListenBrainzSourceConfig } from "../common/infrastructure/config/source/listenbrainz";
import { ListenbrainzApiClient } from "../apis/ListenbrainzApiClient";
import { ListenbrainzApiClient } from "../common/vendor/ListenbrainzApiClient";
export default class ListenbrainzSource extends AbstractSource {

View file

@ -13,7 +13,7 @@ import slightlyDifferentNames from './listenbrainz/correctlyMapped/trackNameSlig
import incorrectMultiArtistsTrackName from './listenbrainz/incorrectlyMapped/multiArtistsInTrackName.json';
import veryWrong from './listenbrainz/incorrectlyMapped/veryWrong.json';
import {ListenbrainzApiClient, ListenResponse} from "../apis/ListenbrainzApiClient";
import {ListenbrainzApiClient, ListenResponse} from "../common/vendor/ListenbrainzApiClient";
interface ExpectedResults {
artists: string[]

View file

@ -17,15 +17,16 @@
"include": [
"**/*.ts",
"**/*.tsx",
"**/*.js"
"**/*.js",
"../core/**/*.ts"
],
"exclude": [
"../../web",
"../../node_modules",
"../../coverage",
"../../tests/*.ts",
"../../_site",
"../../docsite",
"../../build", "../client"
"../../build",
"../client"
]
}

Some files were not shown because too many files have changed in this diff Show more