2021-05-02 12:43:51 +00:00
|
|
|
import { VERSION } from "../../../constants";
|
|
|
|
|
|
|
|
export interface PlexPinResponse {
|
|
|
|
// Only has the fields we care about
|
|
|
|
authToken?: string;
|
|
|
|
code: string;
|
|
|
|
id: number;
|
|
|
|
}
|
|
|
|
|
|
|
|
export interface PlexResource {
|
|
|
|
name: string;
|
|
|
|
provides: string;
|
|
|
|
clientIdentifier: string;
|
2021-05-04 20:51:52 +00:00
|
|
|
owned: boolean;
|
2021-05-02 12:43:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
export const DEFAULT_HEADERS = {
|
|
|
|
"Accept": "application/json",
|
|
|
|
"Content-Type": "application/json",
|
|
|
|
"X-Plex-Product": "authentik",
|
|
|
|
"X-Plex-Version": VERSION,
|
|
|
|
"X-Plex-Device-Vendor": "BeryJu.org",
|
|
|
|
};
|
|
|
|
|
2021-05-02 14:47:20 +00:00
|
|
|
export function popupCenterScreen(url: string, title: string, w: number, h: number): Window | null {
|
|
|
|
const top = (screen.height - h) / 4, left = (screen.width - w) / 2;
|
|
|
|
const popup = window.open(url, title, `scrollbars=yes,width=${w},height=${h},top=${top},left=${left}`);
|
|
|
|
return popup;
|
|
|
|
}
|
|
|
|
|
2021-05-02 12:43:51 +00:00
|
|
|
export class PlexAPIClient {
|
|
|
|
|
|
|
|
token: string;
|
|
|
|
|
|
|
|
constructor(token: string) {
|
|
|
|
this.token = token;
|
|
|
|
}
|
|
|
|
|
|
|
|
static async getPin(clientIdentifier: string): Promise<{ authUrl: string, pin: PlexPinResponse }> {
|
|
|
|
const headers = { ...DEFAULT_HEADERS, ...{
|
|
|
|
"X-Plex-Client-Identifier": clientIdentifier
|
|
|
|
}};
|
|
|
|
const pinResponse = await fetch("https://plex.tv/api/v2/pins.json?strong=true", {
|
|
|
|
method: "POST",
|
|
|
|
headers: headers
|
|
|
|
});
|
|
|
|
const pin: PlexPinResponse = await pinResponse.json();
|
|
|
|
return {
|
|
|
|
authUrl: `https://app.plex.tv/auth#!?clientID=${encodeURIComponent(clientIdentifier)}&code=${pin.code}`,
|
|
|
|
pin: pin
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2021-05-02 14:47:20 +00:00
|
|
|
static async pinStatus(clientIdentifier: string, id: number): Promise<string | undefined> {
|
|
|
|
const headers = { ...DEFAULT_HEADERS, ...{
|
|
|
|
"X-Plex-Client-Identifier": clientIdentifier
|
|
|
|
}};
|
2021-05-02 12:43:51 +00:00
|
|
|
const pinResponse = await fetch(`https://plex.tv/api/v2/pins/${id}`, {
|
2021-05-02 14:47:20 +00:00
|
|
|
headers: headers
|
2021-05-02 12:43:51 +00:00
|
|
|
});
|
|
|
|
const pin: PlexPinResponse = await pinResponse.json();
|
|
|
|
return pin.authToken || "";
|
|
|
|
}
|
|
|
|
|
2021-05-02 14:47:20 +00:00
|
|
|
static async pinPoll(clientIdentifier: string, id: number): Promise<string> {
|
|
|
|
const executePoll = async (
|
|
|
|
resolve: (authToken: string) => void,
|
|
|
|
reject: (e: Error) => void
|
|
|
|
) => {
|
|
|
|
try {
|
2021-05-03 19:00:16 +00:00
|
|
|
const response = await PlexAPIClient.pinStatus(clientIdentifier, id);
|
2021-05-02 14:47:20 +00:00
|
|
|
|
|
|
|
if (response) {
|
|
|
|
resolve(response);
|
|
|
|
} else {
|
|
|
|
setTimeout(executePoll, 500, resolve, reject);
|
|
|
|
}
|
|
|
|
} catch (e) {
|
|
|
|
reject(e);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
return new Promise(executePoll);
|
|
|
|
}
|
|
|
|
|
2021-05-02 12:43:51 +00:00
|
|
|
async getServers(): Promise<PlexResource[]> {
|
|
|
|
const resourcesResponse = await fetch(`https://plex.tv/api/v2/resources?X-Plex-Token=${this.token}&X-Plex-Client-Identifier=authentik`, {
|
|
|
|
headers: DEFAULT_HEADERS
|
|
|
|
});
|
|
|
|
const resources: PlexResource[] = await resourcesResponse.json();
|
|
|
|
return resources.filter(r => {
|
2021-05-04 20:51:52 +00:00
|
|
|
return r.provides.toLowerCase().includes("server") && r.owned;
|
2021-05-02 12:43:51 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|