diff --git a/lib/artist/updateArtistSocials.ts b/lib/artist/updateArtistSocials.ts index 12fc25c7..fc0d63e1 100644 --- a/lib/artist/updateArtistSocials.ts +++ b/lib/artist/updateArtistSocials.ts @@ -1,5 +1,6 @@ import { getSocialPlatformByLink } from "@/lib/artists/getSocialPlatformByLink"; import { getUsernameFromProfileUrl } from "@/lib/socials/getUsernameFromProfileUrl"; +import { normalizeProfileUrl } from "@/lib/socials/normalizeProfileUrl"; import { selectAccountSocials } from "@/lib/supabase/account_socials/selectAccountSocials"; import { deleteAccountSocial } from "@/lib/supabase/account_socials/deleteAccountSocial"; import { insertAccountSocial } from "@/lib/supabase/account_socials/insertAccountSocial"; @@ -23,8 +24,13 @@ export async function updateArtistSocials( // Process each platform type const profilePromises = Object.entries(profileUrls).map(async ([type, value]) => { - const socials = value ? await selectSocials({ profile_url: value }) : null; + const normalizedUrl = normalizeProfileUrl(value); + + const socials = normalizedUrl + ? await selectSocials({ profile_url: normalizedUrl }) + : null; const social = socials && socials.length > 0 ? socials[0] : null; + const existingSocial = (accountSocials || []).find( (account_social: AccountSocialWithSocial) => getSocialPlatformByLink(account_social.social?.profile_url || "") === type, @@ -36,7 +42,7 @@ export async function updateArtistSocials( } // Insert new social if URL provided - if (value) { + if (normalizedUrl) { if (social) { // Social already exists, check if account_social relationship exists const existing = (accountSocials || []).find( @@ -47,10 +53,11 @@ export async function updateArtistSocials( } } else { // Create new social record + const username = getUsernameFromProfileUrl(value); const newSocials = await insertSocials([ { - username: getUsernameFromProfileUrl(value), - profile_url: value, + username, + profile_url: normalizedUrl, }, ]); if (newSocials.length > 0) { diff --git a/lib/chat/toolChains/createNewArtistToolChain.ts b/lib/chat/toolChains/createNewArtistToolChain.ts index 3247a84b..17892afa 100644 --- a/lib/chat/toolChains/createNewArtistToolChain.ts +++ b/lib/chat/toolChains/createNewArtistToolChain.ts @@ -8,7 +8,11 @@ export const createNewArtistToolChain: ToolChainItem[] = [ system: "From the get_spotify_search results, select the artist whose name best matches the user-provided artist name (prefer exact, case-insensitive match; otherwise choose the closest by name and popularity). Update the account using the update_account_info tool with the artist's basic information: name, image, label, etc.", }, - { toolName: "update_artist_socials" }, + { + toolName: "update_artist_socials", + system: + "Using the matched Spotify artist from the get_spotify_search results, update the artist's socials with the Spotify profile URL (found in external_urls.spotify). Pass the URL in the urls array to update_artist_socials.", + }, { toolName: "artist_deep_research" }, { toolName: "spotify_deep_research" }, { toolName: "get_artist_socials" }, diff --git a/lib/socials/__tests__/normalizeProfileUrl.test.ts b/lib/socials/__tests__/normalizeProfileUrl.test.ts new file mode 100644 index 00000000..bf198ea6 --- /dev/null +++ b/lib/socials/__tests__/normalizeProfileUrl.test.ts @@ -0,0 +1,35 @@ +import { describe, it, expect } from "vitest"; +import { normalizeProfileUrl } from "../normalizeProfileUrl"; + +describe("normalizeProfileUrl", () => { + it("removes https:// protocol from URL", () => { + expect(normalizeProfileUrl("https://open.spotify.com/artist/123")).toBe( + "open.spotify.com/artist/123", + ); + }); + + it("removes http:// protocol from URL", () => { + expect(normalizeProfileUrl("http://twitter.com/user")).toBe("twitter.com/user"); + }); + + it("returns URL unchanged if no protocol", () => { + expect(normalizeProfileUrl("open.spotify.com/artist/123")).toBe( + "open.spotify.com/artist/123", + ); + }); + + it("handles empty string", () => { + expect(normalizeProfileUrl("")).toBe(""); + }); + + it("handles null/undefined", () => { + expect(normalizeProfileUrl(null as unknown as string)).toBe(""); + expect(normalizeProfileUrl(undefined as unknown as string)).toBe(""); + }); + + it("removes trailing slash", () => { + expect(normalizeProfileUrl("https://instagram.com/user/")).toBe( + "instagram.com/user", + ); + }); +}); diff --git a/lib/socials/normalizeProfileUrl.ts b/lib/socials/normalizeProfileUrl.ts new file mode 100644 index 00000000..92f348be --- /dev/null +++ b/lib/socials/normalizeProfileUrl.ts @@ -0,0 +1,14 @@ +/** + * Normalizes a profile URL by removing the protocol and trailing slash. + * This ensures consistent URL format for database queries and storage. + * + * @param url - The profile URL to normalize + * @returns The normalized URL without protocol or trailing slash + */ +export function normalizeProfileUrl(url: string | null | undefined): string { + if (!url) return ""; + + return url + .replace(/^https?:\/\//, "") + .replace(/\/$/, ""); +}