Skip to content

Commit

Permalink
add title automatically
Browse files Browse the repository at this point in the history
  • Loading branch information
codegod100 committed Oct 27, 2024
1 parent c9266ab commit 08a69ed
Show file tree
Hide file tree
Showing 6 changed files with 272 additions and 39 deletions.
8 changes: 6 additions & 2 deletions packages/frontpage/app/(app)/post/new/_client.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { Input } from "@/lib/components/ui/input";
import { Button } from "@/lib/components/ui/button";
import { Alert, AlertDescription, AlertTitle } from "@/lib/components/ui/alert";
import { Spinner } from "@/lib/components/ui/spinner";
import { grabTitle } from "@/lib/utils";
import {
MAX_POST_TITLE_LENGTH,
MAX_POST_URL_LENGTH,
Expand Down Expand Up @@ -51,8 +52,11 @@ export function NewPostForm() {
id={`${id}-url`}
type="url"
value={url}
onChange={(e) => {
setUrl(e.currentTarget.value);
onChange={async (e) => {
let url = e.currentTarget.value
const title = await grabTitle(url)
setTitle(title)
setUrl(url);
}}
/>
<InputLengthIndicator
Expand Down
10 changes: 10 additions & 0 deletions packages/frontpage/app/api/title/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { badRequest, createApiRoute } from "@/lib/api-route";
import articleTitle from "@/lib/title"
export const GET = createApiRoute(async (request) => {
const url = new URL(request.url);
const remote_url = url.searchParams.get("url")!;
const response = await fetch(remote_url)
const body = await response.text()
const title: string = articleTitle(body)
return title
});
54 changes: 54 additions & 0 deletions packages/frontpage/lib/title.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// https://github.com/sindresorhus/article-title/blob/main/index.js
// slightly modified because import style
// MIT license
import * as cheerio from 'cheerio';

const matchers = [
'.instapaper_title',
'article h1',
'.entry-content h1',
'.markdown-body h1',
'.entry-title',
'.post-title',
'.pageTitle',
'.post_title',
'.headline h1',
'.headline',
'.story h1',
'.entry-header h1',
'.news_title',
'#page-post h1',
'.postheader h1',
'.postheader h2',
'.type-post h1',
];

const clean = string => string.replace(/\r?\n/g, '').replace(/\s+/g, ' ').trim();

const findSelectorMatch = $ => {
for (const matcher of matchers) {
const element = $(matcher).first().text().trim();

if (element && element.length > 0) {
return element;
}
}
};

export default function articleTitle(html) {
const $ = cheerio.load(html);

let documentTitle = $('title').text().replace(/\r?\n/g, '');
documentTitle = (/^[^|\-/•—]+/.exec(documentTitle) || [])[0] || documentTitle;
documentTitle = (((documentTitle || '').match(/:(?<documentTitle>.*)/) || []).groups || '').documentTitle || documentTitle;
documentTitle = (documentTitle || '').trim();

let title = documentTitle;
const heading = findSelectorMatch($);

if (heading && heading.length > 5 && heading.length < 100) {
title = heading;
}

return clean(title);
}
6 changes: 6 additions & 0 deletions packages/frontpage/lib/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}

export async function grabTitle(url: string): Promise<string> {
const response = await fetch(`/api/title?url=${url}`)
const title = await response.json()
return title
}

export type Prettify<T> = {
[K in keyof T]: T[K];
// eslint-disable-next-line @typescript-eslint/ban-types
Expand Down
1 change: 1 addition & 0 deletions packages/frontpage/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
"@sentry/nextjs": "^8.35.0",
"@vercel/analytics": "^1.3.1",
"@vercel/speed-insights": "^1.0.12",
"cheerio": "^1.0.0",
"class-variance-authority": "^0.7.0",
"clsx": "^2.1.1",
"date-fns": "^3.6.0",
Expand Down
Loading

0 comments on commit 08a69ed

Please sign in to comment.