Compare commits

...
Author SHA1 Message Date
FoxxMD 33d64b240e test: Add atproto identifier 2026-07-10 23:44:54 +00:00
FoxxMD 642af13f3c fix(ui): fix shiki instance creation 2026-07-10 21:26:51 +00:00
FoxxMD 4146b159bd feat(ui): Component list container max width based on selected grid width 2026-07-10 21:11:13 +00:00
FoxxMD 3a3a97132d fix jellyfin import? 2026-07-10 21:03:06 +00:00
FoxxMD 04a5b91694 feat(ui): Implement grid for desktop layout
Allow user-selected max grid width on non-mobile breakpoints

#500
2026-07-10 20:57:03 +00:00
FoxxMD 945f494a2e fix: top-level type import syntax
see eslint.config.js comments
2026-07-10 16:47:38 +00:00
FoxxMD 4b09909b33 update cacheable for per-operation ttl 2026-07-10 15:17:01 +00:00
FoxxMD a5a1365b72 chore: remove tsx from mocha extension 2026-07-10 15:16:42 +00:00
FoxxMD 6bc618c481 always cache mb url so we can log to transform input 2026-07-10 15:16:31 +00:00
FoxxMD 85d1a0e648 chore: fix code styling in musicbrainz transformer 2026-07-10 15:15:57 +00:00
FoxxMD 1ae45c6060 add npm script for generating esbuild bundle metadata 2026-07-10 13:34:15 +00:00
FoxxMD 7daa43a883 tree-shake shiki for chakra usage 2026-07-10 13:34:15 +00:00
FoxxMD f8501b2a2e chore: Remove tsx usage from vscode launch profiles 2026-07-10 13:34:15 +00:00
Matt Foxx 14c35edadf Merge pull request #633 from FoxxMD/node-ts-native
feat: Migrate to native node runtime everywhere
2026-07-09 16:25:27 -04:00
273 changed files with 1296 additions and 1172 deletions
+5 -20
View File
@@ -20,7 +20,7 @@
"request": "launch",
// Debug app in VSCode
"program": "${workspaceFolder}/src/backend/index.ts",
"runtimeExecutable": "${workspaceFolder}/node_modules/.bin/tsx",
"runtimeExecutable": "node",
"console": "integratedTerminal",
"internalConsoleOptions": "neverOpen",
"skipFiles": [
@@ -35,7 +35,7 @@
"request": "launch",
// Debug app in VSCode
"program": "${workspaceFolder}/src/backend/index.ts",
"runtimeExecutable": "${workspaceFolder}/node_modules/.bin/tsx",
"runtimeExecutable": "node",
"console": "integratedTerminal",
"envFile": "${workspaceFolder}/.env",
"env": {
@@ -48,28 +48,13 @@
"${workspaceFolder}/node_modules/**",
],
},
{
"name": "tsx",
"type": "node",
"request": "launch",
// Debug current file in VSCode
"program": "${file}",
"runtimeExecutable": "${workspaceFolder}/node_modules/.bin/tsx",
"console": "integratedTerminal",
"internalConsoleOptions": "neverOpen",
"skipFiles": [
"<node_internals>/**",
// Ignore all dependencies (optional)
"${workspaceFolder}/node_modules/**",
],
},
{
"name": "schema",
"type": "node",
"request": "launch",
// Debug app in VSCode
"program": "${workspaceFolder}/src/backend/utils/SchemaStaticUtil.ts",
"runtimeExecutable": "${workspaceFolder}/node_modules/.bin/tsx",
"runtimeExecutable": "node",
"console": "integratedTerminal",
"internalConsoleOptions": "neverOpen",
"skipFiles": [
@@ -96,7 +81,7 @@
"--recursive",
"${workspaceFolder}/src/backend/tests/**/*.test.ts"
],
"runtimeExecutable": "${workspaceFolder}/node_modules/.bin/tsx",
"runtimeExecutable": "node",
"internalConsoleOptions": "openOnSessionStart",
"name": "Mocha Tests",
"program": "${workspaceFolder}/node_modules/mocha/bin/_mocha",
@@ -120,7 +105,7 @@
"--config", "${workspaceRoot}/.mocharc.json",
"${file}"
],
"runtimeExecutable": "${workspaceFolder}/node_modules/.bin/tsx",
"runtimeExecutable": "node",
"internalConsoleOptions": "openOnSessionStart",
"name": "Mocha Test on File",
"program": "${workspaceFolder}/node_modules/mocha/bin/_mocha",
-1
View File
@@ -1,5 +1,4 @@
{
"mochaExplorer.require": "tsx/esm",
"mochaExplorer.timeout": 1200000,
"mochaExplorer.exit": true,
"search.exclude": {
+40
View File
@@ -74,6 +74,36 @@ export default defineConfig([
},
rules: {
...defaultRules,
// https://typescript-eslint.io/rules/consistent-type-imports/#comparison-with-importsnotusedasvalues--verbatimmodulesyntax
//
// when using tsconfig compiler verbatimModuleSyntax and EX import {type Foo, type Bar} from 'a';
// true => typescript will *still* import a module if all types are inline
// false => typescript will erase the entire module import
//
// we need to use verbatimModuleSyntax: true for nodejs type stripping compatibility so
// its important that we use top-level type imports so we don't accidentally import server-side modules into frontend
// but can still use types where necessary
//
// this rule *should* do this...it does detect imports that are typed but not explicitly declared
// but its not moving inline -> top-level
"@typescript-eslint/consistent-type-imports": [
"error",
{
prefer: 'type-imports',
fixStyle: "separate-type-imports"
}
],
// however, import/consistent-type-specifier-style from eslint-plugin-import *does* move inline => top-level
// but it does not yet support eslint10 :(
//
// TODO eventually add this once plugin-import supports eslint10
// https://github.com/import-js/eslint-plugin-import
// https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/consistent-type-specifier-style.md
// -- this enforces that type-only imports are fixed to top-level type imports IE
// import {type Foo, type Bar} from 'a'; => import type { Foo, Bar} from 'a';
// "import/consistent-type-specifier-style": [
// "error", "prefer-top-level-if-only-type-imports"
// ]
},
extends: [
tsEslint.configs.recommended,
@@ -148,7 +178,9 @@ export default defineConfig([
{ type: 'frontend', mode: 'file', pattern: 'src/client/**/*' },
{ type: 'config', mode: 'file', pattern: 'config/*.example' },
{ type: 'core', mode: 'file', pattern: ['src/core/!(tests)/**','src/core/!(tests)'] },
{ type: 'core-tests', mode: 'file', pattern: ['src/core/tests/**'] },
{ type: 'backend', mode: 'file', pattern: 'src/backend/**/*' },
{ type: 'stories', mode: 'file', pattern: ['src/stories/**/*', '.storybook/**'] },
],
// So it understands TS path aliases when resolving imports
'import/resolver': {
@@ -173,6 +205,14 @@ export default defineConfig([
from: 'backend',
allow: ['backend', 'core', 'config'], // backend can use itself + core
},
{
from: 'stories',
allow: ['stories', 'core', 'frontend', 'core-tests'], // backend can use itself + core
},
{
from: 'core-tests',
allow: ['core', 'core-tests'], // backend can use itself + core
},
],
},
],
+41 -27
View File
@@ -42,7 +42,7 @@
"avahi-browse": "^1.1.4",
"better-sse": "^0.8.0",
"body-parser": "^2.2.2",
"cacheable": "^1.10.4",
"cacheable": "^2.5.0",
"castv2": "^0.1.10",
"clone": "^2.1.2",
"common-tags": "^1.8.2",
@@ -70,7 +70,7 @@
"json-diff-ts": "^5.0.0-alpha.2",
"json5": "^2.2.3",
"jsondiffpatch": "^0.7.3",
"keyv": "^5.5.0",
"keyv": "^5.6.0",
"kodi-api": "^0.2.1",
"lastfm-ts-api": "^2.6.0",
"merge-error-cause": "^5.0.2",
@@ -204,6 +204,7 @@
"ts-json-schema-generator": "^2.3.0",
"typescript": "^6.0.3",
"typescript-eslint": "^8.59.3",
"usehooks-ts": "^3.1.1",
"vite": "^8.0.12",
"with-local-tmp-dir": "^7.0.1"
},
@@ -982,21 +983,21 @@
"license": "(Apache-2.0 AND BSD-3-Clause)"
},
"node_modules/@cacheable/memory": {
"version": "2.0.9",
"resolved": "https://registry.npmjs.org/@cacheable/memory/-/memory-2.0.9.tgz",
"integrity": "sha512-HdMx6DoGywB30vacDbBsITbIX4pgFqj1zsrV58jZBUw3klzkNoXhj7qOqAgledhxG7YZI5rBSJg7Zp8/VG0DuA==",
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/@cacheable/memory/-/memory-2.2.0.tgz",
"integrity": "sha512-CTLKqLItRCEixEAewD3/j9DB3/o96gpTPD4eJ1v+DGOlxZRZncRQkGYqqnAGCscYd6RNeXfGeiuCphsPtqyIfQ==",
"license": "MIT",
"dependencies": {
"@cacheable/utils": "^2.4.1",
"@cacheable/utils": "^2.5.0",
"@keyv/bigmap": "^1.3.1",
"hookified": "^1.15.1",
"keyv": "^5.6.0"
}
},
"node_modules/@cacheable/utils": {
"version": "2.4.1",
"resolved": "https://registry.npmjs.org/@cacheable/utils/-/utils-2.4.1.tgz",
"integrity": "sha512-eiFgzCbIneyMlLOmNG4g9xzF7Hv3Mga4LjxjcSC/ues6VYq2+gUbQI8JqNuw/ZM8tJIeIaBGpswAsqV2V7ApgA==",
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/@cacheable/utils/-/utils-2.5.0.tgz",
"integrity": "sha512-buipgOVDkkPXNR5+xBpDw7Zk2n1EvU7qBJCNUcL7rhQ//kfpOXPAvQ511Os0vpLYJ1pZnvudNytkQt2hst3wqA==",
"license": "MIT",
"dependencies": {
"hashery": "^1.5.1",
@@ -8334,13 +8335,16 @@
}
},
"node_modules/cacheable": {
"version": "1.10.4",
"resolved": "https://registry.npmjs.org/cacheable/-/cacheable-1.10.4.tgz",
"integrity": "sha512-Gd7ccIUkZ9TE2odLQVS+PDjIvQCdJKUlLdJRVvZu0aipj07Qfx+XIej7hhDrKGGoIxV5m5fT/kOJNJPQhQneRg==",
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/cacheable/-/cacheable-2.5.0.tgz",
"integrity": "sha512-60cyAOytib/OzBw1JNSoSV/boK1AtHryDIjvVBk7XbN4ugfkM3+Sry7fEjNgPMGgOjuaZPAp8ruZ0Cxafwyq9g==",
"license": "MIT",
"dependencies": {
"hookified": "^1.11.0",
"keyv": "^5.5.0"
"@cacheable/memory": "^2.2.0",
"@cacheable/utils": "^2.5.0",
"hookified": "^1.15.0",
"keyv": "^5.6.0",
"qified": "^0.10.1"
}
},
"node_modules/cacheable-lookup": {
@@ -11566,19 +11570,6 @@
"hookified": "^1.15.0"
}
},
"node_modules/flat-cache/node_modules/cacheable": {
"version": "2.3.5",
"resolved": "https://registry.npmjs.org/cacheable/-/cacheable-2.3.5.tgz",
"integrity": "sha512-EQfaKe09tl615iNvq/TBRWTFf1AKJNXYQSsMx0Z3EI0nA+pVsVPS8wJhnRlkbdacKPh1d0qVIhwTc2zsQNFEEg==",
"license": "MIT",
"dependencies": {
"@cacheable/memory": "^2.0.8",
"@cacheable/utils": "^2.4.1",
"hookified": "^1.15.0",
"keyv": "^5.6.0",
"qified": "^0.10.1"
}
},
"node_modules/flatted": {
"version": "3.4.2",
"resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz",
@@ -13751,6 +13742,13 @@
"integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==",
"license": "MIT"
},
"node_modules/lodash.debounce": {
"version": "4.0.8",
"resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
"integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==",
"dev": true,
"license": "MIT"
},
"node_modules/lodash.defaults": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz",
@@ -19171,6 +19169,22 @@
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
}
},
"node_modules/usehooks-ts": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/usehooks-ts/-/usehooks-ts-3.1.1.tgz",
"integrity": "sha512-I4diPp9Cq6ieSUH2wu+fDAVQO43xwtulo+fKEidHUwZPnYImbtkTjzIJYcDcJqxgmX31GVqNFURodvcgHcW0pA==",
"dev": true,
"license": "MIT",
"dependencies": {
"lodash.debounce": "^4.0.8"
},
"engines": {
"node": ">=16.15.0"
},
"peerDependencies": {
"react": "^16.8.0 || ^17 || ^18 || ^19 || ^19.0.0-rc"
}
},
"node_modules/util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+5 -3
View File
@@ -25,7 +25,8 @@
"cliff": "git-cliff --unreleased",
"storybook": "storybook dev -p 6006",
"build-storybook": "storybook build",
"atproto:lex:tealfm": "npm exec -- lex-cli pull -c src/backend/common/vendor/teal/lex.config.ts && npm exec -- lex-cli generate -c src/backend/common/vendor/teal/lex.config.ts"
"atproto:lex:tealfm": "npm exec -- lex-cli pull -c src/backend/common/vendor/teal/lex.config.ts && npm exec -- lex-cli generate -c src/backend/common/vendor/teal/lex.config.ts",
"frontend:analyze": "npx esbuild src/client/index-next.tsx --bundle --platform=node --metafile=meta.json --outfile=/dev/null"
},
"exports": {
".": {
@@ -81,7 +82,7 @@
"avahi-browse": "^1.1.4",
"better-sse": "^0.8.0",
"body-parser": "^2.2.2",
"cacheable": "^1.10.4",
"cacheable": "^2.5.0",
"castv2": "^0.1.10",
"clone": "^2.1.2",
"common-tags": "^1.8.2",
@@ -109,7 +110,7 @@
"json-diff-ts": "^5.0.0-alpha.2",
"json5": "^2.2.3",
"jsondiffpatch": "^0.7.3",
"keyv": "^5.5.0",
"keyv": "^5.6.0",
"kodi-api": "^0.2.1",
"lastfm-ts-api": "^2.6.0",
"merge-error-cause": "^5.0.2",
@@ -243,6 +244,7 @@
"ts-json-schema-generator": "^2.3.0",
"typescript": "^6.0.3",
"typescript-eslint": "^8.59.3",
"usehooks-ts": "^3.1.1",
"vite": "^8.0.12",
"with-local-tmp-dir": "^7.0.1"
},
+12 -12
View File
@@ -2,11 +2,11 @@ import { childLogger, type Logger } from "@foxxmd/logging";
import {
cacheFunctions,
} from "@foxxmd/regex-buddy-core";
import EventEmitter from "events";
import { type ComponentType, type LifecycleInput, type LifecycleStep, type PlayData, type PlayObject } from "../../core/Atomic.ts";
import type EventEmitter from "events";
import type {ComponentType, LifecycleInput, LifecycleStep, PlayData, PlayObject} from "../../core/Atomic.ts";
import { buildTrackString } from "../../core/StringUtils.ts";
import { type CommonClientConfig } from "./infrastructure/config/client/index.ts";
import { type CommonSourceConfig } from "./infrastructure/config/source/index.ts";
import type {CommonClientConfig} from "./infrastructure/config/client/index.ts";
import type {CommonSourceConfig} from "./infrastructure/config/source/index.ts";
import { mergeSimpleError, SimpleError, SkipTransformStageError, StagePrerequisiteError, StageTransformError, TransformRulesError } from "./errors/MSErrors.ts";
import {
FLOW_CONTROL_TERM,
@@ -16,29 +16,29 @@ import {
type TransformHook
} from "../../core/Transform.ts";
import AbstractInitializable from "./AbstractInitializable.ts";
import TransformerManager from "./transforms/TransformerManager.ts";
import type TransformerManager from "./transforms/TransformerManager.ts";
import { getRoot } from "../ioc.ts";
import { nanoid } from "nanoid";
import { isDebugMode } from "../utils.ts";
import { findCauseByFunc, findCauseByReference } from "../utils/ErrorUtils.ts";
import { hashObject, parseArrayFromMaybeString } from "../utils/StringUtils.ts";
import { playContentInvariantTransform } from "../utils/PlayComparisonUtils.ts";
import { MSCache } from "./Cache.ts";
import type { MSCache } from "./Cache.ts";
import { diffObjects, diffObjectsConsoleOutput, patchObject } from "../../core/DataUtils.ts";
import clone from "clone";
import { loggerNoop } from "./MaybeLogger.ts";
import { objectsEqual } from "../utils/DataUtils.ts";
import { type RetentionOptions } from "./infrastructure/config/database.ts";
import type {RetentionOptions} from "./infrastructure/config/database.ts";
import { getRetentionCompactAfterFromEnv, getRetentionDeleteAfterFromEnv, isCompactableProperty, parseRetentionOptions, parseRetentionOptionsDurations } from "./database/Database.ts";
import { type DbConcrete } from "./database/drizzle/drizzleUtils.ts";
import { type ComponentSelect } from "./database/drizzle/drizzleTypes.ts";
import type {DbConcrete} from "./database/drizzle/drizzleUtils.ts";
import type {ComponentSelect} from "./database/drizzle/drizzleTypes.ts";
import { DrizzlePlayRepository } from "./database/drizzle/repositories/PlayRepository.ts";
import { type ClientType } from "./infrastructure/config/client/clients.ts";
import { type SourceType } from "./infrastructure/config/source/sources.ts";
import type {ClientType} from "../../core/Atomic.ts";
import type {SourceType} from "../../core/Atomic.ts";
import { DrizzleComponentRepository } from "./database/drizzle/repositories/ComponentRepository.ts";
import dayjs from "dayjs";
import { COMPONENT_STATE, type ComponentCommonApi, type ComponentCommonApiJson, type ComponentState, type PlayApiCommonDetailed } from "../../core/Api.ts";
import { type WebhookPayload } from "./infrastructure/config/health/webhooks.ts";
import type {WebhookPayload} from "./infrastructure/config/health/webhooks.ts";
import type { MarkRequired } from "ts-essentials";
import { serializeError } from "serialize-error";
+2 -2
View File
@@ -1,8 +1,8 @@
import { type Logger } from "@foxxmd/logging";
import type { Logger } from "@foxxmd/logging";
import {truncateStringToLength } from "../../core/StringUtils.ts";
import { hasNodeNetworkException } from "./errors/NodeErrors.ts";
import { hasUpstreamError } from "./errors/UpstreamError.ts";
import { type WebhookPayload } from "./infrastructure/config/health/webhooks.ts";
import type {WebhookPayload} from "./infrastructure/config/health/webhooks.ts";
import { AuthCheckError, BuildDataError, ConnectionCheckError, ParseCacheError, PostInitError, StageError } from "./errors/MSErrors.ts";
import { messageWithCausesTruncatedDefault } from "../../core/ErrorUtils.ts";
import { spawn } from 'abort-controller-x';
+2 -1
View File
@@ -19,7 +19,8 @@ import { Typeson } from 'typeson';
import { builtin } from 'typeson-registry';
import { loggerNoop } from './MaybeLogger.ts';
const configDir = process.env.CONFIG_DIR || path.resolve(projectDir, `./config`);
import prom, { Gauge } from 'prom-client';
import type { Gauge } from 'prom-client';
import prom from 'prom-client';
import { nonEmptyStringOrDefault } from '../../core/StringUtils.ts';
dayjs.extend(utc)
+1 -1
View File
@@ -1,4 +1,4 @@
import { type Logger } from "@foxxmd/logging";
import type { Logger } from "@foxxmd/logging";
export class MaybeLogger {
+2 -2
View File
@@ -3,8 +3,8 @@ import * as path from 'path';
import { childLogger, type Logger } from '@foxxmd/logging';
import { loggerNoop } from '../MaybeLogger.ts';
import { COMPACTABLE, type CompactableProperty, DEFAULT_RETENTION_COMPACT_AFTER, DEFAULT_RETENTION_DELETE_AFTER, type RetentionConfigValue, type RetentionOption, type RetentionValue, type RetentionValueUnparsed } from '../infrastructure/config/database.ts';
import { type DurationValue } from '../infrastructure/Atomic.ts';
import { type Duration } from 'dayjs/plugin/duration.js';
import type {DurationValue} from '../infrastructure/Atomic.ts';
import type {Duration} from 'dayjs/plugin/duration.js';
import dayjs from 'dayjs';
import { parseDurationFromDurationValue } from '../../utils/TimeUtils.ts';
import assert from 'node:assert';
@@ -1,9 +1,9 @@
import type { SqliteDatabase, Migration } from 'sqlite-up';
import { type MigrateBaseContext } from '../appMigrator.ts';
import type {MigrateBaseContext} from '../appMigrator.ts';
import { plays as drizzlePlays } from '../drizzle/schema/schema.ts';
import clone from 'clone';
import { eq } from 'drizzle-orm';
import { type PlayLifecycle, type PlayObject } from '../../../../core/Atomic.ts';
import type {PlayLifecycle, PlayObject} from '../../../../core/Atomic.ts';
export const up: Migration<MigrateBaseContext>['up'] = async (db: SqliteDatabase, ctx: MigrateBaseContext): Promise<void> => {
+2 -2
View File
@@ -1,10 +1,10 @@
import { type DbConcrete } from "./drizzle/drizzleUtils.ts";
import type {DbConcrete} from "./drizzle/drizzleUtils.ts";
import { loggerNoop } from "../MaybeLogger.ts";
import * as path from 'path';
import { childLogger, type Logger } from "@foxxmd/logging";
import { projectDir } from "../index.ts";
import { Migrator } from 'sqlite-up';
import { type MigrationStatus } from "../infrastructure/Atomic.ts";
import type {MigrationStatus} from "../infrastructure/Atomic.ts";
export interface MigrateBaseContext {
db: DbConcrete
@@ -1,6 +1,6 @@
import { type DBQueryConfig, type DBQueryConfigWith, type KnownKeysOnly, type RelationFieldsFilterInternals, type BuildQueryResult, type RelationsFilter } from "drizzle-orm";
import { components, componentMigrations, playInputs, plays, queueStates, relations, playsHistorical } from "./schema/schema.ts";
import {type TSchema, type TableName } from "./schema/schema.ts";
import type {DBQueryConfig, DBQueryConfigWith, KnownKeysOnly, RelationFieldsFilterInternals, BuildQueryResult, RelationsFilter} from "drizzle-orm";
import type { components, componentMigrations, playInputs, plays, queueStates, relations, playsHistorical } from "./schema/schema.ts";
import type {TSchema, TableName} from "./schema/schema.ts";
export type ComponentNew = typeof components.$inferInsert;
@@ -1,6 +1,6 @@
import { drizzle } from 'drizzle-orm/node-sqlite';
import { migrate } from 'drizzle-orm/node-sqlite/migrator';
import { BaseSQLiteDatabase } from "drizzle-orm/sqlite-core";
import type { BaseSQLiteDatabase } from "drizzle-orm/sqlite-core";
import { sql as dsl, type Logger as DrizzleLogger } from 'drizzle-orm';
import * as fs from 'fs/promises';
import * as path from 'path';
@@ -12,7 +12,7 @@ import { projectDir } from '../../index.ts';
import { relations } from './schema/schema.ts';
import { addToContext, executeQuery } from './logContext.ts';
import { migrateApp, getAppMigrationStatus } from '../appMigrator.ts';
import { type MigrationStatus } from '../../infrastructure/Atomic.ts';
import type {MigrationStatus} from '../../infrastructure/Atomic.ts';
export async function getDbMigrationStatus(dbVal: string | DbConcrete, opts: {logger?: Logger, migrationsFolder?: string} = {}): Promise<MigrationStatus> {
const {
@@ -1,8 +1,8 @@
import assert from "node:assert";
import { type PlayHistoricalNew, type PlayHistoricalSelect, type PlayNew, type PlaySelect, type PlaySelectWithQueueStates } from "./drizzleTypes.ts";
import { type PlayInputNew } from "./drizzleTypes.ts";
import { type QueueStateNew } from "./drizzleTypes.ts";
import { type ComponentNew } from "./drizzleTypes.ts";
import type {PlayHistoricalNew, PlayHistoricalSelect, PlayNew, PlaySelect, PlaySelectWithQueueStates} from "./drizzleTypes.ts";
import type {PlayInputNew} from "./drizzleTypes.ts";
import type {QueueStateNew} from "./drizzleTypes.ts";
import type {ComponentNew} from "./drizzleTypes.ts";
import type { MarkOptional } from "ts-essentials";
import { CLIENT_DEAD_QUEUE, type DeadLetterScrobble, type ErrorLike, type PlayObject } from "../../../../core/Atomic.ts";
import dayjs from "dayjs";
@@ -1,4 +1,4 @@
import { type Logger } from '@foxxmd/logging'
import type { Logger } from '@foxxmd/logging'
import { AsyncLocalStorage } from 'async_hooks'
// based on https://numeric.substack.com/p/upgrading-drizzleorm-logging-with
@@ -1,13 +1,13 @@
import { childLogger, type Logger } from "@foxxmd/logging";
import { type DbConcrete } from "../drizzleUtils.ts";
import { type Dayjs } from "dayjs";
import type { DbConcrete } from "../drizzleUtils.ts";
import type { Dayjs } from "dayjs";
import { type RelationsFieldFilter, eq, inArray } from "drizzle-orm";
import { loggerNoop } from "../../../MaybeLogger.ts";
import { capitalize } from "../../../../../core/StringUtils.ts";
import { getConfigByTableName, type TableName } from "../schema/schema.ts";
import assert from 'node:assert';
import { Cacheable } from "cacheable";
import { type DateLike } from "../../../../../core/Atomic.ts";
import type { Cacheable } from "cacheable";
import type { DateLike } from "../../../../../core/Atomic.ts";
import type { CompareDateBetween, CompareDateSingle } from "../../../../../core/Api.ts";
export interface DrizzleRepositoryOpts {
@@ -1,9 +1,9 @@
import { DrizzleBaseRepository, type DrizzleRepositoryOpts } from "./BaseRepository.ts";
import { type DbConcrete } from "../drizzleUtils.ts";
import { type ComponentSelect, type FindWhere } from "../drizzleTypes.ts";
import type {DbConcrete} from "../drizzleUtils.ts";
import type {ComponentSelect, FindWhere} from "../drizzleTypes.ts";
import { components } from "../schema/schema.ts";
import { generateComponentEntity } from "../entityUtils.ts";
import { type ComponentType } from "../../../../../core/Atomic.ts";
import type {ComponentType} from "../../../../../core/Atomic.ts";
export class DrizzleComponentRepository extends DrizzleBaseRepository<'components'> {
@@ -2,17 +2,17 @@ import { type DbConcrete, runTransaction } from "../drizzleUtils.ts";
import { type PlayObject, TA_DEFAULT_ACCURACY, type TemporalAccuracy } from "../../../../../core/Atomic.ts";
import { generatePlayEntity, hydratePlaySelect, type PlayHydateOptions, type PlayHistoricalEntityOpts } from "../entityUtils.ts";
import { plays, playsHistorical } from "../schema/schema.ts";
import { type FindWhere, type FindMany, type WhereClause, type PlayHistoricalSelect, type PlayHistoricalNew } from "../drizzleTypes.ts";;
import type {FindWhere, FindMany, WhereClause, PlayHistoricalSelect, PlayHistoricalNew} from "../drizzleTypes.ts";;
import type { MarkOptional } from "ts-essentials";
import { removeUndefinedKeys } from '../../../../../core/DataUtils.ts';
import { type Dayjs } from "dayjs";
import type {Dayjs} from "dayjs";
import { inArray, sql } from "drizzle-orm";
import { buildDateCompare, type CompareDateOp, type ComponentConstrainedRepoOpts, DrizzleBaseRepository, type DrizzleRepositoryOpts } from "./BaseRepository.ts";
import { type PaginatedResponse } from "../../../../../core/Api.ts";
import type {PaginatedResponse} from "../../../../../core/Api.ts";
import { hashObject } from "../../../../utils/StringUtils.ts";
import { playContentBasicInvariantTransform, playMbidIdentifier } from "../../../../utils/PlayComparisonUtils.ts";
import { comparePlayTemporally, getTemporalAccuracyCloseVal, hasAcceptableTemporalAccuracy } from "../../../../utils/TimeUtils.ts";
import { type SourceType } from "../../../infrastructure/config/source/sources.ts";
import type {SourceType} from "../../../../../core/Atomic.ts";
import { getTemporallyCloseDateCompareOp } from "./PlayRepository.ts";
// https://github.com/drizzle-team/drizzle-orm/issues/695 may be useful for typing models with relations?
@@ -10,14 +10,14 @@ import { playContentBasicInvariantTransform, playMbidIdentifier } from "../../..
import { hashObject } from "../../../../utils/StringUtils.ts";
import { comparePlayTemporally, getTemporalAccuracyCloseVal, hasAcceptableTemporalAccuracy } from "../../../../utils/TimeUtils.ts";
import { type CompactableProperty, type RetentionOptions, retentionPlayTypes } from "../../../infrastructure/config/database.ts";
import { type SourceType } from "../../../infrastructure/config/source/sources.ts";
import { type FindMany, type FindWhere, type FindWith, type PlayInputNew, type PlayNew, type PlaySelect, type PlaySelectWithQueueStates, type PlayWith, type QueueStateSelect, type WhereClause } from "../drizzleTypes.ts";
import type {SourceType} from "../../../../../core/Atomic.ts";
import type {FindMany, FindWhere, FindWith, PlayInputNew, PlayNew, PlaySelect, PlaySelectWithQueueStates, PlayWith, QueueStateSelect, WhereClause} from "../drizzleTypes.ts";
import { type DbConcrete, runTransaction } from "../drizzleUtils.ts";
import { generateInputEntity, generatePlayEntity, hydratePlaySelect, type PlayEntityOpts, type PlayHydateOptions } from "../entityUtils.ts";
import { playInputs, plays, relations } from "../schema/schema.ts";
import { buildDateCompare, type CompareDateOp, type ComponentConstrainedRepoOpts, DrizzleBaseRepository, type DrizzleRepositoryOpts } from "./BaseRepository.ts";
import { type PaginatedResponse } from "../../../../../core/Api.ts";
import { type PaginatedQueryResponse } from "../../../../../core/Api.ts";
import type {PaginatedResponse} from "../../../../../core/Api.ts";
import type {PaginatedQueryResponse} from "../../../../../core/Api.ts";
;
// https://github.com/drizzle-team/drizzle-orm/issues/695 may be useful for typing models with relations?
@@ -1,7 +1,7 @@
import { eq, and, lte, inArray } from "drizzle-orm";
import { DrizzleBaseRepository, type DrizzleRepositoryOpts } from "./BaseRepository.ts";
import { type DbConcrete } from "../drizzleUtils.ts";
import { type QueueStateSelect } from "../drizzleTypes.ts";
import type {DbConcrete} from "../drizzleUtils.ts";
import type {QueueStateSelect} from "../drizzleTypes.ts";
import { queueStates } from "../schema/schema.ts";
import { CLIENT_DEAD_QUEUE } from "../../../../../core/Atomic.ts";
export class DrizzleQueueRepository extends DrizzleBaseRepository<'queueStates'> {
@@ -1,10 +1,10 @@
import { integer, sqliteTable, text, index, uniqueIndex, customType, type AnySQLiteColumn } from "drizzle-orm/sqlite-core";
import { defineRelations } from 'drizzle-orm';
import dayjs, { type Dayjs } from "dayjs";
import { type ErrorLike, type PlayObject } from "../../../../../core/Atomic.ts";
import { COMPONENT_TYPE_CLIENT, COMPONENT_TYPE_SOURCE, type ErrorLike, type PlayObject } from "../../../../../core/Atomic.ts";
import { asPlayCheap } from "../../../../../core/PlayMarshalUtils.ts";
import { type ExternalMetadataTerm, type PlayTransformPartsConfig, type SearchAndReplaceTerm } from "../../../../../core/Transform.ts";
import { type JobRangeCount, type JobRangeTime } from "../../../infrastructure/Job.ts";
import type {ExternalMetadataTerm, PlayTransformPartsConfig, SearchAndReplaceTerm} from "../../../../../core/Transform.ts";
import type {JobRangeCount, JobRangeTime} from "../../../infrastructure/Job.ts";
import { serializeError, deserializeError } from "serialize-error";
import { generatePlayUid } from "../../../../../core/StringUtils.ts";
@@ -165,7 +165,7 @@ export const components = sqliteTable("components", {
id: integer({ mode: 'number' }).primaryKey(),
// user-provided id
uid: text({ length: 200 }).notNull(),
mode: text({enum: ['source','client']}).notNull(),
mode: text({enum: [COMPONENT_TYPE_SOURCE,COMPONENT_TYPE_CLIENT]}).notNull(),
// spotify, lastfm, etc...
type: text({length: 50}).notNull(),
// vanity display name
+1 -1
View File
@@ -1,4 +1,4 @@
import { type ResponseError } from "superagent";
import type {ResponseError} from "superagent";
export const isSuperAgentResponseError = (e: any): e is ResponseError => {
return typeof e === 'object'
+1 -1
View File
@@ -3,7 +3,7 @@ import mergeErrorCause from 'merge-error-cause';
import { findCauseByFunc, isAbortReasonErrorLike } from "../../utils/ErrorUtils.ts";
import { UpstreamError, type UpstreamErrorOptions } from "./UpstreamError.ts";
import {addKnownErrorConstructor, serializeError} from 'serialize-error';
import { type LifecycleInput } from "../../../core/Atomic.ts";
import type {LifecycleInput} from "../../../core/Atomic.ts";
export abstract class NamedError extends Error {
public abstract name: string;
+1 -1
View File
@@ -1,4 +1,4 @@
import { Response } from 'superagent';
import type { Response } from 'superagent';
import { findCauseByFunc } from "../../utils/ErrorUtils.ts";
import { addKnownErrorConstructor } from 'serialize-error';
+7 -26
View File
@@ -1,13 +1,13 @@
import { type Logger, type LogDataPretty } from '@foxxmd/logging';
import type { Logger, LogDataPretty } from '@foxxmd/logging';
import type { Dayjs, ManipulateType } from "dayjs";
import { type Request, type Response } from "express";
import type { Request, Response } from "express";
import type { NextFunction, ParamsDictionary, Query } from "express-serve-static-core";
import { FixedSizeList } from 'fixed-size-list';
import type { FixedSizeList } from 'fixed-size-list';
import { type DeviceId, type ErrorLike, isPlayObject, type PlayMeta, type PlayObject, type PlayObjectMinimal, type PlayPlatformId, type PlayUserId, type UnixTimestamp } from "../../../core/Atomic.ts";
import TupleMap from "../TupleMap.ts";
import { MusicBrainzApi } from 'musicbrainz-api';
import type { SourceType } from './config/source/sources.ts';
import { type ClientType, clientTypes } from './config/client/clients.ts';
import type TupleMap from "../TupleMap.ts";
import type { MusicBrainzApi } from 'musicbrainz-api';
import type { ReportedPlayerStatus, SourceType } from "../../../core/Atomic.ts";
import type { ClientType } from "../../../core/Atomic.ts";
import assert from 'assert';
export interface LeveledLogData extends LogDataPretty {
@@ -16,10 +16,6 @@ export interface LeveledLogData extends LogDataPretty {
export const lowGranularitySources: SourceType[] = ['subsonic', 'ytmusic'];
export const isClientType = (data: string): data is ClientType => {
return clientTypes.includes(data as ClientType);
}
export interface ComponentIdentifier {
type: SourceType | ClientType
name: string
@@ -55,21 +51,6 @@ export interface InternalConfig {
export type InternalConfigOptional = Omit<InternalConfig, 'logger'>
export type ReportedPlayerStatus = 'playing' | 'stopped' | 'paused' | 'unknown';
export const REPORTED_PLAYER_STATUSES = {
playing: 'playing' as ReportedPlayerStatus,
stopped: 'stopped' as ReportedPlayerStatus,
paused: 'paused' as ReportedPlayerStatus,
unknown: 'unknown' as ReportedPlayerStatus
}
export type CalculatedPlayerStatus = ReportedPlayerStatus | 'stale' | 'orphaned';
export const CALCULATED_PLAYER_STATUSES = {
...REPORTED_PLAYER_STATUSES,
stale: 'stale' as CalculatedPlayerStatus,
orphaned: 'orphaned' as CalculatedPlayerStatus,
}
export type ConfigureAsSource = 'source';
export type ConfigureAsClient = 'client';
export type ConfigureAs = ConfigureAsSource | ConfigureAsClient;
+1 -1
View File
@@ -1,4 +1,4 @@
import { type UnixTimestamp } from "../../../core/Atomic.ts"
import type {UnixTimestamp} from "../../../core/Atomic.ts";
export interface JobParameters {
/** maximum number of results to get for the entire job */
@@ -1,13 +1,13 @@
import { type LogOptions } from "@foxxmd/logging";
import { type ClientAIOConfig } from "./client/clients.ts";
import { type CommonClientOptions } from "./client/index.ts";
import { type RequestRetryOptions } from "./common.ts";
import { type WebhookConfig } from "./health/webhooks.ts";
import { type CommonSourceOptions, type SourceRetryOptions } from "./source/index.ts";
import { type SourceAIOConfig } from "./source/sources.ts";
import { type CacheConfigUser, type DurationValue } from "../Atomic.ts";
import { type TransformerCommonConfig } from "../../../../core/Atomic.ts";
import { type RetentionConfig } from "./database.ts";
import type { LogOptions } from "@foxxmd/logging";
import type { ClientAIOConfig } from "./client/clients.ts";
import type { CommonClientOptions } from "./client/index.ts";
import type { RequestRetryOptions } from "./common.ts";
import type { WebhookConfig } from "./health/webhooks.ts";
import type { CommonSourceOptions, SourceRetryOptions } from "./source/index.ts";
import type { SourceAIOConfig } from "./source/sources.ts";
import type { CacheConfigUser, DurationValue } from "../Atomic.ts";
import type { TransformerCommonConfig } from "../../../../core/Atomic.ts";
import type { RetentionConfig } from "./database.ts";
export interface SourceDefaults extends CommonSourceOptions {
@@ -1,4 +1,4 @@
import { type AtprotoDid } from "@atcute/lexicons/syntax";
import type {AtprotoDid} from "@atcute/lexicons/syntax";
export interface ATProtoUserIdentifierData {
/**
@@ -1,11 +1,11 @@
import { type KoitoClientAIOConfig, type KoitoClientConfig } from "./koito.ts";
import { type LastfmClientAIOConfig, type LastfmClientConfig } from "./lastfm.ts";
import { type ListenBrainzClientAIOConfig, type ListenBrainzClientConfig } from "./listenbrainz.ts";
import { type MalojaClientAIOConfig, type MalojaClientConfig } from "./maloja.ts";
import { type TealClientAIOConfig, type TealClientConfig } from "./tealfm.ts";
import { type RockSkyClientAIOConfig, type RockSkyClientConfig } from "./rocksky.ts";
import { type LibrefmClientConfig, type LibrefmClientAIOConfig } from "./librefm.ts";
import { type DiscordClientAIOConfig, type DiscordClientConfig } from "./discord.ts";
import type {KoitoClientAIOConfig, KoitoClientConfig} from "./koito.ts";
import type {LastfmClientAIOConfig, LastfmClientConfig} from "./lastfm.ts";
import type {ListenBrainzClientAIOConfig, ListenBrainzClientConfig} from "./listenbrainz.ts";
import type {MalojaClientAIOConfig, MalojaClientConfig} from "./maloja.ts";
import type {TealClientAIOConfig, TealClientConfig} from "./tealfm.ts";
import type {RockSkyClientAIOConfig, RockSkyClientConfig} from "./rocksky.ts";
import type {LibrefmClientConfig, LibrefmClientAIOConfig} from "./librefm.ts";
import type {DiscordClientAIOConfig, DiscordClientConfig} from "./discord.ts";
export type ClientConfig =
MalojaClientConfig
@@ -57,23 +57,3 @@ export const clientInterfaces = [
...atomicClientInterfaces
];
export type ClientType =
'maloja'
| 'lastfm'
| 'librefm'
| 'listenbrainz'
| 'koito'
| 'tealfm'
| 'rocksky'
| 'discord';
export const clientTypes: ClientType[] = [
'maloja',
'lastfm',
'librefm',
'listenbrainz',
'koito',
'tealfm',
'rocksky',
'discord'
];
@@ -1,5 +1,5 @@
import { type CommonClientConfig, type CommonClientData } from "./index.ts"
import { type ComponentType } from "../../../../../core/Atomic.ts"
import type {CommonClientConfig, CommonClientData} from "./index.ts";
import type {ComponentType} from "../../../../../core/Atomic.ts";
export interface DiscordData {
token?: string
@@ -1,7 +1,7 @@
import { type DurationValue } from "../../Atomic.ts";
import { type PlayTransformOptions } from "../../../../../core/Transform.ts";
import { type CommonConfig, type RequestRetryOptions } from "../common.ts";
import { type RetentionConfig } from "../database.ts";
import type {DurationValue} from "../../Atomic.ts";
import type {PlayTransformOptions} from "../../../../../core/Transform.ts";
import type {CommonConfig, RequestRetryOptions} from "../common.ts";
import type {RetentionConfig} from "../database.ts";
/**
* Scrobble matching (between new source track and existing client scrobbles) logging options. Used for debugging.
@@ -1,6 +1,6 @@
import { type ComponentType, type UnixTimestamp } from "../../../../../core/Atomic.ts"
import { type RequestRetryOptions } from "../common.ts"
import { type CommonClientConfig, type CommonClientData } from "./index.ts"
import type {ComponentType, UnixTimestamp} from "../../../../../core/Atomic.ts";
import type {RequestRetryOptions} from "../common.ts";
import type {CommonClientConfig, CommonClientData} from "./index.ts";
export interface ListensResponse {
items: ListenObjectResponse[]
@@ -1,5 +1,5 @@
import { type RequestRetryOptions } from "../common.ts";
import { type CommonClientConfig, type CommonClientData, type CommonClientOptions, type NowPlayingOptions } from "./index.ts";
import type {RequestRetryOptions} from "../common.ts";
import type {CommonClientConfig, CommonClientData, CommonClientOptions, NowPlayingOptions} from "./index.ts";
export interface LastfmData extends CommonClientData, RequestRetryOptions {
/**
@@ -1,6 +1,6 @@
import { type RequestRetryOptions } from "../common.ts";
import { type CommonClientConfig, type CommonClientData } from "./index.ts";
import { type LastfmClientOptions } from "./lastfm.ts";
import type {RequestRetryOptions} from "../common.ts";
import type {CommonClientConfig, CommonClientData} from "./index.ts";
import type {LastfmClientOptions} from "./lastfm.ts";
export interface LibrefmData extends CommonClientData, RequestRetryOptions {
/**
@@ -1,6 +1,6 @@
import { type ComponentType } from "../../../../../core/Atomic.ts";
import { type RequestRetryOptions } from "../common.ts";
import { type CommonClientConfig, type CommonClientData } from "./index.ts";
import type {ComponentType} from "../../../../../core/Atomic.ts";
import type {RequestRetryOptions} from "../common.ts";
import type {CommonClientConfig, CommonClientData} from "./index.ts";
export interface ListenBrainzData extends RequestRetryOptions{
/**
@@ -1,6 +1,6 @@
import { type ComponentType } from "../../../../../core/Atomic.ts";
import { type RequestRetryOptions } from "../common.ts";
import { type CommonClientConfig, type CommonClientData } from "./index.ts";
import type {ComponentType} from "../../../../../core/Atomic.ts";
import type {RequestRetryOptions} from "../common.ts";
import type {CommonClientConfig, CommonClientData} from "./index.ts";
export interface MalojaData extends RequestRetryOptions {
/**
@@ -1,5 +1,5 @@
import { type RequestRetryOptions } from "../common.ts";
import { type CommonClientConfig, type CommonClientData, type CommonClientOptions, type NowPlayingOptions } from "./index.ts";
import type {RequestRetryOptions} from "../common.ts";
import type {CommonClientConfig, CommonClientData, CommonClientOptions, NowPlayingOptions} from "./index.ts";
export interface RockSkyData extends RequestRetryOptions{
@@ -1,7 +1,7 @@
import { type ComponentType } from "../../../../../core/Atomic.ts"
import { type RequestRetryOptions } from "../common.ts"
import { type ATProtoAppData, type ATProtoUserIdentifierData } from "./atproto.ts"
import { type CommonClientConfig, type CommonClientData, type CommonClientOptions } from "./index.ts"
import type {ComponentType} from "../../../../../core/Atomic.ts";
import type {RequestRetryOptions} from "../common.ts";
import type {ATProtoAppData, ATProtoUserIdentifierData} from "./atproto.ts";
import type {CommonClientConfig, CommonClientData, CommonClientOptions} from "./index.ts";
export type TealData = RequestRetryOptions & ATProtoUserIdentifierData & Partial<ATProtoAppData> & {
/**
@@ -1,5 +1,5 @@
import { type Duration } from "dayjs/plugin/duration.js";
import { type DurationValue } from "../Atomic.ts";
import type {Duration} from "dayjs/plugin/duration.js";
import type {DurationValue} from "../Atomic.ts";
export type RetentionPlayType = 'failed' | 'completed' | 'duped';
export const retentionPlayTypes: RetentionPlayType[] = ['failed','completed','duped'];
@@ -1,4 +1,4 @@
import { type CommonSourceConfig, type CommonSourceData, type CommonSourceOptions, type ManualListeningOptions } from "./index.ts";
import type {CommonSourceConfig, CommonSourceData, CommonSourceOptions, ManualListeningOptions} from "./index.ts";
export interface AzuraStationInfoResponse {
id: string
@@ -1,4 +1,4 @@
import { type CommonSourceConfig, type CommonSourceData } from "./index.ts";
import type {CommonSourceConfig, CommonSourceData} from "./index.ts";
export interface ChromecastData extends CommonSourceData {
/**
@@ -1,6 +1,6 @@
import { type Second } from "../../../../../core/Atomic.ts";
import { type PollingOptions } from "../common.ts";
import { type CommonSourceConfig, type CommonSourceData, type CommonSourceOptions } from "./index.ts";
import type {Second} from "../../../../../core/Atomic.ts";
import type {PollingOptions} from "../common.ts";
import type {CommonSourceConfig, CommonSourceData, CommonSourceOptions} from "./index.ts";
export interface DeezerData extends CommonSourceData, PollingOptions {
/**
@@ -1,4 +1,4 @@
import { type CommonSourceConfig, type CommonSourceData } from "./index.ts";
import type {CommonSourceConfig, CommonSourceData} from "./index.ts";
export interface LastFMEndpointData extends CommonSourceData {
/**
@@ -1,4 +1,4 @@
import { type CommonSourceConfig, type CommonSourceData } from "./index.ts";
import type {CommonSourceConfig, CommonSourceData} from "./index.ts";
export interface ListenbrainzEndpointData extends CommonSourceData {
/**
@@ -1,4 +1,4 @@
import { type CommonSourceConfig, type CommonSourceData, type CommonSourceOptions, type ManualListeningOptions } from "./index.ts";
import type {CommonSourceConfig, CommonSourceData, CommonSourceOptions, ManualListeningOptions} from "./index.ts";
export interface IcecastMetadata {
@@ -1,9 +1,9 @@
import { type FileLogOptions, type LogLevel } from "@foxxmd/logging";
import type { FileLogOptions, LogLevel } from "@foxxmd/logging";
import { type PlayTransformOptions } from "../../../../../core/Transform.ts";
import { type CommonConfig, type RequestRetryOptions } from "../common.ts";
import { type RetentionConfig } from "../database.ts";
import { type DurationValue } from "../../Atomic.ts";
import type { PlayTransformOptions } from "../../../../../core/Transform.ts";
import type { CommonConfig, RequestRetryOptions } from "../common.ts";
import type { RetentionConfig } from "../database.ts";
import type { DurationValue } from "../../Atomic.ts";
export interface SourceRetryOptions extends RequestRetryOptions {
/**
@@ -1,5 +1,5 @@
import { type CommonSourceConfig, type CommonSourceData, type CommonSourceOptions } from "./index.ts";
import {
import type {CommonSourceConfig, CommonSourceData, CommonSourceOptions} from "./index.ts";
import type {
// @ts-expect-error weird typings?
CollectionType,
// @ts-expect-error weird typings?
@@ -1,5 +1,5 @@
import { type PollingOptions, type RequestRetryOptions } from "../common.ts";
import { type CommonSourceConfig, type CommonSourceData } from "./index.ts";
import type {PollingOptions, RequestRetryOptions} from "../common.ts";
import type {CommonSourceConfig, CommonSourceData} from "./index.ts";
export interface JRiverData extends CommonSourceData, PollingOptions, RequestRetryOptions {
/**
@@ -1,5 +1,5 @@
import { type PollingOptions } from "../common.ts";
import { type CommonSourceConfig, type CommonSourceData } from "./index.ts";
import type {PollingOptions} from "../common.ts";
import type {CommonSourceConfig, CommonSourceData} from "./index.ts";
export interface KodiData extends CommonSourceData, PollingOptions {
@@ -1,6 +1,6 @@
import { type KoitoData } from "../client/koito.ts";
import { type PollingOptions } from "../common.ts";
import { type CommonSourceConfig, type CommonSourceData } from "./index.ts";
import type {KoitoData} from "../client/koito.ts";
import type {PollingOptions} from "../common.ts";
import type {CommonSourceConfig, CommonSourceData} from "./index.ts";
export interface KoitoSourceData extends KoitoData, CommonSourceData, PollingOptions {
}
@@ -1,6 +1,6 @@
import { type LastfmData } from "../client/lastfm.ts";
import { type PollingOptions } from "../common.ts";
import { type CommonSourceConfig, type CommonSourceData } from "./index.ts";
import type {LastfmData} from "../client/lastfm.ts";
import type {PollingOptions} from "../common.ts";
import type {CommonSourceConfig, CommonSourceData} from "./index.ts";
export interface LastFmSourceData extends CommonSourceData, PollingOptions, LastfmData{}
@@ -1,6 +1,6 @@
import { type LibrefmData } from "../client/librefm.ts";
import { type PollingOptions } from "../common.ts";
import { type CommonSourceConfig, type CommonSourceData } from "./index.ts";
import type {LibrefmData} from "../client/librefm.ts";
import type {PollingOptions} from "../common.ts";
import type {CommonSourceConfig, CommonSourceData} from "./index.ts";
export interface librefmSourceData extends CommonSourceData, PollingOptions, LibrefmData{}
@@ -1,6 +1,6 @@
import { type ListenBrainzData } from "../client/listenbrainz.ts";
import { type PollingOptions } from "../common.ts";
import { type CommonSourceConfig, type CommonSourceData } from "./index.ts";
import type {ListenBrainzData} from "../client/listenbrainz.ts";
import type {PollingOptions} from "../common.ts";
import type {CommonSourceConfig, CommonSourceData} from "./index.ts";
export interface ListenBrainzSourceData extends ListenBrainzData, CommonSourceData, PollingOptions {
}
@@ -1,6 +1,6 @@
import { type MalojaData } from "../client/maloja.ts";
import { type PollingOptions } from "../common.ts";
import { type CommonSourceConfig, type CommonSourceData } from "./index.ts";
import type {MalojaData} from "../client/maloja.ts";
import type {PollingOptions} from "../common.ts";
import type {CommonSourceConfig, CommonSourceData} from "./index.ts";
export interface MalojaSourceData extends MalojaData, CommonSourceData, PollingOptions {
}
@@ -1,5 +1,5 @@
import { type PollingOptions } from "../common.ts";
import { type CommonSourceConfig, type CommonSourceData } from "./index.ts";
import type {PollingOptions} from "../common.ts";
import type {CommonSourceConfig, CommonSourceData} from "./index.ts";
export interface MopidyData extends CommonSourceData, PollingOptions {
/**
@@ -1,5 +1,5 @@
import { type PollingOptions } from "../common.ts";
import { type CommonSourceConfig, type CommonSourceData, type CommonSourceOptions } from "./index.ts";
import type {PollingOptions} from "../common.ts";
import type {CommonSourceConfig, CommonSourceData, CommonSourceOptions} from "./index.ts";
export interface MPDData extends CommonSourceData, PollingOptions {
/**
@@ -1,4 +1,4 @@
import { type CommonSourceConfig, type CommonSourceData } from "./index.ts";
import type {CommonSourceConfig, CommonSourceData} from "./index.ts";
export const PLAYBACK_STATUS_PLAYING = 'Playing';
export const PLAYBACK_STATUS_PAUSED = 'Paused';
@@ -1,5 +1,6 @@
import { REPORTED_PLAYER_STATUSES, type ReportedPlayerStatus } from "../../Atomic.ts";
import { type CommonSourceConfig, type CommonSourceData } from "./index.ts";
import { REPORTED_PLAYER_STATUSES } from '../../../../../core/Atomic.ts';
import type {ReportedPlayerStatus} from '../../../../../core/Atomic.ts';
import type {CommonSourceConfig, CommonSourceData} from "./index.ts";
export type PlaybackStatus = 'play' | 'stop' | 'pause' | 'fast_reverse' | 'fast_forward'
@@ -1,4 +1,4 @@
import { type CommonSourceConfig, type CommonSourceData } from "./index.ts";
import type {CommonSourceConfig, CommonSourceData} from "./index.ts";
export const PLAYBACK_STATUS_PLAYING_MC = 'playing';
export const PLAYBACK_STATUS_PAUSED_MC = 'paused';
@@ -1,5 +1,5 @@
import { type PollingOptions } from "../common.ts";
import { type CommonSourceConfig, type CommonSourceData, type CommonSourceOptions } from "./index.ts";
import type {PollingOptions} from "../common.ts";
import type {CommonSourceConfig, CommonSourceData, CommonSourceOptions} from "./index.ts";
export interface PlexApiData extends CommonSourceData, PollingOptions {
token?: string
@@ -1,6 +1,6 @@
import { type RockSkyData, type RockSkyOptions } from "../client/rocksky.ts";
import { type PollingOptions } from "../common.ts";
import { type CommonSourceConfig, type CommonSourceData, type CommonSourceOptions } from "./index.ts";
import type {RockSkyData, RockSkyOptions} from "../client/rocksky.ts";
import type {PollingOptions} from "../common.ts";
import type {CommonSourceConfig, CommonSourceData, CommonSourceOptions} from "./index.ts";
export interface RockskySourceData extends RockSkyData, CommonSourceData, PollingOptions {
}
@@ -1,5 +1,5 @@
import { type PollingOptions } from "../common.ts";
import { type CommonSourceConfig, type CommonSourceData, type CommonSourceOptions } from "./index.ts";
import type {PollingOptions} from "../common.ts";
import type {CommonSourceConfig, CommonSourceData, CommonSourceOptions} from "./index.ts";
export interface SonosData extends CommonSourceData, PollingOptions {
/**
@@ -1,32 +1,32 @@
import { type AzuracastSourceAIOConfig, type AzuracastSourceConfig } from "./azuracast.ts";
import { type ChromecastSourceAIOConfig, type ChromecastSourceConfig } from "./chromecast.ts";
import { type ListenbrainzEndpointSourceAIOConfig, type ListenbrainzEndpointSourceConfig } from "./endpointlz.ts";
import { type LastFMEndpointSourceAIOConfig, type LastFMEndpointSourceConfig } from "./endpointlfm.ts";
import { type DeezerInternalSourceConfig, type DeezerSourceConfig, type DeezerCompatConfig, type DeezerAIOCompatConfig } from "./deezer.ts";
import { type JellyApiSourceAIOConfig, type JellyApiSourceConfig } from "./jellyfin.ts";
import { type JRiverSourceAIOConfig, type JRiverSourceConfig } from "./jriver.ts";
import { type KodiSourceAIOConfig, type KodiSourceConfig } from "./kodi.ts";
import { type LastFmSouceAIOConfig, type LastfmSourceConfig } from "./lastfm.ts";
import { type ListenBrainzSourceAIOConfig, type ListenBrainzSourceConfig } from "./listenbrainz.ts";
import { type MopidySourceAIOConfig, type MopidySourceConfig } from "./mopidy.ts";
import { type MPDSourceAIOConfig, type MPDSourceConfig } from "./mpd.ts";
import { type MPRISSourceAIOConfig, type MPRISSourceConfig } from "./mpris.ts";
import { type MusikcubeSourceAIOConfig, type MusikcubeSourceConfig } from "./musikcube.ts";
import { type MusicCastSourceConfig, type MusicCastSourceAIOConfig } from "./musiccast.ts";
import { type PlexApiSourceConfig, type PlexApiSourceAIOConfig } from "./plex.ts";
import { type SpotifySourceAIOConfig, type SpotifySourceConfig } from "./spotify.ts";
import { type SubsonicSourceAIOConfig, type SubSonicSourceConfig } from "./subsonic.ts";
import { type VLCSourceAIOConfig, type VLCSourceConfig } from "./vlc.ts";
import { type WebScrobblerSourceAIOConfig, type WebScrobblerSourceConfig } from "./webscrobbler.ts";
import { type YTMusicSourceAIOConfig, type YTMusicSourceConfig } from "./ytmusic.ts";
import { type YandexMusicBridgeSourceAIOConfig, type YandexMusicBridgeSourceConfig } from "./ymbridge.ts";
import { type IcecastSourceAIOConfig, type IcecastSourceConfig } from "./icecast.ts";
import { type KoitoSourceAIOConfig, type KoitoSourceConfig } from "./koito.ts";
import { type MalojaSourceAIOConfig, type MalojaSourceConfig } from "./maloja.ts";
import { type TealSourceAIOConfig, type TealSourceConfig } from "./tealfm.ts";
import { type RockskySourceAIOConfig, type RockskySourceConfig } from "./rocksky.ts";
import { type LibrefmSouceAIOConfig, type LibrefmSourceConfig } from "./librefm.ts";
import { type SonosSourceAIOConfig, type SonosSourceConfig } from "./sonos.ts";
import type {AzuracastSourceAIOConfig, AzuracastSourceConfig} from "./azuracast.ts";
import type {ChromecastSourceAIOConfig, ChromecastSourceConfig} from "./chromecast.ts";
import type {ListenbrainzEndpointSourceAIOConfig, ListenbrainzEndpointSourceConfig} from "./endpointlz.ts";
import type {LastFMEndpointSourceAIOConfig, LastFMEndpointSourceConfig} from "./endpointlfm.ts";
import type {DeezerInternalSourceConfig, DeezerSourceConfig, DeezerCompatConfig, DeezerAIOCompatConfig} from "./deezer.ts";
import type {JellyApiSourceAIOConfig, JellyApiSourceConfig} from "./jellyfin.ts";
import type {JRiverSourceAIOConfig, JRiverSourceConfig} from "./jriver.ts";
import type {KodiSourceAIOConfig, KodiSourceConfig} from "./kodi.ts";
import type {LastFmSouceAIOConfig, LastfmSourceConfig} from "./lastfm.ts";
import type {ListenBrainzSourceAIOConfig, ListenBrainzSourceConfig} from "./listenbrainz.ts";
import type {MopidySourceAIOConfig, MopidySourceConfig} from "./mopidy.ts";
import type {MPDSourceAIOConfig, MPDSourceConfig} from "./mpd.ts";
import type {MPRISSourceAIOConfig, MPRISSourceConfig} from "./mpris.ts";
import type {MusikcubeSourceAIOConfig, MusikcubeSourceConfig} from "./musikcube.ts";
import type {MusicCastSourceConfig, MusicCastSourceAIOConfig} from "./musiccast.ts";
import type {PlexApiSourceConfig, PlexApiSourceAIOConfig} from "./plex.ts";
import type {SpotifySourceAIOConfig, SpotifySourceConfig} from "./spotify.ts";
import type {SubsonicSourceAIOConfig, SubSonicSourceConfig} from "./subsonic.ts";
import type {VLCSourceAIOConfig, VLCSourceConfig} from "./vlc.ts";
import type {WebScrobblerSourceAIOConfig, WebScrobblerSourceConfig} from "./webscrobbler.ts";
import type {YTMusicSourceAIOConfig, YTMusicSourceConfig} from "./ytmusic.ts";
import type {YandexMusicBridgeSourceAIOConfig, YandexMusicBridgeSourceConfig} from "./ymbridge.ts";
import type {IcecastSourceAIOConfig, IcecastSourceConfig} from "./icecast.ts";
import type {KoitoSourceAIOConfig, KoitoSourceConfig} from "./koito.ts";
import type {MalojaSourceAIOConfig, MalojaSourceConfig} from "./maloja.ts";
import type {TealSourceAIOConfig, TealSourceConfig} from "./tealfm.ts";
import type {RockskySourceAIOConfig, RockskySourceConfig} from "./rocksky.ts";
import type {LibrefmSouceAIOConfig, LibrefmSourceConfig} from "./librefm.ts";
import type {SonosSourceAIOConfig, SonosSourceConfig} from "./sonos.ts";
export type SourceConfig =
@@ -130,69 +130,6 @@ export type RockskySourceConfigs = RockskySourceConfig[];
export type SonosSourceConfigs = SonosSourceConfig[];
export type SourceType =
'spotify'
| 'plex'
| 'subsonic'
| 'jellyfin'
| 'lastfm'
| 'librefm'
| 'deezer'
| 'endpointlz'
| 'endpointlfm'
| 'ytmusic'
| 'ymbridge'
| 'mpris'
| 'mopidy'
| 'musiccast'
| 'listenbrainz'
| 'jriver'
| 'kodi'
| 'webscrobbler'
| 'chromecast'
| 'maloja'
| 'musikcube'
| 'mpd'
| 'vlc'
| 'icecast'
| 'azuracast'
| 'koito'
| 'tealfm'
| 'rocksky'
| 'sonos';
export const sourceTypes: SourceType[] = [
'spotify',
'plex',
'subsonic',
'jellyfin',
'lastfm',
'librefm',
'deezer',
'endpointlz',
'endpointlfm',
'ytmusic',
'ymbridge',
'mpris',
'mopidy',
'musiccast',
'listenbrainz',
'jriver',
'kodi',
'webscrobbler',
'chromecast',
'maloja',
'musikcube',
'mpd',
'vlc',
'icecast',
'azuracast',
'koito',
'tealfm',
'rocksky',
'sonos'
];
export const atomicSourceInterfaces = [
'SpotifySourceConfig',
'PlexApiSourceConfig',
@@ -230,7 +167,4 @@ export const sourceInterfaces = [
...atomicSourceInterfaces
];
export const isSourceType = (data: string): data is SourceType => {
return sourceTypes.includes(data as SourceType);
};
@@ -1,5 +1,5 @@
import { type PollingOptions } from "../common.ts";
import { type CommonSourceConfig, type CommonSourceData } from "./index.ts";
import type {PollingOptions} from "../common.ts";
import type {CommonSourceConfig, CommonSourceData} from "./index.ts";
export interface SpotifySourceData extends CommonSourceData, PollingOptions {
/**
@@ -1,5 +1,5 @@
import { type PollingOptions } from "../common.ts";
import { type CommonSourceConfig, type CommonSourceData } from "./index.ts";
import type {PollingOptions} from "../common.ts";
import type {CommonSourceConfig, CommonSourceData} from "./index.ts";
export interface SubsonicData extends CommonSourceData, PollingOptions {
/**
@@ -1,6 +1,6 @@
import { type TealData, type TealOptions } from "../client/tealfm.ts"
import { type PollingOptions } from "../common.ts"
import { type CommonSourceConfig, type CommonSourceData, type CommonSourceOptions } from "./index.ts"
import type {TealData, TealOptions} from "../client/tealfm.ts";
import type {PollingOptions} from "../common.ts";
import type {CommonSourceConfig, CommonSourceData, CommonSourceOptions} from "./index.ts";
export interface TealSourceData extends TealData, CommonSourceData, PollingOptions {
@@ -1,6 +1,6 @@
import { type VlcMeta } from "vlc-client/dist/Types.js";
import { type PollingOptions } from "../common.ts";
import { type CommonSourceConfig, type CommonSourceData, type CommonSourceOptions } from "./index.ts";
import type {VlcMeta} from "vlc-client/dist/Types.js";
import type {PollingOptions} from "../common.ts";
import type {CommonSourceConfig, CommonSourceData, CommonSourceOptions} from "./index.ts";
export interface VLCData extends CommonSourceData, PollingOptions {
/**
@@ -1,4 +1,4 @@
import { type CommonSourceConfig, type CommonSourceData } from "./index.ts";
import type {CommonSourceConfig, CommonSourceData} from "./index.ts";
export interface WebScrobblerData extends CommonSourceData {
/**
@@ -1,5 +1,5 @@
import { type PollingOptions } from "../common.ts";
import { type CommonSourceConfig, type CommonSourceData } from "./index.ts";
import type {PollingOptions} from "../common.ts";
import type {CommonSourceConfig, CommonSourceData} from "./index.ts";
export interface YandexMusicBridgeData extends CommonSourceData, PollingOptions {
/** URL of the local Python bridge, for example http://yandex-music-bridge:9980 */
@@ -1,5 +1,5 @@
import { type PollingOptions } from "../common.ts";
import { type CommonSourceConfig, type CommonSourceData, type CommonSourceOptions } from "./index.ts";
import type {PollingOptions} from "../common.ts";
import type {CommonSourceConfig, CommonSourceData, CommonSourceOptions} from "./index.ts";
export interface InnertubeOptions {
/**
+2 -1
View File
@@ -1,6 +1,7 @@
import { type FileLogOptions, type Logger, loggerAppRolling, type LogLevel, type LogLevelStreamEntry, type LogOptions, parseLogOptions } from '@foxxmd/logging';
import { buildDestinationJsonPrettyStream, buildDestinationRollingFile, buildDestinationStdout, buildLogger } from "@foxxmd/logging/factory";
import { PassThrough, Transform } from "node:stream";
import type { Transform } from "node:stream";
import { PassThrough } from "node:stream";
import path from "path";
import process from "process";
import { projectDir } from "./index.ts";
@@ -1,15 +1,16 @@
import { childLogger, type Logger } from "@foxxmd/logging";
import { type PlayObject, type TransformerCommon, type TransformerCommonConfig } from "../../../core/Atomic.ts";
import type { PlayObject, TransformerCommon, TransformerCommonConfig } from "../../../core/Atomic.ts";
import { isStageTyped, testWhenConditions } from "../../utils/PlayTransformUtils.ts";
import AbstractInitializable from "../AbstractInitializable.ts";
import { type StageConfig } from "../../../core/Transform.ts";
import { cacheFunctions, parseToRegexOrLiteralSearch, testMaybeRegex, searchAndReplace} from "@foxxmd/regex-buddy-core";
import { Cacheable } from "cacheable";
import type { StageConfig } from "../../../core/Transform.ts";
import type { cacheFunctions} from "@foxxmd/regex-buddy-core";
import { parseToRegexOrLiteralSearch, testMaybeRegex, searchAndReplace} from "@foxxmd/regex-buddy-core";
import type { Cacheable } from "cacheable";
import { hashObject } from "../../utils/StringUtils.ts";
import { playContentInvariantTransform } from "../../utils/PlayComparisonUtils.ts";
import { SkipTransformStageError, StagePrerequisiteError } from "../errors/MSErrors.ts";
import { capitalize } from "../../../core/StringUtils.ts";
import { type StaggerOptions } from "../../utils/AsyncUtils.ts";
import type { StaggerOptions } from "../../utils/AsyncUtils.ts";
export interface TransformerOptions {
logger: Logger
@@ -1,5 +1,5 @@
import { type ArtistCredit, isPlayObject, type ObjectPlayData, type PlayObject, type TrackMeta } from "../../../core/Atomic.ts";
import { type AtomicStageConfig, type StageConfig } from "../../../core/Transform.ts";
import type {AtomicStageConfig, StageConfig} from "../../../core/Transform.ts";
import AbstractTransformer from "./AbstractTransformer.ts";
//export type GenericAtomicStageConfig<A> =
@@ -1,21 +1,21 @@
import { type ArtistCredit, asMBReleasePrimaryGroupType, asMBReleaseSecondaryGroupType, asMBReleaseStatus, DEFAULT_MISSING_TYPES, type LifecycleInput, type MBReleaseGroupPrimaryType, type MBReleaseGroupSecondaryType, type MBReleaseStatus, type MissingMbidType, type PlayObject, type TrackMeta, type TransformerCommon, type TransformOptions } from "../../../core/Atomic.ts";
import { isWhenCondition, testWhenConditions } from "../../utils/PlayTransformUtils.ts";
import { type WebhookPayload } from "../infrastructure/config/health/webhooks.ts";
import { type ExternalMetadataTerm, type PlayTransformMetadataStage } from "../../../core/Transform.ts";
import type {WebhookPayload} from "../infrastructure/config/health/webhooks.ts";
import type {ExternalMetadataTerm, PlayTransformMetadataStage} from "../../../core/Transform.ts";
import AtomicPartsTransformer from "./AtomicPartsTransformer.ts";
import { type TransformerOptions } from "./AbstractTransformer.ts";
import type {TransformerOptions} from "./AbstractTransformer.ts";
import { ARTIST_WEIGHT, type MusicbrainzApiConfigData, TITLE_WEIGHT } from "../infrastructure/Atomic.ts";
import { DELIMITERS } from '../../../core/Atomic.ts';
import { MaybeLogger } from '../MaybeLogger.ts';
import { childLogger } from "@foxxmd/logging";
import { MusicbrainzApiClient, recordingToPlay, type UsingTypes } from "../vendor/musicbrainz/MusicbrainzApiClient.ts";
import { type IRecordingList, type IRecordingMatch } from "musicbrainz-api";
import type {IRecordingList, IRecordingMatch} from "musicbrainz-api";
import { intersect, missingMbidTypes } from "../../utils.ts";
import { removeUndefinedKeys } from '../../../core/DataUtils.ts';
import { SimpleError, SkipTransformStageError, StagePrerequisiteError, StageTransformError } from "../errors/MSErrors.ts";
import { parseArrayFromMaybeString, scoreNormalizedStringsWeighted } from "../../utils/StringUtils.ts";
import clone from "clone";
import { Cacheable } from "cacheable";
import type { Cacheable } from "cacheable";
import { splitByFirstRegexFound } from "../../../core/StringUtils.ts";
import { nativeParse } from "./NativeTransformer.ts";
import { comparePlayArtistsNormalized, scoreTrackWeightedAndNormalized } from "../../utils/PlayComparisonUtils.ts";
@@ -611,7 +611,7 @@ export default class MusicbrainzTransformer extends AtomicPartsTransformer<Exter
// if brainz meta contains track MBID then we should be able to get the exact release
let explicitList: IRecordingMatch[];
let filtered = false;
let filtered: boolean;
[explicitList, filtered] = filterByExplicitTrackMbid(transformData.recordings, play);
if(filtered) {
this.logger.debug(`Found exact release using track MBID`);
@@ -752,8 +752,7 @@ export const filterByValidReleaseStatus = <T extends IRecordingMatch[]>(list: T,
if(releaseStatusAllow.length === 0 && releaseStatusDeny.length === 0) {
return list;
}
const releaseFiltered = list.map(x => {
return {
const releaseFiltered = list.map(x => ({
...x,
releases: x.releases === undefined ? [] : x.releases.filter(y => {
if(releaseStatusAllow.length > 0) {
@@ -761,8 +760,7 @@ export const filterByValidReleaseStatus = <T extends IRecordingMatch[]>(list: T,
}
return !releaseStatusDeny.includes(y.status?.toLocaleLowerCase() as MBReleaseStatus)
})
}
});
}));
return releaseFiltered.filter(x => (
(list.find(y => y.id === x.id).releases ?? []).length === 0
&& releaseAllowEmpty
@@ -779,8 +777,7 @@ export const filterByValidReleaseGroupPrimary = <T extends IRecordingMatch[]>(li
if(releaseGroupPrimaryTypeAllow.length === 0 && releaseGroupPrimaryTypeAllow.length === 0) {
return list;
}
const releaseFiltered = list.map(x => {
return {
const releaseFiltered = list.map(x => ({
...x,
releases: x.releases === undefined ? [] : x.releases.filter(y => {
if(releaseGroupPrimaryTypeAllow.length > 0) {
@@ -788,8 +785,7 @@ export const filterByValidReleaseGroupPrimary = <T extends IRecordingMatch[]>(li
}
return !releaseGroupPrimaryTypeDeny.includes(y["release-group"]?.["primary-type"]?.toLocaleLowerCase() as MBReleaseGroupPrimaryType)
})
}
});
}));
return releaseFiltered.filter(x => (
(list.find(y => y.id === x.id).releases ?? []).length === 0
&& releaseAllowEmpty
@@ -806,8 +802,7 @@ export const filterByValidReleaseGroupSecondary = (list: IRecordingMatch[], stag
if(releaseGroupSecondaryTypeAllow.length === 0 && releaseGroupSecondaryTypeDeny.length === 0) {
return list;
}
const releaseFiltered = list.map(x => {
return {
const releaseFiltered = list.map(x => ({
...x,
releases: x.releases === undefined ? [] : x.releases.filter(y => {
if(releaseGroupSecondaryTypeAllow.length > 0) {
@@ -815,8 +810,7 @@ export const filterByValidReleaseGroupSecondary = (list: IRecordingMatch[], stag
}
return intersect(releaseGroupSecondaryTypeDeny, (y["release-group"]?.["secondary-types"] ?? []).map(x => x.toLocaleLowerCase()) as MBReleaseGroupSecondaryType[]).length === 0;
})
}
});
}));
return releaseFiltered.filter(x => (
(list.find(y => y.id === x.id).releases ?? []).length === 0
&& releaseAllowEmpty
@@ -833,8 +827,7 @@ export const filterByValidReleaseCountry = (list: IRecordingMatch[], stageConfig
if(releaseCountryAllow.length === 0 && releaseCountryDeny.length === 0) {
return list;
}
const releaseFiltered = list.map(x => {
return {
const releaseFiltered = list.map(x => ({
...x,
releases: x.releases === undefined ? [] : x.releases.filter(y => {
if(releaseCountryAllow.length > 0) {
@@ -842,8 +835,7 @@ export const filterByValidReleaseCountry = (list: IRecordingMatch[], stageConfig
}
return !releaseCountryDeny.includes(y.country?.toLocaleLowerCase())
})
}
});
}));
return releaseFiltered.filter(x => (
(list.find(y => y.id === x.id).releases ?? []).length === 0
&& releaseAllowEmpty
@@ -862,8 +854,7 @@ export const filterByExplicitTrackMbid = (list: IRecordingMatch[], play: PlayObj
break;
}
for (const rel of rec.releases) {
// @ts-ignore
if (rel.media.some(x => x.track.some(y => y.id === play.data.meta.brainz.track))) {
if (rel.media.some(x => x.tracks.some(y => y.id === play.data.meta.brainz.track))) {
releaseMatchId = rel.id;
recMatch = rec;
break;
@@ -1,11 +1,11 @@
import { type ArtistCredit, type PlayObject, type TransformerCommon } from "../../../core/Atomic.ts";
import type {ArtistCredit, PlayObject, TransformerCommon} from "../../../core/Atomic.ts";
import { isWhenCondition, testWhenConditions } from "../../utils/PlayTransformUtils.ts";
import { type WebhookPayload } from "../infrastructure/config/health/webhooks.ts";
import { type ExternalMetadataTerm, type PlayTransformNativeStage } from "../../../core/Transform.ts";
import type {WebhookPayload} from "../infrastructure/config/health/webhooks.ts";
import type {ExternalMetadataTerm, PlayTransformNativeStage} from "../../../core/Transform.ts";
import AtomicPartsTransformer from "./AtomicPartsTransformer.ts";
import { parseArtistCredits, parseTrackCredits, uniqueNormalizedStrArr } from "../../utils/StringUtils.ts";
import { parseRegexSingle, parseToRegexOrLiteralSearch } from "@foxxmd/regex-buddy-core";
import { type TransformerOptions } from "./AbstractTransformer.ts";
import type {TransformerOptions} from "./AbstractTransformer.ts";
import { DELIMITERS_NO_AMP } from '../../../core/Atomic.ts';
import { asArray } from "../../utils/DataUtils.ts";
import { MaybeLogger } from '../MaybeLogger.ts';
@@ -1,11 +1,11 @@
import { childLogger, type Logger } from "@foxxmd/logging";
import AbstractTransformer from "./AbstractTransformer.ts";
import { type TransformerCommonConfig } from "../../../core/Atomic.ts";
import type AbstractTransformer from "./AbstractTransformer.ts";
import type {TransformerCommonConfig} from "../../../core/Atomic.ts";
import UserTransformer from "./UserTransformer.ts";
import { type StageConfig } from "../../../core/Transform.ts";
import { type PlayObject } from "../../../core/Atomic.ts";
import type {StageConfig} from "../../../core/Transform.ts";
import type {PlayObject} from "../../../core/Atomic.ts";
import { isStageTyped } from "../../utils/PlayTransformUtils.ts";
import { MSCache } from "../Cache.ts";
import type { MSCache } from "../Cache.ts";
import NativeTransformer from "./NativeTransformer.ts";
import MusicbrainzTransformer, { configFromEnv, type MusicbrainzTransformerConfig } from "./MusicbrainzTransformer.ts";
import { AsyncLocalStorage } from 'node:async_hooks';
@@ -1,8 +1,8 @@
import { searchAndReplace } from "@foxxmd/regex-buddy-core";
import { type ArtistCredit, type PlayObject } from "../../../core/Atomic.ts";
import type {ArtistCredit, PlayObject} from "../../../core/Atomic.ts";
import { configValToSearchReplace, isSearchAndReplaceTerm, isUserStage, testWhenConditions } from "../../utils/PlayTransformUtils.ts";
import { type WebhookPayload } from "../infrastructure/config/health/webhooks.ts";
import { type ConditionalSearchAndReplaceRegExp, type PlayTransformUserStage } from "../../../core/Transform.ts";
import type {WebhookPayload} from "../infrastructure/config/health/webhooks.ts";
import type {ConditionalSearchAndReplaceRegExp, PlayTransformUserStage} from "../../../core/Transform.ts";
import AtomicPartsTransformer from "./AtomicPartsTransformer.ts";
export default class UserTransformer extends AtomicPartsTransformer<ConditionalSearchAndReplaceRegExp[], undefined> {
+2 -2
View File
@@ -1,7 +1,7 @@
import { childLogger, type Logger } from "@foxxmd/logging";
import { type PlayObject } from "../../../core/Atomic.ts";
import type { PlayObject } from "../../../core/Atomic.ts";
import { capitalize } from "../../../core/StringUtils.ts";
import { type AbstractApiOptions, type FormatPlayObjectOptions } from "../infrastructure/Atomic.ts";
import type { AbstractApiOptions, FormatPlayObjectOptions } from "../infrastructure/Atomic.ts";
export default abstract class AbstractApiClient {
name: string;
+3 -2
View File
@@ -1,7 +1,8 @@
import request, { Request, Response } from 'superagent';
import type { Request, Response } from 'superagent';
import request from 'superagent';
import xml2js from 'xml2js';
import { type AbstractApiOptions, DEFAULT_RETRY_MULTIPLIER } from "../infrastructure/Atomic.ts";
import { type JRiverData } from "../infrastructure/config/source/jriver.ts";
import type {JRiverData} from "../infrastructure/config/source/jriver.ts";
import AbstractApiClient from "./AbstractApiClient.ts";
const parser = new xml2js.Parser({'async': true});
+4 -4
View File
@@ -2,10 +2,10 @@ import dayjs from "dayjs";
import { KodiClient } from 'kodi-api'
import normalizeUrl from "normalize-url";
import { URL } from "url";
import { type PlayObject, type PlayObjectMinimal } from "../../../core/Atomic.ts";
import { type RecentlyPlayedOptions } from "../../sources/AbstractSource.ts";
import { type AbstractApiOptions, type FormatPlayObjectOptions } from "../infrastructure/Atomic.ts";
import { type KodiData } from "../infrastructure/config/source/kodi.ts";
import type {PlayObject, PlayObjectMinimal} from "../../../core/Atomic.ts";
import type {RecentlyPlayedOptions} from "../../sources/AbstractSource.ts";
import type {AbstractApiOptions, FormatPlayObjectOptions} from "../infrastructure/Atomic.ts";
import type {KodiData} from "../infrastructure/config/source/kodi.ts";
import AbstractApiClient from "./AbstractApiClient.ts";
import { baseFormatPlayObj } from "../../utils/PlayTransformUtils.ts";
import { artistNamesToCredits } from "../../../core/StringUtils.ts";
+4 -4
View File
@@ -1,5 +1,5 @@
import dayjs, { type Dayjs, type ManipulateType } from "dayjs";
import { type BrainzMeta, type PlayObject, type PlayObjectMinimal, type ScrobbleActionResult, type UnixTimestamp, type URLData, type Writeable } from "../../../core/Atomic.ts";
import type {BrainzMeta, PlayObject, PlayObjectMinimal, ScrobbleActionResult, UnixTimestamp, URLData, Writeable} from "../../../core/Atomic.ts";
import { artistNamesToCredits, artistNameToCredit, nonEmptyStringOrDefault, splitByFirstFound } from "../../../core/StringUtils.ts";
import { sleep } from "../../utils.ts";
import { removeUndefinedKeys } from '../../../core/DataUtils.ts';
@@ -10,12 +10,12 @@ import { getScrobbleTsSOCDate } from "../../utils/TimeUtils.ts";
import { getNodeNetworkException, isNodeNetworkException } from "../errors/NodeErrors.ts";
import { UpstreamError } from "../errors/UpstreamError.ts";
import { type AbstractApiOptions, DEFAULT_RETRY_MULTIPLIER, type FormatPlayObjectOptions, type InternalConfigOptional, type PaginatedListensTimeRangeOptions, type PaginatedTimeRangeListens, type PaginatedTimeRangeListensResult } from "../infrastructure/Atomic.ts";
import { type LastfmData } from "../infrastructure/config/client/lastfm.ts";
import type {LastfmData} from "../infrastructure/config/client/lastfm.ts";
import AbstractApiClient from "./AbstractApiClient.ts";
import { normalizeStr, parseArtistCredits } from "../../utils/StringUtils.ts";
import { LastFMUser, LastFMAuth, LastFMTrack, type LastFMUserGetRecentTracksResponse, type LastFMBooleanNumber, type LastFMUpdateNowPlayingResponse, type LastFMUserGetInfoResponse, type LastFMUserGetRecentTracksParams } from 'lastfm-ts-api';
import clone from 'clone';
import { IncomingMessage } from "http";
import type { IncomingMessage } from "http";
import { baseFormatPlayObj } from "../../utils/PlayTransformUtils.ts";
import { ScrobbleSubmitError, SimpleError } from "../errors/MSErrors.ts";
import { redactString } from "@foxxmd/redact-string";
@@ -237,7 +237,7 @@ export default class LastfmApiClient extends AbstractApiClient implements Pagina
return true;
} catch (e) {
const hint = e.error?.cause?.message ?? undefined;
// eslint-disable-next-line preserve-caught-error
throw new Error(`Could not connect to ${this.upstreamName} API server${hint !== undefined ? ` (${hint})` : ''}`, { cause: e.error ?? e });
}
}
+4 -3
View File
@@ -1,7 +1,8 @@
import { stringSameness } from '@foxxmd/string-sameness';
import dayjs from "dayjs";
import request, { Request, Response } from 'superagent';
import { type BrainzMeta, type PlayObject, type PlayObjectMinimal, type ScrobbleActionResult, type UnixTimestamp, type URLData } from "../../../core/Atomic.ts";
import type { Request, Response } from 'superagent';
import request from 'superagent';
import type {BrainzMeta, PlayObject, PlayObjectMinimal, ScrobbleActionResult, UnixTimestamp, URLData} from "../../../core/Atomic.ts";
import { artistNamesToCredits, combinePartsToString, slice } from "../../../core/StringUtils.ts";
import {
normalizeListenbrainzUrl,
@@ -20,7 +21,7 @@ import AbstractApiClient from "./AbstractApiClient.ts";
import { getBaseFromUrl, isPortReachableConnect, joinedUrl, normalizeWebAddress } from '../../utils/NetworkUtils.ts';
import { unique } from '../../utils.ts';
import { removeUndefinedKeys } from '../../../core/DataUtils.ts';
import { type ListenPayload, type ListenResponse, type ListenType, type SubmitPayload } from '../../../core/vendor/listenbrainz/interfaces.ts';
import type {ListenPayload, ListenResponse, ListenType, SubmitPayload} from '../../../core/vendor/listenbrainz/interfaces.ts';
import { baseFormatPlayObj } from '../../utils/PlayTransformUtils.ts';
import { ScrobbleSubmitError, SimpleError } from '../errors/MSErrors.ts';
import pRetry from 'p-retry';
+10 -9
View File
@@ -1,24 +1,25 @@
import dayjs from "dayjs";
import request, { Request, Response } from 'superagent';
import { type PlayObject, type PlayObjectMinimal, type ScrobbleActionResult, type URLData } from "../../../core/Atomic.ts";
import type { Request, Response } from 'superagent';
import request from 'superagent';
import type {PlayObject, PlayObjectMinimal, ScrobbleActionResult, URLData} from "../../../core/Atomic.ts";
import { artistCreditsToNames, artistNamesToCredits, nonEmptyStringOrDefault } from "../../../core/StringUtils.ts";
import { UpstreamError } from "../errors/UpstreamError.ts";
import { type AbstractApiOptions, type FormatPlayObjectOptions } from "../infrastructure/Atomic.ts";
import { type RockSkyClientData, type RockSkyData, type RockSkyOptions } from "../infrastructure/config/client/rocksky.ts";
import type {AbstractApiOptions, FormatPlayObjectOptions} from "../infrastructure/Atomic.ts";
import type {RockSkyClientData, RockSkyData, RockSkyOptions} from "../infrastructure/config/client/rocksky.ts";
import AbstractApiClient from "./AbstractApiClient.ts";
import { isPortReachableConnect, joinedUrl, normalizeWebAddress } from '../../utils/NetworkUtils.ts';
import { type ListenResponse, type ListenType, type SubmitPayload } from '../../../core/vendor/listenbrainz/interfaces.ts';
import type {ListenResponse, ListenType, SubmitPayload} from '../../../core/vendor/listenbrainz/interfaces.ts';
import { playToListenPayload } from './listenbrainz/lzUtils.ts';
import { type RockskyScrobble } from './rocksky/interfaces.ts';
import { type Handle } from "@atcute/lexicons";
import type {RockskyScrobble} from './rocksky/interfaces.ts';
import type {Handle} from "@atcute/lexicons";
import { getATProtoIdentifier, identifierToAtProtoHandle } from './atproto/atUtils.ts';
import { baseFormatPlayObj } from "../../utils/PlayTransformUtils.ts";
import { ScrobbleSubmitError } from "../errors/MSErrors.ts";
import { tryApiCall } from "../../utils/RequestUtils.ts";
import { type CreateScrobbleInput, RockskyClient } from "@rocksky/sdk";
import { getRoot } from "../../ioc.ts";
import { MSCache } from "../Cache.ts";
import { type HandleData } from "../infrastructure/config/client/atproto.ts";
import type { MSCache } from "../Cache.ts";
import type {HandleData} from "../infrastructure/config/client/atproto.ts";
import { parseRegexSingle } from "@foxxmd/regex-buddy-core";
interface SubmitOptions {
+3 -3
View File
@@ -1,7 +1,7 @@
import { type AbstractApiOptions } from "../../infrastructure/Atomic.ts";
import { type TealClientData } from "../../infrastructure/config/client/tealfm.ts";
import type {AbstractApiOptions} from "../../infrastructure/Atomic.ts";
import type {TealClientData} from "../../infrastructure/config/client/tealfm.ts";
import { getATProtoIdentifier } from "./atUtils.ts";
import { type ATProtoAppData, type ATProtoUserIdentifierData } from "../../infrastructure/config/client/atproto.ts";
import type {ATProtoAppData, ATProtoUserIdentifierData} from "../../infrastructure/config/client/atproto.ts";
import { ATProtoAuthenticatedApiClient } from "./ATProtoAuthenticatedApiClient.ts";
import { PasswordSession, type PasswordSessionData } from '@atcute/password-session';
import { Client } from "@atcute/client";
@@ -2,7 +2,7 @@ import { UpstreamError } from "../../errors/UpstreamError.ts";
import { AbstractATProtoApiClient } from "./AbstractATProtoApiClient.ts";
import { Client, simpleFetchHandler } from '@atcute/client';
import type {} from '@atcute/atproto';
import { type Nsid } from "@atcute/lexicons";
import type {Nsid} from "@atcute/lexicons";
export class ATProtoUnauthenticatedApiClient extends AbstractATProtoApiClient {
@@ -1,17 +1,18 @@
import { getRoot } from "../../../ioc.ts";
import { type AbstractApiOptions } from "../../infrastructure/Atomic.ts";
import type {AbstractApiOptions} from "../../infrastructure/Atomic.ts";
import AbstractApiClient from "../AbstractApiClient.ts";
import { MSCache } from "../../Cache.ts";
import type { MSCache } from "../../Cache.ts";
import { UpstreamError } from "../../errors/UpstreamError.ts";
import { streamBodyProgress } from "../../../utils/NetworkUtils.ts";
import { type ATProtoUserIdentifierData, type HandleData } from "../../infrastructure/config/client/atproto.ts";
import type {ATProtoUserIdentifierData, HandleData} from "../../infrastructure/config/client/atproto.ts";
import { checkPds, isDID, identifierToAtProtoHandle, getATProtoIdentifier } from "./atUtils.ts";
import { Client, ClientResponseError, isXRPCErrorPayload, parseRateLimitHeaders } from '@atcute/client';
import type { Client} from '@atcute/client';
import { ClientResponseError, isXRPCErrorPayload, parseRateLimitHeaders } from '@atcute/client';
import { ComAtprotoSyncGetRepo } from '@atcute/atproto';
import { type AtprotoDid } from "@atcute/lexicons/syntax";
import type {AtprotoDid} from "@atcute/lexicons/syntax";
import { todayAwareFormat } from "../../../../core/TimeUtils.ts";
import dayjs from "dayjs";
import { type Millisecond } from "../../../../core/Atomic.ts";
import type {Millisecond} from "../../../../core/Atomic.ts";
export interface RateLimitInfo {
limit: number
+4 -4
View File
@@ -1,10 +1,10 @@
import { type Handle } from "@atcute/lexicons";
import type { Handle } from "@atcute/lexicons";
import { isHandle, type AtprotoDid } from "@atcute/lexicons/syntax";
import { type Logger } from "@foxxmd/logging";
import type { Logger } from "@foxxmd/logging";
import { parseRegexSingle } from "@foxxmd/regex-buddy-core";
import { loggerNoop, MaybeLogger } from '../../MaybeLogger.ts';
import { type ATProtoUserIdentifierData, type HandleData } from "../../infrastructure/config/client/atproto.ts";
import { Cacheable } from "cacheable";
import type { ATProtoUserIdentifierData, HandleData } from "../../infrastructure/config/client/atproto.ts";
import type { Cacheable } from "cacheable";
import {
CompositeDidDocumentResolver,
CompositeHandleResolver,
+4 -4
View File
@@ -1,9 +1,9 @@
import { type URLData } from "../../../../core/Atomic.ts";
import type {URLData} from "../../../../core/Atomic.ts";
import { joinedUrl, normalizeWSAddress } from "../../../utils/NetworkUtils.ts";
import { type AbstractApiOptions } from "../../infrastructure/Atomic.ts";
import { type AzuracastData, type AzuraStationResponse } from "../../infrastructure/config/source/azuracast.ts";
import type {AbstractApiOptions} from "../../infrastructure/Atomic.ts";
import type {AzuracastData, AzuraStationResponse} from "../../infrastructure/config/source/azuracast.ts";
import AbstractApiClient from "../AbstractApiClient.ts";
import { WS } from 'iso-websocket'
import type { WS } from 'iso-websocket'
export class AzuracastApiClient extends AbstractApiClient {
@@ -1,7 +1,8 @@
import { Media, MediaController, Result } from "@foxxmd/chromecast-client";
import { type PlayObject } from "../../../../core/Atomic.ts";
import { REPORTED_PLAYER_STATUSES, type ReportedPlayerStatus } from "../../infrastructure/Atomic.ts";
import { type PlatformApplication, type PlatformType } from "./interfaces.ts";
import type { Media, MediaController, Result } from "@foxxmd/chromecast-client";
import type {PlayObject} from "../../../../core/Atomic.ts";
import { REPORTED_PLAYER_STATUSES } from '../../../../core/Atomic.ts';
import type {ReportedPlayerStatus} from '../../../../core/Atomic.ts';
import type {PlatformApplication, PlatformType} from "./interfaces.ts";
import { hashObject } from "../../../utils/StringUtils.ts";
export const chromePlayerStateToReported = (state: string): ReportedPlayerStatus => {
+4 -4
View File
@@ -1,7 +1,7 @@
import { createPlatform, MediaController } from "@foxxmd/chromecast-client";
import { type Logger } from "@foxxmd/logging";
import { type Dayjs } from "dayjs";
import { type FormatPlayObjectOptions } from "../../infrastructure/Atomic.ts";
import type { createPlatform, MediaController } from "@foxxmd/chromecast-client";
import type {Logger} from "@foxxmd/logging";
import type {Dayjs} from "dayjs";
import type {FormatPlayObjectOptions} from "../../infrastructure/Atomic.ts";
export type PlatformType = ReturnType<typeof createPlatform>;
export interface PlatformApplication {
+3 -3
View File
@@ -2,12 +2,12 @@ import { isPlayObject } from "../../../../core/Atomic.ts";
import { getRoot } from "../../../ioc.ts";
import { isDebugMode } from "../../../utils.ts";
import { urlContainsKnownMediaDomain } from "../../../utils/RequestUtils.ts";
import { MSCache } from "../../Cache.ts";
import type { MSCache } from "../../Cache.ts";
import { isSuperAgentResponseError } from "../../errors/ErrorUtils.ts";
import { type AbstractApiOptions, type SourceData } from "../../infrastructure/Atomic.ts";
import type {AbstractApiOptions, SourceData} from "../../infrastructure/Atomic.ts";
import { type ActivityAssets, ARTWORK_PLACEHOLDER, type DiscordStrongData, MS_ART } from "../../infrastructure/config/client/discord.ts";
import AbstractApiClient from "../AbstractApiClient.ts";
import { CoverArtApiClient } from "../musicbrainz/CoverArtApiClient.ts";
import type { CoverArtApiClient } from "../musicbrainz/CoverArtApiClient.ts";
import EventEmitter from "events";
import request from 'superagent';
+3 -3
View File
@@ -1,12 +1,12 @@
import { childLogger } from "@foxxmd/logging";
import { type AbstractApiOptions } from "../../infrastructure/Atomic.ts";
import { type ActivityData, type DiscordIPCData, type DiscordStrongData } from "../../infrastructure/config/client/discord.ts";
import type {AbstractApiOptions} from "../../infrastructure/Atomic.ts";
import type {ActivityData, DiscordIPCData, DiscordStrongData} from "../../infrastructure/config/client/discord.ts";
import EventEmitter from "events";
import { getRoot } from "../../../ioc.ts";
import { Client, type SetActivity } from "@xhayper/discord-rpc";
import {realpathSync} from 'fs';
import {sep, join} from 'path';
import { type PathData } from "@xhayper/discord-rpc/dist/transport/IPC.js";
import type {PathData} from "@xhayper/discord-rpc/dist/transport/IPC.js";
import { removeUndefinedKeys } from '../../../../core/DataUtils.ts';
import { playStateToActivityData } from "./DiscordUtils.ts";
import { DiscordAbstractClient } from "./DiscordAbstractClient.ts";
+1 -1
View File
@@ -1,5 +1,5 @@
import dayjs from "dayjs";
import { type PlayObject, type SourcePlayerObj } from "../../../../core/Atomic.ts";
import type {PlayObject, SourcePlayerObj} from "../../../../core/Atomic.ts";
import { GatewayOpcodes, PresenceUpdateStatus } from "discord.js";
import { capitalize } from "../../../../core/StringUtils.ts";
import { urlToMusicService } from '../listenbrainz/lzUtils.ts';
+1 -1
View File
@@ -9,7 +9,7 @@ import pEvent from 'p-event';
import EventEmitter from "events";
import { randomInt } from "crypto";
import request from 'superagent';
import { type AbstractApiOptions } from "../../infrastructure/Atomic.ts";
import type {AbstractApiOptions} from "../../infrastructure/Atomic.ts";
import { isPlayObject, type SourcePlayerObj } from "../../../../core/Atomic.ts";
import dayjs, { type Dayjs } from "dayjs";
import { getRoot } from "../../../ioc.ts";
+7 -6
View File
@@ -1,14 +1,15 @@
import dayjs from "dayjs";
import { type PlayObject, type PlayObjectMinimal, type ScrobbleActionResult, type URLData } from "../../../../core/Atomic.ts";
import { type AbstractApiOptions, type PaginatedListensTimeRangeOptions, type PaginatedTimeRangeListens, type PaginatedTimeRangeListensResult } from "../../infrastructure/Atomic.ts";
import { type GetListensOptions, type KoitoData, type ListenObjectResponse, type ListensResponse } from "../../infrastructure/config/client/koito.ts";
import type {PlayObject, PlayObjectMinimal, ScrobbleActionResult, URLData} from "../../../../core/Atomic.ts";
import type {AbstractApiOptions, PaginatedListensTimeRangeOptions, PaginatedTimeRangeListens, PaginatedTimeRangeListensResult} from "../../infrastructure/Atomic.ts";
import type {GetListensOptions, KoitoData, ListenObjectResponse, ListensResponse} from "../../infrastructure/config/client/koito.ts";
import AbstractApiClient from "../AbstractApiClient.ts";
import { getBaseFromUrl, isPortReachableConnect, joinedUrl, normalizeWebAddress } from "../../../utils/NetworkUtils.ts";
import request, { Request, Response } from 'superagent';
import type { Request, Response } from 'superagent';
import request from 'superagent';
import { UpstreamError } from "../../errors/UpstreamError.ts";
import { playToListenPayload } from '../listenbrainz/lzUtils.ts';
import { type SubmitPayload } from '../../../../core/vendor/listenbrainz/interfaces.ts';
import { type ListenType } from '../../../../core/vendor/listenbrainz/interfaces.ts';
import type {SubmitPayload} from '../../../../core/vendor/listenbrainz/interfaces.ts';
import type {ListenType} from '../../../../core/vendor/listenbrainz/interfaces.ts';
import { baseFormatPlayObj } from "../../../utils/PlayTransformUtils.ts";
import { ScrobbleSubmitError } from "../../errors/MSErrors.ts";
import { tryApiCall } from "../../../utils/RequestUtils.ts";
+3 -3
View File
@@ -1,9 +1,9 @@
import { type PlayObject } from "../../../../core/Atomic.ts";
import type {PlayObject} from "../../../../core/Atomic.ts";
import { isEmptyArrayOrUndefined } from "../../../utils.ts";
import { removeUndefinedKeys } from '../../../../core/DataUtils.ts';
import { getScrobbleTsSOCDate } from "../../../utils/TimeUtils.ts";
import { type SubmitOptions } from "../ListenbrainzApiClient.ts";
import { type ListenPayload, type MinimumTrack, type SubmitListenAdditionalTrackInfo, type SubmitPayload } from "../../../../core/vendor/listenbrainz/interfaces.ts";
import type {SubmitOptions} from "../ListenbrainzApiClient.ts";
import type {ListenPayload, MinimumTrack, SubmitListenAdditionalTrackInfo, SubmitPayload} from "../../../../core/vendor/listenbrainz/interfaces.ts";
import {version as appVersion } from '../../../version.ts';
import { artistCreditsToNames, artistCreditToName } from "../../../../core/StringUtils.ts";
+5 -4
View File
@@ -1,11 +1,12 @@
import dayjs, { type ManipulateType } from 'dayjs';
import request, { Response, Request } from 'superagent';
import type { Response, Request } from 'superagent';
import request from 'superagent';
import compareVersions from "compare-versions";
import AbstractApiClient from "../AbstractApiClient.ts";
import { isPortReachableConnect, normalizeWebAddress } from "../../../utils/NetworkUtils.ts";
import { type MalojaData } from "../../infrastructure/config/client/maloja.ts";
import { type PlayObject, type PlayObjectMinimal, type ScrobbleActionResult, type URLData } from "../../../../core/Atomic.ts";
import { type AbstractApiOptions, type FormatPlayObjectOptions, type PaginatedListensTimeRangeOptions, type PaginatedTimeRangeListens, type PaginatedTimeRangeListensResult } from "../../infrastructure/Atomic.ts";
import type {MalojaData} from "../../infrastructure/config/client/maloja.ts";
import type {PlayObject, PlayObjectMinimal, ScrobbleActionResult, URLData} from "../../../../core/Atomic.ts";
import type {AbstractApiOptions, FormatPlayObjectOptions, PaginatedListensTimeRangeOptions, PaginatedTimeRangeListens, PaginatedTimeRangeListensResult} from "../../infrastructure/Atomic.ts";
import { isNodeNetworkException } from "../../errors/NodeErrors.ts";
import { isSuperAgentResponseError } from "../../errors/ErrorUtils.ts";
import { getNonEmptyVal } from "../../../utils.ts";
+1 -1
View File
@@ -1,4 +1,4 @@
import { type ResponseError } from "superagent";
import type {ResponseError} from "superagent";
import { findCauseByFunc } from "../../../utils/ErrorUtils.ts";
import { isSuperAgentResponseError } from "../../errors/ErrorUtils.ts";
+3 -3
View File
@@ -1,13 +1,13 @@
import { Cacheable } from "cacheable";
import { type AbstractApiOptions } from "../../infrastructure/Atomic.ts";
import type {AbstractApiOptions} from "../../infrastructure/Atomic.ts";
import AbstractApiClient from "../AbstractApiClient.ts";
import request from 'superagent';
import { isSuperAgentResponseError } from "../../errors/ErrorUtils.ts";
import { UpstreamError } from "../../errors/UpstreamError.ts";
import { initMemoryCache } from "../../Cache.ts";
import { joinedUrl } from "../../../utils/NetworkUtils.ts";
import { type RequestRetryOptions } from "../../infrastructure/config/common.ts";
import { type RetryContext } from "p-retry";
import type {RequestRetryOptions} from "../../infrastructure/config/common.ts";
import type {RetryContext} from "p-retry";
import { NO_RETRY_HTTP_STATUS, tryApiCall } from "../../../utils/RequestUtils.ts";
export type ThumbSize = 250 | 500 | 1200;

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