feat: login automatically

This commit is contained in:
trafficlunar 2026-03-05 19:10:09 +00:00
parent 9cc104c6c9
commit 116b91c46e
2 changed files with 37 additions and 26 deletions

View file

@ -1,11 +1,10 @@
import React from "react"; import React from "react";
import { Api, Jellyfin } from "@jellyfin/sdk"; import { Api, Jellyfin } from "@jellyfin/sdk";
import { getUserApi } from "@jellyfin/sdk/lib/utils/api/user-api";
import { getSearchApi } from "@jellyfin/sdk/lib/utils/api/search-api"; import { getSearchApi } from "@jellyfin/sdk/lib/utils/api/search-api";
import { BaseItemKind } from "@jellyfin/sdk/lib/generated-client/models"; import { BaseItemKind } from "@jellyfin/sdk/lib/generated-client/models";
import SettingsModal from "./settings"; import SettingsModal from "./settings";
let hijackActive = false;
export const jellyfin = new Jellyfin({ export const jellyfin = new Jellyfin({
clientInfo: { clientInfo: {
name: "Spicetify", name: "Spicetify",
@ -26,11 +25,31 @@ export const setJellyfinUser = (id: string) => {
jellyfinUser = id; jellyfinUser = id;
}; };
let hijackActive = false;
async function main() { async function main() {
while (!Spicetify.showNotification) { while (!Spicetify.showNotification) {
await new Promise((resolve) => setTimeout(resolve, 100)); await new Promise((resolve) => setTimeout(resolve, 100));
} }
// Automatically login to Jellyfin if settings are present
const url = Spicetify.LocalStorage.get("jellyfin-url");
const token = Spicetify.LocalStorage.get("jellyfin-token");
if (url && token) {
const servers = await jellyfin.discovery.getRecommendedServerCandidates(url);
const best = jellyfin.discovery.findBestServer(servers);
if (!best) {
Spicetify.showNotification("Failed to connect to Jellyfin server!", true);
return;
}
jellyfinApi = jellyfin.createApi(best.address);
jellyfinApi.accessToken = token;
const user = await getUserApi(jellyfinApi).getCurrentUser();
if (user.data.Id) setJellyfinUser(user.data.Id);
}
const audio = new Audio(); const audio = new Audio();
// Topbar button for settings // Topbar button for settings

View file

@ -3,17 +3,16 @@ import React, { useEffect, useState } from "react";
import { getQuickConnectApi } from "@jellyfin/sdk/lib/utils/api/quick-connect-api"; import { getQuickConnectApi } from "@jellyfin/sdk/lib/utils/api/quick-connect-api";
import { getUserApi } from "@jellyfin/sdk/lib/utils/api/user-api"; import { getUserApi } from "@jellyfin/sdk/lib/utils/api/user-api";
import { jellyfin, jellyfinApi, setJellyfinApi, setJellyfinUser } from "./app"; import { jellyfin, jellyfinApi, jellyfinUser, setJellyfinApi, setJellyfinUser } from "./app";
import styles from "./styles.module.css"; import styles from "./styles.module.css";
type View = "url" | "password" | "quick-connect"; type View = "url" | "password" | "quick-connect" | "settings";
export default function SettingsModal() { export default function SettingsModal() {
const [isLoggedIn, setIsLoggedIn] = useState(false);
const [url, setUrl] = useState(Spicetify.LocalStorage.get("jellyfin-url") || ""); const [url, setUrl] = useState(Spicetify.LocalStorage.get("jellyfin-url") || "");
const [username, setUsername] = useState(""); const [username, setUsername] = useState("");
const [password, setPassword] = useState(""); const [password, setPassword] = useState("");
const [view, setView] = useState<View>("url"); const [view, setView] = useState<View>(jellyfinUser ? "settings" : "url");
const [quickConnectCode, setQuickConnectCode] = useState(""); const [quickConnectCode, setQuickConnectCode] = useState("");
const createApi = async () => { const createApi = async () => {
@ -42,16 +41,18 @@ export default function SettingsModal() {
return; return;
} }
jellyfinApi!.accessToken = auth.data.AccessToken; jellyfinApi.accessToken = auth.data.AccessToken;
Spicetify.LocalStorage.set("jellyfin-token", auth.data.AccessToken); Spicetify.LocalStorage.set("jellyfin-token", auth.data.AccessToken);
const user = await getUserApi(jellyfinApi!).getCurrentUser(); const user = await getUserApi(jellyfinApi).getCurrentUser();
if (user.data.Id) { if (user.data.Id) setJellyfinUser(user.data.Id);
setJellyfinUser(user.data.Id!);
Spicetify.LocalStorage.set("jellyfin-user", user.data.Id!);
}
setIsLoggedIn(true); setView("settings");
};
const logout = () => {
Spicetify.LocalStorage.remove("jellyfin-token");
setView("url");
}; };
useEffect(() => { useEffect(() => {
@ -93,12 +94,9 @@ export default function SettingsModal() {
Spicetify.LocalStorage.set("jellyfin-token", auth.data.AccessToken); Spicetify.LocalStorage.set("jellyfin-token", auth.data.AccessToken);
const user = await getUserApi(jellyfinApi!).getCurrentUser(); const user = await getUserApi(jellyfinApi!).getCurrentUser();
if (user.data.Id) { if (user.data.Id) setJellyfinUser(user.data.Id);
setJellyfinUser(user.data.Id!);
Spicetify.LocalStorage.set("jellyfin-user", user.data.Id!);
}
setIsLoggedIn(true); setView("settings");
} catch { } catch {
clearInterval(interval); clearInterval(interval);
Spicetify.showNotification("Quick Connect polling failed!", true); Spicetify.showNotification("Quick Connect polling failed!", true);
@ -110,7 +108,7 @@ export default function SettingsModal() {
return () => clearInterval(interval); return () => clearInterval(interval);
}, [view]); }, [view]);
if (isLoggedIn) if (view === "settings")
return ( return (
<div className={styles.modal}> <div className={styles.modal}>
<svg xmlns="http://www.w3.org/2000/svg" width="64" height="64" viewBox="0 0 512 512"> <svg xmlns="http://www.w3.org/2000/svg" width="64" height="64" viewBox="0 0 512 512">
@ -151,13 +149,7 @@ export default function SettingsModal() {
</select> </select>
<hr className={styles.hr} /> <hr className={styles.hr} />
<button <button onClick={logout} className={styles.button}>
onClick={() => {
setIsLoggedIn(false);
setView("url");
}}
className={styles.button}
>
Log out Log out
</button> </button>
</div> </div>