bump to 1.1.0

This commit is contained in:
kmmiio99o 2025-10-02 23:23:14 +02:00
parent e05df4ac83
commit 1bb01b83aa
4 changed files with 358 additions and 5 deletions

View file

@ -18,6 +18,8 @@ import {
} from "./src/commands/spotify";
import { garyCommand } from "./src/commands/gary";
import { lovefemboysCommand } from "./src/commands/lovefemboys";
import { ipCommand } from "./src/commands/ip";
import { nekoslifeCommand } from "./src/commands/nekoslife";
import settings from "./settings";
// Initialize storage with default values
@ -58,7 +60,9 @@ if (!storage.enabledCommands) {
spotifyArtists: true,
spotifyCover: true,
gary: true,
ip: true, // IP command - enabled by default
lovefemboys: false, // Hidden command - disabled by default
nekoslife: false, // Hidden command - disabled by default
};
}
@ -67,6 +71,7 @@ if (!storage.hiddenSettings) {
storage.hiddenSettings = {
enabled: false,
visible: false,
konochanBypassNsfw: false, // NSFW bypass option
};
}
@ -87,7 +92,9 @@ const commandMap = {
spotifyArtists: spotifyArtistsCommand,
spotifyCover: spotifyCoverCommand,
gary: garyCommand,
ip: ipCommand, // Add IP command
lovefemboys: lovefemboysCommand, // Add hidden command to map
nekoslife: nekoslifeCommand, // Add NekosLife command
};
// Store registered commands for cleanup

View file

