diff --git a/src/app/app.component.spec.ts b/src/app/app.component.spec.ts index 005f4f44..ef0b5c02 100644 --- a/src/app/app.component.spec.ts +++ b/src/app/app.component.spec.ts @@ -7,7 +7,7 @@ import { IntegrationTestRunner } from './testing/integration-test-runner'; import { EventListenerServiceBase } from './services/event-listener/event-listener.service.base'; import { MediaSessionService } from './services/media-session/media-session.service'; import { TrayServiceBase } from './services/tray/tray.service.base'; -import { ScrobblingService } from './services/scrobbling/scrobbling.service'; +import { ScrobblingServiceBase } from './services/scrobbling/scrobbling.service.base'; import { DiscordService } from './services/discord/discord.service'; import { TranslatorServiceBase } from './services/translator/translator.service.base'; import { AppearanceServiceBase } from './services/appearance/appearance.service.base'; @@ -28,7 +28,7 @@ describe('AppComponent', () => { let appearanceServiceMock: IMock; let translatorServiceMock: IMock; let discordServiceMock: IMock; - let scrobblingServiceMock: IMock; + let scrobblingServiceMock: IMock; let trayServiceMock: IMock; let mediaSessionServiceMock: IMock; let eventListenerServiceMock: IMock; @@ -72,7 +72,7 @@ describe('AppComponent', () => { appearanceServiceMock = Mock.ofType(); translatorServiceMock = Mock.ofType(); discordServiceMock = Mock.ofType(); - scrobblingServiceMock = Mock.ofType(); + scrobblingServiceMock = Mock.ofType(); trayServiceMock = Mock.ofType(); mediaSessionServiceMock = Mock.ofType(); eventListenerServiceMock = Mock.ofType(); diff --git a/src/app/app.component.ts b/src/app/app.component.ts index 7c4413f4..f093972d 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -11,7 +11,7 @@ import { AppConfig } from '../environments/environment'; import { NavigationServiceBase } from './services/navigation/navigation.service.base'; import { AppearanceServiceBase } from './services/appearance/appearance.service.base'; import { TranslatorServiceBase } from './services/translator/translator.service.base'; -import { ScrobblingService } from './services/scrobbling/scrobbling.service'; +import { ScrobblingServiceBase } from './services/scrobbling/scrobbling.service.base'; import { TrayServiceBase } from './services/tray/tray.service.base'; import { MediaSessionService } from './services/media-session/media-session.service'; import { EventListenerServiceBase } from './services/event-listener/event-listener.service.base'; @@ -36,7 +36,7 @@ export class AppComponent implements OnInit { private appearanceService: AppearanceServiceBase, private translatorService: TranslatorServiceBase, private discordService: DiscordService, - private scrobblingService: ScrobblingService, + private scrobblingService: ScrobblingServiceBase, private trayService: TrayServiceBase, private mediaSessionService: MediaSessionService, private eventListenerService: EventListenerServiceBase, diff --git a/src/app/app.module.ts b/src/app/app.module.ts index ead83c51..f3ee45e5 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -209,6 +209,7 @@ import { EventListenerServiceBase } from './services/event-listener/event-listen import { LyricsServiceBase } from './services/lyrics/lyrics.service.base'; import { ArtistInformationServiceBase } from './services/artist-information/artist-information.service.base'; import { NowPlayingNavigationServiceBase } from './services/now-playing-navigation/now-playing-navigation.service.base'; +import { ScrobblingServiceBase } from './services/scrobbling/scrobbling.service.base'; import { TracksColumnsServiceBase } from './services/track-columns/tracks-columns.service.base'; import { SemanticZoomServiceBase } from './services/semantic-zoom/semantic-zoom.service.base'; import { TrayServiceBase } from './services/tray/tray.service.base'; @@ -588,6 +589,7 @@ export function appInitializerFactory(translate: TranslateService, injector: Inj { provide: TrayServiceBase, useClass: TrayService }, { provide: SemanticZoomServiceBase, useClass: SemanticZoomService }, { provide: TracksColumnsServiceBase, useClass: TracksColumnsService }, + { provide: ScrobblingServiceBase, useClass: ScrobblingService }, { provide: NowPlayingNavigationServiceBase, useClass: NowPlayingNavigationService }, { provide: ArtistInformationServiceBase, useClass: ArtistInformationService }, { provide: WelcomeServiceBase, useClass: WelcomeService }, diff --git a/src/app/services/scrobbling/scrobbling.service.base.ts b/src/app/services/scrobbling/scrobbling.service.base.ts new file mode 100644 index 00000000..1068816f --- /dev/null +++ b/src/app/services/scrobbling/scrobbling.service.base.ts @@ -0,0 +1,14 @@ +import { Observable } from 'rxjs'; +import { TrackModel } from '../track/track-model'; +import { SignInState } from './sign-in-state'; + +export abstract class ScrobblingServiceBase { + public abstract signInStateChanged$: Observable; + public abstract get signInState(): SignInState; + public abstract username: string; + public abstract password: string; + public abstract initialize(): void; + public abstract signInAsync(): Promise; + public abstract signOut(): void; + public abstract sendTrackLoveAsync(track: TrackModel, love: boolean): Promise; +} diff --git a/src/app/services/scrobbling/scrobbling.service.spec.ts b/src/app/services/scrobbling/scrobbling.service.spec.ts index 966a22ce..a8b4a05b 100644 --- a/src/app/services/scrobbling/scrobbling.service.spec.ts +++ b/src/app/services/scrobbling/scrobbling.service.spec.ts @@ -6,11 +6,12 @@ import { SettingsBase } from '../../common/settings/settings.base'; import { PlaybackProgress } from '../playback/playback-progress'; import { PlaybackStarted } from '../playback/playback-started'; import { TrackModel } from '../track/track-model'; +import { ScrobblingService } from './scrobbling.service'; import { SignInState } from './sign-in-state'; import { PlaybackService } from '../playback/playback.service'; import { LastfmApi } from '../../common/api/lastfm/lastfm.api'; import { TranslatorServiceBase } from '../translator/translator.service.base'; -import { ScrobblingService } from './scrobbling.service'; +import { ScrobblingServiceBase } from './scrobbling.service.base'; import { Track } from '../../data/entities/track'; jest.mock('jimp', () => ({ exec: jest.fn() })); @@ -59,7 +60,7 @@ describe('ScrobblingService', () => { playbackServiceMock.setup((x) => x.playbackSkipped$).returns(() => playbackService_playbackSkipped$); }); - function createService(): ScrobblingService { + function createService(): ScrobblingServiceBase { return new ScrobblingService( playbackServiceMock.object, lastfmApiMock.object, @@ -104,7 +105,7 @@ describe('ScrobblingService', () => { // Arrange // Act - const service: ScrobblingService = createService(); + const service: ScrobblingServiceBase = createService(); // Assert expect(service).toBeDefined(); @@ -115,7 +116,7 @@ describe('ScrobblingService', () => { it('should set username from settings if Last.fm scrobbling is enabled', () => { // Arrange createSettingsMock(true, 'user', 'password', 'key'); - const service: ScrobblingService = createService(); + const service: ScrobblingServiceBase = createService(); // Act service.initialize(); @@ -127,7 +128,7 @@ describe('ScrobblingService', () => { it('should set password from settings if Last.fm scrobbling is enabled', () => { // Arrange createSettingsMock(true, 'user', 'password', 'key'); - const service: ScrobblingService = createService(); + const service: ScrobblingServiceBase = createService(); // Act service.initialize(); @@ -139,7 +140,7 @@ describe('ScrobblingService', () => { it('should not set username from settings if Last.fm scrobbling is disabled', () => { // Arrange createSettingsMock(false, 'user', 'password', 'key'); - const service: ScrobblingService = createService(); + const service: ScrobblingServiceBase = createService(); // Act service.initialize(); @@ -151,7 +152,7 @@ describe('ScrobblingService', () => { it('should not set password from settings if Last.fm scrobbling is disabled', () => { // Arrange createSettingsMock(false, 'user', 'password', 'key'); - const service: ScrobblingService = createService(); + const service: ScrobblingServiceBase = createService(); // Act service.initialize(); @@ -163,7 +164,7 @@ describe('ScrobblingService', () => { it('should set SignInState to SignedOut if Last.fm scrobbling is disabled', () => { // Arrange createSettingsMock(false, 'user', 'password', 'key'); - const service: ScrobblingService = createService(); + const service: ScrobblingServiceBase = createService(); // Act service.initialize(); @@ -175,7 +176,7 @@ describe('ScrobblingService', () => { it('should set SignInState to SignedIn if Last.fm scrobbling is enabled and lastFmUsername, lastFmPassword and lastFmSessionKey are set in the settings', () => { // Arrange createSettingsMock(true, 'user', 'password', 'key'); - const service: ScrobblingService = createService(); + const service: ScrobblingServiceBase = createService(); // Act service.initialize(); @@ -187,7 +188,7 @@ describe('ScrobblingService', () => { it('should set SignInState to SignedOut if Last.fm scrobbling is enabled and lastFmUsername is not set in the settings', () => { // Arrange createSettingsMock(true, '', 'password', 'key'); - const service: ScrobblingService = createService(); + const service: ScrobblingServiceBase = createService(); // Act service.initialize(); @@ -199,7 +200,7 @@ describe('ScrobblingService', () => { it('should set SignInState to SignedOut if Last.fm scrobbling is enabled and lastFmPassword is not set in the settings', () => { // Arrange createSettingsMock(true, 'user', '', 'key'); - const service: ScrobblingService = createService(); + const service: ScrobblingServiceBase = createService(); // Act service.initialize(); @@ -211,7 +212,7 @@ describe('ScrobblingService', () => { it('should set SignInState to SignedOut if Last.fm scrobbling is enabled and lastFmSessionKey is not set in the settings', () => { // Arrange createSettingsMock(true, 'user', 'password', ''); - const service: ScrobblingService = createService(); + const service: ScrobblingServiceBase = createService(); // Act service.initialize(); @@ -228,7 +229,7 @@ describe('ScrobblingService', () => { .setup((x) => x.updateTrackNowPlayingAsync('key', 'artist1', 'title1', 'albumTitle1')) .returns(() => Promise.resolve(true)); createSettingsMock(true, 'user', 'password', 'key'); - const service: ScrobblingService = createService(); + const service: ScrobblingServiceBase = createService(); service.initialize(); const trackModel1: TrackModel = createTrackModel('path1', ';artist1;', 'title1', 'albumTitle1', 300000); @@ -248,7 +249,7 @@ describe('ScrobblingService', () => { .setup((x) => x.updateTrackNowPlayingAsync('key', 'artist1', 'title1', 'albumTitle1')) .returns(() => Promise.resolve(true)); createSettingsMock(false, 'user', 'password', 'key'); - const service: ScrobblingService = createService(); + const service: ScrobblingServiceBase = createService(); service.initialize(); const trackModel1: TrackModel = createTrackModel('path1', ';artist1;', 'title1', 'albumTitle1', 300000); @@ -268,7 +269,7 @@ describe('ScrobblingService', () => { .setup((x) => x.updateTrackNowPlayingAsync('key', 'artist1', 'title1', 'albumTitle1')) .returns(() => Promise.resolve(true)); createSettingsMock(true, 'user', 'password', 'key'); - const service: ScrobblingService = createService(); + const service: ScrobblingServiceBase = createService(); service.initialize(); const trackModel1: TrackModel = createTrackModel('path1', '', 'title1', 'albumTitle1', 300000); @@ -288,7 +289,7 @@ describe('ScrobblingService', () => { .setup((x) => x.updateTrackNowPlayingAsync('key', 'artist1', 'title1', 'albumTitle1')) .returns(() => Promise.resolve(true)); createSettingsMock(true, 'user', 'password', 'key'); - const service: ScrobblingService = createService(); + const service: ScrobblingServiceBase = createService(); service.initialize(); const trackModel1: TrackModel = createTrackModel('path1', ';artist1;', '', 'albumTitle1', 300000); @@ -312,7 +313,7 @@ describe('ScrobblingService', () => { .setup((x) => x.updateTrackNowPlayingAsync('key', 'artist1', 'title1', 'albumTitle1')) .returns(() => Promise.resolve(true)); createSettingsMock(true, 'user', 'password', 'key'); - const service: ScrobblingService = createService(); + const service: ScrobblingServiceBase = createService(); service.initialize(); const trackModel1: TrackModel = createTrackModel('path1', ';artist1;', 'title1', 'albumTitle1', 300000); @@ -339,7 +340,7 @@ describe('ScrobblingService', () => { .setup((x) => x.updateTrackNowPlayingAsync('key', 'artist1', 'title1', 'albumTitle1')) .returns(() => Promise.resolve(true)); createSettingsMock(true, 'user', 'password', 'key'); - const service: ScrobblingService = createService(); + const service: ScrobblingServiceBase = createService(); service.initialize(); const trackModel1: TrackModel = createTrackModel('path1', ';artist1;', 'title1', 'albumTitle1', 900000); @@ -366,7 +367,7 @@ describe('ScrobblingService', () => { .setup((x) => x.updateTrackNowPlayingAsync('key', 'artist1', 'title1', 'albumTitle1')) .returns(() => Promise.resolve(true)); createSettingsMock(true, 'user', 'password', 'key'); - const service: ScrobblingService = createService(); + const service: ScrobblingServiceBase = createService(); service.initialize(); const trackModel1: TrackModel = createTrackModel('path1', ';artist1;', 'title1', 'albumTitle1', 20000); @@ -393,7 +394,7 @@ describe('ScrobblingService', () => { .setup((x) => x.updateTrackNowPlayingAsync('key', 'artist1', 'title1', 'albumTitle1')) .returns(() => Promise.resolve(true)); createSettingsMock(true, 'user', 'password', 'key'); - const service: ScrobblingService = createService(); + const service: ScrobblingServiceBase = createService(); service.initialize(); const trackModel1: TrackModel = createTrackModel('path1', ';artist1;', 'title1', 'albumTitle1', 300000); @@ -421,7 +422,7 @@ describe('ScrobblingService', () => { .setup((x) => x.updateTrackNowPlayingAsync('key', 'artist1', 'title1', 'albumTitle1')) .returns(() => Promise.resolve(true)); createSettingsMock(false, 'user', 'password', 'key'); - const service: ScrobblingService = createService(); + const service: ScrobblingServiceBase = createService(); service.initialize(); const trackModel1: TrackModel = createTrackModel('path1', ';artist1;', 'title1', 'albumTitle1', 300000); @@ -448,7 +449,7 @@ describe('ScrobblingService', () => { .setup((x) => x.updateTrackNowPlayingAsync('key', 'artist1', 'title1', 'albumTitle1')) .returns(() => Promise.resolve(true)); createSettingsMock(true, 'user', 'password', 'key'); - const service: ScrobblingService = createService(); + const service: ScrobblingServiceBase = createService(); service.initialize(); const playbackProgress: PlaybackProgress = new PlaybackProgress(200, 300); @@ -472,7 +473,7 @@ describe('ScrobblingService', () => { .setup((x) => x.updateTrackNowPlayingAsync('key', 'artist1', 'title1', 'albumTitle1')) .returns(() => Promise.resolve(true)); createSettingsMock(true, 'user', 'password', 'key'); - const service: ScrobblingService = createService(); + const service: ScrobblingServiceBase = createService(); service.initialize(); const trackModel1: TrackModel = createTrackModel('path1', '', 'title1', 'albumTitle1', 300000); @@ -499,7 +500,7 @@ describe('ScrobblingService', () => { .setup((x) => x.updateTrackNowPlayingAsync('key', 'artist1', 'title1', 'albumTitle1')) .returns(() => Promise.resolve(true)); createSettingsMock(true, 'user', 'password', 'key'); - const service: ScrobblingService = createService(); + const service: ScrobblingServiceBase = createService(); service.initialize(); const trackModel1: TrackModel = createTrackModel('path1', ';artist1;', '', 'albumTitle1', 300000); @@ -523,7 +524,7 @@ describe('ScrobblingService', () => { it('should not send track love/unlove when not signed in', async () => { // Arrange createSettingsMock(false, 'user', 'password', 'key'); - const service: ScrobblingService = createService(); + const service: ScrobblingServiceBase = createService(); service.initialize(); const trackModel1: TrackModel = createTrackModel('path1', ';artist1a;;artist1b;', 'title1', 'albumTitle1', 300000); @@ -539,7 +540,7 @@ describe('ScrobblingService', () => { it('should not send track love/unlove for an unknown track title', async () => { // Arrange createSettingsMock(true, 'user', 'password', 'key'); - const service: ScrobblingService = createService(); + const service: ScrobblingServiceBase = createService(); service.initialize(); const trackModel1: TrackModel = createTrackModel('path1', ';artist1a;;artist1b;', '', 'albumTitle1', 300000); @@ -555,7 +556,7 @@ describe('ScrobblingService', () => { it('should not send track love/unlove for unknown artists', async () => { // Arrange createSettingsMock(true, 'user', 'password', 'key'); - const service: ScrobblingService = createService(); + const service: ScrobblingServiceBase = createService(); service.initialize(); const trackModel1: TrackModel = createTrackModel('path1', '', 'title1', 'albumTitle1', 300000); @@ -571,7 +572,7 @@ describe('ScrobblingService', () => { it('should send track love for all artists', async () => { // Arrange createSettingsMock(true, 'user', 'password', 'key'); - const service: ScrobblingService = createService(); + const service: ScrobblingServiceBase = createService(); service.initialize(); const trackModel1: TrackModel = createTrackModel('path1', ';artist1a;;artist1b;', 'title1', 'albumTitle1', 300000); @@ -588,7 +589,7 @@ describe('ScrobblingService', () => { it('should send track unlove for all artists', async () => { // Arrange createSettingsMock(true, 'user', 'password', 'key'); - const service: ScrobblingService = createService(); + const service: ScrobblingServiceBase = createService(); service.initialize(); const trackModel1: TrackModel = createTrackModel('path1', ';artist1a;;artist1b;', 'title1', 'albumTitle1', 300000); diff --git a/src/app/services/scrobbling/scrobbling.service.ts b/src/app/services/scrobbling/scrobbling.service.ts index cd08295c..0e66785a 100644 --- a/src/app/services/scrobbling/scrobbling.service.ts +++ b/src/app/services/scrobbling/scrobbling.service.ts @@ -11,11 +11,12 @@ import { PlaybackStarted } from '../playback/playback-started'; import { TrackModel } from '../track/track-model'; import { SignInState } from './sign-in-state'; +import { ScrobblingServiceBase } from './scrobbling.service.base'; import { PlaybackService } from '../playback/playback.service'; import { SettingsBase } from '../../common/settings/settings.base'; -@Injectable({ providedIn: 'root' }) -export class ScrobblingService { +@Injectable() +export class ScrobblingService implements ScrobblingServiceBase { private _signInState: SignInState = SignInState.SignedOut; private sessionKey: string = ''; diff --git a/src/app/ui/components/love/love.component.spec.ts b/src/app/ui/components/love/love.component.spec.ts index 8b36767d..054b3e1f 100644 --- a/src/app/ui/components/love/love.component.spec.ts +++ b/src/app/ui/components/love/love.component.spec.ts @@ -1,7 +1,7 @@ import { IMock, It, Mock, Times } from 'typemoq'; import { LoveComponent } from './love.component'; import { AppearanceServiceBase } from '../../../services/appearance/appearance.service.base'; -import { ScrobblingService } from '../../../services/scrobbling/scrobbling.service'; +import { ScrobblingServiceBase } from '../../../services/scrobbling/scrobbling.service.base'; import { DialogServiceBase } from '../../../services/dialog/dialog.service.base'; import { TranslatorServiceBase } from '../../../services/translator/translator.service.base'; import { DateTime } from '../../../common/date-time'; @@ -14,7 +14,7 @@ jest.mock('jimp', () => ({ exec: jest.fn() })); describe('LoveComponent', () => { let appearanceServiceMock: IMock; - let scrobblingServiceMock: IMock; + let scrobblingServiceMock: IMock; let metadataServiceMock: IMock; let dialogServiceMock: IMock; let dateTimeMock: IMock; @@ -33,7 +33,7 @@ describe('LoveComponent', () => { beforeEach(() => { metadataServiceMock = Mock.ofType(); - scrobblingServiceMock = Mock.ofType(); + scrobblingServiceMock = Mock.ofType(); dialogServiceMock = Mock.ofType(); dateTimeMock = Mock.ofType(); translatorServiceMock = Mock.ofType(); diff --git a/src/app/ui/components/love/love.component.ts b/src/app/ui/components/love/love.component.ts index 99ad93c9..a1613917 100644 --- a/src/app/ui/components/love/love.component.ts +++ b/src/app/ui/components/love/love.component.ts @@ -1,7 +1,7 @@ import { Component, Input } from '@angular/core'; import { TrackModel } from '../../../services/track/track-model'; import { AppearanceServiceBase } from '../../../services/appearance/appearance.service.base'; -import { ScrobblingService } from '../../../services/scrobbling/scrobbling.service'; +import { ScrobblingServiceBase } from '../../../services/scrobbling/scrobbling.service.base'; import { MetadataService } from '../../../services/metadata/metadata.service'; import { DialogServiceBase } from '../../../services/dialog/dialog.service.base'; import { TranslatorServiceBase } from '../../../services/translator/translator.service.base'; @@ -17,7 +17,7 @@ export class LoveComponent { public constructor( private appearanceService: AppearanceServiceBase, - private scrobblingService: ScrobblingService, + private scrobblingService: ScrobblingServiceBase, private metadataService: MetadataService, private dialogService: DialogServiceBase, private translatorService: TranslatorServiceBase, diff --git a/src/app/ui/components/settings/online-settings/online-settings.component.spec.ts b/src/app/ui/components/settings/online-settings/online-settings.component.spec.ts index 52ce118a..86106bbb 100644 --- a/src/app/ui/components/settings/online-settings/online-settings.component.spec.ts +++ b/src/app/ui/components/settings/online-settings/online-settings.component.spec.ts @@ -1,7 +1,7 @@ import { Observable, Subject } from 'rxjs'; import { IMock, Mock, Times } from 'typemoq'; import { OnlineSettingsComponent } from './online-settings.component'; -import { ScrobblingService } from '../../../../services/scrobbling/scrobbling.service'; +import { ScrobblingServiceBase } from '../../../../services/scrobbling/scrobbling.service.base'; import { SignInState } from '../../../../services/scrobbling/sign-in-state'; import { NotificationServiceBase } from '../../../../services/notification/notification.service.base'; import { DiscordService } from '../../../../services/discord/discord.service'; @@ -10,7 +10,7 @@ jest.mock('jimp', () => ({ exec: jest.fn() })); describe('OnlineSettingsComponent', () => { let discordServiceMock: IMock; - let scrobblingServiceMock: IMock; + let scrobblingServiceMock: IMock; let notificationServiceMock: IMock; let settingsStub: any; @@ -34,7 +34,7 @@ describe('OnlineSettingsComponent', () => { beforeEach(() => { discordServiceMock = Mock.ofType(); - scrobblingServiceMock = Mock.ofType(); + scrobblingServiceMock = Mock.ofType(); notificationServiceMock = Mock.ofType(); settingsStub = { enableDiscordRichPresence: true, enableLastFmScrobbling: true, downloadLyricsOnline: true }; diff --git a/src/app/ui/components/settings/online-settings/online-settings.component.ts b/src/app/ui/components/settings/online-settings/online-settings.component.ts index 4f8545a8..841f001a 100644 --- a/src/app/ui/components/settings/online-settings/online-settings.component.ts +++ b/src/app/ui/components/settings/online-settings/online-settings.component.ts @@ -2,7 +2,7 @@ import { Component, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core'; import { Subscription } from 'rxjs'; import { PromiseUtils } from '../../../../common/utils/promise-utils'; import { SignInState } from '../../../../services/scrobbling/sign-in-state'; -import { ScrobblingService } from '../../../../services/scrobbling/scrobbling.service'; +import { ScrobblingServiceBase } from '../../../../services/scrobbling/scrobbling.service.base'; import { SettingsBase } from '../../../../common/settings/settings.base'; import { NotificationServiceBase } from '../../../../services/notification/notification.service.base'; import { DiscordService } from '../../../../services/discord/discord.service'; @@ -20,7 +20,7 @@ export class OnlineSettingsComponent implements OnInit, OnDestroy { public constructor( private discordService: DiscordService, - private scrobblingService: ScrobblingService, + private scrobblingService: ScrobblingServiceBase, private notificationService: NotificationServiceBase, public settings: SettingsBase, ) {}