feat: get all internal links from a Wikipedia article
This commit is contained in:
parent
6c717e5768
commit
0ee7b35530
3
TODO.md
3
TODO.md
@ -2,9 +2,10 @@
|
||||
|
||||
- [x] chore: initial commit (+ mirror on GitHub)
|
||||
- [x] Deploy first staging version (v1.0.0-staging.1)
|
||||
- [ ] Add docs to add locale/edit translations, create component, install a dependency in a package, create a new package, technology used, architecture, links where it's deployed, how to use/install for end users, how to update dependencies with `npx taze -l` etc.
|
||||
- [ ] Implement Wikipedia Game Solver (`website`) with inputs, button to submit, and list all articles to go from one to another, or none if it is not possible
|
||||
- [ ] Implement toast notifications for errors, warnings, and success messages
|
||||
- [ ] v1.0.0-staging.2
|
||||
- [ ] Add docs to add locale/edit translations, create component, install a dependency in a package, create a new package, technology used, architecture, links where it's deployed, how to use/install for end users, how to update dependencies with `npx taze -l` etc.
|
||||
- [ ] Implement CLI (`cli`)
|
||||
- [ ] v1.0.0-staging.3
|
||||
- [ ] Implement REST API (`api`) with JSON responses ([AdonisJS](https://adonisjs.com/))
|
||||
|
@ -23,6 +23,7 @@ const config = {
|
||||
yellow: "#fef08a",
|
||||
transparent: "transparent",
|
||||
inherit: "inherit",
|
||||
current: "currentColor",
|
||||
},
|
||||
fontFamily: {
|
||||
sans: ["'Montserrat'", ...fontFamily.sans],
|
||||
|
@ -5,5 +5,5 @@ export const VERSION =
|
||||
? "0.0.0-development"
|
||||
: packageJSON.version
|
||||
|
||||
export const GIT_REPO_URL =
|
||||
export const GIT_REPO_LINK =
|
||||
"https://git.theoludwig.fr/theoludwig/wikipedia-game-solver"
|
||||
|
@ -18,6 +18,6 @@
|
||||
},
|
||||
"home": {
|
||||
"title": "Wikipedia Game Solver",
|
||||
"description": "Le jeu Wikipédia implique des joueurs en compétition pour naviguer d'une page Wikipédia à une autre en utilisant uniquement des liens internes."
|
||||
"description": "Le jeu Wikipédia implique des joueurs en compétition pour naviguer d'une page <wikipedia>Wikipedia</wikipedia> à une autre en utilisant uniquement des liens internes."
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { useTranslations } from "next-intl"
|
||||
|
||||
import { GIT_REPO_URL } from "@repo/constants"
|
||||
import { GIT_REPO_LINK } from "@repo/constants"
|
||||
import { Link } from "../design/Link/Link"
|
||||
|
||||
export interface FooterProps {
|
||||
@ -24,7 +24,7 @@ export const Footer: React.FC<FooterProps> = (props) => {
|
||||
<p>
|
||||
Version{" "}
|
||||
<Link
|
||||
href={`${GIT_REPO_URL}/releases/tag/v${version}`}
|
||||
href={`${GIT_REPO_LINK}/releases/tag/v${version}`}
|
||||
target="_blank"
|
||||
isExternal={false}
|
||||
>
|
||||
|
@ -1,6 +1,7 @@
|
||||
"use client"
|
||||
|
||||
import { classNames } from "@repo/config-tailwind/classNames"
|
||||
import type { Locale } from "@repo/i18n/config"
|
||||
import { LOCALES } from "@repo/i18n/config"
|
||||
import { usePathname, useRouter } from "@repo/i18n/navigation"
|
||||
import { useLocale, useTranslations } from "next-intl"
|
||||
@ -8,7 +9,7 @@ import { useLocale, useTranslations } from "next-intl"
|
||||
export const Locales: React.FC = () => {
|
||||
const router = useRouter()
|
||||
const pathname = usePathname()
|
||||
const currentLocale = useLocale()
|
||||
const localeCurrent = useLocale() as Locale
|
||||
|
||||
const t = useTranslations()
|
||||
|
||||
@ -21,7 +22,7 @@ export const Locales: React.FC = () => {
|
||||
key={locale}
|
||||
className={classNames("rounded-md p-2", {
|
||||
"border-primary dark:border-primary-dark border":
|
||||
locale === currentLocale,
|
||||
locale === localeCurrent,
|
||||
})}
|
||||
>
|
||||
<button
|
||||
|
@ -1,21 +1,46 @@
|
||||
"use client"
|
||||
|
||||
import type { Locale } from "@repo/i18n/config"
|
||||
import { Button } from "@repo/ui/design/Button"
|
||||
import { Link } from "@repo/ui/design/Link"
|
||||
import { Typography } from "@repo/ui/design/Typography"
|
||||
import { useLocale } from "next-intl"
|
||||
import { useState } from "react"
|
||||
|
||||
const wait = async (ms: number): Promise<void> => {
|
||||
return await new Promise((resolve) => {
|
||||
setTimeout(resolve, ms)
|
||||
})
|
||||
}
|
||||
import {
|
||||
fromLocaleToWikipediaLocale,
|
||||
getWikipediaLink,
|
||||
getWikipediaPageInternalLinks,
|
||||
} from "./wikipedia-api"
|
||||
|
||||
export const WikipediaClient: React.FC = () => {
|
||||
const [isLoading, setIsLoading] = useState(false)
|
||||
|
||||
const localeCurrent = useLocale() as Locale
|
||||
const localeWikipedia = fromLocaleToWikipediaLocale(localeCurrent)
|
||||
|
||||
const handleClick: React.MouseEventHandler<HTMLButtonElement> = async () => {
|
||||
console.log("clicked")
|
||||
setIsLoading(true)
|
||||
await wait(2_000)
|
||||
const fromArticleInput = "Linux"
|
||||
const toArticleInput = "Node.js"
|
||||
console.log({
|
||||
fromArticleInput,
|
||||
toArticleInput,
|
||||
})
|
||||
const [fromArticleWikipediaLinks, toArticleWikipediaLinks] =
|
||||
await Promise.all([
|
||||
getWikipediaPageInternalLinks({
|
||||
title: fromArticleInput,
|
||||
locale: localeWikipedia,
|
||||
}),
|
||||
getWikipediaPageInternalLinks({
|
||||
title: toArticleInput,
|
||||
locale: localeWikipedia,
|
||||
}),
|
||||
])
|
||||
console.log({
|
||||
fromArticleWikipediaLinks,
|
||||
toArticleWikipediaLinks,
|
||||
})
|
||||
setIsLoading(false)
|
||||
}
|
||||
|
||||
@ -24,15 +49,12 @@ export const WikipediaClient: React.FC = () => {
|
||||
<Button onClick={handleClick} isLoading={isLoading} className="w-36">
|
||||
Wikipedia
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
onClick={handleClick}
|
||||
variant="outline"
|
||||
isLoading={isLoading}
|
||||
className="w-36"
|
||||
>
|
||||
Wikipedia
|
||||
</Button>
|
||||
<Typography variant="text1" as="p">
|
||||
<span>Using: </span>
|
||||
<Link href={getWikipediaLink(localeWikipedia)} target="_blank">
|
||||
{getWikipediaLink(localeWikipedia).replace("https://", "")}
|
||||
</Link>
|
||||
</Typography>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
|
@ -1,28 +1,111 @@
|
||||
import type { Locale } from "@repo/i18n/config"
|
||||
|
||||
export const sum = (a: number, b: number): number => {
|
||||
return a + b
|
||||
}
|
||||
|
||||
export const wikipediaAPIBaseURL = new URL("https://en.wikipedia.org/w/api.php")
|
||||
export const WIKIPEDIA_LOCALES = ["en", "fr"] as const
|
||||
export type WikipediaLocale = (typeof WIKIPEDIA_LOCALES)[number]
|
||||
|
||||
// const getWikipediaPageLinks = async (title: string): Promise<string[]> => {
|
||||
// const url = new URL(wikipediaAPIBaseURL)
|
||||
// url.searchParams.append("action", "query")
|
||||
// url.searchParams.append("titles", title)
|
||||
// url.searchParams.append("prop", "links")
|
||||
// url.searchParams.append("pllimit", "max")
|
||||
// url.searchParams.append("format", "json")
|
||||
// url.searchParams.append("origin", "*")
|
||||
// const response = await fetch(url, {
|
||||
// method: "GET",
|
||||
// })
|
||||
// if (!response.ok) {
|
||||
// throw new Error(response.statusText)
|
||||
// }
|
||||
// const json = await response.json()
|
||||
// return json
|
||||
// }
|
||||
export const fromLocaleToWikipediaLocale = (
|
||||
locale: Locale,
|
||||
): WikipediaLocale => {
|
||||
return locale === "en-US" ? "en" : "fr"
|
||||
}
|
||||
|
||||
// const links = await getWikipediaPageLinks("France")
|
||||
// const links2 = await getWikipediaPageLinks("Frddgdgdgance")
|
||||
// console.log("links.length", links)
|
||||
// console.log("links.length", links2)
|
||||
export const getWikipediaLink = (locale: WikipediaLocale): string => {
|
||||
return `https://${locale}.wikipedia.org`
|
||||
}
|
||||
|
||||
interface WikipediaQueryLinksResponse {
|
||||
continue?: {
|
||||
plcontinue: string
|
||||
continue: string
|
||||
}
|
||||
query: {
|
||||
pages: {
|
||||
[key: string]: {
|
||||
pageid: number
|
||||
ns: number
|
||||
title: string
|
||||
links: [
|
||||
{
|
||||
ns: number
|
||||
title: string
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
limits: {
|
||||
links: number
|
||||
}
|
||||
}
|
||||
|
||||
interface GetWikipediaPageInternalLinksInput {
|
||||
title: string
|
||||
locale: WikipediaLocale
|
||||
}
|
||||
|
||||
interface GetWikipediaPageInternalLinksOutput {
|
||||
title: string
|
||||
links: string[]
|
||||
}
|
||||
|
||||
export const getWikipediaPageInternalLinks = async (
|
||||
input: GetWikipediaPageInternalLinksInput,
|
||||
): Promise<GetWikipediaPageInternalLinksOutput> => {
|
||||
const links: string[] = []
|
||||
let title = input.title
|
||||
let plcontinue: string | null = null
|
||||
|
||||
const fetchLinks = async (): Promise<WikipediaQueryLinksResponse> => {
|
||||
const url = new URL("/w/api.php", getWikipediaLink(input.locale))
|
||||
url.searchParams.append("action", "query")
|
||||
url.searchParams.append("titles", title)
|
||||
url.searchParams.append("prop", "links")
|
||||
url.searchParams.append("pllimit", "max")
|
||||
url.searchParams.append("format", "json")
|
||||
url.searchParams.append("origin", "*")
|
||||
if (plcontinue != null) {
|
||||
url.searchParams.set("plcontinue", plcontinue)
|
||||
}
|
||||
const response = await fetch(url, {
|
||||
method: "GET",
|
||||
})
|
||||
if (!response.ok) {
|
||||
throw new Error(response.statusText)
|
||||
}
|
||||
const json = (await response.json()) as WikipediaQueryLinksResponse
|
||||
return json
|
||||
}
|
||||
|
||||
do {
|
||||
try {
|
||||
const response = await fetchLinks()
|
||||
plcontinue = response?.continue?.plcontinue ?? null
|
||||
const pages = Object.keys(response.query.pages)
|
||||
const page = pages[0] ?? ""
|
||||
if (page === "-1" || page === "") {
|
||||
break
|
||||
}
|
||||
const pageData = response.query.pages[page]
|
||||
if (pageData == null) {
|
||||
break
|
||||
}
|
||||
title = pageData.title
|
||||
links.push(
|
||||
...pageData.links.map((link) => {
|
||||
return link.title
|
||||
}),
|
||||
)
|
||||
} catch {
|
||||
break
|
||||
}
|
||||
} while (plcontinue != null)
|
||||
|
||||
return {
|
||||
title,
|
||||
links,
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user