diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b9aff5e65..a0da3af2d 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -3,6 +3,7 @@ on: push: branches: - main + env: FORCE_COLOR: true GITHUB_TOKEN: ${{ secrets.ETOKEN }} @@ -65,10 +66,15 @@ jobs: rm release/*.map - name: Upload Equicord Stable - if: ${{ github.ref_name == 'main' }} run: | gh release upload latest --clobber dist/release/* + - name: Create Tag + uses: butlerlogic/action-autotag@1.1.2 + env: + GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" + tag_prefix: "v" + - name: Upload Plugin JSONs to Equibored repo run: | git config --global user.name "GitHub-Actions" diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index f3df68ee0..0c56e36c0 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -37,9 +37,3 @@ jobs: - name: Test if plugin structure is valid run: pnpm generatePluginJson - - - name: Create Tag - if: ${{ github.ref_name == 'main' }} - uses: butlerlogic/action-autotag@1.1.2 - env: - GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" diff --git a/package.json b/package.json index 15f164078..28023e37d 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "equicord", "private": "true", - "version": "1.12.10", + "version": "1.12.11", "description": "The other cutest Discord client mod", "homepage": "https://github.com/Equicord/Equicord#readme", "bugs": { @@ -115,4 +115,4 @@ "engines": { "node": ">=18" } -} +} \ No newline at end of file diff --git a/packages/discord-types/src/components.d.ts b/packages/discord-types/src/components.d.ts index b5f1fb779..a20156e07 100644 --- a/packages/discord-types/src/components.d.ts +++ b/packages/discord-types/src/components.d.ts @@ -44,12 +44,7 @@ export type FormDivider = ComponentType<{ }>; -export type FormText = ComponentType & TextProps> & { Types: FormTextTypes; }; +export type FormText = ComponentType; export type Tooltip = ComponentType<{ text: ReactNode | ComponentType; diff --git a/src/equicordplugins/customUserColors/index.tsx b/src/equicordplugins/customUserColors/index.tsx index 69a108db0..9efc00684 100644 --- a/src/equicordplugins/customUserColors/index.tsx +++ b/src/equicordplugins/customUserColors/index.tsx @@ -105,7 +105,7 @@ export default definePlugin({ { find: "PrivateChannel.renderAvatar", replacement: { - match: /(subText:\i\(\),)/, + match: /(withDisplayNameStyles\]:\i\}\),children:\i\}\),)/, replace: "$1style:{color:`${$self.colorDMList(arguments[0])}`}," }, predicate: () => settings.store.dmList, diff --git a/src/equicordplugins/dontFilterMe/index.tsx b/src/equicordplugins/dontFilterMe/index.tsx index 13c83540c..aec78e046 100644 --- a/src/equicordplugins/dontFilterMe/index.tsx +++ b/src/equicordplugins/dontFilterMe/index.tsx @@ -23,7 +23,7 @@ function warningEmbedNotice(trigger) { Your message contains a term on the automod preset list. (Term "{trigger}") - + There is a high chance your message will be blocked and potentially moderated by a server moderator. , diff --git a/src/equicordplugins/identity/index.tsx b/src/equicordplugins/identity/index.tsx index 2e6ed7861..e8b228581 100644 --- a/src/equicordplugins/identity/index.tsx +++ b/src/equicordplugins/identity/index.tsx @@ -86,7 +86,7 @@ function ResetCard() { Saving your base profile will allow you to have a backup of your actual profile - + If you save, it will overwrite your previous data. , @@ -107,7 +107,7 @@ function ResetCard() { Loading your base profile will restore your actual profile settings - + If you load, it will overwrite your current profile configuration. , diff --git a/src/equicordplugins/instantScreenshare/utils.tsx b/src/equicordplugins/instantScreenshare/utils.tsx index 7f85ab4a6..4c4d7d4b5 100644 --- a/src/equicordplugins/instantScreenshare/utils.tsx +++ b/src/equicordplugins/instantScreenshare/utils.tsx @@ -95,7 +95,7 @@ function SettingSection() { return ( Media source to stream - Resets to main screen if not found + Resets to main screen if not found ); diff --git a/src/equicordplugins/keywordNotify/index.tsx b/src/equicordplugins/keywordNotify/index.tsx index 33ba20a4a..d89bd4020 100644 --- a/src/equicordplugins/keywordNotify/index.tsx +++ b/src/equicordplugins/keywordNotify/index.tsx @@ -322,8 +322,8 @@ export default definePlugin({ { find: "location:\"RecentsPopout\"});", replacement: { - match: /:(\i)===\i\.\i\.MENTIONS\?\(0,.+?setTab:(\i),onJump:(\i),badgeState:\i,closePopout:(\i)/, - replace: ": $1 === 8 ? $self.tryKeywordMenu($2, $3, $4) $&" + match: /(?<=setTab:(\i),badgeState:\i,closePopout:(\i).{0,50}):(\i)===\i\.\i\.MENTIONS\?\(0,.+?onJump:(\i)/, + replace: ": $3 === 8 ? $self.tryKeywordMenu($1, $2, $4) $&" } }, { diff --git a/src/equicordplugins/musicControls/settings.tsx b/src/equicordplugins/musicControls/settings.tsx index 8e9c4eac0..a3b94de87 100644 --- a/src/equicordplugins/musicControls/settings.tsx +++ b/src/equicordplugins/musicControls/settings.tsx @@ -10,7 +10,8 @@ import { makeRange, OptionType } from "@utils/types"; import { Button, Forms, MaskedLink, showToast, Toasts } from "@webpack/common"; import hoverOnlyStyle from "./hoverOnly.css?managed"; -import { clearLyricsCache } from "./spotify/lyrics/api"; +import { clearLyricsCache, removeTranslations } from "./spotify/lyrics/api"; +import languages from "./spotify/lyrics/providers/translator/languages"; import { Provider } from "./spotify/lyrics/providers/types"; const sliderOptions = { @@ -61,6 +62,15 @@ export const settings = definePluginSettings({ { value: Provider.Lrclib, label: "LRCLIB" }, ], }, + TranslateTo: { + description: "Translate lyrics to - Changing this will clear existing translations", + type: OptionType.SELECT, + options: languages, + onChange: async () => { + await removeTranslations(); + showToast("Translations cleared", Toasts.Type.SUCCESS); + } + }, LyricsConversion: { description: "Automatically translate or romanize lyrics", type: OptionType.SELECT, diff --git a/src/equicordplugins/musicControls/spotify/lyrics/api.tsx b/src/equicordplugins/musicControls/spotify/lyrics/api.tsx index a92381d77..d9a95d040 100644 --- a/src/equicordplugins/musicControls/spotify/lyrics/api.tsx +++ b/src/equicordplugins/musicControls/spotify/lyrics/api.tsx @@ -29,8 +29,7 @@ export const lyricFetchers = { export const providers = Object.keys(lyricFetchers) as Provider[]; export async function getLyrics(track: Track | null): Promise { - if (!track) return null; - if (!track.id) return null; + if (!track || !track.id) return null; const cacheKey = track.id; const cached = await DataStore.get(LyricsCacheKey) as Record; @@ -76,7 +75,7 @@ export async function clearLyricsCache() { export async function getLyricsCount(): Promise { const cache = await DataStore.get(LyricsCacheKey) as Record; - return Object.keys(cache).length; + return Object.keys(cache ?? {}).length; } export async function updateLyrics(trackId: string, newLyrics: SyncedLyric[], provider: Provider) { diff --git a/src/equicordplugins/musicControls/spotify/lyrics/components/lyrics.tsx b/src/equicordplugins/musicControls/spotify/lyrics/components/lyrics.tsx index 7a3770093..9e89a1c84 100644 --- a/src/equicordplugins/musicControls/spotify/lyrics/components/lyrics.tsx +++ b/src/equicordplugins/musicControls/spotify/lyrics/components/lyrics.tsx @@ -14,51 +14,45 @@ import { LyricsContextMenu } from "./ctxMenu"; import { LyricsModal } from "./modal"; import { cl, NoteSvg, useLyrics } from "./util"; +const prevCl = cl("prev"); +const nextCl = cl("next"); +const currentCl = cl("current"); + function LyricsDisplay({ scroll = true }: { scroll?: boolean; }) { const { ShowMusicNoteOnNoLyrics } = settings.use(["ShowMusicNoteOnNoLyrics"]); const { lyricsInfo, lyricRefs, currLrcIndex } = useLyrics({ scroll }); const currentLyrics = lyricsInfo?.lyricsVersions[lyricsInfo.useLyric] || null; - const NoteElement = NoteSvg(cl("music-note")); - const makeClassName = (index: number): string => { - if (currLrcIndex === null) return ""; + if (currLrcIndex == null) return prevCl; const diff = index - currLrcIndex; - if (diff === 0) return cl("current"); - return cl(diff > 0 ? "next" : "prev"); + if (diff === 0) return currentCl; + return diff > 0 ? nextCl : prevCl; }; - if (!lyricsInfo) { - return ShowMusicNoteOnNoLyrics ? ( -
ContextMenuApi.openContextMenu(e, () => )} - > - - {NoteElement} - -
- ) : null; - } - return (
openModal(props => )} + onClick={() => openModal(props => )} onContextMenu={e => ContextMenuApi.openContextMenu(e, () => )} > - {currentLyrics?.map((line, i) => ( + {currentLyrics ? currentLyrics.map((line, i) => (
- {line.text || NoteElement} + {line.text || NoteSvg()}
- ))} + )) : ShowMusicNoteOnNoLyrics ? ( + + + + ) : null}
); } diff --git a/src/equicordplugins/musicControls/spotify/lyrics/components/modal.tsx b/src/equicordplugins/musicControls/spotify/lyrics/components/modal.tsx index 6a3423fec..59831cbc7 100644 --- a/src/equicordplugins/musicControls/spotify/lyrics/components/modal.tsx +++ b/src/equicordplugins/musicControls/spotify/lyrics/components/modal.tsx @@ -17,7 +17,14 @@ const formatTime = (time: number) => { return `${minutes}:${seconds.toString().padStart(2, "0")}`; }; -function ModalHeaderContent({ track }: { track: Track; }) { +function ModalHeaderContent({ track }: { track: Track | null; }) { + if (!track) { + return ( + + No track playing + + ); + } return (
@@ -43,27 +50,30 @@ function ModalHeaderContent({ track }: { track: Track; }) { ); } -export function LyricsModal({ rootProps }: { rootProps: ModalProps; }) { +const modalCurrentLine = cl("modal-line-current"); +const modalLine = cl("modal-line"); + +export function LyricsModal({ props }: { props: ModalProps; }) { const { track, lyricsInfo, currLrcIndex } = useLyrics({ scroll: false }); - const currentLyrics = lyricsInfo?.lyricsVersions[lyricsInfo.useLyric] || null; + const currentLyrics = lyricsInfo?.lyricsVersions[lyricsInfo.useLyric]; return ( - - + + -
+
{currentLyrics ? ( currentLyrics.map((line, i) => ( SpotifyStore.seek(line.time * 1000)}> {formatTime(line.time)} - {line.text || NoteSvg(cl("modal-note"))} + {line.text || NoteSvg()} )) ) : ( diff --git a/src/equicordplugins/musicControls/spotify/lyrics/components/util.tsx b/src/equicordplugins/musicControls/spotify/lyrics/components/util.tsx index 176df03a7..5c63eb967 100644 --- a/src/equicordplugins/musicControls/spotify/lyrics/components/util.tsx +++ b/src/equicordplugins/musicControls/spotify/lyrics/components/util.tsx @@ -12,23 +12,51 @@ import { settings } from "../../../settings"; import { SpotifyStore } from "../../SpotifyStore"; import { SpotifyLrcStore } from "../providers/store"; import { SyncedLyric } from "../providers/types"; + export const scrollClasses = findByPropsLazy("auto", "customTheme"); export const cl = classNameFactory("vc-spotify-lyrics-"); -export function NoteSvg(className: string) { +export function NoteSvg() { return ( - + ); } -const calculateIndexes = (lyrics: SyncedLyric[], position: number, delay: number) => { - const posInSec = position / 1000; - const currentIndex = lyrics.findIndex(l => l.time - (delay / 1000) > posInSec && l.time < posInSec + 8) - 1; - const nextLyric = lyrics.findIndex(l => l.time >= posInSec); - return [currentIndex, nextLyric]; + +const getIndexes = (lyrics: SyncedLyric[], position: number, delay: number) => { + const posInSec = (position + delay) / 1000; + + let left = 0, right = lyrics.length - 1; + let currentIndex: number | null = null; + + while (left <= right) { + const mid = Math.floor((left + right) / 2); + const curr = lyrics[mid]; + const next = lyrics[mid + 1]; + + if (curr.time <= posInSec && (!next || next.time > posInSec)) { + currentIndex = mid; + break; + } + + if (curr.time > posInSec) { + right = mid - 1; + } else { + left = mid + 1; + } + } + + const nextIdx = currentIndex !== null ? currentIndex + 1 : left; + const nextLyricIdx = nextIdx < lyrics.length ? nextIdx : null; + + if (currentIndex !== null && posInSec - lyrics[currentIndex].time > 8) { + return [null, nextLyricIdx]; + } + + return [currentIndex, nextLyricIdx]; }; export function useLyrics({ scroll = true }: { scroll?: boolean; } = {}) { @@ -47,7 +75,7 @@ export function useLyrics({ scroll = true }: { scroll?: boolean; } = {}) { const [position, setPosition] = useState(storePosition); const [lyricRefs, setLyricRefs] = useState[]>([]); - const currentLyrics = lyricsInfo?.lyricsVersions[lyricsInfo.useLyric] || null; + const currentLyrics = lyricsInfo?.lyricsVersions[lyricsInfo.useLyric]; useEffect(() => { if (currentLyrics) { @@ -57,12 +85,15 @@ export function useLyrics({ scroll = true }: { scroll?: boolean; } = {}) { useEffect(() => { - if (currentLyrics && position) { - const [currentIndex, nextLyric] = calculateIndexes(currentLyrics, position, LyricDelay); + if (currentLyrics && position != null) { + const [currentIndex, nextLyricIndex] = getIndexes(currentLyrics, position, LyricDelay); setCurrLrcIndex(currentIndex); - setNextLyric(nextLyric); + setNextLyric(nextLyricIndex); + } else { + setCurrLrcIndex(null); + setNextLyric(null); } - }, [currentLyrics, position]); + }, [currentLyrics, position, LyricDelay]); useEffect(() => { if (scroll && currLrcIndex !== null) { @@ -73,17 +104,15 @@ export function useLyrics({ scroll = true }: { scroll?: boolean; } = {}) { lyricRefs[nextLyric]?.current?.scrollIntoView({ behavior: "smooth", block: "center" }); } } - }, [currLrcIndex, nextLyric, scroll]); + }, [currLrcIndex, nextLyric, scroll, lyricRefs]); useEffect(() => { - if (isPlaying) { - setPosition(SpotifyStore.position); - const interval = setInterval(() => { - setPosition(p => p + 1000); - }, 1000); + if (!isPlaying) return; - return () => clearInterval(interval); - } + setPosition(SpotifyStore.position); + const interval = setInterval(() => setPosition(p => p + 1000), 1000); + + return () => clearInterval(interval); }, [storePosition, isPlaying]); return { track, lyricsInfo, lyricRefs, currLrcIndex, nextLyric }; diff --git a/src/equicordplugins/musicControls/spotify/lyrics/providers/translator/index.ts b/src/equicordplugins/musicControls/spotify/lyrics/providers/translator/index.ts index 02d7308ec..898072d13 100644 --- a/src/equicordplugins/musicControls/spotify/lyrics/providers/translator/index.ts +++ b/src/equicordplugins/musicControls/spotify/lyrics/providers/translator/index.ts @@ -5,7 +5,7 @@ */ import settings from "../../../.."; -import { LyricsData, Provider, SyncedLyric } from "../types"; +import { Provider, SyncedLyric } from "../types"; // stolen from src\plugins\translate\utils.ts @@ -45,7 +45,7 @@ async function googleTranslate(text: string, targetLang: string, romanize: boole } async function processLyrics( - lyrics: LyricsData["lyricsVersions"][Provider], + lyrics: SyncedLyric[], targetLang: string, romanize: boolean ): Promise { @@ -67,7 +67,7 @@ async function processLyrics( }) ); - if (processedLyricsResp[0][1] === null) return null; + if (processedLyricsResp.every(mapping => mapping[1] === null)) return null; return lyrics.map(lyric => ({ ...lyric, @@ -75,13 +75,12 @@ async function processLyrics( })); } -async function translateLyrics(lyrics: LyricsData["lyricsVersions"][Provider]): Promise { - const language = settings.store.TranslateTo; - return processLyrics(lyrics, language, false); +async function translateLyrics(lyrics: SyncedLyric[]) { + return await processLyrics(lyrics, settings.store.TranslateTo, false); } -async function romanizeLyrics(lyrics: LyricsData["lyricsVersions"][Provider]): Promise { - return processLyrics(lyrics, "", true); +async function romanizeLyrics(lyrics: SyncedLyric[]) { + return await processLyrics(lyrics, "", true); } export const lyricsAlternativeFetchers = { diff --git a/src/equicordplugins/musicControls/styles.css b/src/equicordplugins/musicControls/styles.css index 3252938e7..878b13208 100644 --- a/src/equicordplugins/musicControls/styles.css +++ b/src/equicordplugins/musicControls/styles.css @@ -243,4 +243,4 @@ .eq-tidal-lyrics-word-active { transform: none; } -} +} \ No newline at end of file diff --git a/src/equicordplugins/whosWatching/index.tsx b/src/equicordplugins/whosWatching/index.tsx index 8bee85b52..c7e77211a 100644 --- a/src/equicordplugins/whosWatching/index.tsx +++ b/src/equicordplugins/whosWatching/index.tsx @@ -84,7 +84,7 @@ export default definePlugin({ { find: "this.renderEmbeddedActivity()", replacement: { - match: /(?<=render\(\).{0,500}children.{0,50})"div"(?=.{0,500}this\.renderEmbeddedActivity\(\))/, + match: /"div"(?=.{0,100}this.renderActions)/, replace: "$self.WrapperComponent" } } diff --git a/src/plugins/betterSettings/index.tsx b/src/plugins/betterSettings/index.tsx index c844ed5cf..ec2df1ba5 100644 --- a/src/plugins/betterSettings/index.tsx +++ b/src/plugins/betterSettings/index.tsx @@ -126,8 +126,8 @@ export default definePlugin({ find: "#{intl::USER_SETTINGS_ACTIONS_MENU_LABEL}", replacement: [ { - match: /(EXPERIMENTS:.+?)(\(0,\i.\i\)\(\))(?=\.filter\(\i=>\{let\{section:\i\}=)/, - replace: "$1$self.wrapMenu($2)" + match: /(\(0,\i.\i\)\(\))(?=\.filter\(\i=>\{let\{section:\i\}=)/, + replace: "$self.wrapMenu($1)" }, { match: /case \i\.\i\.DEVELOPER_OPTIONS:return \i;/, diff --git a/src/plugins/consoleJanitor/index.tsx b/src/plugins/consoleJanitor/index.tsx index 8a11cf01f..4981ac2ca 100644 --- a/src/plugins/consoleJanitor/index.tsx +++ b/src/plugins/consoleJanitor/index.tsx @@ -60,7 +60,7 @@ const AllowLevelSettings = ErrorBoundary.wrap(() => { return ( Filter List - Always allow loggers of these types + Always allow loggers of these types {Object.keys(settings.store.allowLevel).map(key => ( diff --git a/src/plugins/decor/settings.tsx b/src/plugins/decor/settings.tsx index 46af32d43..b0ab88234 100644 --- a/src/plugins/decor/settings.tsx +++ b/src/plugins/decor/settings.tsx @@ -24,7 +24,7 @@ export const settings = definePluginSettings({ return
- + You can also access Decor decorations from the { diff --git a/src/plugins/decor/ui/modals/ChangeDecorationModal.tsx b/src/plugins/decor/ui/modals/ChangeDecorationModal.tsx index d9cfd50c2..ed81eaf06 100644 --- a/src/plugins/decor/ui/modals/ChangeDecorationModal.tsx +++ b/src/plugins/decor/ui/modals/ChangeDecorationModal.tsx @@ -83,7 +83,7 @@ function SectionHeader({ section }: SectionHeaderProps) { />} {hasSubtitle && - + {section.subtitle} } diff --git a/src/plugins/decor/ui/modals/CreateDecorationModal.tsx b/src/plugins/decor/ui/modals/CreateDecorationModal.tsx index 4afb74643..d772ac4a4 100644 --- a/src/plugins/decor/ui/modals/CreateDecorationModal.tsx +++ b/src/plugins/decor/ui/modals/CreateDecorationModal.tsx @@ -97,7 +97,7 @@ function CreateDecorationModal(props: ModalProps) { filters={[{ name: "Decoration file", extensions: ["png", "apng"] }]} onFileSelect={setFile} /> - + File should be APNG or PNG. @@ -107,7 +107,7 @@ function CreateDecorationModal(props: ModalProps) { value={name} onChange={setName} /> - + This name will be used when referring to this decoration. diff --git a/src/plugins/fakeNitro/index.tsx b/src/plugins/fakeNitro/index.tsx index 0742f0528..cbef80d05 100644 --- a/src/plugins/fakeNitro/index.tsx +++ b/src/plugins/fakeNitro/index.tsx @@ -805,7 +805,7 @@ export default definePlugin({ however you do not have permissions to embed links in the current channel. Are you sure you want to send this message? Your FakeNitro items will appear as a link only. - + You can disable this notice in the plugin settings.
, diff --git a/src/plugins/ignoreActivities/index.tsx b/src/plugins/ignoreActivities/index.tsx index f35879f69..fa5573aa3 100644 --- a/src/plugins/ignoreActivities/index.tsx +++ b/src/plugins/ignoreActivities/index.tsx @@ -82,7 +82,7 @@ function recalculateActivities() { function ImportCustomRPCComponent() { return ( - Import the application id of the CustomRPC plugin to the filter list + Import the application id of the CustomRPC plugin to the filter list