@ -42,7 +42,9 @@ storage.enabledCommands ??= {
spotifyArtists: true,
spotifyCover: true,
gary: true,
ip: true, // IP command - enabled by default
lovefemboys: false, // Hidden command - disabled by default
nekoslife: false, // Hidden command - disabled by default
};
storage.pendingRestart ??= false;
@ -207,7 +209,7 @@ function Header({ onHiddenUnlock }: { onHiddenUnlock?: () => void }) {
);
}
// Hidden Commands Settings Page with NSFW bypass option
// Hidden Commands Settings Page with NSFW bypass option and NekosLife
function HiddenSettingsPage() {
useProxy(storage);
const [, forceUpdate] = React.useReducer((x) => x + 1, 0);
@ -257,6 +259,17 @@ function HiddenSettingsPage() {
forceUpdate();
}}
/>
<FormSwitchRow
label="/nekoslife"
subLabel="Get images/gifs from nekos.life (NSFW content available)"
leading={<FormRow.Icon source={getAssetIDByName("ImageIcon")} />}
value={storage.enabledCommands.nekoslife}
onValueChange={(v) => {
storage.enabledCommands.nekoslife = v;
storage.pendingRestart = true;
forceUpdate();
}}
/>
</BetterTableRowGroup>
<BetterTableRowGroup title="NSFW Bypass Options" icon={getAssetIDByName("WarningIcon")}>
@ -310,8 +323,9 @@ function HiddenSettingsPage() {
onConfirm: () => {
storage.hiddenSettings.enabled = false;
storage.hiddenSettings.visible = false;
storage.hiddenSettings.konochanBypassNsfw = false; // Reset bypass option
storage.hiddenSettings.konochanBypassNsfw = false;
storage.enabledCommands.lovefemboys = false;
storage.enabledCommands.nekoslife = false; // Reset nekoslife too
storage.pendingRestart = true;
showToast("Hidden settings reset", getAssetIDByName("CheckmarkIcon"));
},
@ -692,7 +706,7 @@ function SpotifySettingsPage() {
);
}
// Other Settings Page
// Other Settings Page - Updated with IP command
function OtherSettingsPage() {
useProxy(storage);
const [, forceUpdate] = React.useReducer((x) => x + 1, 0);
@ -727,6 +741,20 @@ function OtherSettingsPage() {
}}
/>
</BetterTableRowGroup>
<BetterTableRowGroup title="Network Commands" icon={getAssetIDByName("GlobeEarthIcon")}>
<FormSwitchRow
label="/ip"
subLabel="IP address and domain lookup"
leading={<FormRow.Icon source={getAssetIDByName("GlobeEarthIcon")} />}
value={storage.enabledCommands.ip}
onValueChange={(v) => {
storage.enabledCommands.ip = v;
storage.pendingRestart = true;
forceUpdate();
}}
/>
</BetterTableRowGroup>
</RN.View>
</ScrollView>
);
@ -845,6 +873,12 @@ function CreditsPage() {
avatar: "https://github.com/Zach11111.png",
github: "https://github.com/Zach11111"
},
{
command: "IP & NekosLife Commands",
author: "scruzism",
avatar: "https://github.com/scruzism.png",
github: "https://github.com/scruzism"
},
];
const handleProfilePress = (githubUrl: string) => {
@ -883,7 +917,7 @@ function CreditsPage() {
<BetterTableRowGroup title="About" icon={getAssetIDByName("InfoIcon")} padding={true}>
<RN.Text style={styles.versionText}>
Commands Plugin Collection{'\n'}
Version 1.0.2
Version 1.1.0
</RN.Text>
</BetterTableRowGroup>
</RN.View>
@ -972,7 +1006,7 @@ export default function Settings() {
/>
<FormRow
label="Other Commands"
subLabel="System info and miscellaneous"
subLabel="System info, network tools, and miscellaneous"
leading={<FormRow.Icon source={getAssetIDByName("MoreHorizontalIcon")} />}
trailing={<FormRow.Arrow />}
onPress={() => navigation.push("VendettaCustomPage", {

View file

@ -0,0 +1,156 @@
import { findByProps } from "@vendetta/metro";
import { showToast } from "@vendetta/ui/toasts";
import { getAssetIDByName } from "@vendetta/ui/assets";
const MessageActions = findByProps("sendMessage");
const messageUtil = findByProps("sendBotMessage", "sendMessage", "receiveMessage");
interface IpWhoisResponse {
success: boolean;
ip: string;
type: string;
as: string;
org: string;
isp: string;
continent: string;
country: string;
country_capital: string;
city: string;
region: string;
country_phone: string;
latitude: number;
longitude: number;
timezone: string;
currency: string;
completed_requests: number;
}
export const ipCommand = {
name: "ip",
displayName: "ip",
description: "IP address and domain lookup",
displayDescription: "IP address and domain lookup",
options: [
{
name: "query",
displayName: "query",
description: "Enter IPv4/IPv6 address or domain name",
displayDescription: "Enter IPv4/IPv6 address or domain name",
type: 3, // String
required: true,
},
{
name: "send",
displayName: "send",
description: "Send to chat",
displayDescription: "Send to chat",
type: 5, // Boolean
required: false,
},
{
name: "ephemeral",
displayName: "ephemeral",
description: "Send as ephemeral message (only you can see)",
displayDescription: "Send as ephemeral message (only you can see)",
type: 5, // Boolean
required: false,
}
],
execute: async (args: any, ctx: any) => {
try {
const query = args.find((arg: any) => arg.name === "query")?.value;
const shouldSend = args.find((arg: any) => arg.name === "send")?.value || false;
const isEphemeral = args.find((arg: any) => arg.name === "ephemeral")?.value || false;
if (!query) {
const errorMsg = "❌ Query parameter is required!";
if (isEphemeral) {
return {
type: 4,
data: {
content: errorMsg,
flags: 64,
},
};
}
showToast(errorMsg, getAssetIDByName("CircleXIcon"));
return { type: 4 };
}
// Show loading toast
if (!isEphemeral && !shouldSend) {
showToast(`Looking up IP information for ${query}...`, getAssetIDByName("DownloadIcon"));
}
// Build API URL with all requested fields
const url = `http://ipwhois.app/json/${encodeURIComponent(query)}?objects=` +
`success,ip,type,as,org,isp,continent,country,country_capital,city,region,` +
`country_phone,latitude,longitude,timezone,currency,completed_requests`;
const response = await fetch(url);
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
const data: IpWhoisResponse = await response.json();
if (!data.success) {
const errorMsg = `❌ Failed to lookup IP information for: ${query}`;
if (isEphemeral) {
return {
type: 4,
data: {
content: errorMsg,
flags: 64,
},
};
}
showToast(errorMsg, getAssetIDByName("CircleXIcon"));
return { type: 4 };
}
// Format the response as code block
const formattedData = JSON.stringify(data, null, 4);
const content = `\`\`\`json\n${formattedData}\n\`\`\``;
if (isEphemeral) {
return {
type: 4,
data: {
content,
flags: 64,
},
};
} else if (shouldSend) {
const fixNonce = Date.now().toString();
MessageActions.sendMessage(ctx.channel.id, { content }, void 0, { nonce: fixNonce });
return { type: 4 };
} else {
// Send as bot message (ephemeral-like)
messageUtil.sendBotMessage(ctx.channel.id, content);
return { type: 4 };
}
} catch (error) {
console.error('[IP] Command error:', error);
const errorMessage = `❌ An error occurred while looking up IP information: ${error.message || 'Unknown error'}`;
const isEphemeral = args?.find?.((arg: any) => arg.name === "ephemeral")?.value ?? false;
if (isEphemeral) {
return {
type: 4,
data: {
content: errorMessage,
flags: 64,
},
};
}
showToast(errorMessage, getAssetIDByName("CircleXIcon"));
return { type: 4 };
}
},
applicationId: "-1",
inputType: 1,
type: 1,
};

View file

@ -0,0 +1,156 @@
import { findByProps } from "@vendetta/metro";
import { showToast } from "@vendetta/ui/toasts";
import { getAssetIDByName } from "@vendetta/ui/assets";
const MessageActions = findByProps("sendMessage");
const messageUtil = findByProps("sendBotMessage", "sendMessage", "receiveMessage");
interface IpWhoisResponse {
success: boolean;
ip: string;
type: string;
as: string;
org: string;
isp: string;
continent: string;
country: string;
country_capital: string;
city: string;
region: string;
country_phone: string;
latitude: number;
longitude: number;
timezone: string;
currency: string;
completed_requests: number;
}
export const ipCommand = {
name: "ip",
displayName: "ip",
description: "IP address and domain lookup",
displayDescription: "IP address and domain lookup",
options: [
{
name: "query",
displayName: "query",
description: "Enter IPv4/IPv6 address or domain name",
displayDescription: "Enter IPv4/IPv6 address or domain name",
type: 3, // String
required: true,
},
{
name: "send",
displayName: "send",
description: "Send to chat",
displayDescription: "Send to chat",
type: 5, // Boolean
required: false,
},
{
name: "ephemeral",
displayName: "ephemeral",
description: "Send as ephemeral message (only you can see)",
displayDescription: "Send as ephemeral message (only you can see)",
type: 5, // Boolean
required: false,
}
],
execute: async (args: any, ctx: any) => {
try {
const query = args.find((arg: any) => arg.name === "query")?.value;
const shouldSend = args.find((arg: any) => arg.name === "send")?.value || false;
const isEphemeral = args.find((arg: any) => arg.name === "ephemeral")?.value || false;
if (!query) {
const errorMsg = "❌ Query parameter is required!";
if (isEphemeral) {
return {
type: 4,
data: {
content: errorMsg,
flags: 64,
},
};
}
showToast(errorMsg, getAssetIDByName("CircleXIcon"));
return { type: 4 };
}
// Show loading toast
if (!isEphemeral && !shouldSend) {
showToast(`Looking up IP information for ${query}...`, getAssetIDByName("DownloadIcon"));
}
// Build API URL with all requested fields
const url = `http://ipwhois.app/json/${encodeURIComponent(query)}?objects=` +
`success,ip,type,as,org,isp,continent,country,country_capital,city,region,` +
`country_phone,latitude,longitude,timezone,currency,completed_requests`;
const response = await fetch(url);
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
const data: IpWhoisResponse = await response.json();
if (!data.success) {
const errorMsg = `❌ Failed to lookup IP information for: ${query}`;
if (isEphemeral) {
return {
type: 4,
data: {
content: errorMsg,
flags: 64,
},
};
}
showToast(errorMsg, getAssetIDByName("CircleXIcon"));
return { type: 4 };
}
// Format the response as code block
const formattedData = JSON.stringify(data, null, 4);
const content = `\`\`\`json\n${formattedData}\n\`\`\``;
if (isEphemeral) {
return {
type: 4,
data: {
content,
flags: 64,
},
};
} else if (shouldSend) {
const fixNonce = Date.now().toString();
MessageActions.sendMessage(ctx.channel.id, { content }, void 0, { nonce: fixNonce });
return { type: 4 };
} else {
// Send as bot message (ephemeral-like)
messageUtil.sendBotMessage(ctx.channel.id, content);
return { type: 4 };
}
} catch (error) {
console.error('[IP] Command error:', error);
const errorMessage = `❌ An error occurred while looking up IP information: ${error.message || 'Unknown error'}`;
const isEphemeral = args?.find?.((arg: any) => arg.name === "ephemeral")?.value ?? false;
if (isEphemeral) {
return {
type: 4,
data: {
content: errorMessage,
flags: 64,
},
};
}
showToast(errorMessage, getAssetIDByName("CircleXIcon"));
return { type: 4 };
}
},
applicationId: "-1",
inputType: 1,
type: 1,
};