Skip to content

Commit

Permalink
extracted yet more of the domControl into the new tidalController
Browse files Browse the repository at this point in the history
  • Loading branch information
Mastermindzh committed Oct 28, 2024
1 parent f608d42 commit d36bc74
Show file tree
Hide file tree
Showing 5 changed files with 414 additions and 266 deletions.
153 changes: 140 additions & 13 deletions src/TidalControllers/DomTidalController.ts
Original file line number Diff line number Diff line change
@@ -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"]',
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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;
}
}
114 changes: 114 additions & 0 deletions src/TidalControllers/MediaSessionTidalController.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { MediaStatus } from "../models/mediaStatus";
import { RepeatState } from "../models/repeatState";
import { DomTidalController } from "./DomTidalController";
import { TidalController } from "./TidalController";

Expand All @@ -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.");
}
}
40 changes: 37 additions & 3 deletions src/TidalControllers/TidalController.ts
Original file line number Diff line number Diff line change
@@ -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;
}
Loading

0 comments on commit d36bc74

Please sign in to comment.