Skip to content

Commit

Permalink
Merge pull request #9 from sjdonado/feat/#7-parse-mobile-links
Browse files Browse the repository at this point in the history
Feat/#7 parse mobile links
  • Loading branch information
sjdonado authored Oct 19, 2023
2 parents 3af9156 + f108b9f commit 1ce83dc
Show file tree
Hide file tree
Showing 13 changed files with 600 additions and 77 deletions.
Binary file modified bun.lockb
Binary file not shown.
5 changes: 4 additions & 1 deletion src/config/constants.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
export const SPOTIFY_LINK_REGEX =
/^https:\/\/open\.spotify\.com\/(track|album|playlist|artist|episode|show)\/.*$/;
/^https:\/\/(open\.spotify\.com\/(track|album|playlist|artist|episode|show)|spotify\.link)\/[^?#]+/;

export const SPOTIFY_LINK_MOBILE_REGEX = /^https:\/\/spotify\.link\/.*$/;
export const SPOTIFY_LINK_DESKTOP_REGEX = /https:\/\/open\.spotify\.com\/[^?]+/;

export const SPOTIFY_ID_REGEX =
/(?<=\/(track|album|playlist|artist|episode|show)\/)[^/?]+/;
6 changes: 2 additions & 4 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,9 @@ import { pageRouter } from './routes/page';
export const app = new Elysia()
.use(html())
.use(staticPlugin({ prefix: '' }))
.on('beforeHandle', ({ request }) => {
.on('beforeHandle', async ({ request }) => {
logger.info(
`${request.method} ${request.url} - ${request.headers.get('user-agent')} - ${
request.body ? JSON.stringify(request.body) : 'no body'
}`
`${request.method} ${request.url} - ${request.headers.get('user-agent')}`
);
})
.use(apiRouter)
Expand Down
33 changes: 26 additions & 7 deletions src/parsers/spotify.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
import axios from 'axios';
import {
SPOTIFY_LINK_DESKTOP_REGEX,
SPOTIFY_LINK_MOBILE_REGEX,
} from '~/config/constants';

import { getCheerioDoc, metaTagContent } from '~/utils/scraper';

Expand All @@ -21,9 +25,21 @@ export type SpotifyMetadata = {

export const parseSpotifyMetadata = async (
spotifyLink: string
): Promise<SpotifyMetadata> => {
): Promise<{ metadata: SpotifyMetadata; url: string }> => {
try {
const { data: html } = await axios.get(spotifyLink);
let url = spotifyLink;
let { data: html } = await axios.get(url, { maxRedirects: 3 });

if (SPOTIFY_LINK_MOBILE_REGEX.test(spotifyLink)) {
url = html.match(SPOTIFY_LINK_DESKTOP_REGEX)?.[0];

if (!url) {
throw new Error(`Could not parse Spotify metadata. Desktop link not found.`);
}

html = (await axios.get(url)).data;
}

const doc = getCheerioDoc(html);

const title = metaTagContent(doc, 'og:title', 'property');
Expand All @@ -40,11 +56,14 @@ export const parseSpotifyMetadata = async (
}

return {
title,
description,
type: type as SpotifyMetadataType,
image,
audio,
metadata: {
title,
description,
type: type as SpotifyMetadataType,
image,
audio,
},
url,
};
} catch (err) {
throw new Error(`[Spotify Parser] (${spotifyLink}) ${err}`);
Expand Down
10 changes: 6 additions & 4 deletions src/routes/api.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { Elysia } from 'elysia';

import { logger } from '~/utils/logger';
import { searchPayloadValidator } from '~/validations/search';

import { apiVersionValidator, searchPayloadValidator } from '~/validations/search';

import { spotifySearch } from '~/services/search';

Expand All @@ -15,15 +16,16 @@ export const apiRouter = new Elysia().group('/api', app =>
message: error.message,
};
})
.get(
.post(
'/search',
async ({ query: { spotifyLink } }) => {
async ({ body: { spotifyLink } }) => {
const spotifyContent = await spotifySearch(spotifyLink);

return spotifyContent;
},
{
query: searchPayloadValidator,
body: searchPayloadValidator,
query: apiVersionValidator,
}
)
);
2 changes: 1 addition & 1 deletion src/routes/page.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Elysia } from 'elysia';

import { logger } from '~/utils/logger';

import { searchPayloadValidator } from '~/validations/search';

import { spotifySearch } from '~/services/search';
Expand All @@ -17,7 +18,6 @@ export const pageRouter = new Elysia()
logger.error(error);

set.status = 200;

return <ErrorMessage />;
})
.get('/', async () => {
Expand Down
10 changes: 5 additions & 5 deletions src/services/search.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,17 +38,17 @@ export interface SpotifyContent {
}

export const spotifySearch = async (spotifyLink: string): Promise<SpotifyContent> => {
const metadata = await parseSpotifyMetadata(spotifyLink);
const { metadata, url } = await parseSpotifyMetadata(spotifyLink);

const id = (spotifyLink.match(SPOTIFY_ID_REGEX) ?? [])[0]!;
const id = (url.match(SPOTIFY_ID_REGEX) ?? [])[0]!;

logger.info(`Searching for: ${id}`);
logger.info(`Searching for: ${url}`);

const cache = await getSpotifySearchFromCache(id);
if (cache) {
await incrementSearchCount();

logger.info(`Found in cache: ${id}`);
logger.info(`Found in cache: ${url} - ${id}`);

return cache;
}
Expand Down Expand Up @@ -85,7 +85,7 @@ export const spotifySearch = async (spotifyLink: string): Promise<SpotifyContent
description: metadata.description,
image: metadata.image,
audio: metadata.audio,
source: spotifyLink,
source: url,
links,
};

Expand Down
7 changes: 6 additions & 1 deletion src/utils/logger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,9 @@ export const stream = pretty({
colorize: true,
});

export const logger = pino(stream);
export const logger = pino(
{
level: process.env.NODE_ENV === 'test' ? 'fatal' : 'info',
},
stream
);
11 changes: 9 additions & 2 deletions src/validations/search.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
import { t } from 'elysia';

import { SPOTIFY_ID_REGEX } from '~/config/constants';
import { SPOTIFY_LINK_REGEX } from '~/config/constants';

export const searchPayloadValidator = t.Object({
spotifyLink: t.RegExp(SPOTIFY_ID_REGEX, { error: 'Invalid spotify link' }),
spotifyLink: t.RegExp(SPOTIFY_LINK_REGEX, { error: 'Invalid spotify link' }),
});

export const apiVersionValidator = t.Object({
v: t.String({
pattern: '1.3',
error: 'Unsupported API version',
}),
});
Loading

0 comments on commit 1ce83dc

Please sign in to comment.