From 41431f8c3b4c358dfb66e9b3997e0560f536718d Mon Sep 17 00:00:00 2001
From: Eduardo Sacco <3680995+nastita@users.noreply.github.com>
Date: Fri, 18 Oct 2024 16:35:50 -0300
Subject: [PATCH 01/36] WIP parser refactor and updates
---
.../grid/utils/__tests__/gridParser.spec.ts | 640 ++++++++++--------
domains/grid/utils/gridParser.ts | 357 +++++-----
2 files changed, 566 insertions(+), 431 deletions(-)
diff --git a/domains/grid/utils/__tests__/gridParser.spec.ts b/domains/grid/utils/__tests__/gridParser.spec.ts
index 9c3a372e..e0fdf2ad 100644
--- a/domains/grid/utils/__tests__/gridParser.spec.ts
+++ b/domains/grid/utils/__tests__/gridParser.spec.ts
@@ -1,5 +1,4 @@
import { describe, expect, it } from 'vitest'
-import { parsePlatformInput } from '../gridParser'
const YOUTUBE_IFRAME_ALLOW =
'accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share'
@@ -8,300 +7,395 @@ const SPOTIFY_IFRAME_ALLOW =
const SOUNDCLOUD_IFRAME_ALLOW =
'autoplay; clipboard-write; encrypted-media; fullscreen; picture-in-picture'
-describe('Widget Input Parsing', () => {
- it.each([
- [
- 'X (Twitter) Post URL',
- GRID_WIDGET_TYPE.X,
- 'https://x.com/feindura/status/1804519711377436675',
- {
- type: GRID_WIDGET_TYPE.X,
- properties: {
- src: 'https://twitter.com/feindura/status/1804519711377436675?ref_src=twsrc%5Etfw',
- type: 'post',
+describe('parsePlatformInput', () => {
+ describe('X', () => {
+ it.each([
+ [
+ 'Handle',
+ GRID_WIDGET_TYPE.X,
+ '@feindura',
+ {
+ type: GRID_WIDGET_TYPE.X,
+ properties: {
+ src: 'https://twitter.com/feindura?ref_src=twsrc%5Etfw',
+ handle: 'feindura',
+ },
},
- },
- ],
- [
- 'X (Twitter) Post Embed Code',
- GRID_WIDGET_TYPE.X,
- '
',
- {
- type: GRID_WIDGET_TYPE.X,
- properties: {
- src: 'https://twitter.com/feindura/status/1804519711377436675?ref_src=twsrc%5Etfw',
- type: 'post',
+ ],
+ [
+ 'Post URL',
+ GRID_WIDGET_TYPE.X,
+ 'https://x.com/feindura/status/1804519711377436675',
+ {
+ type: GRID_WIDGET_TYPE.X,
+ properties: {
+ src: 'https://twitter.com/feindura/status/1804519711377436675',
+ handle: 'feindura',
+ id: '1804519711377436675',
+ },
},
- },
- ],
- [
- 'X (Twitter) Timeline URL',
- GRID_WIDGET_TYPE.X,
- 'https://twitter.com/lukso_io',
- {
- type: GRID_WIDGET_TYPE.X,
- properties: {
- src: 'https://twitter.com/lukso_io?ref_src=twsrc%5Etfw',
- type: 'timeline',
+ ],
+ [
+ 'Post URL twitter.com',
+ GRID_WIDGET_TYPE.X,
+ 'https://twitter.com/feindura/status/1804519711377436675',
+ {
+ type: GRID_WIDGET_TYPE.X,
+ properties: {
+ src: 'https://twitter.com/feindura/status/1804519711377436675',
+ handle: 'feindura',
+ id: '1804519711377436675',
+ },
},
- },
- ],
- [
- 'X (Twitter) Timeline Embed Code',
- GRID_WIDGET_TYPE.X,
- ' ',
- {
- type: GRID_WIDGET_TYPE.X,
- properties: {
- src: 'https://twitter.com/lukso_io?ref_src=twsrc%5Etfw',
- type: 'timeline',
+ ],
+ [
+ 'Post Embed Code',
+ GRID_WIDGET_TYPE.X,
+ ' ',
+ {
+ type: GRID_WIDGET_TYPE.X,
+ properties: {
+ src: 'https://twitter.com/feindura/status/1804519711377436675?ref_src=twsrc%5Etfw',
+ handle: 'feindura',
+ id: '1804519711377436675',
+ },
},
- },
- ],
- [
- 'Instagram Post URL',
- GRID_WIDGET_TYPE.INSTAGRAM,
- 'https://www.instagram.com/p/C98OXs6yhAq/?utm_source=ig_embed&utm_campaign=loading',
- {
- type: GRID_WIDGET_TYPE.INSTAGRAM,
- properties: {
- src: 'https://www.instagram.com/p/C98OXs6yhAq/?utm_source=ig_embed&utm_campaign=loading',
- type: 'p',
+ ],
+ [
+ 'Timeline URL',
+ GRID_WIDGET_TYPE.X,
+ 'https://x.com/lukso_io',
+ {
+ type: GRID_WIDGET_TYPE.X,
+ properties: {
+ src: 'https://twitter.com/lukso_io',
+ handle: 'lukso_io',
+ },
},
- },
- ],
- [
- 'Instagram Post Embed Code',
- GRID_WIDGET_TYPE.INSTAGRAM,
- '
',
- {
- type: GRID_WIDGET_TYPE.INSTAGRAM,
- properties: {
- src: 'https://www.instagram.com/p/C98OXs6yhAq/?utm_source=ig_embed&utm_campaign=loading',
- type: 'p',
+ ],
+ [
+ 'Timeline URL twitter.com',
+ GRID_WIDGET_TYPE.X,
+ 'https://twitter.com/lukso_io',
+ {
+ type: GRID_WIDGET_TYPE.X,
+ properties: {
+ src: 'https://twitter.com/lukso_io',
+ handle: 'lukso_io',
+ },
},
- },
- ],
- [
- 'Instagram Reel URL',
- GRID_WIDGET_TYPE.INSTAGRAM,
- 'https://www.instagram.com/reel/DAlOgHkuyxd/?utm_source=ig_embed&utm_campaign=loading',
- {
- type: GRID_WIDGET_TYPE.INSTAGRAM,
- properties: {
- src: 'https://www.instagram.com/reel/DAlOgHkuyxd/?utm_source=ig_embed&utm_campaign=loading',
- type: 'reel',
+ ],
+ [
+ 'Timeline Embed Code',
+ GRID_WIDGET_TYPE.X,
+ ' ',
+ {
+ type: GRID_WIDGET_TYPE.X,
+ properties: {
+ src: 'https://twitter.com/lukso_io?ref_src=twsrc%5Etfw',
+ handle: 'lukso_io',
+ },
},
- },
- ],
- [
- 'Instagram Reel Embed Code',
- GRID_WIDGET_TYPE.INSTAGRAM,
- '',
- {
- type: GRID_WIDGET_TYPE.INSTAGRAM,
- properties: {
- src: 'https://www.instagram.com/reel/DAlOgHkuyxd/?utm_source=ig_embed&utm_campaign=loading',
- type: 'reel',
+ ],
+ ])(
+ 'correctly parses %s',
+ async (_description, platform, input, expected) => {
+ const result = await parsePlatformInput(platform, input)
+ expect(result).toEqual(expected)
+ }
+ )
+ })
+
+ describe('YOUTUBE', () => {
+ it.each([
+ [
+ 'URL',
+ GRID_WIDGET_TYPE.YOUTUBE,
+ 'https://www.youtube.com/watch?v=Vw4JE64hsO8',
+ {
+ type: GRID_WIDGET_TYPE.IFRAME,
+ properties: {
+ src: 'https://www.youtube.com/embed/Vw4JE64hsO8',
+ allow: YOUTUBE_IFRAME_ALLOW,
+ },
},
- },
- ],
- [
- 'YouTube URL',
- GRID_WIDGET_TYPE.YOUTUBE,
- 'https://www.youtube.com/watch?v=Vw4JE64hsO8',
- {
- type: GRID_WIDGET_TYPE.IFRAME,
- properties: {
- src: 'https://www.youtube.com/embed/Vw4JE64hsO8',
- allow: YOUTUBE_IFRAME_ALLOW,
+ ],
+ [
+ 'Embed Code',
+ GRID_WIDGET_TYPE.YOUTUBE,
+ '',
+ {
+ type: GRID_WIDGET_TYPE.IFRAME,
+ properties: {
+ src: 'https://www.youtube.com/embed/Vw4JE64hsO8',
+ allow: YOUTUBE_IFRAME_ALLOW,
+ },
},
- },
- ],
- [
- 'YouTube Embed Code',
- GRID_WIDGET_TYPE.YOUTUBE,
- '',
- {
- type: GRID_WIDGET_TYPE.IFRAME,
- properties: {
- src: 'https://www.youtube.com/embed/Vw4JE64hsO8',
- allow: YOUTUBE_IFRAME_ALLOW,
+ ],
+ ])(
+ 'correctly parses %s',
+ async (_description, platform, input, expected) => {
+ const result = await parsePlatformInput(platform, input)
+ expect(result).toEqual(expected)
+ }
+ )
+ })
+
+ describe('SPOTIFY', () => {
+ it.each([
+ [
+ 'Track URL',
+ GRID_WIDGET_TYPE.SPOTIFY,
+ 'https://open.spotify.com/track/7xGfFoTpQ2E7fRF5lN10tr',
+ {
+ type: GRID_WIDGET_TYPE.IFRAME,
+ properties: {
+ src: 'https://open.spotify.com/embed/track/7xGfFoTpQ2E7fRF5lN10tr?utm_source=oembed',
+ allow: SPOTIFY_IFRAME_ALLOW,
+ type: 'track',
+ id: '7xGfFoTpQ2E7fRF5lN10tr',
+ },
},
- },
- ],
- [
- 'Spotify Track URL',
- GRID_WIDGET_TYPE.SPOTIFY,
- 'https://open.spotify.com/track/7xGfFoTpQ2E7fRF5lN10tr',
- {
- type: GRID_WIDGET_TYPE.SPOTIFY,
- properties: {
- src: 'https://open.spotify.com/embed/track/7xGfFoTpQ2E7fRF5lN10tr?utm_source=generator',
- allow: SPOTIFY_IFRAME_ALLOW,
- type: 'track',
+ ],
+ [
+ 'Track Embed Code',
+ GRID_WIDGET_TYPE.SPOTIFY,
+ '',
+ {
+ type: GRID_WIDGET_TYPE.IFRAME,
+ properties: {
+ src: 'https://open.spotify.com/embed/track/2BHj31ufdEqVK5CkYDp9mA?utm_source=generator',
+ allow: SPOTIFY_IFRAME_ALLOW,
+ type: 'track',
+ id: '2BHj31ufdEqVK5CkYDp9mA',
+ },
},
- },
- ],
- [
- 'Spotify Track Embed Code',
- GRID_WIDGET_TYPE.SPOTIFY,
- '',
- {
- type: GRID_WIDGET_TYPE.SPOTIFY,
- properties: {
- src: 'https://open.spotify.com/embed/track/2BHj31ufdEqVK5CkYDp9mA?utm_source=generator',
- allow: SPOTIFY_IFRAME_ALLOW,
- type: 'track',
+ ],
+ [
+ 'Track Embed Code with theme',
+ GRID_WIDGET_TYPE.SPOTIFY,
+ '',
+ {
+ type: GRID_WIDGET_TYPE.IFRAME,
+ properties: {
+ src: 'https://open.spotify.com/embed/track/48K735Rd3UQExzjXH004k1?utm_source=generator&theme=0',
+ allow: SPOTIFY_IFRAME_ALLOW,
+ type: 'track',
+ id: '48K735Rd3UQExzjXH004k1',
+ theme: '0',
+ },
},
- },
- ],
- [
- 'Spotify Track Embed Code with theme',
- GRID_WIDGET_TYPE.SPOTIFY,
- '',
- {
- type: GRID_WIDGET_TYPE.SPOTIFY,
- properties: {
- src: 'https://open.spotify.com/embed/track/48K735Rd3UQExzjXH004k1?utm_source=generator&theme=0',
- allow: SPOTIFY_IFRAME_ALLOW,
- type: 'track',
- theme: '0',
+ ],
+ [
+ 'Playlist URL',
+ GRID_WIDGET_TYPE.SPOTIFY,
+ 'https://open.spotify.com/playlist/7KFoK4LJ23EncELJwYmTDG',
+ {
+ type: GRID_WIDGET_TYPE.IFRAME,
+ properties: {
+ src: 'https://open.spotify.com/embed/playlist/7KFoK4LJ23EncELJwYmTDG?utm_source=oembed',
+ allow: SPOTIFY_IFRAME_ALLOW,
+ type: 'playlist',
+ id: '7KFoK4LJ23EncELJwYmTDG',
+ },
},
- },
- ],
- [
- 'Spotify Playlist URL',
- GRID_WIDGET_TYPE.SPOTIFY,
- 'https://open.spotify.com/playlist/7KFoK4LJ23EncELJwYmTDG',
- {
- type: GRID_WIDGET_TYPE.SPOTIFY,
- properties: {
- src: 'https://open.spotify.com/embed/playlist/7KFoK4LJ23EncELJwYmTDG?utm_source=generator',
- allow: SPOTIFY_IFRAME_ALLOW,
- type: 'playlist',
+ ],
+ [
+ 'Playlist Embed Code',
+ GRID_WIDGET_TYPE.SPOTIFY,
+ '',
+ {
+ type: GRID_WIDGET_TYPE.IFRAME,
+ properties: {
+ src: 'https://open.spotify.com/embed/playlist/7KFoK4LJ23EncELJwYmTDG?utm_source=generator',
+ allow: SPOTIFY_IFRAME_ALLOW,
+ type: 'playlist',
+ id: '7KFoK4LJ23EncELJwYmTDG',
+ },
},
- },
- ],
- [
- 'Spotify Playlist Embed Code',
- GRID_WIDGET_TYPE.SPOTIFY,
- '',
- {
- type: GRID_WIDGET_TYPE.SPOTIFY,
- properties: {
- src: 'https://open.spotify.com/embed/playlist/7KFoK4LJ23EncELJwYmTDG?utm_source=generator',
- allow: SPOTIFY_IFRAME_ALLOW,
- type: 'playlist',
+ ],
+ [
+ 'Artist URL',
+ GRID_WIDGET_TYPE.SPOTIFY,
+ 'https://open.spotify.com/artist/4KY9rCrokaoFzvMfX98u1q',
+ {
+ type: GRID_WIDGET_TYPE.IFRAME,
+ properties: {
+ src: 'https://open.spotify.com/embed/artist/4KY9rCrokaoFzvMfX98u1q?utm_source=oembed',
+ allow: SPOTIFY_IFRAME_ALLOW,
+ type: 'artist',
+ id: '4KY9rCrokaoFzvMfX98u1q',
+ },
},
- },
- ],
- [
- 'Spotify Artist URL',
- GRID_WIDGET_TYPE.SPOTIFY,
- 'https://open.spotify.com/artist/4KY9rCrokaoFzvMfX98u1q',
- {
- type: GRID_WIDGET_TYPE.SPOTIFY,
- properties: {
- src: 'https://open.spotify.com/embed/artist/4KY9rCrokaoFzvMfX98u1q?utm_source=generator',
- allow: SPOTIFY_IFRAME_ALLOW,
- type: 'artist',
+ ],
+ [
+ 'Artist Embed Code',
+ GRID_WIDGET_TYPE.SPOTIFY,
+ '',
+ {
+ type: GRID_WIDGET_TYPE.IFRAME,
+ properties: {
+ src: 'https://open.spotify.com/embed/artist/4KY9rCrokaoFzvMfX98u1q?utm_source=generator',
+ allow: SPOTIFY_IFRAME_ALLOW,
+ type: 'artist',
+ id: '4KY9rCrokaoFzvMfX98u1q',
+ },
},
- },
- ],
- [
- 'Spotify Artist Embed Code',
- GRID_WIDGET_TYPE.SPOTIFY,
- '',
- {
- type: GRID_WIDGET_TYPE.SPOTIFY,
- properties: {
- src: 'https://open.spotify.com/embed/artist/4KY9rCrokaoFzvMfX98u1q?utm_source=generator',
- allow: SPOTIFY_IFRAME_ALLOW,
- type: 'artist',
+ ],
+ ])(
+ 'correctly parses %s',
+ async (_description, platform, input, expected) => {
+ const result = await parsePlatformInput(platform, input)
+ expect(result).toEqual(expected)
+ }
+ )
+ })
+
+ describe('SOUNDCLOUD', () => {
+ it.each([
+ [
+ 'Track Share URL',
+ GRID_WIDGET_TYPE.SOUNDCLOUD,
+ 'https://soundcloud.com/occams-laser/with-you',
+ {
+ type: GRID_WIDGET_TYPE.IFRAME,
+ properties: {
+ src: 'https://w.soundcloud.com/player/?visual=true&url=https%3A%2F%2Fapi.soundcloud.com%2Ftracks%2F1856391039&show_artwork=true',
+ allow: SOUNDCLOUD_IFRAME_ALLOW,
+ type: 'tracks',
+ },
},
- },
- ],
- [
- 'SoundCloud Track Share URL',
- GRID_WIDGET_TYPE.SOUNDCLOUD,
- 'https://soundcloud.com/occams-laser/with-you',
- {
- type: GRID_WIDGET_TYPE.IFRAME,
- properties: {
- src: 'https://w.soundcloud.com/player/?visual=true&url=https%3A%2F%2Fapi.soundcloud.com%2Ftracks%2F1856391039&show_artwork=true',
- allow: SOUNDCLOUD_IFRAME_ALLOW,
- type: 'tracks',
+ ],
+ [
+ 'Set Share URL',
+ GRID_WIDGET_TYPE.SOUNDCLOUD,
+ 'https://w.soundcloud.com/player/?visual=true&url=https%3A%2F%2Fapi.soundcloud.com%2Fplaylists%2F505007376&show_artwork=true',
+ {
+ type: GRID_WIDGET_TYPE.IFRAME,
+ properties: {
+ src: 'https://w.soundcloud.com/player/?visual=true&url=https%3A%2F%2Fapi.soundcloud.com%2Fplaylists%2F505007376&show_artwork=true',
+ allow: SPOTIFY_IFRAME_ALLOW,
+ type: 'playlists',
+ },
},
- },
- ],
- [
- 'SoundCloud Set Share URL',
- GRID_WIDGET_TYPE.SOUNDCLOUD,
- 'https://w.soundcloud.com/player/?visual=true&url=https%3A%2F%2Fapi.soundcloud.com%2Fplaylists%2F505007376&show_artwork=true',
- {
- type: GRID_WIDGET_TYPE.IFRAME,
- properties: {
- src: 'https://w.soundcloud.com/player/?visual=true&url=https%3A%2F%2Fapi.soundcloud.com%2Fplaylists%2F505007376&show_artwork=true',
- allow: SPOTIFY_IFRAME_ALLOW,
- type: 'playlists',
+ ],
+ [
+ 'Users Embed Code',
+ GRID_WIDGET_TYPE.SOUNDCLOUD,
+ 'https://soundcloud.com/fabian-vogelsteller',
+ {
+ type: GRID_WIDGET_TYPE.IFRAME,
+ properties: {
+ src: 'https://w.soundcloud.com/player/?visual=true&url=https%3A%2F%2Fapi.soundcloud.com%2Fusers%2F227118126&show_artwork=true',
+ allow: SOUNDCLOUD_IFRAME_ALLOW,
+ type: 'users',
+ },
},
- },
- ],
- [
- 'SoundCloud Users Embed Code',
- GRID_WIDGET_TYPE.SOUNDCLOUD,
- 'https://soundcloud.com/fabian-vogelsteller',
- {
- type: GRID_WIDGET_TYPE.IFRAME,
- properties: {
- src: 'https://w.soundcloud.com/player/?visual=true&url=https%3A%2F%2Fapi.soundcloud.com%2Fusers%2F227118126&show_artwork=true',
- allow: SOUNDCLOUD_IFRAME_ALLOW,
- type: 'users',
+ ],
+ [
+ 'Track Embed Code',
+ GRID_WIDGET_TYPE.SOUNDCLOUD,
+ '',
+ {
+ type: GRID_WIDGET_TYPE.IFRAME,
+ properties: {
+ src: 'https://w.soundcloud.com/player/?url=https://api.soundcloud.com/tracks/1856391039&color=%23ff5500&auto_play=false&hide_related=false&show_comments=true&show_user=true&show_reposts=false&show_teaser=true&visual=true',
+ allow: SOUNDCLOUD_IFRAME_ALLOW,
+ type: 'tracks',
+ },
+ },
+ ],
+ [
+ 'Track Embed Code with URL encoded characters',
+ GRID_WIDGET_TYPE.SOUNDCLOUD,
+ '',
+ {
+ type: GRID_WIDGET_TYPE.IFRAME,
+ properties: {
+ src: 'https://w.soundcloud.com/player/?visual=true&url=https%3A%2F%2Fapi.soundcloud.com%2Ftracks%2F1856391039&show_artwork=true',
+ allow: SOUNDCLOUD_IFRAME_ALLOW,
+ type: 'tracks',
+ },
+ },
+ ],
+ [
+ 'Playlist Embed Code',
+ GRID_WIDGET_TYPE.SOUNDCLOUD,
+ '',
+ {
+ type: GRID_WIDGET_TYPE.IFRAME,
+ properties: {
+ src: 'https://w.soundcloud.com/player/?url=https://api.soundcloud.com/playlists/1850298147&color=%23ff5500&auto_play=false&hide_related=false&show_comments=true&show_user=true&show_reposts=false&show_teaser=true&visual=true',
+ allow: SOUNDCLOUD_IFRAME_ALLOW,
+ type: 'playlists',
+ },
+ },
+ ],
+ ])(
+ 'correctly parses %s',
+ async (_description, platform, input, expected) => {
+ const result = await parsePlatformInput(platform, input)
+ expect(result).toEqual(expected)
+ }
+ )
+ })
+
+ describe('INSTAGRAM', () => {
+ it.each([
+ [
+ 'Post URL',
+ GRID_WIDGET_TYPE.INSTAGRAM,
+ 'https://www.instagram.com/p/C98OXs6yhAq/?utm_source=ig_embed&utm_campaign=loading',
+ {
+ type: GRID_WIDGET_TYPE.INSTAGRAM,
+ properties: {
+ src: 'https://www.instagram.com/p/C98OXs6yhAq/?utm_source=ig_embed&utm_campaign=loading',
+ type: 'p',
+ },
},
- },
- ],
- [
- 'SoundCloud Track Embed Code',
- GRID_WIDGET_TYPE.SOUNDCLOUD,
- '',
- {
- type: GRID_WIDGET_TYPE.IFRAME,
- properties: {
- src: 'https://w.soundcloud.com/player/?url=https://api.soundcloud.com/tracks/1856391039&color=%23ff5500&auto_play=false&hide_related=false&show_comments=true&show_user=true&show_reposts=false&show_teaser=true&visual=true',
- allow: SOUNDCLOUD_IFRAME_ALLOW,
- type: 'tracks',
+ ],
+ [
+ 'Post Embed Code',
+ GRID_WIDGET_TYPE.INSTAGRAM,
+ '
',
+ {
+ type: GRID_WIDGET_TYPE.INSTAGRAM,
+ properties: {
+ src: 'https://www.instagram.com/p/C98OXs6yhAq/?utm_source=ig_embed&utm_campaign=loading',
+ type: 'p',
+ },
},
- },
- ],
- [
- 'SoundCloud Track Embed Code with URL encoded characters',
- GRID_WIDGET_TYPE.SOUNDCLOUD,
- '',
- {
- type: GRID_WIDGET_TYPE.IFRAME,
- properties: {
- src: 'https://w.soundcloud.com/player/?visual=true&url=https%3A%2F%2Fapi.soundcloud.com%2Ftracks%2F1856391039&show_artwork=true',
- allow: SOUNDCLOUD_IFRAME_ALLOW,
- type: 'tracks',
+ ],
+ [
+ 'Reel URL',
+ GRID_WIDGET_TYPE.INSTAGRAM,
+ 'https://www.instagram.com/reel/DAlOgHkuyxd/?utm_source=ig_embed&utm_campaign=loading',
+ {
+ type: GRID_WIDGET_TYPE.INSTAGRAM,
+ properties: {
+ src: 'https://www.instagram.com/reel/DAlOgHkuyxd/?utm_source=ig_embed&utm_campaign=loading',
+ type: 'reel',
+ },
},
- },
- ],
- [
- 'SoundCloud Playlist Embed Code',
- GRID_WIDGET_TYPE.SOUNDCLOUD,
- '',
- {
- type: GRID_WIDGET_TYPE.IFRAME,
- properties: {
- src: 'https://w.soundcloud.com/player/?url=https://api.soundcloud.com/playlists/1850298147&color=%23ff5500&auto_play=false&hide_related=false&show_comments=true&show_user=true&show_reposts=false&show_teaser=true&visual=true',
- allow: SOUNDCLOUD_IFRAME_ALLOW,
- type: 'playlists',
+ ],
+ [
+ 'Reel Embed Code',
+ GRID_WIDGET_TYPE.INSTAGRAM,
+ '',
+ {
+ type: GRID_WIDGET_TYPE.INSTAGRAM,
+ properties: {
+ src: 'https://www.instagram.com/reel/DAlOgHkuyxd/?utm_source=ig_embed&utm_campaign=loading',
+ type: 'reel',
+ },
},
- },
- ],
- ])('correctly parses %s', async (_description, platform, input, expected) => {
- const result = await parsePlatformInput(platform, input)
- expect(result).toEqual(expected)
+ ],
+ ])(
+ 'correctly parses %s',
+ async (_description, platform, input, expected) => {
+ const result = await parsePlatformInput(platform, input)
+ expect(result).toEqual(expected)
+ }
+ )
})
})
diff --git a/domains/grid/utils/gridParser.ts b/domains/grid/utils/gridParser.ts
index c90c9a40..c443150a 100644
--- a/domains/grid/utils/gridParser.ts
+++ b/domains/grid/utils/gridParser.ts
@@ -1,198 +1,239 @@
-export const parsePlatformInput = async (
- platform: GridWidgetType,
- input: string
-): Promise => {
- switch (platform) {
- case GRID_WIDGET_TYPE.X:
- return parseXWidgetInput(input)
- case GRID_WIDGET_TYPE.INSTAGRAM:
- return parseInstagramWidgetInput(input)
- case GRID_WIDGET_TYPE.YOUTUBE:
- return parseYoutubeWidgetInput(input)
- case GRID_WIDGET_TYPE.SPOTIFY:
- return parseSpotifyWidgetInput(input)
- case GRID_WIDGET_TYPE.SOUNDCLOUD:
- return await parseSoundCloudWidgetInput(input)
- default:
- throw new Error('Invalid platform')
- }
+export type RegexWithCallback = {
+ regex: RegExp
+ callback: (url: string) => Promise
}
-const parseYoutubeWidgetInput = (input: string): LayoutItemExtended | never => {
- const YOUTUBE_URL_REGEX =
- /(?:https?:\/\/)?(?:www\.)?youtube\.com\/watch\?v=([^&]+)/
- const YOUTUBE_EMBED_REGEX =
- /(?:https?:\/\/)?(?:www\.)?youtube\.com\/embed\/([^?]+)/
- const YOUTUBE_IFRAME_ALLOW =
- 'accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share'
-
- const youtubeUrlMatch = input.match(YOUTUBE_URL_REGEX)
-
- if (youtubeUrlMatch) {
- return {
- type: GRID_WIDGET_TYPE.IFRAME,
- properties: {
- src: `https://www.youtube.com/embed/${youtubeUrlMatch[1]}`,
- allow: YOUTUBE_IFRAME_ALLOW,
- },
- }
- }
-
- const youtubeEmbedMatch = input.match(YOUTUBE_EMBED_REGEX)
-
- if (youtubeEmbedMatch) {
- return {
- type: GRID_WIDGET_TYPE.IFRAME,
- properties: {
- src: `https://www.youtube.com/embed/${youtubeEmbedMatch[1]}`,
- allow: YOUTUBE_IFRAME_ALLOW,
- },
- }
- }
-
- throw new Error('Invalid YouTube input')
+export type PlatformParsingParameters = {
+ type: GridWidgetType
+ embedRegex: RegExp
+ secondaryRegexesWithCallbacks?: RegexWithCallback[]
+ constantProperties?: Record
}
-const parseXWidgetInput = (input: string): LayoutItemExtended | never => {
- const X_POST_REGEX =
- /https?:\/\/(?:www\.)?(?:x\.com|twitter\.com)\/(\w+)\/status\/(\d+)(?:\?ref_src=twsrc%5Etfw)?/
- const X_TIMELINE_REGEX =
- /https?:\/\/(?:www\.)?(?:x\.com|twitter\.com)\/(\w+)(?:\?ref_src=twsrc%5Etfw)?/
-
- const [, postUser, postId] = input.match(X_POST_REGEX) || []
-
- if (postUser && postId) {
- return {
- type: GRID_WIDGET_TYPE.X,
- properties: {
- src: `https://twitter.com/${postUser}/status/${postId}?ref_src=twsrc%5Etfw`,
- type: 'post',
+const PLATFORM_PARSING_PARAMETERS: Record<
+ GridWidgetType,
+ PlatformParsingParameters | undefined
+> = {
+ [GRID_WIDGET_TYPE.TITLE_LINK]: undefined,
+ [GRID_WIDGET_TYPE.TEXT]: undefined,
+ [GRID_WIDGET_TYPE.IFRAME]: undefined,
+ [GRID_WIDGET_TYPE.IMAGE]: undefined,
+ [GRID_WIDGET_TYPE.X]: {
+ type: GRID_WIDGET_TYPE.X,
+ embedRegex:
+ /https?:\/\/twitter\.com\/(?[a-zA-Z0-9_]+)(?:\/status\/(?\d+))?(?:\?[^"'\s]*)?/,
+ secondaryRegexesWithCallbacks: [
+ // Match a handle with @ symbol
+ {
+ regex: /@([a-zA-Z0-9_]{1,15})/,
+ callback: getXOEmbedFromHandle,
},
- }
- }
-
- const [, timelineUser] = input.match(X_TIMELINE_REGEX) || []
-
- if (timelineUser) {
- return {
- type: GRID_WIDGET_TYPE.X,
- properties: {
- src: `https://twitter.com/${timelineUser}?ref_src=twsrc%5Etfw`,
- type: 'timeline',
+ // Match a Twitter URL with or without https www and status
+ {
+ regex:
+ /(https?:\/\/)?(?:x\.com|twitter\.com)\/[a-zA-Z0-9_]+(?:\/status\/(\d+))?/,
+ callback: async url => sanitizeXEmbedUrl(url),
},
- }
- }
-
- throw new Error('Invalid X input')
-}
-
-const parseSpotifyWidgetInput = (input: string): LayoutItemExtended | never => {
- const SPOTIFY_URL_REGEX =
- /https?:\/\/(?:open\.)?spotify\.com\/(?:embed\/)?(?track|playlist|artist)\/(?[^?]+)(?:\?utm_source=generator)?(?:&theme=(?\d))?/
- const SPOTIFY_IFRAME_ALLOW =
- 'autoplay; clipboard-write; encrypted-media; fullscreen; picture-in-picture'
-
- const { groups } = input.match(SPOTIFY_URL_REGEX) || {}
-
- if (groups?.type && groups?.id) {
- const theme = groups.theme ? `&theme=${groups.theme}` : ''
-
- return {
- type: GRID_WIDGET_TYPE.SPOTIFY,
- properties: {
- src: `https://open.spotify.com/embed/${groups.type}/${groups.id}?utm_source=generator${theme}`,
- type: groups.type,
- allow: SPOTIFY_IFRAME_ALLOW,
- theme: groups.theme,
+ ],
+ },
+ [GRID_WIDGET_TYPE.INSTAGRAM]: {
+ type: GRID_WIDGET_TYPE.INSTAGRAM,
+ embedRegex:
+ /https:\/\/www\.instagram\.com\/(p|reel|profile|tv)\/([\w-]+)\/(\?[^"]*)?/,
+ },
+ [GRID_WIDGET_TYPE.WARPCAST]: undefined,
+ [GRID_WIDGET_TYPE.SPOTIFY]: {
+ type: GRID_WIDGET_TYPE.IFRAME,
+ embedRegex:
+ /https?:\/\/(?:open\.)?spotify\.com\/embed\/?(?track|playlist|artist)\/(?[^?]+)(?:\?utm_source=(?:generator|oembed))?(?:&theme=(?\d))?/,
+ secondaryRegexesWithCallbacks: [
+ {
+ regex:
+ /https:\/\/open\.spotify\.com\/(?track|playlist|artist)\/(?[^?]+)/,
+ callback: getSpotifyOEmbed,
},
- }
- }
-
- throw new Error('Invalid Spotify input')
+ ],
+ constantProperties: {
+ allow:
+ 'autoplay; clipboard-write; encrypted-media; fullscreen; picture-in-picture',
+ },
+ },
+ [GRID_WIDGET_TYPE.SOUNDCLOUD]: {
+ type: GRID_WIDGET_TYPE.IFRAME,
+ embedRegex:
+ /https?:\/\/w\.soundcloud\.com\/player\/\?(?:(?!url=https).)*url=https(?::|%3A)(?:\/|%2F){2}api\.soundcloud\.com(?:\/|%2F)(?tracks|playlists|users)(?:\/|%2F)\d+(?:[^"]*)?/,
+ secondaryRegexesWithCallbacks: [
+ {
+ regex:
+ /https:\/\/soundcloud\.com\/([a-zA-Z0-9_-]+)(?:\/(sets\/[a-zA-Z0-9_-]+|[a-zA-Z0-9_-]+))?\/?/,
+ callback: getSoundCloudOEmbed,
+ },
+ ],
+ constantProperties: {
+ allow:
+ 'autoplay; clipboard-write; encrypted-media; fullscreen; picture-in-picture',
+ },
+ },
+ [GRID_WIDGET_TYPE.YOUTUBE]: {
+ type: GRID_WIDGET_TYPE.IFRAME,
+ embedRegex: /(?:https?:\/\/)?(?:www\.)?youtube\.com\/watch\?v=([^&]+)/,
+ },
+ [GRID_WIDGET_TYPE.ADD_CONTENT]: undefined,
}
-const parseSoundCloudWidgetInput = async (
+export const parsePlatformInput = async (
+ platform: GridWidgetType,
input: string
-): Promise => {
- const SOUNDCLOUD_SHARE_URL_REGEX =
- /https:\/\/soundcloud\.com\/([a-zA-Z0-9_-]+)(?:\/(sets\/[a-zA-Z0-9_-]+|[a-zA-Z0-9_-]+))?\/?/
+): Promise => {
+ const platformParsingParameters = PLATFORM_PARSING_PARAMETERS[platform]
+ if (!platformParsingParameters) throw new Error('Invalid platform')
- // Check if the input already contains an embed URL
+ // Check if the input matches the embed regex
try {
- return parseSoundCloudWidgetInputFromEmbed(input)
+ return parsePlatformEmbed(input, platformParsingParameters)
} catch {}
- // Check if the input is a SoundCloud share URL
- const [shareUrlMatch] = input.match(SOUNDCLOUD_SHARE_URL_REGEX) || []
- if (shareUrlMatch) {
- const soundCloudEmbed = await getSoundCloudEmbedUrl(shareUrlMatch)
+ const { secondaryRegexesWithCallbacks } = platformParsingParameters
+ if (!secondaryRegexesWithCallbacks) throw new Error('Invalid input')
+
+ // Check if the input matches a secondary regex
+ let callbackResult: string | undefined
+ for (const { regex, callback } of secondaryRegexesWithCallbacks) {
+ const match = input.match(regex)
- if (soundCloudEmbed) {
- return parseSoundCloudWidgetInputFromEmbed(soundCloudEmbed)
+ if (match) {
+ callbackResult = await callback(match[0])
+
+ break
}
}
- throw new Error('Invalid SoundCloud input')
+ if (!callbackResult) throw new Error('Invalid input')
+
+ return parsePlatformEmbed(callbackResult, platformParsingParameters)
}
-const parseSoundCloudWidgetInputFromEmbed = (
- input: string
+const parsePlatformEmbed = (
+ input: string,
+ platformParsingParameters: PlatformParsingParameters
): LayoutItemExtended | never => {
- const SOUNDCLOUD_EMBED_URL_REGEX =
- /https?:\/\/w\.soundcloud\.com\/player\/\?(?:(?!url=https).)*url=https(?::|%3A)(?:\/|%2F){2}api\.soundcloud\.com(?:\/|%2F)(tracks|playlists|users)(?:\/|%2F)\d+(?:[^"]*)?/
- const SOUNDCLOUD_IFRAME_ALLOW =
- 'autoplay; clipboard-write; encrypted-media; fullscreen; picture-in-picture'
- const [match, type] = input.match(SOUNDCLOUD_EMBED_URL_REGEX) || []
-
- if (match) {
- return {
- type: GRID_WIDGET_TYPE.IFRAME,
- properties: {
- src: match,
- allow: SOUNDCLOUD_IFRAME_ALLOW,
- type,
+ const { type, embedRegex, constantProperties } = platformParsingParameters
+ const match = input.match(embedRegex)
+
+ if (!match) throw new Error('Invalid input')
+
+ const { groups } = match
+ let extractedProperties: Record = {}
+ if (groups) {
+ // Extract the properties from capture groups from the regex match
+ extractedProperties = Object.entries(groups).reduce(
+ (acc: Record, [key, value]) => {
+ if (value) acc[key] = value
+
+ return acc
},
- }
+ {}
+ )
}
- throw new Error('Invalid SoundCloud input')
+ return {
+ type,
+ properties: {
+ src: match[0],
+ ...constantProperties,
+ ...extractedProperties,
+ },
+ }
}
-const getSoundCloudEmbedUrl = async (
- url: string
-): Promise => {
+// const parseYoutubeWidgetInput = (input: string): LayoutItemExtended | never => {
+// const YOUTUBE_URL_REGEX =
+// /(?:https?:\/\/)?(?:www\.)?youtube\.com\/watch\?v=([^&]+)/
+// const YOUTUBE_EMBED_REGEX =
+// /(?:https?:\/\/)?(?:www\.)?youtube\.com\/embed\/([^?]+)/
+// const YOUTUBE_IFRAME_ALLOW =
+// 'accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share'
+
+// const youtubeUrlMatch = input.match(YOUTUBE_URL_REGEX)
+
+// if (youtubeUrlMatch) {
+// return {
+// type: GRID_WIDGET_TYPE.IFRAME,
+// properties: {
+// src: `https://www.youtube.com/embed/${youtubeUrlMatch[1]}`,
+// allow: YOUTUBE_IFRAME_ALLOW,
+// },
+// }
+// }
+
+// const youtubeEmbedMatch = input.match(YOUTUBE_EMBED_REGEX)
+
+// if (youtubeEmbedMatch) {
+// return {
+// type: GRID_WIDGET_TYPE.IFRAME,
+// properties: {
+// src: `https://www.youtube.com/embed/${youtubeEmbedMatch[1]}`,
+// allow: YOUTUBE_IFRAME_ALLOW,
+// },
+// }
+// }
+
+// throw new Error('Invalid YouTube input')
+// }
+
+async function getSoundCloudOEmbed(url: string): Promise {
const encodedUrl = encodeURI(url)
const response = await fetch(
`https://soundcloud.com/oembed?url=${encodedUrl}&format=json`
)
- if (!response.ok) {
- return response.statusText
- }
+ return response.ok ? ((await response.json())?.html as string) : undefined
+}
- const { html } = await response.json()
- const [, srcMatch] = html.match(/src="([^"]+)"/) || []
+async function getSpotifyOEmbed(url: string): Promise {
+ const response = await fetch(
+ `https://open.spotify.com/oembed?url=${url}&format=json`
+ )
- return srcMatch
+ return response.ok ? ((await response.json())?.html as string) : undefined
}
-const parseInstagramWidgetInput = (
- input: string
-): LayoutItemExtended | never => {
- const INSTAGRAM_URL_REGEX =
- /https:\/\/www\.instagram\.com\/(p|reel|profile|tv)\/([\w-]+)\/(\?[^"]*)?/
+async function getXOEmbedFromHandle(handle: string) {
+ handle = handle.replace('@', '')
+ const response = await fetch(
+ `https://publish.twitter.com/oembed?url=https://twitter.com/${handle}`
+ )
- const [, type, id, params] = input.match(INSTAGRAM_URL_REGEX) || []
+ return response.ok ? ((await response.json())?.html as string) : undefined
+}
- if (id && type) {
- return {
- type: GRID_WIDGET_TYPE.INSTAGRAM,
- properties: {
- src: `https://www.instagram.com/${type}/${id}/${params}`,
- type: type,
- },
- }
+function sanitizeXEmbedUrl(url: string): string {
+ url = url.replace('x.com', 'twitter.com')
+
+ if (!url.startsWith('https://')) {
+ url = `https://${url}`
}
- throw new Error('Invalid Instagram input')
+ return url
}
+
+// const parseInstagramWidgetInput = (
+// input: string
+// ): LayoutItemExtended | never => {
+// const INSTAGRAM_URL_REGEX =
+// /https:\/\/www\.instagram\.com\/(p|reel|profile|tv)\/([\w-]+)\/(\?[^"]*)?/
+
+// const [, type, id, params] = input.match(INSTAGRAM_URL_REGEX) || []
+
+// if (id && type) {
+// return {
+// type: GRID_WIDGET_TYPE.INSTAGRAM,
+// properties: {
+// src: `https://www.instagram.com/${type}/${id}/${params}`,
+// type: type,
+// },
+// }
+// }
+
+// throw new Error('Invalid Instagram input')
+// }
From bab74f0b2a0116c3c433276112e82b09a0f7a9b1 Mon Sep 17 00:00:00 2001
From: Eduardo Sacco <3680995+nastita@users.noreply.github.com>
Date: Mon, 21 Oct 2024 13:21:55 -0300
Subject: [PATCH 02/36] Simplify parser result
---
.../grid/utils/__tests__/gridParser.spec.ts | 223 ++++++------------
domains/grid/utils/gridParser.ts | 15 +-
2 files changed, 75 insertions(+), 163 deletions(-)
diff --git a/domains/grid/utils/__tests__/gridParser.spec.ts b/domains/grid/utils/__tests__/gridParser.spec.ts
index e0fdf2ad..656a86b8 100644
--- a/domains/grid/utils/__tests__/gridParser.spec.ts
+++ b/domains/grid/utils/__tests__/gridParser.spec.ts
@@ -15,11 +15,8 @@ describe('parsePlatformInput', () => {
GRID_WIDGET_TYPE.X,
'@feindura',
{
- type: GRID_WIDGET_TYPE.X,
- properties: {
- src: 'https://twitter.com/feindura?ref_src=twsrc%5Etfw',
- handle: 'feindura',
- },
+ src: 'https://twitter.com/feindura?ref_src=twsrc%5Etfw',
+ handle: 'feindura',
},
],
[
@@ -27,12 +24,9 @@ describe('parsePlatformInput', () => {
GRID_WIDGET_TYPE.X,
'https://x.com/feindura/status/1804519711377436675',
{
- type: GRID_WIDGET_TYPE.X,
- properties: {
- src: 'https://twitter.com/feindura/status/1804519711377436675',
- handle: 'feindura',
- id: '1804519711377436675',
- },
+ src: 'https://twitter.com/feindura/status/1804519711377436675',
+ handle: 'feindura',
+ id: '1804519711377436675',
},
],
[
@@ -40,12 +34,9 @@ describe('parsePlatformInput', () => {
GRID_WIDGET_TYPE.X,
'https://twitter.com/feindura/status/1804519711377436675',
{
- type: GRID_WIDGET_TYPE.X,
- properties: {
- src: 'https://twitter.com/feindura/status/1804519711377436675',
- handle: 'feindura',
- id: '1804519711377436675',
- },
+ src: 'https://twitter.com/feindura/status/1804519711377436675',
+ handle: 'feindura',
+ id: '1804519711377436675',
},
],
[
@@ -53,12 +44,9 @@ describe('parsePlatformInput', () => {
GRID_WIDGET_TYPE.X,
' ',
{
- type: GRID_WIDGET_TYPE.X,
- properties: {
- src: 'https://twitter.com/feindura/status/1804519711377436675?ref_src=twsrc%5Etfw',
- handle: 'feindura',
- id: '1804519711377436675',
- },
+ src: 'https://twitter.com/feindura/status/1804519711377436675?ref_src=twsrc%5Etfw',
+ handle: 'feindura',
+ id: '1804519711377436675',
},
],
[
@@ -66,11 +54,8 @@ describe('parsePlatformInput', () => {
GRID_WIDGET_TYPE.X,
'https://x.com/lukso_io',
{
- type: GRID_WIDGET_TYPE.X,
- properties: {
- src: 'https://twitter.com/lukso_io',
- handle: 'lukso_io',
- },
+ src: 'https://twitter.com/lukso_io',
+ handle: 'lukso_io',
},
],
[
@@ -78,11 +63,8 @@ describe('parsePlatformInput', () => {
GRID_WIDGET_TYPE.X,
'https://twitter.com/lukso_io',
{
- type: GRID_WIDGET_TYPE.X,
- properties: {
- src: 'https://twitter.com/lukso_io',
- handle: 'lukso_io',
- },
+ src: 'https://twitter.com/lukso_io',
+ handle: 'lukso_io',
},
],
[
@@ -90,11 +72,8 @@ describe('parsePlatformInput', () => {
GRID_WIDGET_TYPE.X,
' ',
{
- type: GRID_WIDGET_TYPE.X,
- properties: {
- src: 'https://twitter.com/lukso_io?ref_src=twsrc%5Etfw',
- handle: 'lukso_io',
- },
+ src: 'https://twitter.com/lukso_io?ref_src=twsrc%5Etfw',
+ handle: 'lukso_io',
},
],
])(
@@ -113,11 +92,8 @@ describe('parsePlatformInput', () => {
GRID_WIDGET_TYPE.YOUTUBE,
'https://www.youtube.com/watch?v=Vw4JE64hsO8',
{
- type: GRID_WIDGET_TYPE.IFRAME,
- properties: {
- src: 'https://www.youtube.com/embed/Vw4JE64hsO8',
- allow: YOUTUBE_IFRAME_ALLOW,
- },
+ src: 'https://www.youtube.com/embed/Vw4JE64hsO8',
+ allow: YOUTUBE_IFRAME_ALLOW,
},
],
[
@@ -125,11 +101,8 @@ describe('parsePlatformInput', () => {
GRID_WIDGET_TYPE.YOUTUBE,
'',
{
- type: GRID_WIDGET_TYPE.IFRAME,
- properties: {
- src: 'https://www.youtube.com/embed/Vw4JE64hsO8',
- allow: YOUTUBE_IFRAME_ALLOW,
- },
+ src: 'https://www.youtube.com/embed/Vw4JE64hsO8',
+ allow: YOUTUBE_IFRAME_ALLOW,
},
],
])(
@@ -148,13 +121,9 @@ describe('parsePlatformInput', () => {
GRID_WIDGET_TYPE.SPOTIFY,
'https://open.spotify.com/track/7xGfFoTpQ2E7fRF5lN10tr',
{
- type: GRID_WIDGET_TYPE.IFRAME,
- properties: {
- src: 'https://open.spotify.com/embed/track/7xGfFoTpQ2E7fRF5lN10tr?utm_source=oembed',
- allow: SPOTIFY_IFRAME_ALLOW,
- type: 'track',
- id: '7xGfFoTpQ2E7fRF5lN10tr',
- },
+ src: 'https://open.spotify.com/embed/track/7xGfFoTpQ2E7fRF5lN10tr?utm_source=oembed',
+ allow: SPOTIFY_IFRAME_ALLOW,
+ id: '7xGfFoTpQ2E7fRF5lN10tr',
},
],
[
@@ -162,13 +131,9 @@ describe('parsePlatformInput', () => {
GRID_WIDGET_TYPE.SPOTIFY,
'',
{
- type: GRID_WIDGET_TYPE.IFRAME,
- properties: {
- src: 'https://open.spotify.com/embed/track/2BHj31ufdEqVK5CkYDp9mA?utm_source=generator',
- allow: SPOTIFY_IFRAME_ALLOW,
- type: 'track',
- id: '2BHj31ufdEqVK5CkYDp9mA',
- },
+ src: 'https://open.spotify.com/embed/track/2BHj31ufdEqVK5CkYDp9mA?utm_source=generator',
+ allow: SPOTIFY_IFRAME_ALLOW,
+ id: '2BHj31ufdEqVK5CkYDp9mA',
},
],
[
@@ -176,14 +141,10 @@ describe('parsePlatformInput', () => {
GRID_WIDGET_TYPE.SPOTIFY,
'',
{
- type: GRID_WIDGET_TYPE.IFRAME,
- properties: {
- src: 'https://open.spotify.com/embed/track/48K735Rd3UQExzjXH004k1?utm_source=generator&theme=0',
- allow: SPOTIFY_IFRAME_ALLOW,
- type: 'track',
- id: '48K735Rd3UQExzjXH004k1',
- theme: '0',
- },
+ src: 'https://open.spotify.com/embed/track/48K735Rd3UQExzjXH004k1?utm_source=generator&theme=0',
+ allow: SPOTIFY_IFRAME_ALLOW,
+ id: '48K735Rd3UQExzjXH004k1',
+ theme: '0',
},
],
[
@@ -191,13 +152,9 @@ describe('parsePlatformInput', () => {
GRID_WIDGET_TYPE.SPOTIFY,
'https://open.spotify.com/playlist/7KFoK4LJ23EncELJwYmTDG',
{
- type: GRID_WIDGET_TYPE.IFRAME,
- properties: {
- src: 'https://open.spotify.com/embed/playlist/7KFoK4LJ23EncELJwYmTDG?utm_source=oembed',
- allow: SPOTIFY_IFRAME_ALLOW,
- type: 'playlist',
- id: '7KFoK4LJ23EncELJwYmTDG',
- },
+ src: 'https://open.spotify.com/embed/playlist/7KFoK4LJ23EncELJwYmTDG?utm_source=oembed',
+ allow: SPOTIFY_IFRAME_ALLOW,
+ id: '7KFoK4LJ23EncELJwYmTDG',
},
],
[
@@ -205,13 +162,9 @@ describe('parsePlatformInput', () => {
GRID_WIDGET_TYPE.SPOTIFY,
'',
{
- type: GRID_WIDGET_TYPE.IFRAME,
- properties: {
- src: 'https://open.spotify.com/embed/playlist/7KFoK4LJ23EncELJwYmTDG?utm_source=generator',
- allow: SPOTIFY_IFRAME_ALLOW,
- type: 'playlist',
- id: '7KFoK4LJ23EncELJwYmTDG',
- },
+ src: 'https://open.spotify.com/embed/playlist/7KFoK4LJ23EncELJwYmTDG?utm_source=generator',
+ allow: SPOTIFY_IFRAME_ALLOW,
+ id: '7KFoK4LJ23EncELJwYmTDG',
},
],
[
@@ -219,13 +172,9 @@ describe('parsePlatformInput', () => {
GRID_WIDGET_TYPE.SPOTIFY,
'https://open.spotify.com/artist/4KY9rCrokaoFzvMfX98u1q',
{
- type: GRID_WIDGET_TYPE.IFRAME,
- properties: {
- src: 'https://open.spotify.com/embed/artist/4KY9rCrokaoFzvMfX98u1q?utm_source=oembed',
- allow: SPOTIFY_IFRAME_ALLOW,
- type: 'artist',
- id: '4KY9rCrokaoFzvMfX98u1q',
- },
+ src: 'https://open.spotify.com/embed/artist/4KY9rCrokaoFzvMfX98u1q?utm_source=oembed',
+ allow: SPOTIFY_IFRAME_ALLOW,
+ id: '4KY9rCrokaoFzvMfX98u1q',
},
],
[
@@ -233,13 +182,9 @@ describe('parsePlatformInput', () => {
GRID_WIDGET_TYPE.SPOTIFY,
'',
{
- type: GRID_WIDGET_TYPE.IFRAME,
- properties: {
- src: 'https://open.spotify.com/embed/artist/4KY9rCrokaoFzvMfX98u1q?utm_source=generator',
- allow: SPOTIFY_IFRAME_ALLOW,
- type: 'artist',
- id: '4KY9rCrokaoFzvMfX98u1q',
- },
+ src: 'https://open.spotify.com/embed/artist/4KY9rCrokaoFzvMfX98u1q?utm_source=generator',
+ allow: SPOTIFY_IFRAME_ALLOW,
+ id: '4KY9rCrokaoFzvMfX98u1q',
},
],
])(
@@ -258,12 +203,9 @@ describe('parsePlatformInput', () => {
GRID_WIDGET_TYPE.SOUNDCLOUD,
'https://soundcloud.com/occams-laser/with-you',
{
- type: GRID_WIDGET_TYPE.IFRAME,
- properties: {
- src: 'https://w.soundcloud.com/player/?visual=true&url=https%3A%2F%2Fapi.soundcloud.com%2Ftracks%2F1856391039&show_artwork=true',
- allow: SOUNDCLOUD_IFRAME_ALLOW,
- type: 'tracks',
- },
+ src: 'https://w.soundcloud.com/player/?visual=true&url=https%3A%2F%2Fapi.soundcloud.com%2Ftracks%2F1856391039&show_artwork=true',
+ allow: SOUNDCLOUD_IFRAME_ALLOW,
+ type: 'tracks',
},
],
[
@@ -271,12 +213,9 @@ describe('parsePlatformInput', () => {
GRID_WIDGET_TYPE.SOUNDCLOUD,
'https://w.soundcloud.com/player/?visual=true&url=https%3A%2F%2Fapi.soundcloud.com%2Fplaylists%2F505007376&show_artwork=true',
{
- type: GRID_WIDGET_TYPE.IFRAME,
- properties: {
- src: 'https://w.soundcloud.com/player/?visual=true&url=https%3A%2F%2Fapi.soundcloud.com%2Fplaylists%2F505007376&show_artwork=true',
- allow: SPOTIFY_IFRAME_ALLOW,
- type: 'playlists',
- },
+ src: 'https://w.soundcloud.com/player/?visual=true&url=https%3A%2F%2Fapi.soundcloud.com%2Fplaylists%2F505007376&show_artwork=true',
+ allow: SPOTIFY_IFRAME_ALLOW,
+ type: 'playlists',
},
],
[
@@ -284,12 +223,9 @@ describe('parsePlatformInput', () => {
GRID_WIDGET_TYPE.SOUNDCLOUD,
'https://soundcloud.com/fabian-vogelsteller',
{
- type: GRID_WIDGET_TYPE.IFRAME,
- properties: {
- src: 'https://w.soundcloud.com/player/?visual=true&url=https%3A%2F%2Fapi.soundcloud.com%2Fusers%2F227118126&show_artwork=true',
- allow: SOUNDCLOUD_IFRAME_ALLOW,
- type: 'users',
- },
+ src: 'https://w.soundcloud.com/player/?visual=true&url=https%3A%2F%2Fapi.soundcloud.com%2Fusers%2F227118126&show_artwork=true',
+ allow: SOUNDCLOUD_IFRAME_ALLOW,
+ type: 'users',
},
],
[
@@ -297,12 +233,9 @@ describe('parsePlatformInput', () => {
GRID_WIDGET_TYPE.SOUNDCLOUD,
'',
{
- type: GRID_WIDGET_TYPE.IFRAME,
- properties: {
- src: 'https://w.soundcloud.com/player/?url=https://api.soundcloud.com/tracks/1856391039&color=%23ff5500&auto_play=false&hide_related=false&show_comments=true&show_user=true&show_reposts=false&show_teaser=true&visual=true',
- allow: SOUNDCLOUD_IFRAME_ALLOW,
- type: 'tracks',
- },
+ src: 'https://w.soundcloud.com/player/?url=https://api.soundcloud.com/tracks/1856391039&color=%23ff5500&auto_play=false&hide_related=false&show_comments=true&show_user=true&show_reposts=false&show_teaser=true&visual=true',
+ allow: SOUNDCLOUD_IFRAME_ALLOW,
+ type: 'tracks',
},
],
[
@@ -310,12 +243,9 @@ describe('parsePlatformInput', () => {
GRID_WIDGET_TYPE.SOUNDCLOUD,
'',
{
- type: GRID_WIDGET_TYPE.IFRAME,
- properties: {
- src: 'https://w.soundcloud.com/player/?visual=true&url=https%3A%2F%2Fapi.soundcloud.com%2Ftracks%2F1856391039&show_artwork=true',
- allow: SOUNDCLOUD_IFRAME_ALLOW,
- type: 'tracks',
- },
+ src: 'https://w.soundcloud.com/player/?visual=true&url=https%3A%2F%2Fapi.soundcloud.com%2Ftracks%2F1856391039&show_artwork=true',
+ allow: SOUNDCLOUD_IFRAME_ALLOW,
+ type: 'tracks',
},
],
[
@@ -323,12 +253,9 @@ describe('parsePlatformInput', () => {
GRID_WIDGET_TYPE.SOUNDCLOUD,
'',
{
- type: GRID_WIDGET_TYPE.IFRAME,
- properties: {
- src: 'https://w.soundcloud.com/player/?url=https://api.soundcloud.com/playlists/1850298147&color=%23ff5500&auto_play=false&hide_related=false&show_comments=true&show_user=true&show_reposts=false&show_teaser=true&visual=true',
- allow: SOUNDCLOUD_IFRAME_ALLOW,
- type: 'playlists',
- },
+ src: 'https://w.soundcloud.com/player/?url=https://api.soundcloud.com/playlists/1850298147&color=%23ff5500&auto_play=false&hide_related=false&show_comments=true&show_user=true&show_reposts=false&show_teaser=true&visual=true',
+ allow: SOUNDCLOUD_IFRAME_ALLOW,
+ type: 'playlists',
},
],
])(
@@ -347,11 +274,8 @@ describe('parsePlatformInput', () => {
GRID_WIDGET_TYPE.INSTAGRAM,
'https://www.instagram.com/p/C98OXs6yhAq/?utm_source=ig_embed&utm_campaign=loading',
{
- type: GRID_WIDGET_TYPE.INSTAGRAM,
- properties: {
- src: 'https://www.instagram.com/p/C98OXs6yhAq/?utm_source=ig_embed&utm_campaign=loading',
- type: 'p',
- },
+ src: 'https://www.instagram.com/p/C98OXs6yhAq/?utm_source=ig_embed&utm_campaign=loading',
+ type: 'p',
},
],
[
@@ -359,11 +283,8 @@ describe('parsePlatformInput', () => {
GRID_WIDGET_TYPE.INSTAGRAM,
'
',
{
- type: GRID_WIDGET_TYPE.INSTAGRAM,
- properties: {
- src: 'https://www.instagram.com/p/C98OXs6yhAq/?utm_source=ig_embed&utm_campaign=loading',
- type: 'p',
- },
+ src: 'https://www.instagram.com/p/C98OXs6yhAq/?utm_source=ig_embed&utm_campaign=loading',
+ type: 'p',
},
],
[
@@ -371,11 +292,8 @@ describe('parsePlatformInput', () => {
GRID_WIDGET_TYPE.INSTAGRAM,
'https://www.instagram.com/reel/DAlOgHkuyxd/?utm_source=ig_embed&utm_campaign=loading',
{
- type: GRID_WIDGET_TYPE.INSTAGRAM,
- properties: {
- src: 'https://www.instagram.com/reel/DAlOgHkuyxd/?utm_source=ig_embed&utm_campaign=loading',
- type: 'reel',
- },
+ src: 'https://www.instagram.com/reel/DAlOgHkuyxd/?utm_source=ig_embed&utm_campaign=loading',
+ type: 'reel',
},
],
[
@@ -383,11 +301,8 @@ describe('parsePlatformInput', () => {
GRID_WIDGET_TYPE.INSTAGRAM,
'',
{
- type: GRID_WIDGET_TYPE.INSTAGRAM,
- properties: {
- src: 'https://www.instagram.com/reel/DAlOgHkuyxd/?utm_source=ig_embed&utm_campaign=loading',
- type: 'reel',
- },
+ src: 'https://www.instagram.com/reel/DAlOgHkuyxd/?utm_source=ig_embed&utm_campaign=loading',
+ type: 'reel',
},
],
])(
diff --git a/domains/grid/utils/gridParser.ts b/domains/grid/utils/gridParser.ts
index c443150a..3db63ece 100644
--- a/domains/grid/utils/gridParser.ts
+++ b/domains/grid/utils/gridParser.ts
@@ -84,7 +84,7 @@ const PLATFORM_PARSING_PARAMETERS: Record<
export const parsePlatformInput = async (
platform: GridWidgetType,
input: string
-): Promise => {
+): Promise => {
const platformParsingParameters = PLATFORM_PARSING_PARAMETERS[platform]
if (!platformParsingParameters) throw new Error('Invalid platform')
@@ -116,8 +116,8 @@ export const parsePlatformInput = async (
const parsePlatformEmbed = (
input: string,
platformParsingParameters: PlatformParsingParameters
-): LayoutItemExtended | never => {
- const { type, embedRegex, constantProperties } = platformParsingParameters
+): GridWidgetProperties | never => {
+ const { embedRegex, constantProperties } = platformParsingParameters
const match = input.match(embedRegex)
if (!match) throw new Error('Invalid input')
@@ -137,12 +137,9 @@ const parsePlatformEmbed = (
}
return {
- type,
- properties: {
- src: match[0],
- ...constantProperties,
- ...extractedProperties,
- },
+ src: match[0],
+ ...constantProperties,
+ ...extractedProperties,
}
}
From 776467d5986e6d1076bb3810bc535ed807f3741d Mon Sep 17 00:00:00 2001
From: Eduardo Sacco <3680995+nastita@users.noreply.github.com>
Date: Mon, 21 Oct 2024 13:33:50 -0300
Subject: [PATCH 03/36] update yt parsing params
---
domains/grid/utils/gridParser.ts | 59 ++++++++++++--------------------
1 file changed, 22 insertions(+), 37 deletions(-)
diff --git a/domains/grid/utils/gridParser.ts b/domains/grid/utils/gridParser.ts
index 3db63ece..6ec270e7 100644
--- a/domains/grid/utils/gridParser.ts
+++ b/domains/grid/utils/gridParser.ts
@@ -75,8 +75,18 @@ const PLATFORM_PARSING_PARAMETERS: Record<
},
},
[GRID_WIDGET_TYPE.YOUTUBE]: {
- type: GRID_WIDGET_TYPE.IFRAME,
- embedRegex: /(?:https?:\/\/)?(?:www\.)?youtube\.com\/watch\?v=([^&]+)/,
+ type: GRID_WIDGET_TYPE.YOUTUBE,
+ embedRegex: /(?:https?:\/\/)?(?:www\.)?youtube\.com\/embed\/([^?]+)/,
+ secondaryRegexesWithCallbacks: [
+ {
+ regex: /(?:https?:\/\/)?(?:www\.)?youtube\.com\/watch\?v=([^&]+)/,
+ callback: async url => sanitizeYoutubeEmbedUrl(url),
+ },
+ ],
+ constantProperties: {
+ allow:
+ 'accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share',
+ },
},
[GRID_WIDGET_TYPE.ADD_CONTENT]: undefined,
}
@@ -143,41 +153,6 @@ const parsePlatformEmbed = (
}
}
-// const parseYoutubeWidgetInput = (input: string): LayoutItemExtended | never => {
-// const YOUTUBE_URL_REGEX =
-// /(?:https?:\/\/)?(?:www\.)?youtube\.com\/watch\?v=([^&]+)/
-// const YOUTUBE_EMBED_REGEX =
-// /(?:https?:\/\/)?(?:www\.)?youtube\.com\/embed\/([^?]+)/
-// const YOUTUBE_IFRAME_ALLOW =
-// 'accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share'
-
-// const youtubeUrlMatch = input.match(YOUTUBE_URL_REGEX)
-
-// if (youtubeUrlMatch) {
-// return {
-// type: GRID_WIDGET_TYPE.IFRAME,
-// properties: {
-// src: `https://www.youtube.com/embed/${youtubeUrlMatch[1]}`,
-// allow: YOUTUBE_IFRAME_ALLOW,
-// },
-// }
-// }
-
-// const youtubeEmbedMatch = input.match(YOUTUBE_EMBED_REGEX)
-
-// if (youtubeEmbedMatch) {
-// return {
-// type: GRID_WIDGET_TYPE.IFRAME,
-// properties: {
-// src: `https://www.youtube.com/embed/${youtubeEmbedMatch[1]}`,
-// allow: YOUTUBE_IFRAME_ALLOW,
-// },
-// }
-// }
-
-// throw new Error('Invalid YouTube input')
-// }
-
async function getSoundCloudOEmbed(url: string): Promise {
const encodedUrl = encodeURI(url)
const response = await fetch(
@@ -214,6 +189,16 @@ function sanitizeXEmbedUrl(url: string): string {
return url
}
+function sanitizeYoutubeEmbedUrl(url: string): string {
+ url = url.replace('watch?v=', 'embed/')
+
+ if (!url.startsWith('https://')) {
+ url = `https://${url}`
+ }
+
+ return url
+}
+
// const parseInstagramWidgetInput = (
// input: string
// ): LayoutItemExtended | never => {
From c4793da8143eff3b7bb26c9ed19c46050d4a9674 Mon Sep 17 00:00:00 2001
From: Eduardo Sacco <3680995+nastita@users.noreply.github.com>
Date: Mon, 21 Oct 2024 14:19:17 -0300
Subject: [PATCH 04/36] Update IG parsing parameters
---
.../grid/utils/__tests__/gridParser.spec.ts | 8 +++++++
domains/grid/utils/gridParser.ts | 23 +------------------
2 files changed, 9 insertions(+), 22 deletions(-)
diff --git a/domains/grid/utils/__tests__/gridParser.spec.ts b/domains/grid/utils/__tests__/gridParser.spec.ts
index 656a86b8..aadb0844 100644
--- a/domains/grid/utils/__tests__/gridParser.spec.ts
+++ b/domains/grid/utils/__tests__/gridParser.spec.ts
@@ -276,6 +276,8 @@ describe('parsePlatformInput', () => {
{
src: 'https://www.instagram.com/p/C98OXs6yhAq/?utm_source=ig_embed&utm_campaign=loading',
type: 'p',
+ id: 'C98OXs6yhAq',
+ params: '?utm_source=ig_embed&utm_campaign=loading',
},
],
[
@@ -285,6 +287,8 @@ describe('parsePlatformInput', () => {
{
src: 'https://www.instagram.com/p/C98OXs6yhAq/?utm_source=ig_embed&utm_campaign=loading',
type: 'p',
+ id: 'C98OXs6yhAq',
+ params: '?utm_source=ig_embed&utm_campaign=loading',
},
],
[
@@ -294,6 +298,8 @@ describe('parsePlatformInput', () => {
{
src: 'https://www.instagram.com/reel/DAlOgHkuyxd/?utm_source=ig_embed&utm_campaign=loading',
type: 'reel',
+ id: 'DAlOgHkuyxd',
+ params: '?utm_source=ig_embed&utm_campaign=loading',
},
],
[
@@ -303,6 +309,8 @@ describe('parsePlatformInput', () => {
{
src: 'https://www.instagram.com/reel/DAlOgHkuyxd/?utm_source=ig_embed&utm_campaign=loading',
type: 'reel',
+ id: 'DAlOgHkuyxd',
+ params: '?utm_source=ig_embed&utm_campaign=loading',
},
],
])(
diff --git a/domains/grid/utils/gridParser.ts b/domains/grid/utils/gridParser.ts
index 6ec270e7..d5f68751 100644
--- a/domains/grid/utils/gridParser.ts
+++ b/domains/grid/utils/gridParser.ts
@@ -39,7 +39,7 @@ const PLATFORM_PARSING_PARAMETERS: Record<
[GRID_WIDGET_TYPE.INSTAGRAM]: {
type: GRID_WIDGET_TYPE.INSTAGRAM,
embedRegex:
- /https:\/\/www\.instagram\.com\/(p|reel|profile|tv)\/([\w-]+)\/(\?[^"]*)?/,
+ /https:\/\/www\.instagram\.com\/(?p|reel|profile|tv)\/(?[\w-]+)\/(?\?[^"]*)?/,
},
[GRID_WIDGET_TYPE.WARPCAST]: undefined,
[GRID_WIDGET_TYPE.SPOTIFY]: {
@@ -198,24 +198,3 @@ function sanitizeYoutubeEmbedUrl(url: string): string {
return url
}
-
-// const parseInstagramWidgetInput = (
-// input: string
-// ): LayoutItemExtended | never => {
-// const INSTAGRAM_URL_REGEX =
-// /https:\/\/www\.instagram\.com\/(p|reel|profile|tv)\/([\w-]+)\/(\?[^"]*)?/
-
-// const [, type, id, params] = input.match(INSTAGRAM_URL_REGEX) || []
-
-// if (id && type) {
-// return {
-// type: GRID_WIDGET_TYPE.INSTAGRAM,
-// properties: {
-// src: `https://www.instagram.com/${type}/${id}/${params}`,
-// type: type,
-// },
-// }
-// }
-
-// throw new Error('Invalid Instagram input')
-// }
From 8d89fc5c898bcf2034199f08eeaba8f96a4bf60a Mon Sep 17 00:00:00 2001
From: Eduardo Sacco <3680995+nastita@users.noreply.github.com>
Date: Mon, 21 Oct 2024 16:31:32 -0300
Subject: [PATCH 05/36] Fix parsePlatformInput calls after updates
---
domains/grid/components/AddWidgetGenericPlatform.vue | 7 ++-----
1 file changed, 2 insertions(+), 5 deletions(-)
diff --git a/domains/grid/components/AddWidgetGenericPlatform.vue b/domains/grid/components/AddWidgetGenericPlatform.vue
index 674e0515..23970a83 100644
--- a/domains/grid/components/AddWidgetGenericPlatform.vue
+++ b/domains/grid/components/AddWidgetGenericPlatform.vue
@@ -25,10 +25,7 @@ const handleSave = async () => {
}
try {
- const { properties } = await parsePlatformInput(
- props.type,
- inputValue.value
- )
+ const properties = await parsePlatformInput(props.type, inputValue.value)
if (isEdit.value) {
updateGridLayoutItem(props.id, {
@@ -71,7 +68,7 @@ const handleInput = async (customEvent: CustomEvent) => {
// validation
try {
- const { properties } = await parsePlatformInput(props.type, input.value)
+ const properties = await parsePlatformInput(props.type, input.value)
inputValue.value = properties.src
} catch (error) {
console.warn(error)
From 34933f6cc7838b7fbada27f27e0b1b4df4eba36a Mon Sep 17 00:00:00 2001
From: Eduardo Sacco <3680995+nastita@users.noreply.github.com>
Date: Mon, 21 Oct 2024 16:34:22 -0300
Subject: [PATCH 06/36] Update spotify test cases
---
.../grid/utils/__tests__/gridParser.spec.ts | 21 ++++++++++++-------
1 file changed, 14 insertions(+), 7 deletions(-)
diff --git a/domains/grid/utils/__tests__/gridParser.spec.ts b/domains/grid/utils/__tests__/gridParser.spec.ts
index aadb0844..8452534b 100644
--- a/domains/grid/utils/__tests__/gridParser.spec.ts
+++ b/domains/grid/utils/__tests__/gridParser.spec.ts
@@ -122,8 +122,9 @@ describe('parsePlatformInput', () => {
'https://open.spotify.com/track/7xGfFoTpQ2E7fRF5lN10tr',
{
src: 'https://open.spotify.com/embed/track/7xGfFoTpQ2E7fRF5lN10tr?utm_source=oembed',
- allow: SPOTIFY_IFRAME_ALLOW,
+ type: 'track',
id: '7xGfFoTpQ2E7fRF5lN10tr',
+ allow: SPOTIFY_IFRAME_ALLOW,
},
],
[
@@ -132,8 +133,9 @@ describe('parsePlatformInput', () => {
'',
{
src: 'https://open.spotify.com/embed/track/2BHj31ufdEqVK5CkYDp9mA?utm_source=generator',
- allow: SPOTIFY_IFRAME_ALLOW,
+ type: 'track',
id: '2BHj31ufdEqVK5CkYDp9mA',
+ allow: SPOTIFY_IFRAME_ALLOW,
},
],
[
@@ -142,8 +144,9 @@ describe('parsePlatformInput', () => {
'',
{
src: 'https://open.spotify.com/embed/track/48K735Rd3UQExzjXH004k1?utm_source=generator&theme=0',
- allow: SPOTIFY_IFRAME_ALLOW,
+ type: 'track',
id: '48K735Rd3UQExzjXH004k1',
+ allow: SPOTIFY_IFRAME_ALLOW,
theme: '0',
},
],
@@ -153,8 +156,9 @@ describe('parsePlatformInput', () => {
'https://open.spotify.com/playlist/7KFoK4LJ23EncELJwYmTDG',
{
src: 'https://open.spotify.com/embed/playlist/7KFoK4LJ23EncELJwYmTDG?utm_source=oembed',
- allow: SPOTIFY_IFRAME_ALLOW,
+ type: 'playlist',
id: '7KFoK4LJ23EncELJwYmTDG',
+ allow: SPOTIFY_IFRAME_ALLOW,
},
],
[
@@ -163,8 +167,9 @@ describe('parsePlatformInput', () => {
'',
{
src: 'https://open.spotify.com/embed/playlist/7KFoK4LJ23EncELJwYmTDG?utm_source=generator',
- allow: SPOTIFY_IFRAME_ALLOW,
+ type: 'playlist',
id: '7KFoK4LJ23EncELJwYmTDG',
+ allow: SPOTIFY_IFRAME_ALLOW,
},
],
[
@@ -173,8 +178,9 @@ describe('parsePlatformInput', () => {
'https://open.spotify.com/artist/4KY9rCrokaoFzvMfX98u1q',
{
src: 'https://open.spotify.com/embed/artist/4KY9rCrokaoFzvMfX98u1q?utm_source=oembed',
- allow: SPOTIFY_IFRAME_ALLOW,
+ type: 'artist',
id: '4KY9rCrokaoFzvMfX98u1q',
+ allow: SPOTIFY_IFRAME_ALLOW,
},
],
[
@@ -183,8 +189,9 @@ describe('parsePlatformInput', () => {
'',
{
src: 'https://open.spotify.com/embed/artist/4KY9rCrokaoFzvMfX98u1q?utm_source=generator',
- allow: SPOTIFY_IFRAME_ALLOW,
+ type: 'artist',
id: '4KY9rCrokaoFzvMfX98u1q',
+ allow: SPOTIFY_IFRAME_ALLOW,
},
],
])(
From 8267b2830515068a5d7c3582bf94d45992c94798 Mon Sep 17 00:00:00 2001
From: Eduardo Sacco <3680995+nastita@users.noreply.github.com>
Date: Mon, 21 Oct 2024 17:04:12 -0300
Subject: [PATCH 07/36] Fix lint issues
---
domains/grid/utils/gridParser.ts | 19 ++++++++-----------
1 file changed, 8 insertions(+), 11 deletions(-)
diff --git a/domains/grid/utils/gridParser.ts b/domains/grid/utils/gridParser.ts
index d5f68751..8078fffc 100644
--- a/domains/grid/utils/gridParser.ts
+++ b/domains/grid/utils/gridParser.ts
@@ -171,30 +171,27 @@ async function getSpotifyOEmbed(url: string): Promise {
}
async function getXOEmbedFromHandle(handle: string) {
- handle = handle.replace('@', '')
const response = await fetch(
- `https://publish.twitter.com/oembed?url=https://twitter.com/${handle}`
+ `https://publish.twitter.com/oembed?url=https://twitter.com/${handle.replace('@', '')}`
)
return response.ok ? ((await response.json())?.html as string) : undefined
}
function sanitizeXEmbedUrl(url: string): string {
- url = url.replace('x.com', 'twitter.com')
-
- if (!url.startsWith('https://')) {
- url = `https://${url}`
+ let newUrl = url.replace('x.com', 'twitter.com')
+ if (!newUrl.startsWith('https://')) {
+ newUrl = `https://${newUrl}`
}
- return url
+ return newUrl
}
function sanitizeYoutubeEmbedUrl(url: string): string {
- url = url.replace('watch?v=', 'embed/')
-
+ let newUrl = url.replace('watch?v=', 'embed/')
if (!url.startsWith('https://')) {
- url = `https://${url}`
+ newUrl = `https://${newUrl}`
}
- return url
+ return newUrl
}
From 0d51b4a45c396a63ec63f708ad6416f19c73cec4 Mon Sep 17 00:00:00 2001
From: Dominik Zborowski
Date: Thu, 31 Oct 2024 00:18:00 +0100
Subject: [PATCH 08/36] Remove autoplay from iframes
---
domains/grid/shared/config.ts | 8 +++-----
domains/grid/utils/__tests__/gridParser.spec.ts | 6 +++---
2 files changed, 6 insertions(+), 8 deletions(-)
diff --git a/domains/grid/shared/config.ts b/domains/grid/shared/config.ts
index 79062289..388ef6d9 100644
--- a/domains/grid/shared/config.ts
+++ b/domains/grid/shared/config.ts
@@ -102,8 +102,7 @@ export const PLATFORM_PARSING_PARAMETERS: Partial<
},
],
constantProperties: {
- allow:
- 'autoplay; clipboard-write; encrypted-media; fullscreen; picture-in-picture',
+ allow: 'clipboard-write; encrypted-media; fullscreen; picture-in-picture',
},
},
[GRID_WIDGET_TYPE.enum.SOUNDCLOUD]: {
@@ -118,8 +117,7 @@ export const PLATFORM_PARSING_PARAMETERS: Partial<
},
],
constantProperties: {
- allow:
- 'autoplay; clipboard-write; encrypted-media; fullscreen; picture-in-picture',
+ allow: 'clipboard-write; encrypted-media; fullscreen; picture-in-picture',
},
},
[GRID_WIDGET_TYPE.enum.YOUTUBE]: {
@@ -133,7 +131,7 @@ export const PLATFORM_PARSING_PARAMETERS: Partial<
],
constantProperties: {
allow:
- 'accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share',
+ 'accelerometer; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share',
},
},
}
diff --git a/domains/grid/utils/__tests__/gridParser.spec.ts b/domains/grid/utils/__tests__/gridParser.spec.ts
index 588a7932..ba097314 100644
--- a/domains/grid/utils/__tests__/gridParser.spec.ts
+++ b/domains/grid/utils/__tests__/gridParser.spec.ts
@@ -1,11 +1,11 @@
import { describe, expect, it } from 'vitest'
const YOUTUBE_IFRAME_ALLOW =
- 'accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share'
+ 'accelerometer; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share'
const SPOTIFY_IFRAME_ALLOW =
- 'autoplay; clipboard-write; encrypted-media; fullscreen; picture-in-picture'
+ 'clipboard-write; encrypted-media; fullscreen; picture-in-picture'
const SOUNDCLOUD_IFRAME_ALLOW =
- 'autoplay; clipboard-write; encrypted-media; fullscreen; picture-in-picture'
+ 'clipboard-write; encrypted-media; fullscreen; picture-in-picture'
describe('parsePlatformInput', () => {
describe('X', () => {
From 5f7257323a8535b7e6e2fbd84e3b2877805fc939 Mon Sep 17 00:00:00 2001
From: Dominik Zborowski
Date: Thu, 31 Oct 2024 01:39:27 +0100
Subject: [PATCH 09/36] Add mode support in fetcher
---
utils/fetcher.ts | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/utils/fetcher.ts b/utils/fetcher.ts
index a2f83c42..11bc26b2 100644
--- a/utils/fetcher.ts
+++ b/utils/fetcher.ts
@@ -2,7 +2,8 @@
* Generic url fetcher.
*
* @param string url - an url to call
- * @param string address - a method used in the request, either 'GET' or 'POST'
+ * @param string method - a method used in the request, either 'GET' or 'POST'
+ * @param RequestMode mode - a mode of the request
* @param Request data - a request data to be sent
* @param Record headers - additional headers to be sent
* @returns a result from calling the url
@@ -11,6 +12,7 @@
export const fetcher = async (config: {
url: string
method: 'GET' | 'POST'
+ mode?: RequestMode
data?: Request
headers?: Record
}): Promise => {
@@ -21,6 +23,7 @@ export const fetcher = async (config: {
...(config.data ? { 'Content-Type': 'application/json' } : {}),
},
redirect: 'follow',
+ mode: config.mode || 'cors',
}
if (config.data) {
fetchConfig.body = JSON.stringify(config.data)
From a6d157084db21eb7c0958d648754d19a2a680f84 Mon Sep 17 00:00:00 2001
From: Dominik Zborowski
Date: Thu, 31 Oct 2024 02:09:55 +0100
Subject: [PATCH 10/36] Move parser to own folder
---
.../grid/{utils => platform-parser}/__tests__/gridParser.spec.ts | 0
domains/grid/{utils => platform-parser}/gridParser.ts | 0
2 files changed, 0 insertions(+), 0 deletions(-)
rename domains/grid/{utils => platform-parser}/__tests__/gridParser.spec.ts (100%)
rename domains/grid/{utils => platform-parser}/gridParser.ts (100%)
diff --git a/domains/grid/utils/__tests__/gridParser.spec.ts b/domains/grid/platform-parser/__tests__/gridParser.spec.ts
similarity index 100%
rename from domains/grid/utils/__tests__/gridParser.spec.ts
rename to domains/grid/platform-parser/__tests__/gridParser.spec.ts
diff --git a/domains/grid/utils/gridParser.ts b/domains/grid/platform-parser/gridParser.ts
similarity index 100%
rename from domains/grid/utils/gridParser.ts
rename to domains/grid/platform-parser/gridParser.ts
From 6834c38acb1e5319471c59000c49056ed5ab6b5b Mon Sep 17 00:00:00 2001
From: Eduardo Sacco <3680995+nastita@users.noreply.github.com>
Date: Fri, 1 Nov 2024 19:39:41 -0300
Subject: [PATCH 11/36] WIP: Updating parser
---
.../__tests__/gridParser.spec.ts | 331 ------------------
.../__tests__/instagramParser.spec.ts | 53 +++
.../__tests__/soundcloudParser.spec.ts | 71 ++++
.../__tests__/spotifyParser.spec.ts | 90 +++++
.../platform-parser/__tests__/xParser.spec.ts | 80 +++++
.../__tests__/youtubeParser.spec.ts | 29 ++
domains/grid/platform-parser/gridParser.ts | 142 ++------
.../grid/platform-parser/instagramParser.ts | 11 +
.../grid/platform-parser/soundcloudParser.ts | 27 ++
domains/grid/platform-parser/spotifyParser.ts | 28 ++
domains/grid/platform-parser/xParser.ts | 38 ++
domains/grid/platform-parser/youtubeParser.ts | 27 ++
domains/grid/shared/config.ts | 78 +----
domains/schema/xWidgetSchema.ts | 7 +-
14 files changed, 507 insertions(+), 505 deletions(-)
delete mode 100644 domains/grid/platform-parser/__tests__/gridParser.spec.ts
create mode 100644 domains/grid/platform-parser/__tests__/instagramParser.spec.ts
create mode 100644 domains/grid/platform-parser/__tests__/soundcloudParser.spec.ts
create mode 100644 domains/grid/platform-parser/__tests__/spotifyParser.spec.ts
create mode 100644 domains/grid/platform-parser/__tests__/xParser.spec.ts
create mode 100644 domains/grid/platform-parser/__tests__/youtubeParser.spec.ts
create mode 100644 domains/grid/platform-parser/instagramParser.ts
create mode 100644 domains/grid/platform-parser/soundcloudParser.ts
create mode 100644 domains/grid/platform-parser/spotifyParser.ts
create mode 100644 domains/grid/platform-parser/xParser.ts
create mode 100644 domains/grid/platform-parser/youtubeParser.ts
diff --git a/domains/grid/platform-parser/__tests__/gridParser.spec.ts b/domains/grid/platform-parser/__tests__/gridParser.spec.ts
deleted file mode 100644
index ba097314..00000000
--- a/domains/grid/platform-parser/__tests__/gridParser.spec.ts
+++ /dev/null
@@ -1,331 +0,0 @@
-import { describe, expect, it } from 'vitest'
-
-const YOUTUBE_IFRAME_ALLOW =
- 'accelerometer; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share'
-const SPOTIFY_IFRAME_ALLOW =
- 'clipboard-write; encrypted-media; fullscreen; picture-in-picture'
-const SOUNDCLOUD_IFRAME_ALLOW =
- 'clipboard-write; encrypted-media; fullscreen; picture-in-picture'
-
-describe('parsePlatformInput', () => {
- describe('X', () => {
- it.each([
- [
- 'Handle',
- GRID_WIDGET_TYPE.enum.X,
- '@feindura',
- {
- src: 'https://twitter.com/feindura?ref_src=twsrc%5Etfw',
- handle: 'feindura',
- },
- ],
- [
- 'Post URL',
- GRID_WIDGET_TYPE.enum.X,
- 'https://x.com/feindura/status/1804519711377436675',
- {
- src: 'https://twitter.com/feindura/status/1804519711377436675',
- handle: 'feindura',
- id: '1804519711377436675',
- },
- ],
- [
- 'Post URL twitter.com',
- GRID_WIDGET_TYPE.enum.X,
- 'https://twitter.com/feindura/status/1804519711377436675',
- {
- src: 'https://twitter.com/feindura/status/1804519711377436675',
- handle: 'feindura',
- id: '1804519711377436675',
- },
- ],
- [
- 'Post Embed Code',
- GRID_WIDGET_TYPE.enum.X,
- ' ',
- {
- src: 'https://twitter.com/feindura/status/1804519711377436675?ref_src=twsrc%5Etfw',
- handle: 'feindura',
- id: '1804519711377436675',
- },
- ],
- [
- 'Timeline URL',
- GRID_WIDGET_TYPE.enum.X,
- 'https://x.com/lukso_io',
- {
- src: 'https://twitter.com/lukso_io',
- handle: 'lukso_io',
- },
- ],
- [
- 'Timeline URL twitter.com',
- GRID_WIDGET_TYPE.enum.X,
- 'https://twitter.com/lukso_io',
- {
- src: 'https://twitter.com/lukso_io',
- handle: 'lukso_io',
- },
- ],
- [
- 'Timeline Embed Code',
- GRID_WIDGET_TYPE.enum.X,
- ' ',
- {
- src: 'https://twitter.com/lukso_io?ref_src=twsrc%5Etfw',
- handle: 'lukso_io',
- },
- ],
- ])(
- 'correctly parses %s',
- async (_description, platform, input, expected) => {
- const result = await parsePlatformInput(platform, input)
- expect(result).toEqual(expected)
- }
- )
- })
-
- describe('YOUTUBE', () => {
- it.each([
- [
- 'URL',
- GRID_WIDGET_TYPE.enum.YOUTUBE,
- 'https://www.youtube.com/watch?v=Vw4JE64hsO8',
- {
- src: 'https://www.youtube.com/embed/Vw4JE64hsO8',
- allow: YOUTUBE_IFRAME_ALLOW,
- },
- ],
- [
- 'Embed Code',
- GRID_WIDGET_TYPE.enum.YOUTUBE,
- '',
- {
- src: 'https://www.youtube.com/embed/Vw4JE64hsO8',
- allow: YOUTUBE_IFRAME_ALLOW,
- },
- ],
- ])(
- 'correctly parses %s',
- async (_description, platform, input, expected) => {
- const result = await parsePlatformInput(platform, input)
- expect(result).toEqual(expected)
- }
- )
- })
-
- describe('SPOTIFY', () => {
- it.each([
- [
- 'Track URL',
- GRID_WIDGET_TYPE.enum.SPOTIFY,
- 'https://open.spotify.com/track/7xGfFoTpQ2E7fRF5lN10tr',
- {
- src: 'https://open.spotify.com/embed/track/7xGfFoTpQ2E7fRF5lN10tr?utm_source=oembed',
- type: 'track',
- id: '7xGfFoTpQ2E7fRF5lN10tr',
- allow: SPOTIFY_IFRAME_ALLOW,
- },
- ],
- [
- 'Track Embed Code',
- GRID_WIDGET_TYPE.enum.SPOTIFY,
- '',
- {
- src: 'https://open.spotify.com/embed/track/2BHj31ufdEqVK5CkYDp9mA?utm_source=generator',
- type: 'track',
- id: '2BHj31ufdEqVK5CkYDp9mA',
- allow: SPOTIFY_IFRAME_ALLOW,
- },
- ],
- [
- 'Track Embed Code with theme',
- GRID_WIDGET_TYPE.enum.SPOTIFY,
- '',
- {
- src: 'https://open.spotify.com/embed/track/48K735Rd3UQExzjXH004k1?utm_source=generator&theme=0',
- type: 'track',
- id: '48K735Rd3UQExzjXH004k1',
- allow: SPOTIFY_IFRAME_ALLOW,
- theme: '0',
- },
- ],
- [
- 'Playlist URL',
- GRID_WIDGET_TYPE.enum.SPOTIFY,
- 'https://open.spotify.com/playlist/7KFoK4LJ23EncELJwYmTDG',
- {
- src: 'https://open.spotify.com/embed/playlist/7KFoK4LJ23EncELJwYmTDG?utm_source=oembed',
- type: 'playlist',
- id: '7KFoK4LJ23EncELJwYmTDG',
- allow: SPOTIFY_IFRAME_ALLOW,
- },
- ],
- [
- 'Playlist Embed Code',
- GRID_WIDGET_TYPE.enum.SPOTIFY,
- '',
- {
- src: 'https://open.spotify.com/embed/playlist/7KFoK4LJ23EncELJwYmTDG?utm_source=generator',
- type: 'playlist',
- id: '7KFoK4LJ23EncELJwYmTDG',
- allow: SPOTIFY_IFRAME_ALLOW,
- },
- ],
- [
- 'Artist URL',
- GRID_WIDGET_TYPE.enum.SPOTIFY,
- 'https://open.spotify.com/artist/4KY9rCrokaoFzvMfX98u1q',
- {
- src: 'https://open.spotify.com/embed/artist/4KY9rCrokaoFzvMfX98u1q?utm_source=oembed',
- type: 'artist',
- id: '4KY9rCrokaoFzvMfX98u1q',
- allow: SPOTIFY_IFRAME_ALLOW,
- },
- ],
- [
- 'Artist Embed Code',
- GRID_WIDGET_TYPE.enum.SPOTIFY,
- '',
- {
- src: 'https://open.spotify.com/embed/artist/4KY9rCrokaoFzvMfX98u1q?utm_source=generator',
- type: 'artist',
- id: '4KY9rCrokaoFzvMfX98u1q',
- allow: SPOTIFY_IFRAME_ALLOW,
- },
- ],
- ])(
- 'correctly parses %s',
- async (_description, platform, input, expected) => {
- const result = await parsePlatformInput(platform, input)
- expect(result).toEqual(expected)
- }
- )
- })
-
- describe('SOUNDCLOUD', () => {
- it.each([
- [
- 'Track Share URL',
- GRID_WIDGET_TYPE.enum.SOUNDCLOUD,
- 'https://soundcloud.com/occams-laser/with-you',
- {
- src: 'https://w.soundcloud.com/player/?visual=true&url=https%3A%2F%2Fapi.soundcloud.com%2Ftracks%2F1856391039&show_artwork=true',
- allow: SOUNDCLOUD_IFRAME_ALLOW,
- type: 'tracks',
- },
- ],
- [
- 'Set Share URL',
- GRID_WIDGET_TYPE.enum.SOUNDCLOUD,
- 'https://w.soundcloud.com/player/?visual=true&url=https%3A%2F%2Fapi.soundcloud.com%2Fplaylists%2F505007376&show_artwork=true',
- {
- src: 'https://w.soundcloud.com/player/?visual=true&url=https%3A%2F%2Fapi.soundcloud.com%2Fplaylists%2F505007376&show_artwork=true',
- allow: SPOTIFY_IFRAME_ALLOW,
- type: 'playlists',
- },
- ],
- [
- 'Users Embed Code',
- GRID_WIDGET_TYPE.enum.SOUNDCLOUD,
- 'https://soundcloud.com/fabian-vogelsteller',
- {
- src: 'https://w.soundcloud.com/player/?visual=true&url=https%3A%2F%2Fapi.soundcloud.com%2Fusers%2F227118126&show_artwork=true',
- allow: SOUNDCLOUD_IFRAME_ALLOW,
- type: 'users',
- },
- ],
- [
- 'Track Embed Code',
- GRID_WIDGET_TYPE.enum.SOUNDCLOUD,
- '',
- {
- src: 'https://w.soundcloud.com/player/?url=https://api.soundcloud.com/tracks/1856391039&color=%23ff5500&auto_play=false&hide_related=false&show_comments=true&show_user=true&show_reposts=false&show_teaser=true&visual=true',
- allow: SOUNDCLOUD_IFRAME_ALLOW,
- type: 'tracks',
- },
- ],
- [
- 'Track Embed Code with URL encoded characters',
- GRID_WIDGET_TYPE.enum.SOUNDCLOUD,
- '',
- {
- src: 'https://w.soundcloud.com/player/?visual=true&url=https%3A%2F%2Fapi.soundcloud.com%2Ftracks%2F1856391039&show_artwork=true',
- allow: SOUNDCLOUD_IFRAME_ALLOW,
- type: 'tracks',
- },
- ],
- [
- 'Playlist Embed Code',
- GRID_WIDGET_TYPE.enum.SOUNDCLOUD,
- '',
- {
- src: 'https://w.soundcloud.com/player/?url=https://api.soundcloud.com/playlists/1850298147&color=%23ff5500&auto_play=false&hide_related=false&show_comments=true&show_user=true&show_reposts=false&show_teaser=true&visual=true',
- allow: SOUNDCLOUD_IFRAME_ALLOW,
- type: 'playlists',
- },
- ],
- ])(
- 'correctly parses %s',
- async (_description, platform, input, expected) => {
- const result = await parsePlatformInput(platform, input)
- expect(result).toEqual(expected)
- }
- )
- })
-
- describe('INSTAGRAM', () => {
- it.each([
- [
- 'Post URL',
- GRID_WIDGET_TYPE.enum.INSTAGRAM,
- 'https://www.instagram.com/p/C98OXs6yhAq/?utm_source=ig_embed&utm_campaign=loading',
- {
- src: 'https://www.instagram.com/p/C98OXs6yhAq/?utm_source=ig_embed&utm_campaign=loading',
- type: 'p',
- id: 'C98OXs6yhAq',
- params: '?utm_source=ig_embed&utm_campaign=loading',
- },
- ],
- [
- 'Post Embed Code',
- GRID_WIDGET_TYPE.enum.INSTAGRAM,
- '
',
- {
- src: 'https://www.instagram.com/p/C98OXs6yhAq/?utm_source=ig_embed&utm_campaign=loading',
- type: 'p',
- id: 'C98OXs6yhAq',
- params: '?utm_source=ig_embed&utm_campaign=loading',
- },
- ],
- [
- 'Reel URL',
- GRID_WIDGET_TYPE.enum.INSTAGRAM,
- 'https://www.instagram.com/reel/DAlOgHkuyxd/?utm_source=ig_embed&utm_campaign=loading',
- {
- src: 'https://www.instagram.com/reel/DAlOgHkuyxd/?utm_source=ig_embed&utm_campaign=loading',
- type: 'reel',
- id: 'DAlOgHkuyxd',
- params: '?utm_source=ig_embed&utm_campaign=loading',
- },
- ],
- [
- 'Reel Embed Code',
- GRID_WIDGET_TYPE.enum.INSTAGRAM,
- '',
- {
- src: 'https://www.instagram.com/reel/DAlOgHkuyxd/?utm_source=ig_embed&utm_campaign=loading',
- type: 'reel',
- id: 'DAlOgHkuyxd',
- params: '?utm_source=ig_embed&utm_campaign=loading',
- },
- ],
- ])(
- 'correctly parses %s',
- async (_description, platform, input, expected) => {
- const result = await parsePlatformInput(platform, input)
- expect(result).toEqual(expected)
- }
- )
- })
-})
diff --git a/domains/grid/platform-parser/__tests__/instagramParser.spec.ts b/domains/grid/platform-parser/__tests__/instagramParser.spec.ts
new file mode 100644
index 00000000..4ef59d20
--- /dev/null
+++ b/domains/grid/platform-parser/__tests__/instagramParser.spec.ts
@@ -0,0 +1,53 @@
+import { describe, expect, it } from 'vitest'
+
+describe('INSTAGRAM Input Parser', () => {
+ it.each([
+ [
+ 'Post URL',
+ GRID_WIDGET_TYPE.enum.INSTAGRAM,
+ 'https://www.instagram.com/p/C98OXs6yhAq/?utm_source=ig_embed&utm_campaign=loading',
+ {
+ src: 'https://www.instagram.com/p/C98OXs6yhAq/?utm_source=ig_embed&utm_campaign=loading',
+ type: 'p',
+ id: 'C98OXs6yhAq',
+ params: '?utm_source=ig_embed&utm_campaign=loading',
+ },
+ ],
+ [
+ 'Post Embed Code',
+ GRID_WIDGET_TYPE.enum.INSTAGRAM,
+ '
',
+ {
+ src: 'https://www.instagram.com/p/C98OXs6yhAq/?utm_source=ig_embed&utm_campaign=loading',
+ type: 'p',
+ id: 'C98OXs6yhAq',
+ params: '?utm_source=ig_embed&utm_campaign=loading',
+ },
+ ],
+ [
+ 'Reel URL',
+ GRID_WIDGET_TYPE.enum.INSTAGRAM,
+ 'https://www.instagram.com/reel/DAlOgHkuyxd/?utm_source=ig_embed&utm_campaign=loading',
+ {
+ src: 'https://www.instagram.com/reel/DAlOgHkuyxd/?utm_source=ig_embed&utm_campaign=loading',
+ type: 'reel',
+ id: 'DAlOgHkuyxd',
+ params: '?utm_source=ig_embed&utm_campaign=loading',
+ },
+ ],
+ [
+ 'Reel Embed Code',
+ GRID_WIDGET_TYPE.enum.INSTAGRAM,
+ '',
+ {
+ src: 'https://www.instagram.com/reel/DAlOgHkuyxd/?utm_source=ig_embed&utm_campaign=loading',
+ type: 'reel',
+ id: 'DAlOgHkuyxd',
+ params: '?utm_source=ig_embed&utm_campaign=loading',
+ },
+ ],
+ ])('correctly parses %s', async (_description, platform, input, expected) => {
+ const result = await parsePlatformInput(platform, input)
+ expect(result).toEqual(expected)
+ })
+})
diff --git a/domains/grid/platform-parser/__tests__/soundcloudParser.spec.ts b/domains/grid/platform-parser/__tests__/soundcloudParser.spec.ts
new file mode 100644
index 00000000..38dcb32b
--- /dev/null
+++ b/domains/grid/platform-parser/__tests__/soundcloudParser.spec.ts
@@ -0,0 +1,71 @@
+import { describe, expect, it } from 'vitest'
+const SOUNDCLOUD_IFRAME_ALLOW =
+ 'clipboard-write; encrypted-media; fullscreen; picture-in-picture'
+
+describe('SOUNDCLOUD Input Parser', () => {
+ it.each([
+ [
+ 'Track Share URL',
+ GRID_WIDGET_TYPE.enum.SOUNDCLOUD,
+ 'https://soundcloud.com/occams-laser/with-you',
+ {
+ src: 'https://w.soundcloud.com/player/?visual=true&url=https%3A%2F%2Fapi.soundcloud.com%2Ftracks%2F1856391039&show_artwork=true',
+ allow: SOUNDCLOUD_IFRAME_ALLOW,
+ type: 'tracks',
+ },
+ ],
+ [
+ 'Set Share URL',
+ GRID_WIDGET_TYPE.enum.SOUNDCLOUD,
+ 'https://w.soundcloud.com/player/?visual=true&url=https%3A%2F%2Fapi.soundcloud.com%2Fplaylists%2F505007376&show_artwork=true',
+ {
+ src: 'https://w.soundcloud.com/player/?visual=true&url=https%3A%2F%2Fapi.soundcloud.com%2Fplaylists%2F505007376&show_artwork=true',
+ allow: SOUNDCLOUD_IFRAME_ALLOW,
+ type: 'playlists',
+ },
+ ],
+ [
+ 'Users Embed Code',
+ GRID_WIDGET_TYPE.enum.SOUNDCLOUD,
+ 'https://soundcloud.com/fabian-vogelsteller',
+ {
+ src: 'https://w.soundcloud.com/player/?visual=true&url=https%3A%2F%2Fapi.soundcloud.com%2Fusers%2F227118126&show_artwork=true',
+ allow: SOUNDCLOUD_IFRAME_ALLOW,
+ type: 'users',
+ },
+ ],
+ [
+ 'Track Embed Code',
+ GRID_WIDGET_TYPE.enum.SOUNDCLOUD,
+ '',
+ {
+ src: 'https://w.soundcloud.com/player/?url=https://api.soundcloud.com/tracks/1856391039&color=%23ff5500&auto_play=false&hide_related=false&show_comments=true&show_user=true&show_reposts=false&show_teaser=true&visual=true',
+ allow: SOUNDCLOUD_IFRAME_ALLOW,
+ type: 'tracks',
+ },
+ ],
+ [
+ 'Track Embed Code with URL encoded characters',
+ GRID_WIDGET_TYPE.enum.SOUNDCLOUD,
+ '',
+ {
+ src: 'https://w.soundcloud.com/player/?visual=true&url=https%3A%2F%2Fapi.soundcloud.com%2Ftracks%2F1856391039&show_artwork=true',
+ allow: SOUNDCLOUD_IFRAME_ALLOW,
+ type: 'tracks',
+ },
+ ],
+ [
+ 'Playlist Embed Code',
+ GRID_WIDGET_TYPE.enum.SOUNDCLOUD,
+ '',
+ {
+ src: 'https://w.soundcloud.com/player/?url=https://api.soundcloud.com/playlists/1850298147&color=%23ff5500&auto_play=false&hide_related=false&show_comments=true&show_user=true&show_reposts=false&show_teaser=true&visual=true',
+ allow: SOUNDCLOUD_IFRAME_ALLOW,
+ type: 'playlists',
+ },
+ ],
+ ])('correctly parses %s', async (_description, platform, input, expected) => {
+ const result = await parsePlatformInput(platform, input)
+ expect(result).toEqual(expected)
+ })
+})
diff --git a/domains/grid/platform-parser/__tests__/spotifyParser.spec.ts b/domains/grid/platform-parser/__tests__/spotifyParser.spec.ts
new file mode 100644
index 00000000..c8dcb0d6
--- /dev/null
+++ b/domains/grid/platform-parser/__tests__/spotifyParser.spec.ts
@@ -0,0 +1,90 @@
+import { describe, expect, it } from 'vitest'
+
+const SPOTIFY_IFRAME_ALLOW =
+ 'clipboard-write; encrypted-media; fullscreen; picture-in-picture'
+
+describe('SPOTIFY Input Parser', () => {
+ it.each([
+ [
+ 'Track URL',
+ GRID_WIDGET_TYPE.enum.SPOTIFY,
+ 'https://open.spotify.com/track/7xGfFoTpQ2E7fRF5lN10tr',
+ {
+ src: 'https://open.spotify.com/embed/track/7xGfFoTpQ2E7fRF5lN10tr?utm_source=oembed',
+ type: 'track',
+ id: '7xGfFoTpQ2E7fRF5lN10tr',
+ allow: SPOTIFY_IFRAME_ALLOW,
+ },
+ ],
+ [
+ 'Track Embed Code',
+ GRID_WIDGET_TYPE.enum.SPOTIFY,
+ '',
+ {
+ src: 'https://open.spotify.com/embed/track/2BHj31ufdEqVK5CkYDp9mA?utm_source=generator',
+ type: 'track',
+ id: '2BHj31ufdEqVK5CkYDp9mA',
+ allow: SPOTIFY_IFRAME_ALLOW,
+ },
+ ],
+ [
+ 'Track Embed Code with theme',
+ GRID_WIDGET_TYPE.enum.SPOTIFY,
+ '',
+ {
+ src: 'https://open.spotify.com/embed/track/48K735Rd3UQExzjXH004k1?utm_source=generator&theme=0',
+ type: 'track',
+ id: '48K735Rd3UQExzjXH004k1',
+ allow: SPOTIFY_IFRAME_ALLOW,
+ theme: '0',
+ },
+ ],
+ [
+ 'Playlist URL',
+ GRID_WIDGET_TYPE.enum.SPOTIFY,
+ 'https://open.spotify.com/playlist/7KFoK4LJ23EncELJwYmTDG',
+ {
+ src: 'https://open.spotify.com/embed/playlist/7KFoK4LJ23EncELJwYmTDG?utm_source=oembed',
+ type: 'playlist',
+ id: '7KFoK4LJ23EncELJwYmTDG',
+ allow: SPOTIFY_IFRAME_ALLOW,
+ },
+ ],
+ [
+ 'Playlist Embed Code',
+ GRID_WIDGET_TYPE.enum.SPOTIFY,
+ '',
+ {
+ src: 'https://open.spotify.com/embed/playlist/7KFoK4LJ23EncELJwYmTDG?utm_source=generator',
+ type: 'playlist',
+ id: '7KFoK4LJ23EncELJwYmTDG',
+ allow: SPOTIFY_IFRAME_ALLOW,
+ },
+ ],
+ [
+ 'Artist URL',
+ GRID_WIDGET_TYPE.enum.SPOTIFY,
+ 'https://open.spotify.com/artist/4KY9rCrokaoFzvMfX98u1q',
+ {
+ src: 'https://open.spotify.com/embed/artist/4KY9rCrokaoFzvMfX98u1q?utm_source=oembed',
+ type: 'artist',
+ id: '4KY9rCrokaoFzvMfX98u1q',
+ allow: SPOTIFY_IFRAME_ALLOW,
+ },
+ ],
+ [
+ 'Artist Embed Code',
+ GRID_WIDGET_TYPE.enum.SPOTIFY,
+ '',
+ {
+ src: 'https://open.spotify.com/embed/artist/4KY9rCrokaoFzvMfX98u1q?utm_source=generator',
+ type: 'artist',
+ id: '4KY9rCrokaoFzvMfX98u1q',
+ allow: SPOTIFY_IFRAME_ALLOW,
+ },
+ ],
+ ])('correctly parses %s', async (_description, platform, input, expected) => {
+ const result = await parsePlatformInput(platform, input)
+ expect(result).toEqual(expected)
+ })
+})
diff --git a/domains/grid/platform-parser/__tests__/xParser.spec.ts b/domains/grid/platform-parser/__tests__/xParser.spec.ts
new file mode 100644
index 00000000..b3023375
--- /dev/null
+++ b/domains/grid/platform-parser/__tests__/xParser.spec.ts
@@ -0,0 +1,80 @@
+import { describe, expect, it } from 'vitest'
+
+describe('X Input Parser', () => {
+ it.each([
+ [
+ 'Handle',
+ '@feindura',
+ {
+ type: 'timeline',
+ username: 'feindura',
+ },
+ ],
+ [
+ 'Handle without @',
+ 'feindura',
+ {
+ type: 'timeline',
+ username: 'feindura',
+ },
+ ],
+ [
+ 'Status URL',
+ 'https://x.com/feindura/status/1804519711377436675',
+ {
+ type: 'status',
+ username: 'feindura',
+ id: '1804519711377436675',
+ },
+ ],
+ [
+ 'Status URL twitter.com',
+
+ 'https://twitter.com/feindura/status/1804519711377436675',
+ {
+ type: 'status',
+ username: 'feindura',
+ id: '1804519711377436675',
+ },
+ ],
+ [
+ 'Status Embed Code with extra props',
+ ' ',
+ {
+ type: 'status',
+ username: 'feindura',
+ id: '1804519711377436675',
+ theme: 'dark',
+ language: 'en',
+ doNotTrack: true,
+ },
+ ],
+ [
+ 'Timeline URL',
+ 'https://x.com/lukso_io',
+ {
+ type: 'timeline',
+ username: 'lukso_io',
+ },
+ ],
+ [
+ 'Timeline URL twitter.com',
+ 'https://twitter.com/lukso_io',
+ {
+ type: 'timeline',
+ username: 'lukso_io',
+ },
+ ],
+ [
+ 'Timeline Embed Code',
+ ' ',
+ {
+ type: 'timeline',
+ username: 'lukso_io',
+ },
+ ],
+ ])('correctly parses %s', async (_description, input, expected) => {
+ const result = await parsePlatformInput(GRID_WIDGET_TYPE.Enum.X, input)
+ expect(result).toEqual(expected)
+ })
+})
diff --git a/domains/grid/platform-parser/__tests__/youtubeParser.spec.ts b/domains/grid/platform-parser/__tests__/youtubeParser.spec.ts
new file mode 100644
index 00000000..1c5530f5
--- /dev/null
+++ b/domains/grid/platform-parser/__tests__/youtubeParser.spec.ts
@@ -0,0 +1,29 @@
+import { describe, expect, it } from 'vitest'
+const YOUTUBE_IFRAME_ALLOW =
+ 'accelerometer; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share'
+
+describe('YOUTUBE Input Parser', () => {
+ it.each([
+ [
+ 'URL',
+ GRID_WIDGET_TYPE.enum.YOUTUBE,
+ 'https://www.youtube.com/watch?v=Vw4JE64hsO8',
+ {
+ src: 'https://www.youtube.com/embed/Vw4JE64hsO8',
+ allow: YOUTUBE_IFRAME_ALLOW,
+ },
+ ],
+ [
+ 'Embed Code',
+ GRID_WIDGET_TYPE.enum.YOUTUBE,
+ '',
+ {
+ src: 'https://www.youtube.com/embed/Vw4JE64hsO8',
+ allow: YOUTUBE_IFRAME_ALLOW,
+ },
+ ],
+ ])('correctly parses %s', async (_description, platform, input, expected) => {
+ const result = await parsePlatformInput(platform, input)
+ expect(result).toEqual(expected)
+ })
+})
diff --git a/domains/grid/platform-parser/gridParser.ts b/domains/grid/platform-parser/gridParser.ts
index be4d1fa7..5c400c9a 100644
--- a/domains/grid/platform-parser/gridParser.ts
+++ b/domains/grid/platform-parser/gridParser.ts
@@ -1,13 +1,13 @@
export type RegexWithCallback = {
regex: RegExp
- callback: (url: string) => Promise
+ callback: (
+ matches: RegExpMatchArray[]
+ ) => Promise | undefined>
}
export type PlatformParsingParameters = {
- type: GridWidgetType
- embedRegex: RegExp
- secondaryRegexesWithCallbacks?: RegexWithCallback[]
- constantProperties?: Record
+ // type: GridWidgetType // TODO: Does the parser need to select the type?
+ regexWithCallbacks?: RegexWithCallback[]
}
export const parsePlatformInput = async (
@@ -20,115 +20,45 @@ export const parsePlatformInput = async (
throw new Error('Invalid platform')
}
- // Check if the input matches the embed regex
- try {
- return parsePlatformEmbed(input, platformParsingParameters)
- } catch {}
+ const { regexWithCallbacks: regexesWithCallbacks } = platformParsingParameters
- const { secondaryRegexesWithCallbacks } = platformParsingParameters
-
- if (!secondaryRegexesWithCallbacks) {
- throw new Error('Invalid input')
+ if (!regexesWithCallbacks?.length) {
+ throw new Error('No regex patterns configured')
}
- // Check if the input matches a secondary regex
- let callbackResult: string | undefined
-
- for (const { regex, callback } of secondaryRegexesWithCallbacks) {
- const match = input.match(regex)
-
- if (match) {
- callbackResult = await callback(match[0])
-
- break
+ // Check each regex in order
+ for (const { regex, callback } of regexesWithCallbacks) {
+ let matches: RegExpMatchArray[] = []
+ // Check if the regex is global
+ if (regex.global) {
+ matches = Array.from(input.matchAll(regex))
+ } else {
+ const match = input.match(regex)
+ console.log(JSON.stringify(match))
+ if (match) {
+ matches.push(match)
+ }
}
- }
-
- if (!callbackResult) {
- throw new Error('Invalid input')
- }
-
- return parsePlatformEmbed(callbackResult, platformParsingParameters)
-}
-const parsePlatformEmbed = (
- input: string,
- platformParsingParameters: PlatformParsingParameters
-) => {
- const { embedRegex, constantProperties } = platformParsingParameters
- const match = input.match(embedRegex)
-
- if (!match) {
- throw new Error('Invalid input')
- }
-
- const { groups } = match
- let extractedProperties: Record = {}
-
- if (groups) {
- // Extract the properties from capture groups from the regex match
- extractedProperties = Object.entries(groups).reduce(
- (acc: Record, [key, value]) => {
- if (value) acc[key] = value
-
- return acc
- },
- {}
- )
- }
-
- return {
- src: match[0],
- ...constantProperties,
- ...extractedProperties,
+ if (matches.length) {
+ console.log(matches)
+ return await callback(matches)
+ }
}
-}
-
-export async function getSoundCloudOEmbed(
- url: string
-): Promise {
- const encodedUrl = encodeURI(url)
- const response = await fetch(
- `https://soundcloud.com/oembed?url=${encodedUrl}&format=json`
- )
- return response.ok ? ((await response.json())?.html as string) : undefined
+ throw new Error('Invalid input')
}
-export async function getSpotifyOEmbed(
- url: string
-): Promise {
- const response = await fetch(
- `https://open.spotify.com/oembed?url=${url}&format=json`
+export const getPropertiesFromGroups = (matches: RegExpMatchArray[]) => {
+ return matches.reduce(
+ (acc, match) => ({
+ ...acc,
+ ...Object.fromEntries(
+ Object.entries(match.groups || {}).filter(
+ ([, value]) => value !== undefined
+ ) // Filter out undefined values
+ ),
+ }),
+ {} as Record
)
-
- return response.ok ? ((await response.json())?.html as string) : undefined
-}
-
-export async function getXOEmbedFromHandle(handle: string) {
- const response = await fetch(
- `https://publish.twitter.com/oembed?url=https://twitter.com/${handle.replace('@', '')}`
- )
-
- return response.ok ? ((await response.json())?.html as string) : undefined
-}
-
-export function sanitizeXEmbedUrl(url: string): string {
- let newUrl = url.replace('x.com', 'twitter.com')
-
- if (!newUrl.startsWith('https://')) {
- newUrl = `https://${newUrl}`
- }
-
- return newUrl
-}
-
-export function sanitizeYoutubeEmbedUrl(url: string): string {
- let newUrl = url.replace('watch?v=', 'embed/')
-
- if (!url.startsWith('https://')) {
- newUrl = `https://${newUrl}`
- }
-
- return newUrl
}
diff --git a/domains/grid/platform-parser/instagramParser.ts b/domains/grid/platform-parser/instagramParser.ts
new file mode 100644
index 00000000..3fa88a0a
--- /dev/null
+++ b/domains/grid/platform-parser/instagramParser.ts
@@ -0,0 +1,11 @@
+export const PLATFORM_PARSING_PARAMETERS_INSTAGRAM: PlatformParsingParameters =
+ {
+ // type: GRID_WIDGET_TYPE.enum.INSTAGRAM,
+ regexWithCallbacks: [
+ {
+ regex:
+ /https:\/\/www\.instagram\.com\/(?p|reel|profile|tv)\/(?[\w-]+)\/(?\?[^"]*)?/,
+ callback: async () => undefined,
+ },
+ ],
+ }
diff --git a/domains/grid/platform-parser/soundcloudParser.ts b/domains/grid/platform-parser/soundcloudParser.ts
new file mode 100644
index 00000000..5b4b52dc
--- /dev/null
+++ b/domains/grid/platform-parser/soundcloudParser.ts
@@ -0,0 +1,27 @@
+export const PLATFORM_PARSING_PARAMETERS_SOUNDCLOUD: PlatformParsingParameters =
+ {
+ // type: GRID_WIDGET_TYPE.enum.IFRAME,
+ regexWithCallbacks: [
+ {
+ regex:
+ /https?:\/\/w\.soundcloud\.com\/player\/\?(?:(?!url=https).)*url=https(?::|%3A)(?:\/|%2F){2}api\.soundcloud\.com(?:\/|%2F)(?tracks|playlists|users)(?:\/|%2F)\d+(?:[^"]*)?/,
+ callback: async () => undefined,
+ },
+ {
+ regex:
+ /https:\/\/soundcloud\.com\/([a-zA-Z0-9_-]+)(?:\/(sets\/[a-zA-Z0-9_-]+|[a-zA-Z0-9_-]+))?\/?/,
+ callback: async () => undefined,
+ },
+ ],
+ }
+
+export async function getSoundCloudOEmbed(
+ url: string
+): Promise {
+ const encodedUrl = encodeURI(url)
+ const response = await fetch(
+ `https://soundcloud.com/oembed?url=${encodedUrl}&format=json`
+ )
+
+ return response.ok ? ((await response.json())?.html as string) : undefined
+}
diff --git a/domains/grid/platform-parser/spotifyParser.ts b/domains/grid/platform-parser/spotifyParser.ts
new file mode 100644
index 00000000..ef8da138
--- /dev/null
+++ b/domains/grid/platform-parser/spotifyParser.ts
@@ -0,0 +1,28 @@
+export const PLATFORM_PARSING_PARAMETERS_SPOTIFY: PlatformParsingParameters = {
+ // type: GRID_WIDGET_TYPE.enum.IFRAME,
+ regexWithCallbacks: [
+ {
+ regex:
+ /https?:\/\/(?:open\.)?spotify\.com\/embed\/?(?track|playlist|artist)\/(?[^?]+)(?:\?utm_source=(?:generator|oembed))?(?:&theme=(?\d))?/,
+ callback: async () => undefined,
+ },
+ {
+ regex:
+ /https:\/\/open\.spotify\.com\/(?track|playlist|artist)\/(?[^?]+)/,
+ callback: async () => undefined,
+ },
+ ],
+ // constantProperties: {
+ // allow: 'clipboard-write; encrypted-media; fullscreen; picture-in-picture',
+ // },
+}
+
+export async function getSpotifyOEmbed(
+ url: string
+): Promise {
+ const response = await fetch(
+ `https://open.spotify.com/oembed?url=${url}&format=json`
+ )
+
+ return response.ok ? ((await response.json())?.html as string) : undefined
+}
diff --git a/domains/grid/platform-parser/xParser.ts b/domains/grid/platform-parser/xParser.ts
new file mode 100644
index 00000000..2cbfc37a
--- /dev/null
+++ b/domains/grid/platform-parser/xParser.ts
@@ -0,0 +1,38 @@
+import { getPropertiesFromGroups } from './gridParser'
+
+export const PLATFORM_PARSING_PARAMETERS_X: PlatformParsingParameters = {
+ // type: GRID_WIDGET_TYPE.enum.X,
+ regexWithCallbacks: [
+ {
+ regex:
+ /(?:https?:\/\/(?:(?:www\.)?(?:twitter|x)\.com)\/(?[a-zA-Z0-9_]+)(?:\/status\/(?\d+))?(?:\?[^"'\s]*)?)|(?:data-media-max-width="(?\d+)")|(?:data-theme="(?\w+)")|(?:data-lang="(?\w+)")|(?:data-dnt="(?true|false)")/g,
+ callback: async (matches: RegExpMatchArray[]) => {
+ // Flatten all matches' groups into a single object
+ const properties = getPropertiesFromGroups(matches)
+ const { username, id, mediaWidth, theme, language, doNotTrack } =
+ properties
+
+ return {
+ type: mediaWidth ? 'video' : id ? 'status' : 'timeline',
+ username,
+ ...(id && { id }),
+ ...(theme && { theme }),
+ ...(language && { language }),
+ ...(doNotTrack && { doNotTrack: doNotTrack === 'true' }),
+ }
+ },
+ },
+ // Match a handle with @ symbol
+ {
+ regex: /^@?(?[a-zA-Z0-9_]{1,15})$/,
+ callback: async (matches: RegExpMatchArray[]) => {
+ const { username } = matches[0]?.groups ?? {} // Get the first match's first group
+
+ return {
+ type: 'timeline',
+ username,
+ }
+ },
+ },
+ ],
+}
diff --git a/domains/grid/platform-parser/youtubeParser.ts b/domains/grid/platform-parser/youtubeParser.ts
new file mode 100644
index 00000000..181a2c7e
--- /dev/null
+++ b/domains/grid/platform-parser/youtubeParser.ts
@@ -0,0 +1,27 @@
+export const PLATFORM_PARSING_PARAMETERS_YOUTUBE: PlatformParsingParameters = {
+ // type: GRID_WIDGET_TYPE.enum.YOUTUBE,
+ regexWithCallbacks: [
+ {
+ regex: /(?:https?:\/\/)?(?:www\.)?youtube\.com\/embed\/([^?]+)/,
+ callback: async () => undefined,
+ },
+ {
+ regex: /(?:https?:\/\/)?(?:www\.)?youtube\.com\/watch\?v=([^&]+)/,
+ callback: async () => undefined,
+ },
+ ],
+ // constantProperties: {
+ // allow:
+ // 'accelerometer; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share',
+ // },
+}
+
+export function sanitizeYoutubeEmbedUrl(url: string): string {
+ let newUrl = url.replace('watch?v=', 'embed/')
+
+ if (!url.startsWith('https://')) {
+ newUrl = `https://${newUrl}`
+ }
+
+ return newUrl
+}
diff --git a/domains/grid/shared/config.ts b/domains/grid/shared/config.ts
index 388ef6d9..51d8cbb7 100644
--- a/domains/grid/shared/config.ts
+++ b/domains/grid/shared/config.ts
@@ -1,5 +1,11 @@
import { type ZodEffects, type ZodObject, z } from 'zod'
+import { PLATFORM_PARSING_PARAMETERS_X } from '../platform-parser/xParser'
+import { PLATFORM_PARSING_PARAMETERS_INSTAGRAM } from '../platform-parser/instagramParser'
+import { PLATFORM_PARSING_PARAMETERS_SOUNDCLOUD } from '../platform-parser/soundcloudParser'
+import { PLATFORM_PARSING_PARAMETERS_YOUTUBE } from '../platform-parser/youtubeParser'
+import { PLATFORM_PARSING_PARAMETERS_SPOTIFY } from '../platform-parser/spotifyParser'
+
export const GRID_WIDGET_TYPE = z.enum([
// custom
'TEXT',
@@ -67,71 +73,9 @@ export const GRID_COLUMNS_MAX = 4
export const PLATFORM_PARSING_PARAMETERS: Partial<
Record
> = {
- [GRID_WIDGET_TYPE.enum.X]: {
- type: GRID_WIDGET_TYPE.enum.X,
- embedRegex:
- /https?:\/\/twitter\.com\/(?[a-zA-Z0-9_]+)(?:\/status\/(?\d+))?(?:\?[^"'\s]*)?/,
- secondaryRegexesWithCallbacks: [
- // Match a handle with @ symbol
- {
- regex: /@([a-zA-Z0-9_]{1,15})/,
- callback: getXOEmbedFromHandle,
- },
- // Match a Twitter URL with or without https www and status
- {
- regex:
- /(https?:\/\/)?(?:x\.com|twitter\.com)\/[a-zA-Z0-9_]+(?:\/status\/(\d+))?/,
- callback: async url => sanitizeXEmbedUrl(url),
- },
- ],
- },
- [GRID_WIDGET_TYPE.enum.INSTAGRAM]: {
- type: GRID_WIDGET_TYPE.enum.INSTAGRAM,
- embedRegex:
- /https:\/\/www\.instagram\.com\/(?p|reel|profile|tv)\/(?[\w-]+)\/(?\?[^"]*)?/,
- },
- [GRID_WIDGET_TYPE.enum.SPOTIFY]: {
- type: GRID_WIDGET_TYPE.enum.IFRAME,
- embedRegex:
- /https?:\/\/(?:open\.)?spotify\.com\/embed\/?(?track|playlist|artist)\/(?[^?]+)(?:\?utm_source=(?:generator|oembed))?(?:&theme=(?\d))?/,
- secondaryRegexesWithCallbacks: [
- {
- regex:
- /https:\/\/open\.spotify\.com\/(?track|playlist|artist)\/(?[^?]+)/,
- callback: getSpotifyOEmbed,
- },
- ],
- constantProperties: {
- allow: 'clipboard-write; encrypted-media; fullscreen; picture-in-picture',
- },
- },
- [GRID_WIDGET_TYPE.enum.SOUNDCLOUD]: {
- type: GRID_WIDGET_TYPE.enum.IFRAME,
- embedRegex:
- /https?:\/\/w\.soundcloud\.com\/player\/\?(?:(?!url=https).)*url=https(?::|%3A)(?:\/|%2F){2}api\.soundcloud\.com(?:\/|%2F)(?tracks|playlists|users)(?:\/|%2F)\d+(?:[^"]*)?/,
- secondaryRegexesWithCallbacks: [
- {
- regex:
- /https:\/\/soundcloud\.com\/([a-zA-Z0-9_-]+)(?:\/(sets\/[a-zA-Z0-9_-]+|[a-zA-Z0-9_-]+))?\/?/,
- callback: getSoundCloudOEmbed,
- },
- ],
- constantProperties: {
- allow: 'clipboard-write; encrypted-media; fullscreen; picture-in-picture',
- },
- },
- [GRID_WIDGET_TYPE.enum.YOUTUBE]: {
- type: GRID_WIDGET_TYPE.enum.YOUTUBE,
- embedRegex: /(?:https?:\/\/)?(?:www\.)?youtube\.com\/embed\/([^?]+)/,
- secondaryRegexesWithCallbacks: [
- {
- regex: /(?:https?:\/\/)?(?:www\.)?youtube\.com\/watch\?v=([^&]+)/,
- callback: async url => sanitizeYoutubeEmbedUrl(url),
- },
- ],
- constantProperties: {
- allow:
- 'accelerometer; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share',
- },
- },
+ [GRID_WIDGET_TYPE.enum.X]: PLATFORM_PARSING_PARAMETERS_X,
+ [GRID_WIDGET_TYPE.enum.INSTAGRAM]: PLATFORM_PARSING_PARAMETERS_INSTAGRAM,
+ [GRID_WIDGET_TYPE.enum.SPOTIFY]: PLATFORM_PARSING_PARAMETERS_SPOTIFY,
+ [GRID_WIDGET_TYPE.enum.SOUNDCLOUD]: PLATFORM_PARSING_PARAMETERS_SOUNDCLOUD,
+ [GRID_WIDGET_TYPE.enum.YOUTUBE]: PLATFORM_PARSING_PARAMETERS_YOUTUBE,
}
diff --git a/domains/schema/xWidgetSchema.ts b/domains/schema/xWidgetSchema.ts
index f6bf72b7..1f933796 100644
--- a/domains/schema/xWidgetSchema.ts
+++ b/domains/schema/xWidgetSchema.ts
@@ -3,7 +3,12 @@ import { z } from 'zod'
export const xWidgetSchema = z
.object({
src: z.string(),
- type: z.string().optional(),
+ type: z.string(),
+ username: z.string(),
+ id: z.string().optional(),
+ theme: z.string().optional(),
+ language: z.string().optional(),
+ doNotTrack: z.boolean().optional(),
})
.transform((values, ctx) =>
platformTransform(values, ctx, GRID_WIDGET_TYPE.enum.X)
From efcbbfc5941baf82e766caf9aaa336ae07e729ff Mon Sep 17 00:00:00 2001
From: Eduardo Sacco <3680995+nastita@users.noreply.github.com>
Date: Sun, 3 Nov 2024 11:46:40 -0300
Subject: [PATCH 12/36] Update iframe parsers
---
.../__tests__/soundcloudParser.spec.ts | 44 ++++++----
.../__tests__/spotifyParser.spec.ts | 69 ++++++++-------
.../__tests__/youtubeParser.spec.ts | 20 ++++-
domains/grid/platform-parser/gridParser.ts | 2 +-
.../platform-parser/iframeParserFactory.ts | 84 +++++++++++++++++++
.../grid/platform-parser/soundcloudParser.ts | 54 +++++++-----
domains/grid/platform-parser/spotifyParser.ts | 38 ++++-----
domains/grid/platform-parser/youtubeParser.ts | 66 ++++++++++-----
8 files changed, 267 insertions(+), 110 deletions(-)
create mode 100644 domains/grid/platform-parser/iframeParserFactory.ts
diff --git a/domains/grid/platform-parser/__tests__/soundcloudParser.spec.ts b/domains/grid/platform-parser/__tests__/soundcloudParser.spec.ts
index 38dcb32b..19b99c39 100644
--- a/domains/grid/platform-parser/__tests__/soundcloudParser.spec.ts
+++ b/domains/grid/platform-parser/__tests__/soundcloudParser.spec.ts
@@ -9,9 +9,11 @@ describe('SOUNDCLOUD Input Parser', () => {
GRID_WIDGET_TYPE.enum.SOUNDCLOUD,
'https://soundcloud.com/occams-laser/with-you',
{
- src: 'https://w.soundcloud.com/player/?visual=true&url=https%3A%2F%2Fapi.soundcloud.com%2Ftracks%2F1856391039&show_artwork=true',
- allow: SOUNDCLOUD_IFRAME_ALLOW,
- type: 'tracks',
+ allow:
+ 'autoplay; clipboard-write; encrypted-media; fullscreen; picture-in-picture',
+ height: '166',
+ src: 'https://w.soundcloud.com/player/?url=https://soundcloud.com/occams-laser/with-you',
+ width: '100%',
},
],
[
@@ -19,9 +21,11 @@ describe('SOUNDCLOUD Input Parser', () => {
GRID_WIDGET_TYPE.enum.SOUNDCLOUD,
'https://w.soundcloud.com/player/?visual=true&url=https%3A%2F%2Fapi.soundcloud.com%2Fplaylists%2F505007376&show_artwork=true',
{
- src: 'https://w.soundcloud.com/player/?visual=true&url=https%3A%2F%2Fapi.soundcloud.com%2Fplaylists%2F505007376&show_artwork=true',
- allow: SOUNDCLOUD_IFRAME_ALLOW,
- type: 'playlists',
+ allow:
+ 'autoplay; clipboard-write; encrypted-media; fullscreen; picture-in-picture',
+ height: '166',
+ src: 'https://w.soundcloud.com/player/?url=https://api.soundcloud.com/playlists/505007376&show_artwork=true',
+ width: '100%',
},
],
[
@@ -29,9 +33,11 @@ describe('SOUNDCLOUD Input Parser', () => {
GRID_WIDGET_TYPE.enum.SOUNDCLOUD,
'https://soundcloud.com/fabian-vogelsteller',
{
- src: 'https://w.soundcloud.com/player/?visual=true&url=https%3A%2F%2Fapi.soundcloud.com%2Fusers%2F227118126&show_artwork=true',
- allow: SOUNDCLOUD_IFRAME_ALLOW,
- type: 'users',
+ allow:
+ 'autoplay; clipboard-write; encrypted-media; fullscreen; picture-in-picture',
+ height: '166',
+ src: 'https://w.soundcloud.com/player/?url=https://soundcloud.com/fabian-vogelsteller',
+ width: '100%',
},
],
[
@@ -39,9 +45,11 @@ describe('SOUNDCLOUD Input Parser', () => {
GRID_WIDGET_TYPE.enum.SOUNDCLOUD,
'',
{
+ allow: 'autoplay',
+ height: '300',
src: 'https://w.soundcloud.com/player/?url=https://api.soundcloud.com/tracks/1856391039&color=%23ff5500&auto_play=false&hide_related=false&show_comments=true&show_user=true&show_reposts=false&show_teaser=true&visual=true',
- allow: SOUNDCLOUD_IFRAME_ALLOW,
- type: 'tracks',
+ style: 'color: #cccccc; text-decoration: none;',
+ width: '100%',
},
],
[
@@ -49,9 +57,11 @@ describe('SOUNDCLOUD Input Parser', () => {
GRID_WIDGET_TYPE.enum.SOUNDCLOUD,
'',
{
- src: 'https://w.soundcloud.com/player/?visual=true&url=https%3A%2F%2Fapi.soundcloud.com%2Ftracks%2F1856391039&show_artwork=true',
- allow: SOUNDCLOUD_IFRAME_ALLOW,
- type: 'tracks',
+ allow:
+ 'autoplay; clipboard-write; encrypted-media; fullscreen; picture-in-picture',
+ height: '400',
+ src: 'https://w.soundcloud.com/player/?url=https://api.soundcloud.com/tracks/1856391039&show_artwork=true',
+ width: '100%',
},
],
[
@@ -59,9 +69,11 @@ describe('SOUNDCLOUD Input Parser', () => {
GRID_WIDGET_TYPE.enum.SOUNDCLOUD,
'',
{
+ allow: 'autoplay',
+ height: '300',
src: 'https://w.soundcloud.com/player/?url=https://api.soundcloud.com/playlists/1850298147&color=%23ff5500&auto_play=false&hide_related=false&show_comments=true&show_user=true&show_reposts=false&show_teaser=true&visual=true',
- allow: SOUNDCLOUD_IFRAME_ALLOW,
- type: 'playlists',
+ style: 'color: #cccccc; text-decoration: none;',
+ width: '100%',
},
],
])('correctly parses %s', async (_description, platform, input, expected) => {
diff --git a/domains/grid/platform-parser/__tests__/spotifyParser.spec.ts b/domains/grid/platform-parser/__tests__/spotifyParser.spec.ts
index c8dcb0d6..c19e623f 100644
--- a/domains/grid/platform-parser/__tests__/spotifyParser.spec.ts
+++ b/domains/grid/platform-parser/__tests__/spotifyParser.spec.ts
@@ -1,8 +1,5 @@
import { describe, expect, it } from 'vitest'
-const SPOTIFY_IFRAME_ALLOW =
- 'clipboard-write; encrypted-media; fullscreen; picture-in-picture'
-
describe('SPOTIFY Input Parser', () => {
it.each([
[
@@ -10,10 +7,9 @@ describe('SPOTIFY Input Parser', () => {
GRID_WIDGET_TYPE.enum.SPOTIFY,
'https://open.spotify.com/track/7xGfFoTpQ2E7fRF5lN10tr',
{
- src: 'https://open.spotify.com/embed/track/7xGfFoTpQ2E7fRF5lN10tr?utm_source=oembed',
- type: 'track',
- id: '7xGfFoTpQ2E7fRF5lN10tr',
- allow: SPOTIFY_IFRAME_ALLOW,
+ src: 'https://open.spotify.com/embed/track/7xGfFoTpQ2E7fRF5lN10tr',
+ allow:
+ 'clipboard-write; encrypted-media; fullscreen; picture-in-picture',
},
],
[
@@ -22,9 +18,14 @@ describe('SPOTIFY Input Parser', () => {
'',
{
src: 'https://open.spotify.com/embed/track/2BHj31ufdEqVK5CkYDp9mA?utm_source=generator',
- type: 'track',
- id: '2BHj31ufdEqVK5CkYDp9mA',
- allow: SPOTIFY_IFRAME_ALLOW,
+ allow:
+ 'autoplay; clipboard-write; encrypted-media; fullscreen; picture-in-picture',
+ style: 'border-radius:12px',
+ width: '100%',
+ allowfullscreen: true,
+ frameBorder: 0,
+ height: '352',
+ loading: 'lazy',
},
],
[
@@ -33,10 +34,14 @@ describe('SPOTIFY Input Parser', () => {
'',
{
src: 'https://open.spotify.com/embed/track/48K735Rd3UQExzjXH004k1?utm_source=generator&theme=0',
- type: 'track',
- id: '48K735Rd3UQExzjXH004k1',
- allow: SPOTIFY_IFRAME_ALLOW,
- theme: '0',
+ allow:
+ 'autoplay; clipboard-write; encrypted-media; fullscreen; picture-in-picture',
+ allowfullscreen: true,
+ frameBorder: 0,
+ height: '352',
+ loading: 'lazy',
+ style: 'border-radius:12px',
+ width: '100%',
},
],
[
@@ -44,10 +49,9 @@ describe('SPOTIFY Input Parser', () => {
GRID_WIDGET_TYPE.enum.SPOTIFY,
'https://open.spotify.com/playlist/7KFoK4LJ23EncELJwYmTDG',
{
- src: 'https://open.spotify.com/embed/playlist/7KFoK4LJ23EncELJwYmTDG?utm_source=oembed',
- type: 'playlist',
- id: '7KFoK4LJ23EncELJwYmTDG',
- allow: SPOTIFY_IFRAME_ALLOW,
+ src: 'https://open.spotify.com/embed/playlist/7KFoK4LJ23EncELJwYmTDG',
+ allow:
+ 'clipboard-write; encrypted-media; fullscreen; picture-in-picture',
},
],
[
@@ -56,9 +60,14 @@ describe('SPOTIFY Input Parser', () => {
'',
{
src: 'https://open.spotify.com/embed/playlist/7KFoK4LJ23EncELJwYmTDG?utm_source=generator',
- type: 'playlist',
- id: '7KFoK4LJ23EncELJwYmTDG',
- allow: SPOTIFY_IFRAME_ALLOW,
+ allow:
+ 'autoplay; clipboard-write; encrypted-media; fullscreen; picture-in-picture',
+ allowfullscreen: true,
+ frameBorder: 0,
+ height: '352',
+ loading: 'lazy',
+ style: 'border-radius:12px',
+ width: '100%',
},
],
[
@@ -66,10 +75,9 @@ describe('SPOTIFY Input Parser', () => {
GRID_WIDGET_TYPE.enum.SPOTIFY,
'https://open.spotify.com/artist/4KY9rCrokaoFzvMfX98u1q',
{
- src: 'https://open.spotify.com/embed/artist/4KY9rCrokaoFzvMfX98u1q?utm_source=oembed',
- type: 'artist',
- id: '4KY9rCrokaoFzvMfX98u1q',
- allow: SPOTIFY_IFRAME_ALLOW,
+ src: 'https://open.spotify.com/embed/artist/4KY9rCrokaoFzvMfX98u1q',
+ allow:
+ 'clipboard-write; encrypted-media; fullscreen; picture-in-picture',
},
],
[
@@ -78,9 +86,14 @@ describe('SPOTIFY Input Parser', () => {
'',
{
src: 'https://open.spotify.com/embed/artist/4KY9rCrokaoFzvMfX98u1q?utm_source=generator',
- type: 'artist',
- id: '4KY9rCrokaoFzvMfX98u1q',
- allow: SPOTIFY_IFRAME_ALLOW,
+ allow:
+ 'autoplay; clipboard-write; encrypted-media; fullscreen; picture-in-picture',
+ allowfullscreen: true,
+ frameBorder: 0,
+ height: '352',
+ loading: 'lazy',
+ style: 'border-radius:12px',
+ width: '100%',
},
],
])('correctly parses %s', async (_description, platform, input, expected) => {
diff --git a/domains/grid/platform-parser/__tests__/youtubeParser.spec.ts b/domains/grid/platform-parser/__tests__/youtubeParser.spec.ts
index 1c5530f5..86a58061 100644
--- a/domains/grid/platform-parser/__tests__/youtubeParser.spec.ts
+++ b/domains/grid/platform-parser/__tests__/youtubeParser.spec.ts
@@ -9,8 +9,14 @@ describe('YOUTUBE Input Parser', () => {
GRID_WIDGET_TYPE.enum.YOUTUBE,
'https://www.youtube.com/watch?v=Vw4JE64hsO8',
{
- src: 'https://www.youtube.com/embed/Vw4JE64hsO8',
- allow: YOUTUBE_IFRAME_ALLOW,
+ allow:
+ 'accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share',
+ allowfullscreen: true,
+ frameborder: '0',
+ height: '315',
+ referrerpolicy: 'strict-origin-when-cross-origin',
+ src: 'https://www.youtube-nocookie.com/embed/Vw4JE64hsO8',
+ width: '560',
},
],
[
@@ -18,8 +24,14 @@ describe('YOUTUBE Input Parser', () => {
GRID_WIDGET_TYPE.enum.YOUTUBE,
'',
{
- src: 'https://www.youtube.com/embed/Vw4JE64hsO8',
- allow: YOUTUBE_IFRAME_ALLOW,
+ allow:
+ 'accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share',
+ allowfullscreen: true,
+ frameborder: '0',
+ height: '315',
+ referrerpolicy: 'strict-origin-when-cross-origin',
+ src: 'https://www.youtube-nocookie.com/embed/Vw4JE64hsO8?si=OwVdFZCStaL90G2W',
+ width: '560',
},
],
])('correctly parses %s', async (_description, platform, input, expected) => {
diff --git a/domains/grid/platform-parser/gridParser.ts b/domains/grid/platform-parser/gridParser.ts
index 5c400c9a..ee80572b 100644
--- a/domains/grid/platform-parser/gridParser.ts
+++ b/domains/grid/platform-parser/gridParser.ts
@@ -2,7 +2,7 @@ export type RegexWithCallback = {
regex: RegExp
callback: (
matches: RegExpMatchArray[]
- ) => Promise | undefined>
+ ) => Promise | undefined>
}
export type PlatformParsingParameters = {
diff --git a/domains/grid/platform-parser/iframeParserFactory.ts b/domains/grid/platform-parser/iframeParserFactory.ts
new file mode 100644
index 00000000..4c5565ab
--- /dev/null
+++ b/domains/grid/platform-parser/iframeParserFactory.ts
@@ -0,0 +1,84 @@
+import { getPropertiesFromGroups } from './gridParser'
+
+// Common iframe attributes regex patterns
+const COMMON_IFRAME_ATTRIBUTES: Record = {
+ style: '(?:style="(?