Add vencore support to Multi Scrobbler

This commit is contained in:
kmmiio99o 2025-10-05 13:22:12 +02:00
parent d4f81b1668
commit b577148e1f

View file

@ -15,197 +15,197 @@ const bunny = window.bunny;
const tabsNavigationRef = bunny?.metro?.findByPropsLazy("getRootNavigationRef"); const tabsNavigationRef = bunny?.metro?.findByPropsLazy("getRootNavigationRef");
const settingConstants = bunny?.metro?.findByPropsLazy( const settingConstants = bunny?.metro?.findByPropsLazy(
"SETTING_RENDERER_CONFIG", "SETTING_RENDERER_CONFIG",
); );
const SettingsOverviewScreen = bunny?.metro?.findByNameLazy( const SettingsOverviewScreen = bunny?.metro?.findByNameLazy(
"SettingsOverviewScreen", "SettingsOverviewScreen",
false, false,
); );
function Section({ tabs }) { function Section({ tabs }) {
const navigation = NavigationNative.useNavigation(); const navigation = NavigationNative.useNavigation();
return React.createElement(FormRow, { return React.createElement(FormRow, {
label: tabs.title(), label: tabs.title(),
leading: React.createElement(FormRow.Icon, { source: tabs.icon }), leading: React.createElement(FormRow.Icon, { source: tabs.icon }),
trailing: React.createElement(React.Fragment, {}, [ trailing: React.createElement(React.Fragment, {}, [
tabs.trailing ? tabs.trailing() : null, tabs.trailing ? tabs.trailing() : null,
React.createElement(FormRow.Arrow, { key: "arrow" }), React.createElement(FormRow.Arrow, { key: "arrow" }),
]), ]),
onPress: () => { onPress: () => {
const Component = tabs.page; const Component = tabs.page;
navigation.navigate("VendettaCustomPage", { navigation.navigate("VendettaCustomPage", {
title: tabs.title(), title: tabs.title(),
render: () => React.createElement(Component), render: () => React.createElement(Component),
}); });
}, },
}); });
} }
function patchPanelUI(tabs, patches) { function patchPanelUI(tabs, patches) {
try { try {
patches.push( patches.push(
after( after(
"default", "default",
bunny?.metro?.findByNameLazy("UserSettingsOverviewWrapper", false), bunny?.metro?.findByNameLazy("UserSettingsOverviewWrapper", false),
(_, ret) => { (_, ret) => {
const UserSettingsOverview = findInReactTree( const UserSettingsOverview = findInReactTree(
ret.props.children, ret.props.children,
(n) => n.type?.name === "UserSettingsOverview", (n) => n.type?.name === "UserSettingsOverview",
);
if (UserSettingsOverview) {
patches.push(
after(
"render",
UserSettingsOverview.type.prototype,
(_args, res) => {
const sections = findInReactTree(
res.props.children,
(n) => n?.children?.[1]?.type === FormSection,
)?.children;
if (sections) {
const index = sections.findIndex((c) =>
["BILLING_SETTINGS", "PREMIUM_SETTINGS"].includes(
c?.props?.label,
),
); );
if (UserSettingsOverview) { sections.splice(
patches.push( -~index || 4,
after( 0,
"render", React.createElement(Section, { key: tabs.key, tabs }),
UserSettingsOverview.type.prototype, );
(_args, res) => { }
const sections = findInReactTree(
res.props.children,
(n) => n?.children?.[1]?.type === FormSection,
)?.children;
if (sections) {
const index = sections.findIndex((c) =>
["BILLING_SETTINGS", "PREMIUM_SETTINGS"].includes(
c?.props?.label,
),
);
sections.splice(
-~index || 4,
0,
React.createElement(Section, { key: tabs.key, tabs }),
);
}
},
),
);
}
}, },
true, ),
), );
); }
} catch (error) { },
logger.info("Panel UI patch failed graciously 💔", error); true,
} ),
);
} catch (error) {
logger.info("Panel UI patch failed graciously 💔", error);
}
} }
function patchTabsUI(tabs, patches) { function patchTabsUI(tabs, patches) {
if (!settingConstants || !SettingsOverviewScreen || !tabsNavigationRef) { if (!settingConstants || !SettingsOverviewScreen || !tabsNavigationRef) {
console.warn("[LastFm] Missing required constants for tabs UI patch"); console.warn("[LastFm] Missing required constants for tabs UI patch");
return; return;
} }
const row = {}; const row = {};
row[tabs.key] = { row[tabs.key] = {
type: "pressable", type: "pressable",
title: tabs.title, title: tabs.title,
icon: tabs.icon, icon: tabs.icon,
IconComponent: IconComponent:
tabs.icon && tabs.icon &&
(() => { (() => {
const actualIconSource = const actualIconSource =
typeof tabs.icon === "object" && tabs.icon.uri !== undefined typeof tabs.icon === "object" && tabs.icon.uri !== undefined
? tabs.icon.uri ? tabs.icon.uri
: tabs.icon; : tabs.icon;
return React.createElement(TableRowIcon, { source: actualIconSource }); return React.createElement(TableRowIcon, { source: actualIconSource });
}), }),
usePredicate: tabs.predicate, usePredicate: tabs.predicate,
useTrailing: tabs.trailing, useTrailing: tabs.trailing,
onPress: () => { onPress: () => {
const navigation = tabsNavigationRef.getRootNavigationRef(); const navigation = tabsNavigationRef.getRootNavigationRef();
const Component = tabs.page; const Component = tabs.page;
navigation.navigate("VendettaCustomPage", { navigation.navigate("VendettaCustomPage", {
title: tabs.title(), title: tabs.title(),
render: () => React.createElement(Component), render: () => React.createElement(Component),
}); });
}, },
withArrow: true, withArrow: true,
}; };
let rendererConfigValue = settingConstants.SETTING_RENDERER_CONFIG; let rendererConfigValue = settingConstants.SETTING_RENDERER_CONFIG;
Object.defineProperty(settingConstants, "SETTING_RENDERER_CONFIG", { Object.defineProperty(settingConstants, "SETTING_RENDERER_CONFIG", {
enumerable: true, enumerable: true,
configurable: true, configurable: true,
get: () => ({ get: () => ({
...rendererConfigValue, ...rendererConfigValue,
...row, ...row,
}), }),
set: (v) => (rendererConfigValue = v), set: (v) => (rendererConfigValue = v),
}); });
const firstRender = Symbol("LastFm-pinToSettings"); const firstRender = Symbol("LastFm-pinToSettings");
patches.push( patches.push(
after("default", SettingsOverviewScreen, (args, ret) => { after("default", SettingsOverviewScreen, (args, ret) => {
if (!args[0][firstRender]) { if (!args[0][firstRender]) {
args[0][firstRender] = true; args[0][firstRender] = true;
const { sections } = findInReactTree( const { sections } = findInReactTree(
ret, ret,
(i) => i.props?.sections, (i) => i.props?.sections,
).props; ).props;
const section = sections?.find((x) => const section = sections?.find((x) =>
["Bunny", "Revenge", "Kettu"].some( ["Bunny", "Revenge", "Kettu", "Vencore"].some(
(mod) => x.label === mod && x.title === mod, (mod) => x.label === mod && x.title === mod,
), ),
); );
if (section?.settings) { if (section?.settings) {
section.settings = [...section.settings, tabs.key]; section.settings = [...section.settings, tabs.key];
} }
} }
}), }),
); );
} }
function patchSettingsPin(tabs) { function patchSettingsPin(tabs) {
const patches = []; const patches = [];
let disabled = false; let disabled = false;
const realPredicate = tabs.predicate || (() => true); const realPredicate = tabs.predicate || (() => true);
tabs.predicate = () => (disabled ? false : realPredicate()); tabs.predicate = () => (disabled ? false : realPredicate());
patchPanelUI(tabs, patches); patchPanelUI(tabs, patches);
patchTabsUI(tabs, patches); patchTabsUI(tabs, patches);
patches.push(() => (disabled = true)); patches.push(() => (disabled = true));
return () => { return () => {
for (const x of patches) { for (const x of patches) {
x(); x();
} }
}; };
} }
export default function patchSidebar() { export default function patchSidebar() {
// Check if sidebar option is enabled in plugin settings // Check if sidebar option is enabled in plugin settings
if (!plugin.storage.addToSidebar) { if (!plugin.storage.addToSidebar) {
console.log("[Multi Scrobbler] Sidebar disabled in settings"); console.log("[Multi Scrobbler] Sidebar disabled in settings");
return () => {}; return () => {};
} }
console.log( console.log(
"[Multi Scrobbler] Patching sidebar using custom patchSettingsPin...", "[Multi Scrobbler] Patching sidebar using custom patchSettingsPin...",
); );
try { try {
const unpatch = patchSettingsPin({ const unpatch = patchSettingsPin({
key: "LastFmScrobbler", key: "LastFmScrobbler",
icon: getAssetIDByName("MusicIcon"), icon: getAssetIDByName("MusicIcon"),
title: () => "Multi Scrobbler", title: () => "Multi Scrobbler",
predicate: () => plugin.storage.addToSidebar === true, predicate: () => plugin.storage.addToSidebar === true,
page: Settings, page: Settings,
}); });
console.log("[Multi Scrobbler] Successfully patched sidebar"); console.log("[Multi Scrobbler] Successfully patched sidebar");
return unpatch; return unpatch;
} catch (error) { } catch (error) {
console.error("[Multi Scrobbler] Failed to patch sidebar:", error); console.error("[Multi Scrobbler] Failed to patch sidebar:", error);
return () => {}; return () => {};
} }
} }