Merge branch 'dev'
This commit is contained in:
commit
91131e46c5
5 changed files with 92 additions and 17 deletions
|
|
@ -162,6 +162,7 @@ export const globPlugins = kind => ({
|
|||
const fileName = file.name;
|
||||
if (fileName.startsWith("_") || fileName.startsWith(".")) continue;
|
||||
if (fileName === "index.ts") continue;
|
||||
if (/\.(zip|rar|7z|tar|gz|bz2)/.test(fileName)) continue;
|
||||
|
||||
const target = getPluginTarget(fileName);
|
||||
|
||||
|
|
|
|||
|
|
@ -135,7 +135,7 @@ function CloudTab() {
|
|||
<Forms.FormText variant="text-md/normal" className={Margins.bottom20}>
|
||||
Equicord comes with a cloud integration allowing settings to be synced across apps and devices.
|
||||
<br />
|
||||
We use Vencord's <Link href="https://github.com/Vencord/Backend">cloud source code</Link> to provide our cloud instance which has a 32MB backup cap.
|
||||
We use Vencord's <Link href="https://github.com/Vencord/Backend">cloud source code</Link> to provide our cloud instance which has a 60MB backup cap.
|
||||
<br />
|
||||
Our <Link href="https://vencord.dev/cloud/privacy">privacy policy</Link> allows you to see what information we store, how we use it, and data retention.
|
||||
<br />
|
||||
|
|
|
|||
|
|
@ -19,6 +19,11 @@ interface ActivityAssets {
|
|||
small_text?: string;
|
||||
}
|
||||
|
||||
interface ActivityButton {
|
||||
label: string;
|
||||
url: string;
|
||||
}
|
||||
|
||||
interface Activity {
|
||||
state: string;
|
||||
details?: string;
|
||||
|
|
@ -26,6 +31,7 @@ interface Activity {
|
|||
start?: number;
|
||||
};
|
||||
assets?: ActivityAssets;
|
||||
buttons?: Array<string>;
|
||||
name: string;
|
||||
application_id: string;
|
||||
metadata?: {
|
||||
|
|
@ -50,8 +56,6 @@ interface MediaData {
|
|||
position?: number;
|
||||
}
|
||||
|
||||
|
||||
|
||||
const settings = definePluginSettings({
|
||||
serverUrl: {
|
||||
description: "Jellyfin server URL (e.g., https://jellyfin.example.com)",
|
||||
|
|
@ -78,6 +82,11 @@ const settings = definePluginSettings({
|
|||
description: "Custom Rich Presence name (only used if 'Custom' is selected).\nOptions: {name}, {series}, {season}, {episode}, {artist}, {album}, {year}",
|
||||
type: OptionType.STRING,
|
||||
},
|
||||
showTMDBButton: {
|
||||
description: "Show TheMovieDB button in Rich Presence",
|
||||
type: OptionType.BOOLEAN,
|
||||
default: true,
|
||||
},
|
||||
overrideRichPresenceType: {
|
||||
description: "Override the rich presence type",
|
||||
type: OptionType.SELECT,
|
||||
|
|
@ -123,6 +132,27 @@ function setActivity(activity: Activity | null) {
|
|||
});
|
||||
}
|
||||
|
||||
async function fetchTmdbData(query: string) {
|
||||
try {
|
||||
const res = await fetch(`https://api.vmohammad.dev/tmdb/search/multi?q=${encodeURIComponent(query)}`);
|
||||
if (!res.ok) throw `${res.status} ${res.statusText}`;
|
||||
const data = await res.json();
|
||||
if (data.results && data.results.length > 0) {
|
||||
const topResult = data.results[0];
|
||||
return {
|
||||
url: `https://www.themoviedb.org/${topResult.media_type}/${topResult.id}`,
|
||||
posterPath: topResult.poster_path
|
||||
? `https://image.tmdb.org/t/p/original${topResult.poster_path}`
|
||||
: null
|
||||
};
|
||||
}
|
||||
return null;
|
||||
} catch (e) {
|
||||
console.error("Failed to fetch TMDb data:", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export default definePlugin({
|
||||
name: "JellyfinRichPresence",
|
||||
description: "Rich presence for Jellyfin media server",
|
||||
|
|
@ -274,15 +304,29 @@ export default definePlugin({
|
|||
break;
|
||||
}
|
||||
|
||||
const largeImage = mediaData.imageUrl;
|
||||
let tmdbData: { url: string; posterPath?: string | null } | null = null;
|
||||
if (settings.store.showTMDBButton) {
|
||||
tmdbData = await fetchTmdbData(mediaData.seriesName || mediaData.name);
|
||||
}
|
||||
|
||||
const assets: ActivityAssets = {
|
||||
large_image: largeImage ? await getApplicationAsset(largeImage) : await getApplicationAsset("jellyfin"),
|
||||
large_text: mediaData.album || mediaData.seriesName || undefined,
|
||||
large_image: tmdbData?.posterPath ? await getApplicationAsset(tmdbData.posterPath) : mediaData.imageUrl ? await getApplicationAsset(mediaData.imageUrl) : undefined,
|
||||
large_text: mediaData.seriesName || mediaData.album || undefined,
|
||||
};
|
||||
|
||||
const buttons: ActivityButton[] = [];
|
||||
if (settings.store.showTMDBButton) {
|
||||
const result = await fetchTmdbData(mediaData.seriesName || mediaData.name);
|
||||
if (result?.url) tmdbData = { url: result.url };
|
||||
buttons.push({
|
||||
label: "View on TheMovieDB",
|
||||
url: `${tmdbData?.url}`
|
||||
});
|
||||
}
|
||||
|
||||
const getDetails = () => {
|
||||
if (mediaData.type === "Episode" && mediaData.seriesName) {
|
||||
return mediaData.name;
|
||||
return mediaData.seriesName;
|
||||
}
|
||||
return mediaData.name;
|
||||
};
|
||||
|
|
@ -291,7 +335,7 @@ export default definePlugin({
|
|||
if (mediaData.type === "Episode" && mediaData.seriesName) {
|
||||
const season = mediaData.seasonNumber ? `S${mediaData.seasonNumber}` : "";
|
||||
const episode = mediaData.episodeNumber ? `E${mediaData.episodeNumber}` : "";
|
||||
return `${mediaData.seriesName} ${season}${episode}`.trim();
|
||||
return `${mediaData.name} (${season} - ${episode})`.trim();
|
||||
}
|
||||
return mediaData.artist || (mediaData.year ? `(${mediaData.year})` : undefined);
|
||||
};
|
||||
|
|
@ -309,8 +353,12 @@ export default definePlugin({
|
|||
assets,
|
||||
timestamps,
|
||||
|
||||
buttons: buttons.length ? buttons.map(v => v.label) : undefined,
|
||||
metadata: {
|
||||
button_urls: buttons.map(v => v.url),
|
||||
},
|
||||
type: richPresenceType,
|
||||
flags: 1,
|
||||
flags: 1
|
||||
};
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ function splitTextWithIndicators(text: string): ReactNode[] {
|
|||
const nodes: ReactNode[] = [];
|
||||
let lastIndex = 0;
|
||||
let count = 0;
|
||||
const regex = /\/([a-z]{1,20})(?=\s|$|[^\w])/gi;
|
||||
const regex = /(?:^|\s)\/([^/\s]+)(?:$|\s|\p{P})/giu;
|
||||
let match: RegExpExecArray | null;
|
||||
|
||||
while ((match = regex.exec(text)) && count < settings.store.maxIndicators) {
|
||||
|
|
|
|||
|
|
@ -17,16 +17,15 @@
|
|||
*/
|
||||
|
||||
import { app } from "electron";
|
||||
import { copyFileSync, existsSync, readFileSync, writeFileSync } from "fs";
|
||||
import { join } from "path";
|
||||
|
||||
export const DATA_DIR = process.env.EQUICORD_USER_DATA_DIR ?? process.env.VENCORD_USER_DATA_DIR ?? (
|
||||
const suffix = IS_DEV ? "dev" : "";
|
||||
|
||||
export const DATA_DIR = process.env.EQUICORD_USER_DATA_DIR ?? (
|
||||
process.env.DISCORD_USER_DATA_DIR
|
||||
? IS_VESKTOP
|
||||
? join(process.env.DISCORD_USER_DATA_DIR, "..", "VencordData")
|
||||
: join(process.env.DISCORD_USER_DATA_DIR, "..", "EquicordData")
|
||||
: IS_VESKTOP
|
||||
? join(app.getPath("userData"), "..", "Vencord")
|
||||
: join(app.getPath("userData"), "..", "Equicord")
|
||||
? join(process.env.DISCORD_USER_DATA_DIR, "..", "EquicordData", suffix)
|
||||
: join(app.getPath("userData"), "..", "Equicord", suffix)
|
||||
);
|
||||
|
||||
export const SETTINGS_DIR = join(DATA_DIR, "settings");
|
||||
|
|
@ -34,6 +33,7 @@ export const THEMES_DIR = join(DATA_DIR, "themes");
|
|||
export const QUICKCSS_PATH = join(SETTINGS_DIR, "quickCss.css");
|
||||
export const SETTINGS_FILE = join(SETTINGS_DIR, "settings.json");
|
||||
export const NATIVE_SETTINGS_FILE = join(SETTINGS_DIR, "native-settings.json");
|
||||
export const DEV_MIGRATED = join(SETTINGS_DIR, "migration");
|
||||
export const ALLOWED_PROTOCOLS = [
|
||||
"https:",
|
||||
"http:",
|
||||
|
|
@ -45,3 +45,29 @@ export const ALLOWED_PROTOCOLS = [
|
|||
];
|
||||
|
||||
export const IS_VANILLA = /* @__PURE__ */ process.argv.includes("--vanilla");
|
||||
|
||||
if (IS_DEV) {
|
||||
const prodDir = join(DATA_DIR, "..");
|
||||
const settings = join(prodDir, "settings", "settings.json");
|
||||
const quickCss = join(prodDir, "settings", "quickCss.css");
|
||||
|
||||
let migrated = false;
|
||||
if (existsSync(DEV_MIGRATED)) {
|
||||
const content = readFileSync(DEV_MIGRATED, "utf-8");
|
||||
migrated = content.includes("migrated");
|
||||
}
|
||||
|
||||
if (!migrated) {
|
||||
setTimeout(() => {
|
||||
try {
|
||||
if (existsSync(settings)) copyFileSync(settings, SETTINGS_FILE);
|
||||
if (existsSync(quickCss)) copyFileSync(quickCss, QUICKCSS_PATH);
|
||||
writeFileSync(DEV_MIGRATED, "migrated");
|
||||
app.relaunch();
|
||||
app.exit(0);
|
||||
} catch (err) {
|
||||
console.error("[Equicord] Failed to copy prod data:", err);
|
||||
}
|
||||
}, 5000);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue