···1616import { initServer } from "./server/index.js";
1717import { createHeartbeatClientsTask } from "./tasks/heartbeatClients.js";
1818import { createHeartbeatSourcesTask } from "./tasks/heartbeatSources.js";
1919-import { isDebugMode, parseBool, readJson, retry, sleep } from "./utils.js";
1919+import { isDebugMode, parseBool, retry, sleep } from "./utils.js";
2020+import { readJson } from './utils/DataUtils.js';
2021import { createVegaGenerator } from './utils/SchemaUtils.js';
2122import ScrobbleClients from './scrobblers/ScrobbleClients.js';
2223import ScrobbleSources from './sources/ScrobbleSources.js';
···6263 let appConfigFail: Error | undefined = undefined;
6364 let config = {};
6465 try {
6565- config = await readJson(`${configDir}/config.json`, {throwOnNotFound: false});
6666+ config = await readJson(`${configDir}/config.json`, {throwOnNotFound: false, logger: childLogger(initLogger, 'Secrets')});
6667 } catch (e) {
6768 appConfigFail = e;
6869 }
+4-3
src/backend/scrobblers/ScrobbleClients.ts
···1010import { MalojaClientConfig } from "../common/infrastructure/config/client/maloja.js";
1111import { WildcardEmitter } from "../common/WildcardEmitter.js";
1212import { Notifiers } from "../notifier/Notifiers.js";
1313-import { isDebugMode, readJson } from "../utils.js";
1313+import { isDebugMode } from "../utils.js";
1414+import { readJson } from '../utils/DataUtils.js';
1415import { joinedUrl } from "../utils/NetworkUtils.js";
1516import { getTypeSchemaFromConfigGenerator } from "../utils/SchemaUtils.js";
1617import { validateJson } from "../utils/ValidationUtils.js";
···128129129130 let configFile;
130131 try {
131131- configFile = await readJson(`${this.configDir}/config.json`, {throwOnNotFound: false});
132132+ configFile = await readJson(`${this.configDir}/config.json`, {throwOnNotFound: false, logger: childLogger(this.logger, `Secrets`)});
132133 } catch (e) {
133134 // think this should stay as show-stopper since config could include important defaults (delay, retries) we don't want to ignore
134135 throw new Error('config.json could not be parsed');
···294295 }
295296 let rawClientConfigs;
296297 try {
297297- rawClientConfigs = await readJson(`${this.configDir}/${clientType}.json`, {throwOnNotFound: false});
298298+ rawClientConfigs = await readJson(`${this.configDir}/${clientType}.json`, {throwOnNotFound: false, logger: childLogger(this.logger, `${clientType} Secrets`)});
298299 } catch (e) {
299300 const errMsg = `${clientType}.json config file could not be parsed`;
300301 this.emitter.emit('error', errMsg);
+1-1
src/backend/sources/DeezerInternalSource.ts
···55import { DEFAULT_RETRY_MULTIPLIER, FormatPlayObjectOptions, InternalConfig } from "../common/infrastructure/Atomic.js";
66import { DeezerInternalSourceConfig, DeezerInternalTrackData, DeezerSourceConfig } from "../common/infrastructure/config/source/deezer.js";
77import { TRANSFORM_HOOK } from "../common/infrastructure/Transform.js";
88-import { parseRetryAfterSecsFromObj, playObjDataMatch, readJson, sleep, sortByOldestPlayDate, writeFile, } from "../utils.js";
88+import { parseRetryAfterSecsFromObj, playObjDataMatch, sleep, sortByOldestPlayDate} from "../utils.js";
99import AbstractSource, { RecentlyPlayedOptions } from "./AbstractSource.js";
1010import { CookieJar, Cookie } from 'tough-cookie';
1111import { MixedCookieAgent } from 'http-cookie-agent/http';
+3-2
src/backend/sources/DeezerSource.ts
···66import { PlayObject } from "../../core/Atomic.js";
77import { DEFAULT_RETRY_MULTIPLIER, FormatPlayObjectOptions, InternalConfig } from "../common/infrastructure/Atomic.js";
88import { DeezerSourceConfig } from "../common/infrastructure/config/source/deezer.js";
99-import { parseRetryAfterSecsFromObj, readJson, sleep, sortByOldestPlayDate, writeFile, } from "../utils.js";
99+import { parseRetryAfterSecsFromObj, sleep, sortByOldestPlayDate, writeFile, } from "../utils.js";
1010+import { readJson } from '../utils/DataUtils.js';
1011import { joinedUrl } from "../utils/NetworkUtils.js";
1112import AbstractSource, { RecentlyPlayedOptions } from "./AbstractSource.js";
1213···9596 this.logger.warn('This Source is DEPRECATED! Deezer has dropped support official API support. New apps cannot be created and existing apps are not guaranteed to continue working. Refer to the MS documentation for a new Deezer Source implementation.');
96979798 try {
9898- const credFile = await readJson(this.workingCredsPath, {throwOnNotFound: false});
9999+ const credFile = await readJson(this.workingCredsPath, {throwOnNotFound: false, interpolateEnvs: false});
99100 if(credFile !== undefined) {
100101 this.config.data.accessToken = credFile.accessToken;
101102 } else {
+4-3
src/backend/sources/ScrobbleSources.ts
···3434import { WebScrobblerSourceConfig } from "../common/infrastructure/config/source/webscrobbler.js";
3535import { YTMusicData, YTMusicSourceConfig } from "../common/infrastructure/config/source/ytmusic.js";
3636import { WildcardEmitter } from "../common/WildcardEmitter.js";
3737-import { parseBool, readJson } from "../utils.js";
3737+import { parseBool } from "../utils.js";
3838+import { readJson } from '../utils/DataUtils.js';
3839import { validateJson } from "../utils/ValidationUtils.js";
3940import AbstractSource from "./AbstractSource.js";
4041import { AzuracastSource } from "./AzuracastSource.js";
···270271271272 let configFile;
272273 try {
273273- configFile = await readJson(`${this.internalConfig.configDir}/config.json`, {throwOnNotFound: false});
274274+ configFile = await readJson(`${this.internalConfig.configDir}/config.json`, {throwOnNotFound: false, logger: childLogger(this.logger, `Secrets`)});
274275 } catch (e) {
275276 throw new Error('config.json could not be parsed');
276277 }
···711712 }
712713 let rawSourceConfigs;
713714 try {
714714- rawSourceConfigs = await readJson(`${this.internalConfig.configDir}/${sourceType}.json`, {throwOnNotFound: false});
715715+ rawSourceConfigs = await readJson(`${this.internalConfig.configDir}/${sourceType}.json`, {throwOnNotFound: false, logger: childLogger(this.logger, `${sourceType} Secrets`)});
715716 } catch (e) {
716717 const errMsg = `${sourceType}.json config file could not be parsed`;
717718 this.emitter.emit('error', errMsg);
+2-2
src/backend/sources/SpotifySource.ts
···1919import { SpotifySourceConfig } from "../common/infrastructure/config/source/spotify.js";
2020import {
2121 parseRetryAfterSecsFromObj,
2222- readJson,
2322 sleep,
2423 sortByOldestPlayDate,
2524 writeFile,
2625} from "../utils.js";
2626+import { readJson } from '../utils/DataUtils.js';
2727import { findCauseByFunc } from "../utils/ErrorUtils.js";
2828import { joinedUrl } from "../utils/NetworkUtils.js";
2929import { RecentlyPlayedOptions } from "./AbstractSource.js";
···219219220220 let spotifyCreds = {};
221221 try {
222222- spotifyCreds = await readJson(this.workingCredsPath, {throwOnNotFound: false}) as any;
222222+ spotifyCreds = await readJson(this.workingCredsPath, {throwOnNotFound: false, interpolateEnvs: false}) as any;
223223 } catch (e) {
224224 this.logger.warn('Current spotify credentials file exists but could not be parsed', { path: this.workingCredsPath });
225225 }
+1-1
src/backend/tests/utils/strings.test.ts
···33import {
44 compareNormalizedStrings,
55 normalizeStr,
66- replaceInterpolatedValues,
76} from "../../utils/StringUtils.js";
77+import { replaceInterpolatedValues } from "../../utils/DataUtils.js";
88import { splitByFirstFound } from '../../../core/StringUtils.js';
99import { noCasePropObj } from '../../utils/DataUtils.js';
1010
-19
src/backend/utils.ts
···55import utc from 'dayjs/plugin/utc.js';
66import { Request } from "express";
77import { accessSync, constants, promises } from "fs";
88-import JSON5 from 'json5';
98// https://github.com/jfromaniello/url-join#in-nodejs
109import pathUtil from "path";
1110import { TimeoutError, WebapiError } from "spotify-web-api-node/src/response-error.js";
···25242625//const { default: Ajv } = AjvNS;
2726dayjs.extend(utc);
2828-2929-export async function readJson(this: any, path: any, {throwOnNotFound = true} = {}) {
3030- try {
3131- await promises.access(path, constants.R_OK);
3232- const data = await promises.readFile(path);
3333- return JSON5.parse(data as unknown as string);
3434- } catch (e) {
3535- const {code} = e;
3636- if (code === 'ENOENT') {
3737- if (throwOnNotFound) {
3838- throw new Error(`No file found at given path: ${path}`, {cause: e});
3939- } else {
4040- return;
4141- }
4242- }
4343- throw new Error(`Encountered error while parsing file: ${path}`, {cause: e})
4444- }
4545-}
46274728export async function readText(path: any) {
4829 await promises.access(path, constants.R_OK);