diff --git a/src/TidalControllers/DomTidalController.ts b/src/TidalControllers/DomTidalController.ts index 045107b..8ed6f7a 100644 --- a/src/TidalControllers/DomTidalController.ts +++ b/src/TidalControllers/DomTidalController.ts @@ -1,7 +1,20 @@ +import { MediaStatus } from "../models/mediaStatus"; +import { RepeatState } from "../models/repeatState"; import { TidalController } from "./TidalController"; export class DomTidalController implements TidalController { - public elements = { + private currentPlayStatus = MediaStatus.paused; + + /** + * Convert the duration from MM:SS to seconds + * @param {*} duration + */ + private convertDuration(duration: string) { + const parts = duration.split(":"); + return parseInt(parts[1]) + 60 * parseInt(parts[0]); + } + + private readonly elements = { play: '*[data-test="play"]', pause: '*[data-test="pause"]', next: '*[data-test="next"]', @@ -93,15 +106,14 @@ export class DomTidalController implements TidalController { globalThis.location.href.includes("/playlist/") || globalThis.location.href.includes("/mix/") ) { - // TODO: fix - // if (currentPlayStatus === MediaStatus.playing) { - // // find the currently playing element from the list (which might be in an album icon), traverse back up to the mediaItem (row) and select the album cell. - // // document.querySelector("[class^='isPlayingIcon'], [data-test-is-playing='true']").closest('[data-type="mediaItem"]').querySelector('[class^="album"]').textContent - // const row = window.document.querySelector(this.currentlyPlaying).closest(this.mediaItem); - // if (row) { - // return row.querySelector(this.album_name_cell).textContent; - // } - // } + if (this.currentPlayStatus === MediaStatus.playing) { + // find the currently playing element from the list (which might be in an album icon), traverse back up to the mediaItem (row) and select the album cell. + // document.querySelector("[class^='isPlayingIcon'], [data-test-is-playing='true']").closest('[data-type="mediaItem"]').querySelector('[class^="album"]').textContent + const row = window.document.querySelector(this.currentlyPlaying).closest(this.mediaItem); + if (row) { + return row.querySelector(this.album_name_cell).textContent; + } + } } // see whether we're on the queue page and get it from there @@ -162,7 +174,122 @@ export class DomTidalController implements TidalController { this.elements.click("home"); } - hookup = (): void => { - throw new Error("Method not implemented."); - }; + openSettings(): void { + this.elements.click("settings"); + setTimeout(() => { + this.elements.click("openSettings"); + }, 100); + } + + toggleFavorite(): void { + this.elements.click("favorite"); + } + + back(): void { + this.elements.click("back"); + } + forward(): void { + this.elements.click("forward"); + } + repeat(): void { + this.elements.click("repeat"); + } + + next(): void { + this.elements.click("next"); + } + previous(): void { + this.elements.click("previous"); + } + toggleShuffle(): void { + this.elements.click("shuffle"); + } + getCurrentlyPlayingStatus() { + const pause = this.elements.get("pause"); + + // if pause button is visible tidal is playing + if (pause) { + return MediaStatus.playing; + } else { + return MediaStatus.paused; + } + } + + getCurrentShuffleState() { + const shuffle = this.elements.get("shuffle"); + return shuffle?.getAttribute("aria-checked") === "true"; + } + + getCurrentRepeatState() { + const repeat = this.elements.get("repeat"); + switch (repeat?.getAttribute("data-type")) { + case "button__repeatAll": + return RepeatState.all; + case "button__repeatSingle": + return RepeatState.single; + default: + return RepeatState.off; + } + } + + play(): void { + this.playPause(); + } + pause(): void { + this.playPause(); + } + stop(): void { + this.playPause(); + } + + getCurrentPosition() { + return this.elements.getText("current"); + } + getCurrentPositionInSeconds(): number { + return this.convertDuration(this.getCurrentPosition()) * 1000 * 1000; + } + + getTrackId(): string { + const URLelement = this.elements.get("title").querySelector("a"); + if (URLelement !== null) { + const id = URLelement.href.replace(/\D/g, ""); + return id; + } + + return window.location.toString(); + } + + getCurrentTime(): string { + return this.elements.getText("current"); + } + getDuration(): string { + return this.elements.getText("duration"); + } + + getAlbumName(): string { + return this.elements.getAlbumName(); + } + getTitle(): string { + return this.elements.getText("title"); + } + getArtists(): string[] { + return this.elements.getArtistsArray(); + } + + getArtistsString(): string { + return this.elements.getArtistsString(this.getArtists()); + } + getPlayingFrom(): string { + return this.elements.getText("playing_from"); + } + + isFavorite(): boolean { + return this.elements.isFavorite(); + } + getSongIcon(): string { + return this.elements.getSongIcon(); + } + setPlayStatus(status: MediaStatus): void { + this.currentPlayStatus = status; + } } diff --git a/src/TidalControllers/MediaSessionTidalController.ts b/src/TidalControllers/MediaSessionTidalController.ts index e6b4c5b..a474759 100644 --- a/src/TidalControllers/MediaSessionTidalController.ts +++ b/src/TidalControllers/MediaSessionTidalController.ts @@ -1,3 +1,5 @@ +import { MediaStatus } from "../models/mediaStatus"; +import { RepeatState } from "../models/repeatState"; import { DomTidalController } from "./DomTidalController"; import { TidalController } from "./TidalController"; @@ -7,13 +9,125 @@ export class MediaSessionTidalController implements TidalController { constructor() { this.domMediaController = new DomTidalController(); } + // example of using the original domMediaController as a fallback goToHome(): void { this.domMediaController.goToHome(); } + + setPlayStatus(status: MediaStatus): void { + globalThis.alert("Method not implemented: " + status); + throw new Error("Method not implemented."); + } + getDuration(): string { + globalThis.alert("Method not implemented"); + throw new Error("Method not implemented."); + } + getAlbumName(): string { + globalThis.alert("Method not implemented"); + throw new Error("Method not implemented."); + } + getTitle(): string { + globalThis.alert("Method not implemented"); + throw new Error("Method not implemented."); + } + getArtists(): string[] { + globalThis.alert("Method not implemented"); + throw new Error("Method not implemented."); + } + getArtistsString(): string { + globalThis.alert("Method not implemented"); + throw new Error("Method not implemented."); + } + getPlayingFrom(): string { + globalThis.alert("Method not implemented"); + throw new Error("Method not implemented."); + } + isFavorite(): boolean { + globalThis.alert("Method not implemented"); + throw new Error("Method not implemented."); + } + getSongIcon(): string { + globalThis.alert("Method not implemented"); + throw new Error("Method not implemented."); + } + getCurrentTime(): string { + globalThis.alert("Method not implemented"); + throw new Error("Method not implemented."); + } + getCurrentPosition(): string { + globalThis.alert("Method not implemented"); + throw new Error("Method not implemented."); + } + getCurrentPositionInSeconds(): number { + globalThis.alert("Method not implemented"); + throw new Error("Method not implemented."); + } + getTrackId(): string { + globalThis.alert("Method not implemented"); + throw new Error("Method not implemented."); + } + play(): void { + globalThis.alert("Method not implemented"); + throw new Error("Method not implemented."); + } + pause(): void { + globalThis.alert("Method not implemented"); + throw new Error("Method not implemented."); + } + stop(): void { + globalThis.alert("Method not implemented"); + throw new Error("Method not implemented."); + } + getCurrentShuffleState(): boolean { + globalThis.alert("Method not implemented"); + throw new Error("Method not implemented."); + } + getCurrentRepeatState(): RepeatState { + globalThis.alert("Method not implemented"); + throw new Error("Method not implemented."); + } + getCurrentlyPlayingStatus(): MediaStatus { + globalThis.alert("Method not implemented"); + throw new Error("Method not implemented."); + } + back(): void { + globalThis.alert("Method not implemented"); + throw new Error("Method not implemented."); + } + forward(): void { + globalThis.alert("Method not implemented"); + throw new Error("Method not implemented."); + } + repeat(): void { + globalThis.alert("Method not implemented"); + throw new Error("Method not implemented."); + } + next(): void { + globalThis.alert("Method not implemented"); + throw new Error("Method not implemented."); + } + previous(): void { + globalThis.alert("Method not implemented"); + throw new Error("Method not implemented."); + } + toggleShuffle(): void { + globalThis.alert("Method not implemented"); + throw new Error("Method not implemented."); + } + openSettings(): void { + globalThis.alert("Method not implemented"); + throw new Error("Method not implemented."); + } + toggleFavorite(): void { + globalThis.alert("Method not implemented"); + throw new Error("Method not implemented."); + } playPause(): void { globalThis.alert("Method not implemented"); + throw new Error("Method not implemented."); } hookup(): void { globalThis.alert("Method not implemented"); + throw new Error("Method not implemented."); } } diff --git a/src/TidalControllers/TidalController.ts b/src/TidalControllers/TidalController.ts index 3d68e3e..7bb1b9d 100644 --- a/src/TidalControllers/TidalController.ts +++ b/src/TidalControllers/TidalController.ts @@ -1,13 +1,47 @@ +import { MediaStatus } from "../models/mediaStatus"; +import { RepeatState } from "../models/repeatState"; + export interface TidalController { + goToHome(): void; + openSettings(): void; + /** * Play or pause the current media */ playPause(): void; + play(): void; + pause(): void; + stop(): void; + toggleFavorite(): void; + back(): void; + forward(): void; + repeat(): void; + next(): void; + previous(): void; + toggleShuffle(): void; /** - * Hook up the controller to the current web instance + * Update the current status of tidal (e.g playing or paused) */ - hookup(): void; + getCurrentlyPlayingStatus(): MediaStatus; + getCurrentShuffleState(): boolean; + getCurrentRepeatState(): RepeatState; + getCurrentPosition(): string; + getCurrentPositionInSeconds(): number; + getTrackId(): string; + getCurrentTime(): string; + getDuration(): string; + getAlbumName(): string; + getTitle(): string; + getArtists(): string[]; + getArtistsString(): string; + getPlayingFrom(): string; + getSongIcon(): string; - goToHome(): void; + isFavorite(): boolean; + // add an observable to react on instead of a hookup function + // onMediaChange(): any; + + // this can probably be removed after ^ + setPlayStatus(status: MediaStatus): void; } diff --git a/src/features/api/swagger.json b/src/features/api/swagger.json index 30d5f98..bac2fc9 100644 --- a/src/features/api/swagger.json +++ b/src/features/api/swagger.json @@ -21,7 +21,9 @@ "/current": { "get": { "summary": "Get current media info", - "tags": ["current"], + "tags": [ + "current" + ], "responses": { "200": { "description": "Current media info", @@ -39,7 +41,9 @@ "/current/image": { "get": { "summary": "Get current media image", - "tags": ["current"], + "tags": [ + "current" + ], "responses": { "200": { "description": "Current media image", @@ -61,7 +65,9 @@ "/player/play": { "post": { "summary": "Play the current media", - "tags": ["player"], + "tags": [ + "player" + ], "responses": { "200": { "description": "Ok", @@ -79,7 +85,9 @@ "/player/favorite/toggle": { "post": { "summary": "Add the current media to your favorites, or remove it if its already added to your favorites", - "tags": ["player"], + "tags": [ + "player" + ], "responses": { "200": { "description": "Ok", @@ -97,7 +105,9 @@ "/player/pause": { "post": { "summary": "Pause the current media", - "tags": ["player"], + "tags": [ + "player" + ], "responses": { "200": { "description": "Ok", @@ -115,7 +125,9 @@ "/player/next": { "post": { "summary": "Play the next song", - "tags": ["player"], + "tags": [ + "player" + ], "responses": { "200": { "description": "Ok", @@ -133,7 +145,9 @@ "/player/previous": { "post": { "summary": "Play the previous song", - "tags": ["player"], + "tags": [ + "player" + ], "responses": { "200": { "description": "Ok", @@ -151,7 +165,9 @@ "/player/shuffle/toggle": { "post": { "summary": "Play the previous song", - "tags": ["player"], + "tags": [ + "player" + ], "responses": { "200": { "description": "Ok", @@ -169,7 +185,9 @@ "/player/repeat/toggle": { "post": { "summary": "Toggle the repeat status, toggles between \"off\" , \"single\" and \"all\"", - "tags": ["player"], + "tags": [ + "player" + ], "responses": { "200": { "description": "Ok", @@ -187,7 +205,9 @@ "/player/playpause": { "post": { "summary": "Start playing the media if paused, or pause the media if playing", - "tags": ["player"], + "tags": [ + "player" + ], "responses": { "200": { "description": "Ok", @@ -205,7 +225,9 @@ "/settings/skipped-artists": { "get": { "summary": "get a list of artists that TIDAL Hi-Fi will skip if skipping is enabled", - "tags": ["settings"], + "tags": [ + "settings" + ], "responses": { "200": { "description": "The list book.", @@ -221,7 +243,9 @@ }, "post": { "summary": "Add new artists to the list of skipped artists", - "tags": ["settings"], + "tags": [ + "settings" + ], "requestBody": { "required": true, "content": { @@ -242,7 +266,9 @@ "/settings/skipped-artists/delete": { "post": { "summary": "Remove artists from the list of skipped artists", - "tags": ["settings"], + "tags": [ + "settings" + ], "requestBody": { "required": true, "content": { @@ -263,7 +289,9 @@ "/settings/skipped-artists/current": { "post": { "summary": "Add the current artist to the list of skipped artists", - "tags": ["settings"], + "tags": [ + "settings" + ], "responses": { "200": { "description": "Ok" @@ -272,7 +300,9 @@ }, "delete": { "summary": "Remove the current artist from the list of skipped artists", - "tags": ["settings"], + "tags": [ + "settings" + ], "responses": { "200": { "description": "Ok" @@ -283,7 +313,9 @@ "/image": { "get": { "summary": "Get current image", - "tags": ["legacy"], + "tags": [ + "legacy" + ], "deprecated": true, "responses": { "200": { @@ -306,7 +338,9 @@ "/play": { "get": { "summary": "Play the current media", - "tags": ["legacy"], + "tags": [ + "legacy" + ], "deprecated": true, "responses": { "200": { @@ -325,7 +359,9 @@ "/favorite/toggle": { "get": { "summary": "Add the current media to your favorites, or remove it if its already added to your favorites", - "tags": ["legacy"], + "tags": [ + "legacy" + ], "deprecated": true, "responses": { "200": { @@ -344,7 +380,9 @@ "/pause": { "get": { "summary": "Pause the current media", - "tags": ["legacy"], + "tags": [ + "legacy" + ], "deprecated": true, "responses": { "200": { @@ -363,7 +401,9 @@ "/next": { "get": { "summary": "Play the next song", - "tags": ["legacy"], + "tags": [ + "legacy" + ], "deprecated": true, "responses": { "200": { @@ -382,7 +422,9 @@ "/previous": { "get": { "summary": "Play the previous song", - "tags": ["legacy"], + "tags": [ + "legacy" + ], "deprecated": true, "responses": { "200": { @@ -401,7 +443,9 @@ "/playpause": { "get": { "summary": "Toggle play/pause", - "tags": ["legacy"], + "tags": [ + "legacy" + ], "deprecated": true, "responses": { "200": { @@ -514,7 +558,10 @@ "items": { "type": "string" }, - "example": ["Artist1", "Artist2"] + "example": [ + "Artist1", + "Artist2" + ] } } }, @@ -532,4 +579,4 @@ "description": "The settings management API" } ] -} +} \ No newline at end of file diff --git a/src/preload.ts b/src/preload.ts index 8c7d981..d7262f1 100644 --- a/src/preload.ts +++ b/src/preload.ts @@ -28,7 +28,6 @@ import { TidalController } from "./TidalControllers/TidalController"; const notificationPath = `${app.getPath("userData")}/notification.jpg`; let currentSong = ""; let player: Player; -let currentPlayStatus = MediaStatus.paused; let currentListenBrainzDelayId: ReturnType; let scrobbleWaitingForDelay = false; @@ -48,151 +47,6 @@ if (true) { tidalController = new MediaSessionTidalController(); } -const elements = { - play: '*[data-test="play"]', - pause: '*[data-test="pause"]', - next: '*[data-test="next"]', - previous: 'button[data-test="previous"]', - title: '*[data-test^="footer-track-title"]', - artists: '*[data-test^="grid-item-detail-text-title-artist"]', - home: '*[data-test="menu--home"]', - back: '[title^="Back"]', - forward: '[title^="Next"]', - search: '[class^="searchField"]', - shuffle: '*[data-test="shuffle"]', - repeat: '*[data-test="repeat"]', - account: '*[data-test^="profile-image-button"]', - settings: '*[data-test^="sidebar-menu-button"]', - openSettings: '*[data-test^="open-settings"]', - media: '*[data-test="current-media-imagery"]', - image: "img", - current: '*[data-test="current-time"]', - duration: '*[class^=playbackControlsContainer] *[data-test="duration"]', - bar: '*[data-test="progress-bar"]', - footer: "#footerPlayer", - mediaItem: "[data-type='mediaItem']", - album_header_title: '*[class^="playingFrom"] span:nth-child(2)', - playing_from: '*[class^="playingFrom"] span:nth-child(2)', - queue_album: "*[class^=playQueueItemsContainer] *[class^=groupTitle] span:nth-child(2)", - currentlyPlaying: "[class^='isPlayingIcon'], [data-test-is-playing='true']", - album_name_cell: '[class^="album"]', - tracklist_row: '[data-test="tracklist-row"]', - volume: '*[data-test="volume"]', - favorite: '*[data-test="footer-favorite-button"]', - /** - * Get an element from the dom - * @param {*} key key in elements object to fetch - */ - get: function (key: string) { - return window.document.querySelector(this[key.toLowerCase()]); - }, - - /** - * Get the icon of the current media - */ - getSongIcon: function () { - const figure = this.get("media"); - - if (figure) { - const mediaElement = figure.querySelector(this["image"]); - if (mediaElement) { - return mediaElement.src.replace("80x80", "640x640"); - } - } - - return ""; - }, - - /** - * returns an array of all artists in the current media - * @returns {Array} artists - */ - getArtistsArray: function () { - const footer = this.get("footer"); - - if (footer) { - const artists = footer.querySelectorAll(this.artists); - if (artists) return Array.from(artists).map((artist) => (artist as HTMLElement).textContent); - } - return []; - }, - - /** - * unify the artists array into a string separated by commas - * @param {Array} artistsArray - * @returns {String} artists - */ - getArtistsString: function (artistsArray: string[]) { - if (artistsArray.length > 0) return artistsArray.join(", "); - return "unknown artist(s)"; - }, - - getAlbumName: function () { - //If listening to an album, get its name from the header title - if (window.location.href.includes("/album/")) { - const albumName = window.document.querySelector(this.album_header_title); - if (albumName) { - return albumName.textContent; - } - //If listening to a playlist or a mix, get album name from the list - } else if ( - window.location.href.includes("/playlist/") || - window.location.href.includes("/mix/") - ) { - if (currentPlayStatus === MediaStatus.playing) { - // find the currently playing element from the list (which might be in an album icon), traverse back up to the mediaItem (row) and select the album cell. - // document.querySelector("[class^='isPlayingIcon'], [data-test-is-playing='true']").closest('[data-type="mediaItem"]').querySelector('[class^="album"]').textContent - const row = window.document.querySelector(this.currentlyPlaying).closest(this.mediaItem); - if (row) { - return row.querySelector(this.album_name_cell).textContent; - } - } - } - - // see whether we're on the queue page and get it from there - const queueAlbumName = elements.getText("queue_album"); - if (queueAlbumName) { - return queueAlbumName; - } - - return ""; - }, - - isMuted: function () { - return this.get("volume").getAttribute("aria-checked") === "false"; // it's muted if aria-checked is false - }, - - isFavorite: function () { - return this.get("favorite").getAttribute("aria-checked") === "true"; - }, - - /** - * Shorthand function to get the text of a dom element - * @param {*} key key in elements object to fetch - */ - getText: function (key: string) { - const element = this.get(key); - return element ? element.textContent : ""; - }, - - /** - * Shorthand function to click a dom element - * @param {*} key key in elements object to fetch - */ - click: function (key: string) { - this.get(key).click(); - return this; - }, - - /** - * Shorthand function to focus a dom element - * @param {*} key key in elements object to fetch - */ - focus: function (key: string) { - return this.get(key).focus(); - }, -}; - /** * Get the update frequency from the store * make sure it returns a number, if not use the default @@ -220,30 +74,26 @@ ListenBrainzStore.clear(); */ function addHotKeys() { if (settingsStore.get(settings.enableCustomHotkeys)) { - addHotkey("Control+p", function () { - elements.click("settings"); - setTimeout(() => { - elements.click("openSettings"); - }, 100); + addHotkey("Control+p", () => { + tidalController.openSettings(); }); - addHotkey("Control+l", function () { + addHotkey("Control+l", () => { handleLogout(); }); - - addHotkey("Control+a", function () { - elements.click("favorite"); + addHotkey("Control+a", () => { + tidalController.toggleFavorite(); }); - addHotkey("Control+h", function () { + addHotkey("Control+h", () => { tidalController.goToHome(); }); addHotkey("backspace", function () { - elements.click("back"); + tidalController.back(); }); addHotkey("shift+backspace", function () { - elements.click("forward"); + tidalController.forward(); }); addHotkey("control+u", function () { @@ -252,7 +102,7 @@ function addHotKeys() { }); addHotkey("control+r", function () { - elements.click("repeat"); + tidalController.repeat(); }); addHotkey("control+w", async function () { const url = SharingService.getUniversalLink(getTrackURL()); @@ -322,19 +172,19 @@ function addIPCEventListeners() { tidalController.playPause(); break; case globalEvents.next: - elements.click("next"); + tidalController.next(); break; case globalEvents.previous: - elements.click("previous"); + tidalController.previous(); break; case globalEvents.toggleFavorite: - elements.click("favorite"); + tidalController.toggleFavorite(); break; case globalEvents.toggleShuffle: - elements.click("shuffle"); + tidalController.toggleShuffle(); break; case globalEvents.toggleRepeat: - elements.click("repeat"); + tidalController.repeat(); break; default: break; @@ -343,39 +193,6 @@ function addIPCEventListeners() { }); } -/** - * Update the current status of tidal (e.g playing or paused) - */ -function getCurrentlyPlayingStatus() { - const pause = elements.get("pause"); - let status = undefined; - - // if pause button is visible tidal is playing - if (pause) { - status = MediaStatus.playing; - } else { - status = MediaStatus.paused; - } - return status; -} - -function getCurrentShuffleState() { - const shuffle = elements.get("shuffle"); - return shuffle?.getAttribute("aria-checked") === "true"; -} - -function getCurrentRepeatState() { - const repeat = elements.get("repeat"); - switch (repeat?.getAttribute("data-type")) { - case "button__repeatAll": - return RepeatState.all; - case "button__repeatSingle": - return RepeatState.single; - default: - return RepeatState.off; - } -} - /** * Convert the duration from MM:SS to seconds * @param {*} duration @@ -457,14 +274,33 @@ function addMPRIS() { case events.playpause: tidalController.playPause(); break; - default: - elements.click(eventValue); + case events.next: + tidalController.next(); + break; + case events.previous: + tidalController.previous(); + break; + case events.pause: + tidalController.pause(); + break; + case events.stop: + tidalController.stop(); + break; + case events.play: + tidalController.play(); + break; + case events.loopStatus: + tidalController.repeat(); + break; + case events.shuffle: + tidalController.toggleShuffle(); + break; } }); }); // Override get position function player.getPosition = function () { - return convertDuration(elements.getText("current")) * 1000 * 1000; + return tidalController.getCurrentPositionInSeconds(); }; player.on("quit", function () { app.quit(); @@ -485,7 +321,7 @@ function updateMpris(mediaInfo: MediaInfo) { "xesam:album": mediaInfo.album, "mpris:artUrl": mediaInfo.image, "mpris:length": convertDuration(mediaInfo.duration) * 1000 * 1000, - "mpris:trackid": "/org/mpris/MediaPlayer2/track/" + getTrackID(), + "mpris:trackid": "/org/mpris/MediaPlayer2/track/" + tidalController.getTrackId(), }, ...ObjectToDotNotation(mediaInfo, "custom:"), }; @@ -528,34 +364,24 @@ function updateListenBrainz(mediaInfo: MediaInfo) { * If it's a song it returns the track URL, if not it will return undefined */ function getTrackURL() { - const id = getTrackID(); + const id = tidalController.getTrackId(); return `https://tidal.com/browse/track/${id}`; } -function getTrackID() { - const URLelement = elements.get("title").querySelector("a"); - if (URLelement !== null) { - const id = URLelement.href.replace(/\D/g, ""); - return id; - } - - return window.location; -} - /** * Watch for song changes and update title + notify */ setInterval(function () { - const title = elements.getText("title"); - const artistsArray = elements.getArtistsArray(); - const artistsString = elements.getArtistsString(artistsArray); + const title = tidalController.getTitle(); + const artistsArray = tidalController.getArtists(); + const artistsString = tidalController.getArtistsString(); const songDashArtistTitle = `${title} - ${artistsString}`; const staticTitle = "TIDAL Hi-Fi"; const titleOrArtistsChanged = currentSong !== songDashArtistTitle; - const current = elements.getText("current"); - const currentStatus = getCurrentlyPlayingStatus(); - const shuffleState = getCurrentShuffleState(); - const repeatState = getCurrentRepeatState(); + const current = tidalController.getCurrentTime(); + const currentStatus = tidalController.getCurrentlyPlayingStatus(); + const shuffleState = tidalController.getCurrentShuffleState(); + const repeatState = tidalController.getCurrentRepeatState(); const playStateChanged = currentStatus != currentlyPlaying; const shuffleStateChanged = shuffleState != currentShuffleState; @@ -570,13 +396,13 @@ setInterval(function () { if (repeatStateChanged) currentRepeatState = repeatState; skipArtistsIfFoundInSkippedArtistsList(artistsArray); - const album = elements.getAlbumName(); - const duration = elements.getText("duration"); + const album = tidalController.getAlbumName(); + const duration = tidalController.getDuration(); const options: MediaInfo = { title, artists: artistsString, album: album, - playingFrom: elements.getText("playing_from"), + playingFrom: tidalController.getPlayingFrom(), status: currentStatus, url: getTrackURL(), current, @@ -585,7 +411,7 @@ setInterval(function () { durationInSeconds: convertDurationToSeconds(duration), image: "", icon: "", - favorite: elements.isFavorite(), + favorite: tidalController.isFavorite(), player: { status: currentStatus, @@ -600,9 +426,9 @@ setInterval(function () { : setTitle(songDashArtistTitle); getTrackURL(); currentSong = songDashArtistTitle; - currentPlayStatus = currentStatus; + tidalController.setPlayStatus(currentStatus); - const image = elements.getSongIcon(); + const image = tidalController.getSongIcon(); new Promise((resolve) => { if (image.startsWith("http")) { @@ -644,7 +470,7 @@ setInterval(function () { const artistNames = Object.values(artists).map((artist) => artist); const foundArtist = artistNames.some((artist) => artistsToSkip.includes(artist)); if (foundArtist) { - elements.click("next"); + tidalController.next(); } } }