refactor: switch from Fetch API to Axios (#1520)

* refactor: switch from Fetch API to Axios

* fix: remove unwanted changes

* fix: rewrite error handling for Axios and remove IPv4 first setting

* style: run prettier

* style: run prettier

* fix: add back custom proxy agent

* fix: add back custom proxy agent

* fix: correct rebase issue

* fix: resolve review comments
This commit is contained in:
Gauthier
2025-04-08 13:20:10 +02:00
committed by GitHub
parent 21400cecdc
commit a488f850f3
112 changed files with 1654 additions and 3032 deletions

View File

@@ -1,46 +0,0 @@
const getCsrfToken = (): string | null => {
if (typeof window !== 'undefined') {
const match = document.cookie.match(/XSRF-TOKEN=([^;]+)/);
return match ? decodeURIComponent(match[1]) : null;
}
return null;
};
const isSameOrigin = (url: RequestInfo | URL): boolean => {
const parsedUrl = new URL(
url instanceof Request ? url.url : url.toString(),
window.location.origin
);
return parsedUrl.origin === window.location.origin;
};
// We are using a custom fetch implementation to add the X-XSRF-TOKEN heade
// to all requests. This is required when CSRF protection is enabled.
if (typeof window !== 'undefined') {
const originalFetch: typeof fetch = window.fetch;
(window as typeof globalThis).fetch = async (
input: RequestInfo | URL,
init?: RequestInit
): Promise<Response> => {
if (!isSameOrigin(input)) {
return originalFetch(input, init);
}
const csrfToken = getCsrfToken();
const headers = {
...(init?.headers || {}),
...(csrfToken ? { 'XSRF-TOKEN': csrfToken } : {}),
};
const newInit: RequestInit = {
...init,
headers,
};
return originalFetch(input, newInit);
};
}
export {};

View File

@@ -1,3 +1,6 @@
import type { AxiosError, AxiosResponse } from 'axios';
import axios from 'axios';
interface JellyfinAuthenticationResult {
Id: string;
AccessToken: string;
@@ -15,34 +18,30 @@ class JellyAPI {
resolve: (result: JellyfinAuthenticationResult) => void,
reject: (e: Error) => void
) => {
fetch(Hostname + '/Users/AuthenticateByName', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Emby-Authorization':
'MediaBrowser Client="Jellyfin Web", Device="Firefox", DeviceId="TW96aWxsYS81LjAgKFdpbmRvd3MgTlQgMTAuMDsgV2luNjQ7IHg2NDsgcnY6ODUuMCkgR2Vja28vMjAxMDAxMDEgRmlyZWZveC84NS4wfDE2MTI5MjcyMDM5NzM1", Version="10.8.0"',
},
body: JSON.stringify({
Username: Username,
Pw: Password,
}),
})
.then((res) => {
if (!res.ok) {
throw new Error('Network response was not ok');
axios
.post(
Hostname + '/Users/AuthenticateByName',
{
Username: Username,
Pw: Password,
},
{
headers: {
'X-Emby-Authorization':
'MediaBrowser Client="Jellyfin Web", Device="Firefox", DeviceId="TW96aWxsYS81LjAgKFdpbmRvd3MgTlQgMTAuMDsgV2luNjQ7IHg2NDsgcnY6ODUuMCkgR2Vja28vMjAxMDAxMDEgRmlyZWZveC84NS4wfDE2MTI5MjcyMDM5NzM1", Version="10.8.0"',
},
}
return res.json();
})
.then((data) => {
)
.then((resp: AxiosResponse) => {
const response: JellyfinAuthenticationResult = {
Id: data.User.Id,
AccessToken: data.AccessToken,
ServerId: data.ServerId,
Id: resp.data.User.Id,
AccessToken: resp.data.AccessToken,
ServerId: resp.data.ServerId,
};
resolve(response);
})
.catch((error) => {
reject(error);
.catch((e: AxiosError) => {
reject(e);
});
}
);

View File

@@ -1,3 +1,4 @@
import axios from 'axios';
import Bowser from 'bowser';
interface PlexHeaders extends Record<string, string> {
@@ -77,14 +78,13 @@ class PlexOAuth {
'You must initialize the plex headers clientside to login'
);
}
const res = await fetch('https://plex.tv/api/v2/pins?strong=true', {
method: 'POST',
headers: this.plexHeaders,
});
if (!res.ok) throw new Error();
const data = await res.json();
const response = await axios.post(
'https://plex.tv/api/v2/pins?strong=true',
undefined,
{ headers: this.plexHeaders }
);
this.pin = { id: data.id, code: data.code };
this.pin = { id: response.data.id, code: response.data.code };
return this.pin;
}
@@ -136,17 +136,16 @@ class PlexOAuth {
throw new Error('Unable to poll when pin is not initialized.');
}
const res = await fetch(`https://plex.tv/api/v2/pins/${this.pin.id}`, {
headers: this.plexHeaders,
});
if (!res.ok) throw new Error();
const data = await res.json();
const response = await axios.get(
`https://plex.tv/api/v2/pins/${this.pin.id}`,
{ headers: this.plexHeaders }
);
if (data?.authToken) {
this.authToken = data.authToken as string;
if (response.data?.authToken) {
this.authToken = response.data.authToken as string;
this.closePopup();
resolve(this.authToken);
} else if (!data?.authToken && !this.popup?.closed) {
} else if (!response.data?.authToken && !this.popup?.closed) {
setTimeout(executePoll, 1000, resolve, reject);
} else {
reject(new Error('Popup closed without completing login'));