diff --git a/flatpak/README.md b/flatpak/README.md index bd6ede0a..5008be83 100644 --- a/flatpak/README.md +++ b/flatpak/README.md @@ -1,6 +1,6 @@ NOTE: This steps are for building the flatpak entirely locally, from source. If you want to install the application normally then [get it through flathub](/docs/installation.md#flatpak) -Flatpak build is a little convoluted until someone sets me straight... +The final build repo for the flathub version can be found at [flathub/io.github.foxxmd.multiscrobbler](https://github.com/flathub/io.github.foxxmd.multiscrobbler) # 1. Install Requirements diff --git a/flatpak/io.github.foxxmd.multiscrobbler.yml b/flatpak/io.github.foxxmd.multiscrobbler.yml index 15045926..cb6a2c70 100644 --- a/flatpak/io.github.foxxmd.multiscrobbler.yml +++ b/flatpak/io.github.foxxmd.multiscrobbler.yml @@ -55,7 +55,8 @@ modules: sources: - type: git url: https://github.com/FoxxMD/multi-scrobbler - commit: 9a578e54a89f87c82ff811bb04257c9b641b199a + tag: 0.4.5 + commit: 5e905eae1798482dbcef504500d26a028c2e15cb dest: main # Wrapper to launch the app - type: script -- 2.51.2 From 3400e747a84f847a8ac1225c64381b932910db05 Mon Sep 17 00:00:00 2001 From: FoxxMD Date: Mon, 3 Apr 2023 15:46:43 -0400 Subject: [PATCH 02/13] Fix listenbrainz example Thanks @captainnapalm --- config/listenbrainz.json.example | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/listenbrainz.json.example b/config/listenbrainz.json.example index be3ce43c..9e0e6781 100644 --- a/config/listenbrainz.json.example +++ b/config/listenbrainz.json.example @@ -1,7 +1,7 @@ [ { "name": "brainz", - "configureAs": "client" + "configureAs": "client", "data": { "token": "029b081ba-9156-4pe7-88e5-3be671f5ea2b", "username": "FoxxMD" -- 2.51.2 From 1677c0021fb981e024e6932dad6c954a63cb417a Mon Sep 17 00:00:00 2001 From: FoxxMD Date: Mon, 3 Apr 2023 15:59:29 -0400 Subject: [PATCH 03/13] Update maloja track parsing in preparation for Maloja 3.2 Album structure changes --- src/clients/MalojaScrobbler.ts | 14 +++++++++----- src/common/infrastructure/Atomic.ts | 13 +++++++++---- 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/src/clients/MalojaScrobbler.ts b/src/clients/MalojaScrobbler.ts index 9fa06536..0720fdef 100644 --- a/src/clients/MalojaScrobbler.ts +++ b/src/clients/MalojaScrobbler.ts @@ -65,10 +65,7 @@ export default class MalojaScrobbler extends AbstractScrobbleClient { track: { artists: mArtists, title: mTitle, - album: { - name: mAlbum, - artists: albumArtists - } = {}, + album: mAlbum, // length of the track length: mLength, } = {}, @@ -79,7 +76,14 @@ export default class MalojaScrobbler extends AbstractScrobbleClient { time = mTime; title = mTitle; duration = mLength; - album = mAlbum; + if(mAlbum !== null) { + const { + albumtitle, + name: mAlbumName, + artists: albumArtists + } = mAlbum || {}; + album = albumtitle ?? mAlbumName; + } } else { // scrobble data structure for v2 and below const { diff --git a/src/common/infrastructure/Atomic.ts b/src/common/infrastructure/Atomic.ts index f93a82ca..f8ce6927 100644 --- a/src/common/infrastructure/Atomic.ts +++ b/src/common/infrastructure/Atomic.ts @@ -148,6 +148,14 @@ export interface MalojaV2ScrobbleData { time: number } +export interface MalojaAlbumData +{ + name?: string + albumtitle?: string + artists: string[] +} + + export interface MalojaV3ScrobbleData { /** * unix timestamp (seconds) scrobble was made at @@ -156,10 +164,7 @@ export interface MalojaV3ScrobbleData { track: { artists: string[] title: string - album?: { - name: string - artists: string[] - } + album?: MalojaAlbumData | null /** * length of the track * */ -- 2.51.2 From e67ef5fb0f8a10dd80e5e0dca01ac05f0c5a0667 Mon Sep 17 00:00:00 2001 From: FoxxMD Date: Mon, 3 Apr 2023 16:10:58 -0400 Subject: [PATCH 04/13] fix: try to limit number of plays returned by deezer --- src/sources/DeezerSource.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sources/DeezerSource.ts b/src/sources/DeezerSource.ts index caf262aa..0f78d2a1 100644 --- a/src/sources/DeezerSource.ts +++ b/src/sources/DeezerSource.ts @@ -102,7 +102,7 @@ export default class DeezerSource extends AbstractSource { } getRecentlyPlayed = async (options: RecentlyPlayedOptions = {}) => { - const resp = await this.callApi(request.get(`${this.baseUrl}/user/me/history`)); + const resp = await this.callApi(request.get(`${this.baseUrl}/user/me/history?limit=20`)); return resp.data.map((x: any) => DeezerSource.formatPlayObj(x)).sort(sortByOldestPlayDate); } -- 2.51.2 From 045cae66f5f476e8f2d12f13fe8056f03802be36 Mon Sep 17 00:00:00 2001 From: FoxxMD Date: Tue, 18 Apr 2023 10:51:25 -0400 Subject: [PATCH 05/13] fix: Respect maloja response status and throw on error Don't assume track scrobble correctly. Check body status prop and throw on error or log warnings if they are present Maybe fixes #57 --- src/apis/maloja/interfaces.ts | 82 +++++++++++++++++ src/clients/MalojaScrobbler.ts | 131 +++++++++++++++++++--------- src/common/infrastructure/Atomic.ts | 59 ------------- 3 files changed, 174 insertions(+), 98 deletions(-) create mode 100644 src/apis/maloja/interfaces.ts diff --git a/src/apis/maloja/interfaces.ts b/src/apis/maloja/interfaces.ts new file mode 100644 index 00000000..ba6644ee --- /dev/null +++ b/src/apis/maloja/interfaces.ts @@ -0,0 +1,82 @@ +export interface MalojaV2ScrobbleData { + artists: string[] + title: string + album: string + /** + * Length of the track + * */ + duration: number + /** + * unix timestamp (seconds) scrobble was made at + * */ + time: number +} + +export interface MalojaAlbumData { + name?: string + albumtitle?: string + artists: string[] +} + +export interface MalojaV3ScrobbleData { + /** + * unix timestamp (seconds) scrobble was made at + * */ + time: number + track: { + artists: string[] + title: string + album?: MalojaAlbumData | null + /** + * length of the track + * */ + length: number + } + /** + * how long the track was listened to before it was scrobbled + * */ + duration: number +} + +export type MalojaScrobbleData = MalojaV2ScrobbleData | MalojaV3ScrobbleData; + +export interface MalojaScrobbleRequestData { + key: string + title: string + album: string + time: number + length: number +} + +export interface MalojaScrobbleV2RequestData extends MalojaScrobbleRequestData { + artist: string +} + +export interface MalojaScrobbleV3RequestData extends MalojaScrobbleRequestData { + artists: string[] +} + +interface MalojaScrobbleWarning { + type: string + value: string[] | string + desc: string +} + +export interface MalojaResponseV3CommonData { + status: 'failure' | 'error' | 'success' | 'ok' + error?: { + type: string + value?: string | object + desc: string + } +} + +export interface MalojaScrobbleV3ResponseData extends MalojaResponseV3CommonData { + track?: { + title: string + artists: string[] + album?: MalojaAlbumData | null + } + desc: string + warnings?: MalojaScrobbleWarning[] +} diff --git a/src/clients/MalojaScrobbler.ts b/src/clients/MalojaScrobbler.ts index 0720fdef..e1c42a75 100644 --- a/src/clients/MalojaScrobbler.ts +++ b/src/clients/MalojaScrobbler.ts @@ -14,18 +14,18 @@ import { import { FormatPlayObjectOptions, INITIALIZING, - MalojaScrobbleData, - MalojaScrobbleRequestData, - MalojaScrobbleV2RequestData, - MalojaScrobbleV3RequestData, - MalojaV2ScrobbleData, - MalojaV3ScrobbleData, PlayObject, TrackStringOptions } from "../common/infrastructure/Atomic.js"; import {MalojaClientConfig} from "../common/infrastructure/config/client/maloja.js"; import {Notifiers} from "../notifier/Notifiers.js"; import {Logger} from '@foxxmd/winston'; +import { + MalojaScrobbleData, + MalojaScrobbleRequestData, + MalojaScrobbleV2RequestData, + MalojaScrobbleV3RequestData, MalojaScrobbleV3ResponseData, MalojaV2ScrobbleData, MalojaV3ScrobbleData +} from "../apis/maloja/interfaces"; const feat = ["ft.", "ft", "feat.", "feat", "featuring", "Ft.", "Ft", "Feat.", "Feat", "Featuring"]; @@ -388,6 +388,8 @@ export default class MalojaScrobbler extends AbstractScrobbleClient { length: duration, }; + let responseBody: MalojaScrobbleV3ResponseData; + try { // 3.0.3 has a BC for something (maybe seconds => length ?) -- see #42 in repo if(this.serverVersion === undefined || compareVersions(this.serverVersion, '3.0.2') > 0) { @@ -402,53 +404,77 @@ export default class MalojaScrobbler extends AbstractScrobbleClient { .type('json') .send(scrobbleData)); - let scrobbleResponse = {}; + let scrobbleResponse: any | undefined = undefined, + scrobbledPlay: PlayObject; if(this.serverVersion === undefined || compareVersions(this.serverVersion, '3.0.0') >= 0) { + responseBody = response.body; const { - body: { - // @ts-expect-error TS(2525): Initializer provides no value for this binding ele... Remove this comment to see the full error message track, - } = {} - } = response; - scrobbleResponse = { - time: playDate.unix(), - track: { - ...track, - length: duration - }, - } - if(album !== undefined) { - const { - album: malojaAlbum = {}, - } = track; - // @ts-expect-error TS(2339): Property 'track' does not exist on type '{}'. - scrobbleResponse.track.album = { - ...malojaAlbum, - name: album + status, + warnings = [], + } = responseBody; + if(status === 'success') { + if(track !== undefined) { + scrobbleResponse = { + time: playDate.unix(), + track: { + ...track, + length: duration + }, + } + if (album !== undefined) { + const { + album: malojaAlbum = {}, + } = track; + scrobbleResponse.track.album = { + ...malojaAlbum, + name: album + } + } + } + if(warnings.length > 0) { + for(const w of warnings) { + this.logger.warn(`Maloja Warning: ${w.desc} => ${JSON.stringify(w.value)}`) + } } + } else { + throw new Error(buildErrorString(response)); } } else { - const {body: { - // @ts-expect-error TS(2525): Initializer provides no value for this binding ele... Remove this comment to see the full error message - track: { - time: mTime = playDate.unix(), - duration: mDuration = duration, - album: mAlbum = album, - ...rest - } - } = {}} = response; + const { + body: { + track: { + time: mTime = playDate.unix(), + duration: mDuration = duration, + album: mAlbum = album, + ...rest + } = {} + } = {} + } = response; scrobbleResponse = {...rest, album: mAlbum, time: mTime, duration: mDuration}; } - this.addScrobbledTrack(playObj, this.formatPlayObj(scrobbleResponse)); - if (newFromSource) { - this.logger.info(`Scrobbled (New) => (${source}) ${buildTrackString(playObj)}`); + let warning = ''; + if(scrobbleResponse === undefined) { + warning = `WARNING: Maloja did not return track data in scrobble response! Maybe it didn't scrobble correctly??`; + scrobbledPlay = playObj; + } else { + scrobbledPlay = this.formatPlayObj(scrobbleResponse) + } + this.addScrobbledTrack(playObj, scrobbledPlay); + const scrobbleInfo = `Scrobbled (${newFromSource ? 'New' : 'Backlog'}) => (${source}) ${buildTrackString(playObj)}`; + if(warning !== '') { + this.logger.warn(`${scrobbleInfo} | ${warning}`); + this.logger.debug(`Response: ${this.logger.debug(JSON.stringify(response.body))}`); } else { - this.logger.info(`Scrobbled (Backlog) => (${source}) ${buildTrackString(playObj)}`); + this.logger.info(scrobbleInfo); } } catch (e) { await this.notifier.notify({title: `Client - ${capitalize(this.type)} - ${this.name} - Scrobble Error`, message: `Failed to scrobble => ${buildTrackString(playObj)} | Error: ${e.message}`, priority: 'error'}); this.logger.error(`Scrobble Error (${sType})`, {playInfo: buildTrackString(playObj), payload: scrobbleData}); + if(responseBody !== undefined) { + this.logger.error('Raw Response:', responseBody); + } throw e; } finally { this.logger.debug('Raw Payload:', scrobbleData); @@ -457,3 +483,30 @@ export default class MalojaScrobbler extends AbstractScrobbleClient { return true; } } + +const buildErrorString = (body: MalojaScrobbleV3ResponseData) => { + let valString: string | undefined = undefined; + const { + status, + error: { + type, + value, + desc + } = {} + } = body; + if(value !== undefined && value !== null) { + if(typeof value === 'string') { + valString = value; + } else if(Array.isArray(value)) { + valString = value.map(x => { + if(typeof x === 'string') { + return x; + } + return JSON.stringify(x); + }).join(', '); + } else { + valString = JSON.stringify(value); + } + } + return `Maloja API returned ${status} of type ${type} "${desc}"${valString !== undefined ? `: ${valString}` : ''}`; +} diff --git a/src/common/infrastructure/Atomic.ts b/src/common/infrastructure/Atomic.ts index f8ce6927..177f47f8 100644 --- a/src/common/infrastructure/Atomic.ts +++ b/src/common/infrastructure/Atomic.ts @@ -134,65 +134,6 @@ export interface ScrobbledPlayObject { scrobble: PlayObject } -export interface MalojaV2ScrobbleData { - artists: string[] - title: string - album: string - /** - * Length of the track - * */ - duration: number - /** - * unix timestamp (seconds) scrobble was made at - * */ - time: number -} - -export interface MalojaAlbumData -{ - name?: string - albumtitle?: string - artists: string[] -} - - -export interface MalojaV3ScrobbleData { - /** - * unix timestamp (seconds) scrobble was made at - * */ - time: number - track: { - artists: string[] - title: string - album?: MalojaAlbumData | null - /** - * length of the track - * */ - length: number - } - /** - * how long the track was listened to before it was scrobbled - * */ - duration: number -} - -export type MalojaScrobbleData = MalojaV2ScrobbleData | MalojaV3ScrobbleData; - -export interface MalojaScrobbleRequestData { - key: string - title: string - album: string - time: number - length: number -} - -export interface MalojaScrobbleV2RequestData extends MalojaScrobbleRequestData { - artist: string -} - -export interface MalojaScrobbleV3RequestData extends MalojaScrobbleRequestData { - artists: string[] -} export interface RemoteIdentityParts { host: string, -- 2.51.2 From 09f4503593de1edcc6314e01a85283d442ad5f77 Mon Sep 17 00:00:00 2001 From: FoxxMD Date: Fri, 19 May 2023 12:25:22 -0400 Subject: [PATCH 06/13] fix: Handle null/non-string values when truncating #76 --- src/utils.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/utils.ts b/src/utils.ts index b44b7326..95eb495c 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -77,7 +77,13 @@ export const truncateStringArrToLength = (length: any, truncStr = '...') => { const truncater = truncateStringToLength(length, truncStr); return (strings: any) => strings.map(truncater); } -export const truncateStringToLength = (length: any, truncStr = '...') => (str: any) => str.length > length ? `${str.slice(0, length)}${truncStr}` : str; +export const truncateStringToLength = (length: any, truncStr = '...') => (val: any = '') => { + if(val === null) { + return ''; + } + const str = typeof val !== 'string' ? val.toString() : val; + return str.length > length ? `${str.slice(0, length)}${truncStr}` : str; +} const defaultTransformer = (input: any) => input; -- 2.51.2 From 5a1c9315137ae21b5494650bb566c5b831f8a5ed Mon Sep 17 00:00:00 2001 From: FoxxMD Date: Wed, 24 May 2023 10:45:07 -0400 Subject: [PATCH 07/13] fix: Re-initialize auth state after receiving auth callback So we don't have to restart after authenticating in order to start polling #76 --- src/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/index.ts b/src/index.ts index 68ebc726..d36da4a8 100644 --- a/src/index.ts +++ b/src/index.ts @@ -520,6 +520,7 @@ const configDir = process.env.CONFIG_DIR || path.resolve(projectDir, `./config`) const tokenResult = await source.handleAuthCodeCallback(req.query); let responseContent = 'OK'; if (tokenResult === true) { + await source.testAuth(); source.poll(); } else { responseContent = tokenResult; -- 2.51.2 From a5417277a8c02c3229a64b64ebe0cae8790d6473 Mon Sep 17 00:00:00 2001 From: FoxxMD Date: Wed, 24 May 2023 11:04:51 -0400 Subject: [PATCH 08/13] feat: Use pre/post auth hooks for polling start to simplify logic * Removes need to override poll() in child class and better defines when logic should be performed * Fixes app crash when spotify credentials are present but invalid #76 --- src/sources/AbstractSource.ts | 20 +++++++++++++++++--- src/sources/SpotifySource.ts | 11 +++++++---- src/sources/YTMusicSource.ts | 6 +++--- 3 files changed, 27 insertions(+), 10 deletions(-) diff --git a/src/sources/AbstractSource.ts b/src/sources/AbstractSource.ts index e0fc1ccd..8edcf085 100644 --- a/src/sources/AbstractSource.ts +++ b/src/sources/AbstractSource.ts @@ -159,11 +159,18 @@ export default abstract class AbstractSource { this.emitter.emit('notify', payload); } - poll = async () => { - await this.startPolling(); + onPollPreAuthCheck = async (): Promise => { + return true; } - startPolling = async () => { + onPollPostAuthCheck = async (): Promise => { + return true; + } + + poll = async () => { + if(!await this.onPollPreAuthCheck()) { + return; + } if(this.requiresAuth && !this.authed) { if(this.requiresAuthInteraction) { this.notify({title: `${this.identifier} - Polling Error`, message: 'Cannot start polling because user interaction is required for authentication', priority: 'error'}); @@ -174,6 +181,13 @@ export default abstract class AbstractSource { } return; } + if(!await this.onPollPostAuthCheck()) { + return; + } + await this.startPolling(); + } + + startPolling = async () => { // reset poll attempts if already previously run this.pollRetries = 0; diff --git a/src/sources/SpotifySource.ts b/src/sources/SpotifySource.ts index e5d53a05..c141aaaf 100644 --- a/src/sources/SpotifySource.ts +++ b/src/sources/SpotifySource.ts @@ -364,12 +364,15 @@ export default class SpotifySource extends MemorySource { } } - poll = async () => { + onPollPreAuthCheck = async () => { if (this.spotifyApi === undefined) { this.logger.warn('Cannot poll spotify without valid credentials configuration') - return; + return false; } + return true; + } + onPollPostAuthCheck = async () => { // test capabilities try { await this.getCurrentPlaybackState(false); @@ -378,12 +381,12 @@ export default class SpotifySource extends MemorySource { this.logger.warn('multi-scrobbler does not have sufficient permissions to access Spotify API "Get Playback State". MS will continue to work but accuracy for determining if/when a track played from a Spotify Connect device (smart device controlled through Spotify app) may be degraded. To fix this re-authenticate MS with Spotify and restart polling.'); } + // and record backlogged tracks this.logger.info('Checking recently played API for tracks to backlog...'); const backlogPlays = await this.getPlayHistory({formatted: true}); this.scrobble(backlogPlays); this.logger.info('Backlog complete.'); - - await this.startPolling(); + return true; } } diff --git a/src/sources/YTMusicSource.ts b/src/sources/YTMusicSource.ts index d8085c06..6c5a041e 100644 --- a/src/sources/YTMusicSource.ts +++ b/src/sources/YTMusicSource.ts @@ -180,8 +180,8 @@ export default class YTMusicSource extends AbstractSource { return this.authed; } - poll = async () => { - if(this.authed && !this.polling) { + onPollPostAuthCheck = async () => { + if(!this.polling) { this.logger.verbose('Hydrating initial recently played tracks for reference.'); const referencePlays = await this.getRecentlyPlayed(); const reversedPlays = [...referencePlays]; @@ -194,6 +194,6 @@ export default class YTMusicSource extends AbstractSource { } } } - await this.startPolling(); + return true; } } -- 2.51.2 From c10d46b77435402dc284b574836b1713c9a5fc2d Mon Sep 17 00:00:00 2001 From: FoxxMD Date: Wed, 24 May 2023 11:47:29 -0400 Subject: [PATCH 09/13] fix: Passing wrong argument to tautulli payload formatter #77 --- src/index.ts | 2 +- src/sources/TautulliSource.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/index.ts b/src/index.ts index d36da4a8..fd71a303 100644 --- a/src/index.ts +++ b/src/index.ts @@ -244,7 +244,7 @@ const configDir = process.env.CONFIG_DIR || path.resolve(projectDir, `./config`) app.postAsync('/tautulli', async function(this: any, req, res) { tauIngress.trackIngress(req, false); - const payload = TautulliSource.formatPlayObj(req.body, {newFromSource: true}); + const payload = TautulliSource.formatPlayObj(req, {newFromSource: true}); // try to get config name from payload if (req.body.scrobblerConfig !== undefined) { const source = scrobbleSources.getByName(req.body.scrobblerConfig); diff --git a/src/sources/TautulliSource.ts b/src/sources/TautulliSource.ts index bb5ea0e3..2550368b 100644 --- a/src/sources/TautulliSource.ts +++ b/src/sources/TautulliSource.ts @@ -4,6 +4,7 @@ import {TautulliSourceConfig} from "../common/infrastructure/config/source/tautu import {FormatPlayObjectOptions, InternalConfig, PlayObject} from "../common/infrastructure/Atomic.js"; import {combinePartsToString, truncateStringToLength} from "../utils.js"; import EventEmitter from "events"; +import {Request} from "express"; const shortDeviceId = truncateStringToLength(10, ''); @@ -13,8 +14,7 @@ export default class TautulliSource extends PlexSource { constructor(name: any, config: TautulliSourceConfig, internal: InternalConfig, emitter: EventEmitter) { super(name, config, internal, 'tautulli', emitter); } - - static formatPlayObj(obj: any, options: FormatPlayObjectOptions = {}): PlayObject { + static formatPlayObj(obj: Request, options: FormatPlayObjectOptions = {}): PlayObject { const {newFromSource = false} = options; const { artist_name, -- 2.51.2 From 6d9783c5f55cd14ea51149200ac0539e3574f7ba Mon Sep 17 00:00:00 2001 From: FoxxMD Date: Thu, 25 May 2023 11:46:00 -0400 Subject: [PATCH 10/13] fix(tautulli): More response formatting safeguards #77 * Log warning if payload is empty * Destructure request body with default empty object --- src/sources/TautulliSource.ts | 40 ++++++++++--------- .../ingressNotifiers/TautulliNotifier.ts | 5 ++- 2 files changed, 25 insertions(+), 20 deletions(-) diff --git a/src/sources/TautulliSource.ts b/src/sources/TautulliSource.ts index 2550368b..588c9666 100644 --- a/src/sources/TautulliSource.ts +++ b/src/sources/TautulliSource.ts @@ -17,25 +17,27 @@ export default class TautulliSource extends PlexSource { static formatPlayObj(obj: Request, options: FormatPlayObjectOptions = {}): PlayObject { const {newFromSource = false} = options; const { - artist_name, - track_name, - track_artist, - album_name, - media_type, - title, - library_name, - server, - version, - duration, - username, - library, - machine_id = '', - session_key, - action, - platform, - device, - player, - } = obj.body; + body :{ + artist_name, + track_name, + track_artist, + album_name, + media_type, + title, + library_name, + server, + version, + duration, + username, + library, + machine_id = '', + session_key, + action, + platform, + device, + player, + } = {} + } = obj; let artists = [artist_name]; if (track_artist !== undefined && track_artist !== artist_name) { artists.push(track_artist); diff --git a/src/sources/ingressNotifiers/TautulliNotifier.ts b/src/sources/ingressNotifiers/TautulliNotifier.ts index 81743ae0..7e070ef2 100644 --- a/src/sources/ingressNotifiers/TautulliNotifier.ts +++ b/src/sources/ingressNotifiers/TautulliNotifier.ts @@ -16,7 +16,10 @@ export class TautulliNotifier extends IngressNotifier { if(!this.seenServers.includes(playObj.meta.server)) { this.seenServers.push(playObj.meta.server); - let msg = [`Received valid data from server ${playObj.meta.server} for the first time.`]; + let msg = [`Received data from server ${playObj.meta.server} for the first time.`]; + if(req.body === undefined) { + msg.push('WARNING: Payload was empty.'); + } if(playObj.meta.library === undefined) { msg.push('WARNING: library was not defined in payload. If you want to filter plays by library this must be present in webhook payload.'); } -- 2.51.2 From cc8c7d84e2bfdf1f3bf93075198385fc0fca18e7 Mon Sep 17 00:00:00 2001 From: FoxxMD Date: Thu, 25 May 2023 12:18:29 -0400 Subject: [PATCH 11/13] fix(kodi): Fix hardcoded string #79 Probably leftover from debugging, oops --- src/apis/KodiApiClient.ts | 2 +- src/sources/KodiSource.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/apis/KodiApiClient.ts b/src/apis/KodiApiClient.ts index f1e0e367..f45b2e0e 100644 --- a/src/apis/KodiApiClient.ts +++ b/src/apis/KodiApiClient.ts @@ -53,7 +53,7 @@ export class KodiApiClient extends AbstractApiClient { const { url = 'http://localhost:8080/jsonrpc' } = config; - this.url = KodiApiClient.parseConnectionUrl('http://localhost:8080'); + this.url = KodiApiClient.parseConnectionUrl(url); const auth = new Buffer(`${config.username}:${config.password}`).toString('base64'); this.client = new KodiClient({ clientType: this.url.protocol.replace(':', '') as ('http' | 'https'), diff --git a/src/sources/KodiSource.ts b/src/sources/KodiSource.ts index 2a51052a..90abf381 100644 --- a/src/sources/KodiSource.ts +++ b/src/sources/KodiSource.ts @@ -22,7 +22,6 @@ export class KodiSource extends MemorySource { } = data || {}; super('kodi', name, {...config, data: {interval, maxInterval, ...rest}}, internal, emitter); - this.client = new KodiApiClient(name, data); this.requiresAuth = true; this.canPoll = true; this.multiPlatform = true; @@ -34,6 +33,7 @@ export class KodiSource extends MemorySource { url } = {} } = this.config; + this.client = new KodiApiClient(this.name, this.config.data); this.logger.debug(`Config URL: '${url ?? '(None Given)'}' => Normalized: '${this.client.url.toString()}'`) this.initialized = true; return true; -- 2.51.2 From 39f933418e86f453e9eacf3dee11e632a7a22ecf Mon Sep 17 00:00:00 2001 From: FoxxMD Date: Tue, 30 May 2023 10:32:20 -0400 Subject: [PATCH 12/13] fix(ntfy): Include authorization object correctly in publish request data #80 --- src/notifier/NtfyWebhookNotifier.ts | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/notifier/NtfyWebhookNotifier.ts b/src/notifier/NtfyWebhookNotifier.ts index c981b8d4..4ae4903f 100644 --- a/src/notifier/NtfyWebhookNotifier.ts +++ b/src/notifier/NtfyWebhookNotifier.ts @@ -7,6 +7,7 @@ import { import {publish} from 'ntfy'; import request from "superagent"; import {Logger} from '@foxxmd/winston'; +import {Config} from "ntfy/interfaces"; export class NtfyWebhookNotifier extends AbstractWebhookNotifier { @@ -54,21 +55,20 @@ export class NtfyWebhookNotifier extends AbstractWebhookNotifier { doNotify = async (payload: WebhookPayload) => { try { - let authorization = {}; - if (this.config.username !== undefined) { - authorization = { - username: this.config.username, - password: this.config.password, - } - } - await publish({ + const req: Config = { message: payload.message, topic: this.config.topic, title: payload.title, server: this.config.url, priority: this.priorities[payload.priority], - ...authorization, - }); + }; + if (this.config.username !== undefined) { + req.authorization = { + username: this.config.username, + password: this.config.password, + } + } + await publish(req); this.logger.debug(`Pushed notification.`); } catch (e: any) { this.logger.error(`Failed to push notification: ${e.message}`) -- 2.51.2 From 88efe2ad87a5bf9f5b730fbb8b7811a4c651ea1e Mon Sep 17 00:00:00 2001 From: FoxxMD Date: Wed, 7 Jun 2023 09:23:40 -0400 Subject: [PATCH 13/13] Bump versions for release --- flatpak/io.github.foxxmd.multiscrobbler.metainfo.xml | 1 + flatpak/io.github.foxxmd.multiscrobbler.yml | 2 +- package.json | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/flatpak/io.github.foxxmd.multiscrobbler.metainfo.xml b/flatpak/io.github.foxxmd.multiscrobbler.metainfo.xml index b70bda70..ceee911f 100644 --- a/flatpak/io.github.foxxmd.multiscrobbler.metainfo.xml +++ b/flatpak/io.github.foxxmd.multiscrobbler.metainfo.xml @@ -41,6 +41,7 @@ + diff --git a/flatpak/io.github.foxxmd.multiscrobbler.yml b/flatpak/io.github.foxxmd.multiscrobbler.yml index cb6a2c70..ecd22ce4 100644 --- a/flatpak/io.github.foxxmd.multiscrobbler.yml +++ b/flatpak/io.github.foxxmd.multiscrobbler.yml @@ -55,7 +55,7 @@ modules: sources: - type: git url: https://github.com/FoxxMD/multi-scrobbler - tag: 0.4.5 + tag: 0.4.6 commit: 5e905eae1798482dbcef504500d26a028c2e15cb dest: main # Wrapper to launch the app diff --git a/package.json b/package.json index b5318a50..1dc21233 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "multi-scrobbler", - "version": "0.4.0", + "version": "0.4.6", "description": "scrobble plays from multiple sources to multiple clients", "main": "src/index.js", "scripts": {