import { social } from '@crawlee/utils'; const { EMAIL_REGEX, EMAIL_REGEX_GLOBAL, FACEBOOK_REGEX, FACEBOOK_REGEX_GLOBAL, INSTAGRAM_REGEX, INSTAGRAM_REGEX_GLOBAL, LINKEDIN_REGEX, LINKEDIN_REGEX_GLOBAL, TWITTER_REGEX, TWITTER_REGEX_GLOBAL, YOUTUBE_REGEX, YOUTUBE_REGEX_GLOBAL, TIKTOK_REGEX, TIKTOK_REGEX_GLOBAL, PINTEREST_REGEX, PINTEREST_REGEX_GLOBAL, DISCORD_REGEX, DISCORD_REGEX_GLOBAL, emailsFromText, emailsFromUrls, parseHandlesFromHtml, phonesFromText, phonesFromUrls, } = social; describe('utils.social', () => { describe('emailsFromText()', () => { const testEmailsFromText = (text: string, phones: string[]) => { expect(emailsFromText(text)).toEqual(phones); }; test('works with arg with no emails or invalid', () => { // @ts-expect-error invalid input type expect(emailsFromText()).toEqual([]); testEmailsFromText('', []); // @ts-expect-error invalid input type testEmailsFromText(null, []); // @ts-expect-error invalid input type testEmailsFromText(undefined, []); // @ts-expect-error invalid input type testEmailsFromText({}, []); testEmailsFromText(' ', []); testEmailsFromText(' \n\n\r\t\n ', []); }); test('extracts emails correctly', () => { testEmailsFromText(' info@example.com ', ['info@example.com']); testEmailsFromText( ` info@example.com info+something@example.NET john.bob.dole@some-domain.co.uk `, ['info@example.com', 'info+something@example.NET', 'john.bob.dole@some-domain.co.uk'], ); testEmailsFromText( ` this'is'also'valid'email@EXAMPLE.travel easy-address@some-domain.co.uk \n\n easy-address@some-domain.co.uk not @ an.email.com @also.not.an.email `, [ "this'is'also'valid'email@EXAMPLE.travel", 'easy-address@some-domain.co.uk', 'easy-address@some-domain.co.uk', ], ); testEmailsFromText(' some.super.long.email.address@some.super.long.domain.name.co.br ', [ 'some.super.long.email.address@some.super.long.domain.name.co.br', ]); }); }); describe('emailsFromUrls()', () => { test('throws on invalid arg', () => { expect(() => { // @ts-expect-error invalid input type emailsFromUrls(); }).toThrowError(/must be an array/); expect(() => { // @ts-expect-error invalid input type emailsFromUrls({}); }).toThrowError(/must be an array/); expect(() => { // @ts-expect-error invalid input type emailsFromUrls('fwefwef'); }).toThrowError(/must be an array/); expect(() => { // @ts-expect-error invalid input type emailsFromUrls(12345); }).toThrowError(/must be an array/); }); test('extracts emails correctly', () => { expect(emailsFromUrls([])).toEqual([]); // @ts-expect-error invalid input type expect(emailsFromUrls([1, 2, {}, 'fwef', null, undefined])).toEqual([]); expect(emailsFromUrls(['mailto:info@example.com'])).toEqual(['info@example.com']); expect( emailsFromUrls([ 'http://www.example.com', 'mailto:info@example.com', 'mailto:info@example.com', 'email.without.mailto.prefix@example.com', '', '\n\n\n', ]), ).toEqual(['info@example.com', 'info@example.com']); expect( emailsFromUrls([ 'http://www.example.com', 'mailto:info@example.com', 'mailto:info@example.com', 'email.without.mailto.prefix@example.com', '', '\n\n\n', ]), ).toEqual(['info@example.com', 'info@example.com']); }); }); describe('phonesFromText()', () => { const testPhonesFromText = (text: string, phones: string[]) => { expect(phonesFromText(text)).toEqual(phones); }; test('works with arg with no phones or invalid', () => { // @ts-expect-error invalid input type expect(phonesFromText()).toEqual([]); testPhonesFromText('', []); // @ts-expect-error invalid input type testPhonesFromText(null, []); // @ts-expect-error invalid input type testPhonesFromText(undefined, []); // @ts-expect-error testPhonesFromText({}, []); testPhonesFromText(' ', []); testPhonesFromText(' \n\n\r\t\n ', []); }); test('extracts phones correctly', () => { testPhonesFromText( ` +420775123456 +420775123456 +420 775 123 456 775123456 775123456 \n\n 00420775123456 1234567 1234567890 +44 7911 123456 `, [ '+420775123456', '+420775123456', '+420 775 123 456', '775123456', '775123456', '00420775123456', '1234567', '1234567890', '+44 7911 123456', ], ); testPhonesFromText( ` 413-577-1234 00413-577-1234 981-413-777-8888 413.233.2343 +413.233.2343 or 413 233 2343 562-3113 123456789 401 311 7898 123456789 `, [ '413-577-1234', '00413-577-1234', '981-413-777-8888', '413.233.2343', '+413.233.2343', '413 233 2343', '562-3113', '123456789', '401 311 7898', '123456789', ], ); testPhonesFromText( ` 1 (413) 555-2378 +1 (413) 555-2378 1(413)555-2378 001 (413) 555-2378 1 (413) 555 2378 1(413)555-2378 or 1(413)555.2378 or 1 (413) 555-2378 or 1 (413) 555 2378 or (303) 494-2320 `, [ '1 (413) 555-2378', '+1 (413) 555-2378', '1(413)555-2378', '001 (413) 555-2378', '1 (413) 555 2378', '1(413)555-2378', '1(413)555.2378', '1 (413) 555-2378', '1 (413) 555 2378', '(303) 494-2320', ], ); testPhonesFromText( ` 123-456-789 123 456 789 123.456.789 123.456.789.123 +123.456.789.123 `, ['123-456-789', '123 456 789', '123.456.789', '123.456.789.123', '+123.456.789.123'], ); testPhonesFromText( ` (000)000-0000 (000)000 0000 (000)000.0000 (000) 000-0000 (000) 000 0000 (000) 000.0000 `, [ '(000)000-0000', '(000)000 0000', '(000)000.0000', '(000) 000-0000', '(000) 000 0000', '(000) 000.0000', ], ); testPhonesFromText( ` 000-0000 000 0000 000.0000 0000000 0000000000 (000)0000000 `, ['000-0000', '000 0000', '000.0000', '0000000', '0000000000', '(000)0000000'], ); }); test('skips invalid phones', () => { testPhonesFromText( ` 2018-10-11 123 456789 345 1 2 3 4 5 6 7 8 `, [], ); }); }); describe('phonesFromUrls()', () => { test('throws on invalid arg', () => { expect(() => { // @ts-expect-error invalid input type phonesFromUrls(); }).toThrowError(/must be an array/); expect(() => { // @ts-expect-error invalid input type phonesFromUrls({}); }).toThrowError(/must be an array/); expect(() => { // @ts-expect-error invalid input type phonesFromUrls('fwefwef'); }).toThrowError(/must be an array/); expect(() => { // @ts-expect-error invalid input type phonesFromUrls(12345); }).toThrowError(/must be an array/); }); test('extracts phones correctly', () => { expect(phonesFromUrls([])).toEqual([]); // @ts-expect-error invalid input type expect(phonesFromUrls([1, 2, {}, 'fwef', null, undefined])).toEqual([]); expect( phonesFromUrls([ 'tel:12345678', 'tel:/22345678', // 'tel://32345678', 'PHONE:42345678', // 'phone:/52345678', 'phone://62345678', 'telephone:72345678', 'telephone:/82345678', 'telephone://92345678', 'callto:97345678', 'CALLTO:/+98345678', 'callto://9992345678', ]), ).toEqual([ '12345678', '22345678', '32345678', '42345678', '52345678', '62345678', '72345678', '82345678', '92345678', '97345678', '+98345678', '9992345678', ]); expect( phonesFromUrls([ 'https://www.example.com', 'ftp://www.example.com', '1234567', '+42055555567', 'tel://+42012345678', 'tel://+420.123.456', 'http://www.example.com', ]), ).toEqual(['+42012345678', '+420.123.456']); }); }); describe('parseHandlesFromHtml()', () => { const EMPTY_RESULT: social.SocialHandles = { emails: [], phones: [], phonesUncertain: [], linkedIns: [], twitters: [], instagrams: [], facebooks: [], youtubes: [], tiktoks: [], pinterests: [], discords: [], }; test('handles invalid arg', () => { // @ts-expect-error invalid input type expect(parseHandlesFromHtml()).toEqual(EMPTY_RESULT); // @ts-expect-error invalid input type expect(parseHandlesFromHtml(undefined)).toEqual(EMPTY_RESULT); // @ts-expect-error invalid input type expect(parseHandlesFromHtml(null)).toEqual(EMPTY_RESULT); // @ts-expect-error invalid input type expect(parseHandlesFromHtml({})).toEqual(EMPTY_RESULT); // @ts-expect-error invalid input type expect(parseHandlesFromHtml(1234)).toEqual(EMPTY_RESULT); }); test('works', () => { expect(parseHandlesFromHtml('')).toEqual(EMPTY_RESULT); expect(parseHandlesFromHtml(' ')).toEqual(EMPTY_RESULT); const html = 'use the data in this [YouTube Video](https://www.youtube.com/watch?v=BsidLZKdYWQ).\\n\\n## Sample result\\n' + 'use the data in this [YouTube Video](https://www.youtube.com/watch?v=BsidLZKd123).\\\\n\\\\n## Sample result\\\\n'; expect(parseHandlesFromHtml(html)).toMatchObject({ youtubes: [ 'https://www.youtube.com/watch?v=BsidLZKd123', 'https://www.youtube.com/watch?v=BsidLZKdYWQ', ], }); expect( parseHandlesFromHtml(` Bla

bob@example.com

bob@example.com testing skipping duplicates xxx@blabla

carl@example.com

+420775222222 +4207751111111 +4207751111111 test duplicate 1 2 3 4 5 6 7 8 9 0 https://www.linkedin.com/in/bobnewman https://www.linkedin.com/in/alicenewman/ https://www.linkedin.com/in/alicenewman/ duplicate http://www.linkedin.com/in/nohttps/ https://cz.linkedin.com/in/somecountry https://www.linkedin.com/in/carl-newman/ignored-sub-link https://www.linkedin.com/in/first-last-123456a Profile Sub-link Company https://www.instagram.com/old_prague/ https://www.instagram.com/old_prague/ duplicate instagram.com/old_prague https://www.instagram.com/newyorkarea/ link sub-link link https://www.twitter.com/apify https://www.twitter.com/apify duplicate link link link link https://www.facebook.com/bob.username123/ https://www.facebook.com/bob.username123/ duplicate http://www.facebook.com/alice.username123 link x Youtube Youtube Channel link link Profile Most popular video m.tiktok.com/v/1234567890123456789 duplicate Profile Top pin My board pinterest.com/my_username My favourite pin duplicate Join us on Discord Join our Discord community
+4207751111111eva@example.com
`), ).toEqual({ discords: ['discord.gg/discord-developers', 'https://discord.com/invite/jyEM2PRvMU/'], emails: [ 'alice@example.com', 'bob@example.com', 'carl@example.com', 'david@example.com', 'eva@example.com', ], phones: ['+42077533333'], phonesUncertain: [ '+4207751111111', '+420775222222', // tiktok videos have purely numeric ids so this can't be avoided '123456789012345', ], linkedIns: [ 'http://www.linkedin.com/in/nohttps/', 'https://cz.linkedin.com/in/somecountry', 'https://www.linkedin.com/in/alicenewman/', 'https://www.linkedin.com/in/bobnewman', 'https://www.linkedin.com/in/carl-newman-5555555a/', 'https://www.linkedin.com/in/carl-newman/', 'https://www.linkedin.com/in/first-last-123456a', 'https://www.linkedin.com/in/jancurn', 'www.linkedin.com/company/delegatus', ], instagrams: [ 'https://www.instagram.com/newyorkarea/', 'https://www.instagram.com/old_prague/', 'https://www.instagram.com/york', 'https://www.instagram.com/york2/', 'instagram.com/old_prague', ], pinterests: [ 'https://pinterest.com/pin/10084556789', 'https://uk.pinterest.com/user/board/', 'https://www.pinterest.com/jack', 'pinterest.com/my_username', ], tiktoks: [ 'https://tiktok.com/@jack1234', 'https://www.tiktok.com/@username/video/1234567890123456789', 'https://www.tiktok.com/embed/1234567890123456789/', 'https://www.tiktok.com/trending?shareId=1234567890123456789/', 'm.tiktok.com/v/1234567890123456789', ], twitters: [ 'https://www.twitter.com/apify', 'twitter.com/betasomething', 'twitter.com/cblabla/', 'x.com/apify', 'x.com/cblabla/', ], facebooks: [ 'facebook.com/carl.username123/', 'fb.com/dada5678', 'fb.com/pages/page-name/142434434', 'http://www.facebook.com/alice.username123', 'https://www.facebook.com/bob.username123/', 'https://www.facebook.com/pages/category/category-name/page-name-and-ID/', 'https://www.facebook.com/profile.php?id=1155802082', ], youtubes: ['https://youtu.be/kM7YfhfkiEE', 'https://youtube.com/@channel'], }); }); test('data is set correctly', () => { const data = {} as any; parseHandlesFromHtml( ` Bla Body content `, data, ); expect(data.$('body').text().trim()).toBe('Body content'); expect(data.text.trim()).toBe('Body content'); }); }); describe('EMAIL_REGEX', () => { test('works', () => { expect(EMAIL_REGEX).toBeInstanceOf(RegExp); expect(EMAIL_REGEX_GLOBAL).toBeInstanceOf(RegExp); expect(EMAIL_REGEX.flags).toBe('i'); expect(EMAIL_REGEX_GLOBAL.flags).toBe('gi'); expect(EMAIL_REGEX.test('bob@example.com')).toBe(true); expect(EMAIL_REGEX.test('ALICE@EXAMPLE.COM')).toBe(true); expect(EMAIL_REGEX.test('bob+something@example.co.uk')).toBe(true); expect(EMAIL_REGEX.test('really.long.email.address@really.long.domain.name.travel')).toBe(true); expect(EMAIL_REGEX.test('really-long-email-address@really.long.domain.name.travel')).toBe(true); expect(EMAIL_REGEX.test('really_long_email_address@really.long.domain.name.travel')).toBe(true); expect(EMAIL_REGEX.test('a alice@example.com')).toBe(false); expect(EMAIL_REGEX.test('bob@example.com alice@example.com')).toBe(false); expect(EMAIL_REGEX.test('')).toBe(false); expect(EMAIL_REGEX.test('dummy')).toBe(false); expect(EMAIL_REGEX_GLOBAL.test('bob@example.com')).toBe(true); expect('bob@example.com alice@example.com'.match(EMAIL_REGEX_GLOBAL)).toEqual([ 'bob@example.com', 'alice@example.com', ]); expect(''.match(EMAIL_REGEX_GLOBAL)).toBe(null); expect(' dummy '.match(EMAIL_REGEX_GLOBAL)).toBe(null); }); }); describe('LINKEDIN_REGEX', () => { test('works', () => { expect(LINKEDIN_REGEX).toBeInstanceOf(RegExp); expect(LINKEDIN_REGEX_GLOBAL).toBeInstanceOf(RegExp); expect(LINKEDIN_REGEX.flags).toBe('i'); expect(LINKEDIN_REGEX_GLOBAL.flags).toBe('gi'); expect(LINKEDIN_REGEX.test('https://www.linkedin.com/in/bobnewman')).toBe(true); expect(LINKEDIN_REGEX.test('https://www.linkedin.com/in/bobnewman/')).toBe(true); expect(LINKEDIN_REGEX.test('http://www.linkedin.com/in/bobnewman')).toBe(true); expect(LINKEDIN_REGEX.test('http://ie.linkedin.com/in/bobnewman')).toBe(true); expect(LINKEDIN_REGEX.test('https://linkedin.com/in/bobnewman')).toBe(true); expect(LINKEDIN_REGEX.test('https://www.linkedin.com/in/carl-newman')).toBe(true); expect(LINKEDIN_REGEX.test('https://www.linkedin.com/in/first-last-123456a')).toBe(true); expect(LINKEDIN_REGEX.test('https://www.linkedin.com/in/first_last_1%23456a')).toBe(true); expect(LINKEDIN_REGEX.test('HTTPS://WWW.LINKEDIN.COM/IN/CARL-NEWMAN')).toBe(true); expect(LINKEDIN_REGEX.test('www.linkedin.com/in/bobnewman')).toBe(true); expect(LINKEDIN_REGEX.test('linkedin.com/in/bobnewman')).toBe(true); expect(LINKEDIN_REGEX.test('https://www.linkedin.com/in/alan-turing')).toBe(true); expect(LINKEDIN_REGEX.test('en.linkedin.com/in/alan-turing')).toBe(true); expect(LINKEDIN_REGEX.test('linkedin.com/in/alan-turing')).toBe(true); expect(LINKEDIN_REGEX.test('https://www.linkedin.com/company/delegatus')).toBe(true); // Test there is just on matching group for the username expect('https://www.linkedin.com/in/bobnewman/'.match(LINKEDIN_REGEX)![1]).toBe('bobnewman'); expect('http://www.linkedin.com/in/bobnewman'.match(LINKEDIN_REGEX)![1]).toBe('bobnewman'); expect('www.linkedin.com/in/bobnewman/'.match(LINKEDIN_REGEX)![1]).toBe('bobnewman'); expect('linkedin.com/in/bobnewman'.match(LINKEDIN_REGEX)![1]).toBe('bobnewman'); expect(LINKEDIN_REGEX.test('')).toBe(false); expect(LINKEDIN_REGEX.test('dummy')).toBe(false); expect(LINKEDIN_REGEX.test('a https://www.linkedin.com/in/bobnewman')).toBe(false); expect(LINKEDIN_REGEX.test('https://linkedin.com/in/bobnewman/sub-page')).toBe(false); expect(LINKEDIN_REGEX.test('xhttps://www.linkedin.com/in/carl-newman')).toBe(false); expect(LINKEDIN_REGEX.test('0https://www.linkedin.com/in/carl-newman')).toBe(false); expect(LINKEDIN_REGEX.test('_https://www.linkedin.com/in/carl-newman')).toBe(false); expect(LINKEDIN_REGEX.test('xlinkedin.com/in/bobnewman')).toBe(false); expect(LINKEDIN_REGEX.test('_linkedin.com/in/bobnewman')).toBe(false); expect(LINKEDIN_REGEX.test('0linkedin.com/in/bobnewman')).toBe(false); expect(LINKEDIN_REGEX.test('https://www.linkedin.com/in/bobnewman/?param=bla')).toBe(false); expect(LINKEDIN_REGEX.test('://linkedin.com/in/bobnewman')).toBe(false); expect(LINKEDIN_REGEX.test('https://www.linkedin.com/in/bob https://www.linkedin.com/in/alice')).toBe( false, ); expect(LINKEDIN_REGEX_GLOBAL.test('https://www.linkedin.com/in/bobnewman')).toBe(true); expect( ` https://www.linkedin.com/in/bobnewman "http://ie.linkedin.com/in/alicenewman" https://www.linkedin.com/in/someverylongnamesomeverylongnamesomeverylongnamesomeverylongnamesomeverylongnamesomeverylongname linkedin.com/in/carlnewman `.match(LINKEDIN_REGEX_GLOBAL), ).toEqual([ 'https://www.linkedin.com/in/bobnewman', 'http://ie.linkedin.com/in/alicenewman', 'linkedin.com/in/carlnewman', ]); expect( ` -https://www.linkedin.com/in/bobnewman/sub-dir :http://ie.linkedin.com/in/alicenewman?param=1 xlinkedin.com/in/carlnewman alinkedin.com/in/carlnewman _linkedin.com/in/carlnewman `.match(LINKEDIN_REGEX_GLOBAL), ).toEqual(['https://www.linkedin.com/in/bobnewman/', 'http://ie.linkedin.com/in/alicenewman']); expect(''.match(LINKEDIN_REGEX_GLOBAL)).toBe(null); }); }); describe('INSTAGRAM_REGEX', () => { test('works', () => { expect(INSTAGRAM_REGEX).toBeInstanceOf(RegExp); expect(INSTAGRAM_REGEX_GLOBAL).toBeInstanceOf(RegExp); expect(INSTAGRAM_REGEX.flags).toBe('i'); expect(INSTAGRAM_REGEX_GLOBAL.flags).toBe('gi'); expect(INSTAGRAM_REGEX.test('https://www.instagram.com/old_prague')).toBe(true); expect(INSTAGRAM_REGEX.test('https://www.instagram.com/old_prague/')).toBe(true); expect(INSTAGRAM_REGEX.test('http://www.instagram.com/old_prague/')).toBe(true); expect(INSTAGRAM_REGEX.test('https://instagram.com/old_prague/')).toBe(true); expect(INSTAGRAM_REGEX.test('HTTPS://INSTAGR.AM/OLD_PRAGUE/')).toBe(true); expect(INSTAGRAM_REGEX.test('http://instagr.am/old_prague/')).toBe(true); expect(INSTAGRAM_REGEX.test('https://www.instagr.am/old_prague/')).toBe(true); expect(INSTAGRAM_REGEX.test('www.instagram.com/old_prague/')).toBe(true); expect(INSTAGRAM_REGEX.test('instagram.com/old_prague/')).toBe(true); expect(INSTAGRAM_REGEX.test('www.instagr.am/old_prague/')).toBe(true); expect(INSTAGRAM_REGEX.test('instagr.am/old_prague/')).toBe(true); // Test there is just on matching group for the username expect('https://www.instagram.com/old_prague/'.match(INSTAGRAM_REGEX)![1]).toBe('old_prague'); expect('http://www.instagram.com/old_prague/'.match(INSTAGRAM_REGEX)![1]).toBe('old_prague'); expect('www.instagram.com/old_prague'.match(INSTAGRAM_REGEX)![1]).toBe('old_prague'); expect('instagram.com/old_prague'.match(INSTAGRAM_REGEX)![1]).toBe('old_prague'); expect(INSTAGRAM_REGEX.test('')).toBe(false); expect(INSTAGRAM_REGEX.test('dummy')).toBe(false); expect(INSTAGRAM_REGEX.test('a https://www.instagram.com/old_prague')).toBe(false); expect(INSTAGRAM_REGEX.test('https://www.instagram.com/a')).toBe(false); expect(INSTAGRAM_REGEX.test('https://www.instagram.com/old_prague/sub-page')).toBe(false); expect(INSTAGRAM_REGEX.test('xhttps://www.instagram.com/old_prague')).toBe(false); expect(INSTAGRAM_REGEX.test('0https://www.instagram.com/old_prague')).toBe(false); expect(INSTAGRAM_REGEX.test('_https://www.instagram.com/old_prague')).toBe(false); expect(INSTAGRAM_REGEX.test('xinstagram.com/old_prague')).toBe(false); expect(INSTAGRAM_REGEX.test('_instagram.com/old_prague')).toBe(false); expect(INSTAGRAM_REGEX.test('0instagram.com/old_prague')).toBe(false); expect(social.INSTAGRAM_REGEX.test('https://www.instagram.com/explore/')).toBe(false); expect(social.INSTAGRAM_REGEX.test('https://www.instagram.com/_n/')).toBe(false); expect(social.INSTAGRAM_REGEX.test('https://www.instagram.com/_u/')).toBe(false); expect(INSTAGRAM_REGEX.test('https://www.instagram.com/old_prague/?param=bla')).toBe(false); expect(INSTAGRAM_REGEX.test('://www.instagram.com/old_prague')).toBe(false); expect(INSTAGRAM_REGEX.test('http://www.instagram.com/old_prague http://www.instagram.com/old_brno')).toBe( false, ); expect(INSTAGRAM_REGEX_GLOBAL.test('https://www.instagram.com/old_prague')).toBe(true); expect( ` https://www.instagram.com/old_prague https://www.instagram.com/someverylongusernamethatisnotgood "instagram.com/old_brno" http://instagr.am/old_plzen `.match(INSTAGRAM_REGEX_GLOBAL), ).toEqual([ 'https://www.instagram.com/old_prague', 'instagram.com/old_brno', 'http://instagr.am/old_plzen', ]); expect( ` -https://www.instagram.com/old_prague/sub-dir instagr.am/old_plzen?param=1 xinstagram.com/old_brno ainstagram.com/old_brno _instagram.com/old_brno `.match(INSTAGRAM_REGEX_GLOBAL), ).toEqual(['https://www.instagram.com/old_prague/', 'instagr.am/old_plzen']); expect(''.match(INSTAGRAM_REGEX_GLOBAL)).toBe(null); }); }); describe('TWITTER_REGEX', () => { test('works', () => { expect(TWITTER_REGEX).toBeInstanceOf(RegExp); expect(TWITTER_REGEX_GLOBAL).toBeInstanceOf(RegExp); expect(TWITTER_REGEX.flags).toBe('i'); expect(TWITTER_REGEX_GLOBAL.flags).toBe('gi'); expect(TWITTER_REGEX.test('https://www.twitter.com/apify')).toBe(true); expect(TWITTER_REGEX.test('https://www.twitter.com/apify/')).toBe(true); expect(TWITTER_REGEX.test('https://www.twitter.com/aa_bb_123')).toBe(true); expect(TWITTER_REGEX.test('http://www.twitter.com/apify')).toBe(true); expect(TWITTER_REGEX.test('https://twitter.com/apify')).toBe(true); expect(TWITTER_REGEX.test('http://twitter.com/apify')).toBe(true); expect(TWITTER_REGEX.test('www.twitter.com/apify')).toBe(true); expect(TWITTER_REGEX.test('twitter.com/apify')).toBe(true); expect(TWITTER_REGEX.test('https://www.x.com/apify')).toBe(true); expect(TWITTER_REGEX.test('https://www.x.com/@apify')).toBe(true); expect(TWITTER_REGEX.test('https://www.x.com/aa_bb_123')).toBe(true); expect(TWITTER_REGEX.test('x.com/apify')).toBe(true); // Test there is just on matching group for the username expect('https://www.twitter.com/apify/'.match(TWITTER_REGEX)![1]).toBe('apify'); expect('http://www.twitter.com/apify'.match(TWITTER_REGEX)![1]).toBe('apify'); expect('www.twitter.com/apify'.match(TWITTER_REGEX)![1]).toBe('apify'); expect('twitter.com/apify'.match(TWITTER_REGEX)![1]).toBe('apify'); expect('https://www.x.com/apify/'.match(TWITTER_REGEX)![1]).toBe('apify'); expect('http://www.x.com/@apify'.match(TWITTER_REGEX)![1]).toBe('apify'); expect(TWITTER_REGEX.test('')).toBe(false); expect(TWITTER_REGEX.test('dummy')).toBe(false); expect(TWITTER_REGEX.test('a https://www.twitter.com/apify')).toBe(false); expect(TWITTER_REGEX.test('https://www.twitter.com/apify/sub-page')).toBe(false); expect(TWITTER_REGEX.test('xhttps://www.twitter.com/apify')).toBe(false); expect(TWITTER_REGEX.test('0https://www.twitter.com/apify')).toBe(false); expect(TWITTER_REGEX.test('_https://www.twitter.com/apify')).toBe(false); expect(TWITTER_REGEX.test('xtwitter.com/apify')).toBe(false); expect(TWITTER_REGEX.test('_twitter.com/apify')).toBe(false); expect(TWITTER_REGEX.test('0twitter.com/apify')).toBe(false); expect(TWITTER_REGEX.test('https://www.twitter.com/apify?param=bla')).toBe(false); expect(TWITTER_REGEX.test('://www.twitter.com/apify')).toBe(false); expect(TWITTER_REGEX.test('https://www.twitter.com/apify https://www.twitter.com/jack')).toBe(false); expect(TWITTER_REGEX.test('https://www.twitter.com/oauth')).toBe(false); expect(TWITTER_REGEX.test('https://www.twitter.com/account')).toBe(false); expect(TWITTER_REGEX.test('https://www.twitter.com/privacy/')).toBe(false); expect(TWITTER_REGEX_GLOBAL.test('https://x.com/i/flow/login')).toBe(false); expect(TWITTER_REGEX_GLOBAL.test('https://business.x.com/en')).toBe(false); expect(TWITTER_REGEX_GLOBAL.test('https://x.com/privacy')).toBe(false); expect(TWITTER_REGEX_GLOBAL.test('https://help.x.com/en/using-x/download-the-x-app')).toBe(false); expect(TWITTER_REGEX_GLOBAL.test('https://careers.x.com/en')).toBe(false); expect(TWITTER_REGEX_GLOBAL.test('https://developer.x.com/en')).toBe(false); expect(TWITTER_REGEX_GLOBAL.test('https://x.com/i/directory/profiles')).toBe(false); expect(TWITTER_REGEX_GLOBAL.test('https://x.com/settings/account/personalization')).toBe(false); expect(TWITTER_REGEX_GLOBAL.test('https://x.com/explore')).toBe(false); expect(TWITTER_REGEX_GLOBAL.test('https://x.com/i/premium_sign_up')).toBe(false); expect(TWITTER_REGEX_GLOBAL.test('https://x.com/compose/post')).toBe(false); expect(TWITTER_REGEX_GLOBAL.test('https://www.twitter.com/apify')).toBe(true); expect( ` https://www.twitter.com/apify www.twitter.com/jack/sub-dir www.twitter.com/invalidverylongtwitterhandlenotgood twitter.com/bob123?param=1 www.x.com/apify/sub-dir `.match(TWITTER_REGEX_GLOBAL), ).toEqual([ 'https://www.twitter.com/apify', 'www.twitter.com/jack/', 'twitter.com/bob123', 'www.x.com/apify/', ]); expect( ` -https://www.twitter.com/apify twitter.com/jack twitter.com/carl123 xtwitter.com/bob atwitter.com/bob _twitter.com/bob `.match(TWITTER_REGEX_GLOBAL), ).toEqual(['https://www.twitter.com/apify', 'twitter.com/jack', 'twitter.com/carl123']); expect(''.match(TWITTER_REGEX_GLOBAL)).toBe(null); }); }); describe('FACEBOOK_REGEX', () => { test('works', () => { expect(FACEBOOK_REGEX).toBeInstanceOf(RegExp); expect(FACEBOOK_REGEX_GLOBAL).toBeInstanceOf(RegExp); expect(FACEBOOK_REGEX.flags).toBe('i'); expect(FACEBOOK_REGEX_GLOBAL.flags).toBe('gi'); expect(FACEBOOK_REGEX.test('https://www.facebook.com/someusername')).toBe(true); expect(FACEBOOK_REGEX.test('https://www.facebook.com/someusername/')).toBe(true); expect(FACEBOOK_REGEX.test('https://www.facebook.com/some-username-1234')).toBe(true); expect(FACEBOOK_REGEX.test('https://www.facebook.com/some-username-1234/')).toBe(true); expect(FACEBOOK_REGEX.test('http://www.facebook.com/some.username123')).toBe(true); expect(FACEBOOK_REGEX.test('www.facebook.com/someusername')).toBe(true); expect(FACEBOOK_REGEX.test('facebook.com/someusername')).toBe(true); expect(FACEBOOK_REGEX.test('https://www.fb.com/someusername')).toBe(true); expect(FACEBOOK_REGEX.test('https://www.fb.com/someusername/')).toBe(true); expect(FACEBOOK_REGEX.test('http://www.fb.com/some.username123')).toBe(true); expect(FACEBOOK_REGEX.test('www.fb.com/someusername')).toBe(true); expect(FACEBOOK_REGEX.test('fb.com/someusername')).toBe(true); expect(FACEBOOK_REGEX.test('https://www.facebook.com/profile.php?id=1155802082')).toBe(true); expect(FACEBOOK_REGEX.test('http://www.facebook.com/profile.php?id=1155802082')).toBe(true); expect(FACEBOOK_REGEX.test('www.facebook.com/profile.php?id=1155802082')).toBe(true); expect(FACEBOOK_REGEX.test('facebook.com/profile.php?id=1155802082')).toBe(true); expect(FACEBOOK_REGEX.test('fb.com/profile.php?id=1155802082')).toBe(true); expect(FACEBOOK_REGEX.test('https://www.facebook.com/pageName')).toBe(true); expect(FACEBOOK_REGEX.test('https://www.facebook.com/pages/KinEssor-Groupe-Conseil/208264345877578')).toBe( true, ); expect( FACEBOOK_REGEX.test( 'https://www.facebook.com/pages/category/Lawyer---Law-Firm/Delegatus-services-juridiques-inc-131011223614905/', ), ).toBe(true); // Test there is just on matching group for the username expect('https://www.facebook.com/someusername/'.match(FACEBOOK_REGEX)![1]).toBe('someusername'); expect('https://www.facebook.com/someusername'.match(FACEBOOK_REGEX)![1]).toBe('someusername'); expect('https://www.facebook.com/profile.php?id=1155802082'.match(FACEBOOK_REGEX)![1]).toBe( 'profile.php?id=1155802082', ); expect('fb.com/someusername'.match(FACEBOOK_REGEX)![1]).toBe('someusername'); expect('facebook.com/pages/KinEssor-Groupe-Conseil/208264345877578'.match(FACEBOOK_REGEX)![1]).toBe( 'pages/KinEssor-Groupe-Conseil/208264345877578', ); expect(FACEBOOK_REGEX.test('')).toBe(false); expect(FACEBOOK_REGEX.test('dummy')).toBe(false); expect(FACEBOOK_REGEX.test('a https://www.facebook.com/someusername')).toBe(false); expect(FACEBOOK_REGEX.test('https://www.facebook.com/a')).toBe(false); expect(FACEBOOK_REGEX.test('https://www.facebook.com/someusername/sub-page')).toBe(false); expect(FACEBOOK_REGEX.test('http://www.facebook.com/profile.php')).toBe(false); expect(FACEBOOK_REGEX.test('xhttps://www.facebook.com/someusername')).toBe(false); expect(FACEBOOK_REGEX.test('0https://www.facebook.com/someusername')).toBe(false); expect(FACEBOOK_REGEX.test('_https://www.facebook.com/someusername')).toBe(false); expect(FACEBOOK_REGEX.test('xfacebook.com/someusername')).toBe(false); expect(FACEBOOK_REGEX.test('_facebook.com/someusername')).toBe(false); expect(FACEBOOK_REGEX.test('0facebook.com/someusername')).toBe(false); expect(FACEBOOK_REGEX.test('https://www.facebook.com/someusername?param=bla')).toBe(false); expect(FACEBOOK_REGEX.test('://www.facebook.com/someusername')).toBe(false); expect(FACEBOOK_REGEX.test('https://www.facebook.com/someusername https://www.facebook.com/jack')).toBe( false, ); expect(FACEBOOK_REGEX.test('https://www.facebook.com/groups')).toBe(false); expect(FACEBOOK_REGEX.test('https://www.facebook.com/events')).toBe(false); expect(FACEBOOK_REGEX.test('https://www.facebook.com/policies/')).toBe(false); expect(FACEBOOK_REGEX.test('https://www.facebook.com/pages')).toBe(false); expect(FACEBOOK_REGEX.test('https://www.facebook.com/pages/')).toBe(false); expect(FACEBOOK_REGEX.test('https://www.facebook.com/pages/?category=liked&ref=bookmarks')).toBe(false); expect(FACEBOOK_REGEX.test('https://www.facebook.com/pages/merge')).toBe(false); expect(FACEBOOK_REGEX.test('https://www.facebook.com/pages/search')).toBe(false); expect(FACEBOOK_REGEX.test('https://www.facebook.com/pages/create')).toBe(false); expect(FACEBOOK_REGEX.test('https://www.facebook.com/pages/createCustomWebsiteName')).toBe(true); expect(FACEBOOK_REGEX_GLOBAL.test('https://www.facebook.com/someusername')).toBe(true); expect( ` https://www.facebook.com/someusername?param=123 www.facebook.com/another123/sub-dir www.facebook.com/pages/ facebook.com/pages/some-page https://www.facebook.com/waytoolongusernamewaytoolongusernamewaytoolongusernamewaytoolongusernamewaytoolongusername fb.com/bob123 `.match(FACEBOOK_REGEX_GLOBAL), ).toEqual([ 'https://www.facebook.com/someusername', 'www.facebook.com/another123/', 'facebook.com/pages/some-page', 'fb.com/bob123', ]); expect( ` -https://www.facebook.com/someusername/ facebook.com/jack4567 fb.com/carl123 xfacebook.com/bob afacebook.com/bob _facebook.com/bob `.match(FACEBOOK_REGEX_GLOBAL), ).toEqual(['https://www.facebook.com/someusername/', 'facebook.com/jack4567', 'fb.com/carl123']); expect(''.match(FACEBOOK_REGEX_GLOBAL)).toBe(null); }); }); describe('YOUTUBE_REGEX', () => { it('works', () => { expect(YOUTUBE_REGEX).toBeInstanceOf(RegExp); expect(YOUTUBE_REGEX_GLOBAL).toBeInstanceOf(RegExp); expect(YOUTUBE_REGEX.flags).toBe('i'); expect(YOUTUBE_REGEX_GLOBAL.flags).toBe('gi'); expect(''.match(social.YOUTUBE_REGEX_GLOBAL)).toBe(null); expect(' dummy '.match(social.YOUTUBE_REGEX_GLOBAL)).toBe(null); expect(YOUTUBE_REGEX.test('https://www.youtube.com/watch?v=kM7YfhfkiEE')).toBe(true); expect(YOUTUBE_REGEX.test('https://youtu.be/kM7YfhfkiEE')).toBe(true); expect(YOUTUBE_REGEX.test('https://www.youtube.com/c/TrapNation')).toBe(true); expect(YOUTUBE_REGEX.test('https://www.youtube.com/channel/UCklie6BM0fhFvzWYqQVoCTA')).toBe(true); expect(YOUTUBE_REGEX.test('https://www.youtube.com/user/pewdiepie')).toBe(true); expect(YOUTUBE_REGEX.test('https://www.youtube.com/linkinpark')).toBe(true); expect(YOUTUBE_REGEX.test('https://www.youtube.com/@LinkinPark')).toBe(true); expect(YOUTUBE_REGEX.test('https://www.youtube.com/c/@TrapNation')).toBe(true); expect(YOUTUBE_REGEX.test('https://www.youtube.com/user/@PewDiePie')).toBe(false); expect(YOUTUBE_REGEX.test('https://www.youtube.com/channel/@TrapNation')).toBe(false); expect(YOUTUBE_REGEX.test('https://youtu.be/@kM7YfhfkiEE')).toBe(false); expect(YOUTUBE_REGEX.test('://www.youtube.com/c/TrapNation')).toBe(false); expect(YOUTUBE_REGEX.test('https://youtu.be/kM7YfhfkiEE https://www.youtube.com/user/pewdiepie')).toBe( false, ); expect(YOUTUBE_REGEX.test('xyoutu.be/kM7YfhfkiEE')).toBe(false); expect(YOUTUBE_REGEX.test('-https://www.youtube.com/user/pewdiepie')).toBe(false); // Test there is just on matching group for the channel, video or username expect('https://www.youtube.com/watch?v=kM7YfhfkiEE'.match(social.YOUTUBE_REGEX)![1]).toBe('kM7YfhfkiEE'); expect('https://youtu.be/kM7YfhfkiEE'.match(social.YOUTUBE_REGEX)![1]).toBe('kM7YfhfkiEE'); expect('https://www.youtube.com/c/TrapNation'.match(social.YOUTUBE_REGEX)![1]).toBe('TrapNation'); expect('https://www.youtube.com/channel/UCklie6BM0fhFvzWYqQVoCTA'.match(social.YOUTUBE_REGEX)![1]).toBe( 'UCklie6BM0fhFvzWYqQVoCTA', ); expect('https://www.youtube.com/user/pewdiepie'.match(social.YOUTUBE_REGEX)![1]).toBe('pewdiepie'); expect( ` https://www.youtube.com/apify/ -https://www.youtube.com/someusername/ youtube.com/jack4567 https://www.youtube.com/watch?v=kM7YfhfkiEE byoutube.com/bob ayoutube.com/bob _youtube.com/bob www.youtube.com/c/TrapNation https://www.youtube.com/channel/UCklie6BM0fhFvzWYqQVoCTA youtube.com/user/pewdiepie www.youtube.com/@LinkinPark youtube.com/linkinpark `.match(YOUTUBE_REGEX_GLOBAL), ).toEqual([ 'https://www.youtube.com/apify', 'https://www.youtube.com/someusername', 'youtube.com/jack4567', 'https://www.youtube.com/watch?v=kM7YfhfkiEE', 'www.youtube.com/c/TrapNation', 'https://www.youtube.com/channel/UCklie6BM0fhFvzWYqQVoCTA', 'youtube.com/user/pewdiepie', 'www.youtube.com/@LinkinPark', 'youtube.com/linkinpark', ]); }); }); describe('TIKTOK_REGEX', () => { it('works', () => { expect(TIKTOK_REGEX).toBeInstanceOf(RegExp); expect(TIKTOK_REGEX_GLOBAL).toBeInstanceOf(RegExp); expect(TIKTOK_REGEX.flags).toBe('i'); expect(TIKTOK_REGEX_GLOBAL.flags).toBe('gi'); expect(''.match(TIKTOK_REGEX_GLOBAL)).toBe(null); expect(' dummy '.match(TIKTOK_REGEX_GLOBAL)).toBe(null); expect(TIKTOK_REGEX.test('https://www.tiktok.com/trending?shareId=123456789')).toBe(true); expect(TIKTOK_REGEX.test('https://www.tiktok.com/embed/123456789')).toBe(true); expect(TIKTOK_REGEX.test('https://m.tiktok.com/v/123456789')).toBe(true); expect(TIKTOK_REGEX.test('https://www.tiktok.com/@user')).toBe(true); expect(TIKTOK_REGEX.test('https://www.tiktok.com/@user/video/123456789')).toBe(true); expect(TIKTOK_REGEX.test('_https://www.tiktok.com/trending?shareId=123456789')).toBe(false); expect(TIKTOK_REGEX.test('xtiktok.com/embed/123456789/')).toBe(false); expect(TIKTOK_REGEX.test('_pinterest.com/someusername')).toBe(false); expect(TIKTOK_REGEX.test('0https://www.tiktok.com/trending?shareId=123456789')).toBe(false); // Test there is just one matching group for video id or username expect('https://www.tiktok.com/trending?shareId=123456789'.match(TIKTOK_REGEX)![1]).toBe( 'trending?shareId=123456789', ); expect('www.tiktok.com/embed/123456789/'.match(TIKTOK_REGEX)![1]).toBe('embed/123456789'); expect('tiktok.com/@jack'.match(TIKTOK_REGEX)![1]).toBe('@jack'); expect('https://www.tiktok.com/@username/video/123456789'.match(TIKTOK_REGEX)![1]).toBe( '@username/video/123456789', ); expect( ` https://www.tiktok.com/trending?shareId=123456789 www.tiktok.com/embed/123456789/ m.tiktok.com/v/123456789 tiktok.com/@user https://www.tiktok.com/@username/video/123456789 -https://www.tiktok.com/@username/video/82347868 atiktok.com/embed/123456789/ _tiktok.com/embed/123456789/ www.tiktok.com/embed/nonNumericVideoId https://www.tiktok.com/@jack1234/invalidSubpath/ https://www.tiktok.com/trending?shareId=1234567898904582904537057328079034789063454432789054378 https://www.tiktok.com/@userWithLongVideoName/video/123456789890458290453705732807903478904327890543654645365478 `.match(TIKTOK_REGEX_GLOBAL), ).toEqual([ 'https://www.tiktok.com/trending?shareId=123456789', 'www.tiktok.com/embed/123456789/', 'm.tiktok.com/v/123456789', 'tiktok.com/@user', 'https://www.tiktok.com/@username/video/123456789', 'https://www.tiktok.com/@username/video/82347868', 'https://www.tiktok.com/@jack1234/', 'https://www.tiktok.com/@userWithLongVideoName/', ]); }); }); describe('PINTEREST_REGEX', () => { it('works', () => { expect(PINTEREST_REGEX).toBeInstanceOf(RegExp); expect(PINTEREST_REGEX_GLOBAL).toBeInstanceOf(RegExp); expect(PINTEREST_REGEX.flags).toBe('i'); expect(PINTEREST_REGEX_GLOBAL.flags).toBe('gi'); expect(''.match(PINTEREST_REGEX_GLOBAL)).toBe(null); expect(' dummy '.match(PINTEREST_REGEX_GLOBAL)).toBe(null); expect(PINTEREST_REGEX.test('https://pinterest.com/pin/123456789')).toBe(true); expect(PINTEREST_REGEX.test('https://www.pinterest.cz/pin/123456789')).toBe(true); expect(PINTEREST_REGEX.test('https://www.pinterest.com/user')).toBe(true); expect(PINTEREST_REGEX.test('https://www.pinterest.co.uk/user')).toBe(true); expect(PINTEREST_REGEX.test('pinterest.com/user_name.gold')).toBe(true); expect(PINTEREST_REGEX.test('https://cz.pinterest.com/user/board')).toBe(true); expect(PINTEREST_REGEX.test('_https://pinterest.com/pin/123456789')).toBe(false); expect(PINTEREST_REGEX.test('xpinterest.com/user_name.gold')).toBe(false); expect(PINTEREST_REGEX.test('_pinterest.com/someusername')).toBe(false); expect(PINTEREST_REGEX.test('0pinterest.com/someusername')).toBe(false); // Test there is just on matching group for the pin, board or username expect('https://pinterest.com/pin/123456789'.match(PINTEREST_REGEX)![1]).toBe('pin/123456789'); expect('https://www.pinterest.com/username'.match(PINTEREST_REGEX)![1]).toBe('username'); expect('pinterest.com/user_name.gold'.match(PINTEREST_REGEX)![1]).toBe('user_name.gold'); expect('https://cz.pinterest.com/username/board'.match(PINTEREST_REGEX)![1]).toBe('username/board'); expect( ` https://pinterest.com/pin/123456789 -https://pinterest.com/pin/10084556789/ https://www.pinterest.cz/pin/123456789 https://www.pinterest.com/user https://uk.pinterest.com/user https://www.pinterest.co.uk/user pinterest.com/user_name.gold https://cz.pinterest.com/user/board https://www.pinterest.cz/pin/nonNumericPinId `.match(PINTEREST_REGEX_GLOBAL), ).toEqual([ 'https://pinterest.com/pin/123456789', 'https://pinterest.com/pin/10084556789/', 'https://www.pinterest.cz/pin/123456789', 'https://www.pinterest.com/user', 'https://uk.pinterest.com/user', 'https://www.pinterest.co.uk/user', 'pinterest.com/user_name.gold', 'https://cz.pinterest.com/user/board', ]); }); }); describe('DISCORD_REGEX', () => { it('works', () => { expect(DISCORD_REGEX).toBeInstanceOf(RegExp); expect(DISCORD_REGEX_GLOBAL).toBeInstanceOf(RegExp); expect(DISCORD_REGEX.flags).toBe('i'); expect(DISCORD_REGEX_GLOBAL.flags).toBe('gi'); expect(''.match(DISCORD_REGEX_GLOBAL)).toBe(null); expect(' dummy '.match(DISCORD_REGEX_GLOBAL)).toBe(null); expect(DISCORD_REGEX.test('https://discord.gg/discord-developers')).toBe(true); expect(DISCORD_REGEX.test('https://discord.com/invite/jyEM2PRvMU')).toBe(true); expect(DISCORD_REGEX.test('https://discordapp.com/channels/231496023303957476')).toBe(true); expect(DISCORD_REGEX.test('https://discord.com/channels/231496023303957476/2332823543826404586')).toBe( true, ); expect(DISCORD_REGEX.test('https://ptb.discord.com/channels/231496023303957476/2332823543826404586')).toBe( true, ); expect(DISCORD_REGEX.test('ptb.discord.com/invite/jyEM2PRvMU')).toBe(true); expect(DISCORD_REGEX.test('canary.discord.com/invite/jyEM2PRvMU')).toBe(true); expect(DISCORD_REGEX.test('https://discord.com/channels/nonNumbericChannelId')).toBe(false); expect(DISCORD_REGEX.test('9discord.gg/discord-developers')).toBe(false); expect(DISCORD_REGEX.test('-discordapp.com/channels/231496023303957476/')).toBe(false); // Test there is just on matching group for the channel or invite (matches discord.* / discordapp.* prefix as well as they differ) expect('https://discord.gg/discord-developers'.match(DISCORD_REGEX)![1]).toBe( 'discord.gg/discord-developers', ); expect('https://discord.com/invite/jyEM2PRvMU'.match(DISCORD_REGEX)![1]).toBe( 'discord.com/invite/jyEM2PRvMU', ); expect('https://discordapp.com/channels/231496023303957476'.match(DISCORD_REGEX)![1]).toBe( 'discordapp.com/channels/231496023303957476', ); expect('https://discord.com/channels/231496023303957476/2332823543826404586'.match(DISCORD_REGEX)![1]).toBe( 'discord.com/channels/231496023303957476/2332823543826404586', ); expect( ` https://discord.gg/discord-developers/ https://discord.com/invite/jyEM2PRvMU -https://discordapp.com/channels/231496023303957476/ https://discord.com/channels/231496023303957476/2332823543826404586 discord.gg/discord-developers https://discordapp.com/channels/nonNumbericChannelId `.match(DISCORD_REGEX_GLOBAL), ).toEqual([ 'https://discord.gg/discord-developers/', 'https://discord.com/invite/jyEM2PRvMU', 'https://discordapp.com/channels/231496023303957476/', 'https://discord.com/channels/231496023303957476/2332823543826404586', 'discord.gg/discord-developers', ]); }); }); });