diff --git a/main.ts b/main.ts index 501ba48..5c19c8c 100644 --- a/main.ts +++ b/main.ts @@ -1,6 +1,7 @@ -import { Mwn, MwnWikitext } from 'npm:mwn' +import { Mwn } from 'npm:mwn' import process from "node:process"; import { parseSummary } from "./parse.ts"; +import { bucketEvents, writeSection } from "./write.ts"; async function getWorkshopVideos(bot: Mwn): Promise { const response = await bot.request({ @@ -26,6 +27,15 @@ export interface VideoDescription { date: string patterns: string notes: string + path: string + title: string +} + +async function fetchPages(pages: string[], bot: Mwn): Promise { + const d = await Promise.allSettled(pages.map(async (v) => + parseSummary(await new bot.Page(v).text(), v) + )) + return d.filter(v => v.status === "fulfilled").map(v => v.value) } @@ -33,27 +43,20 @@ async function main() { const bot = new Mwn({ apiUrl: 'https://dancing.thasky.one/api.php', username: process.env.BOTNAME, - password: process.env.BOTPW, - userAgent: 'mwn bot', - }); try { await bot.login(); - const relevantFiles = await getWorkshopVideos(bot) - const file_content = await bot.read(relevantFiles[0]) - if (file_content.revisions === undefined) { - throw new Error("Page has no revisions") - } - const content = file_content.revisions[0].content - if (content === undefined) { - throw new Error("Latest revision has no content") - } - console.log(content) - console.dir(bot.Wikitext.parseSections(content)[2]) - // parseSummary(content, relevantFiles[0]) + // const relevantFiles = await getWorkshopVideos(bot) + // const d = await fetchPages(relevantFiles, bot) + // await Deno.writeTextFile("./descriptions.json", JSON.stringify(d)); + const d = JSON.parse(await Deno.readTextFile('./descriptions.json')); + const t = writeSection(bucketEvents(d)) + const response = await bot.save('Video Description (Automated)', "{{TOC|limit=3}}\n\n" + t, 'Generated descriptions'); + console.log(response) + } catch (error) { console.error('Error:', error); } finally { diff --git a/parse.ts b/parse.ts index 8b64787..dd66420 100644 --- a/parse.ts +++ b/parse.ts @@ -3,19 +3,31 @@ import { VideoDescription } from "./main.ts"; function parseTemplate(description: string): Record { - const r = new Mwn().Wikitext.parseTemplates(description, { + const u = new (new Mwn().Wikitext)(description) + const r = u.parseTemplates({ namePredicate: (name) => name === "DanceWorkshopDescription", }) if (r.length < 1) { throw new Error("Could not find DanceWorkshopDescription") } + if (r.length > 1) { + console.warn("More than one DanceWorkshopDescription template found") + } const p = r[0] const properties = p.parameters.map(v => ({ [v.name]: v.value })) return Object.assign({}, ...properties) } -function parseSection(description:string, header: string) : string { - +function parseBlock(header: string, text: string): string { + const regex = new RegExp(`===\\s*${header}\\s*===\\s*(?(^\\s*[:*]+.*$\\s+)+)`, "m") + const match = text.match(regex) + if (!match) { + throw new Error(`Could not find block ${header}`) + } + if (!match.groups) { + throw new Error("Faulty regex") + } + return match.groups['content'].trim() } export function parseSummary(description: string, name: string): VideoDescription { @@ -38,17 +50,7 @@ export function parseSummary(description: string, name: string): VideoDescriptio b.event = properties['event'] || b.location - function parseBlock(header: string, text: string): string { - const regex = new RegExp(`===\\s*${header}\\s*===\\s*(?(^\\s*[:*]+.*$\\s+)+)`, "m") - const match = text.match(regex) - if (!match) { - throw new Error(`Could not find block ${header}`) - } - if (!match.groups) { - throw new Error("Faulty regex") - } - return match.groups['content'] - } + if (!Object.hasOwn(properties, 'patterns')) { console.warn(`Page ${name} has old template usage [no 'patterns' key]`) b.patterns = parseBlock("Shown Patterns", description) @@ -62,6 +64,8 @@ export function parseSummary(description: string, name: string): VideoDescriptio } else { b.notes = properties['notes'] } - + b.path = name + const titleMatch = name.match(/File:WCS \w+ (?.+)\.[^.]+/) + b.title = titleMatch?.groups ? titleMatch.groups['title'] : name return (b as VideoDescription) } diff --git a/run.sh b/run.sh index 6c61cd6..ce7967b 100644 --- a/run.sh +++ b/run.sh @@ -1 +1 @@ -deno run --env-file=.env --deny-read --allow-net=dancing.thasky.one:443 -E main.ts +deno run --env-file=.env --allow-read=./descriptions.json --allow-net=dancing.thasky.one:443 -E main.ts diff --git a/write.ts b/write.ts new file mode 100644 index 0000000..82f3741 --- /dev/null +++ b/write.ts @@ -0,0 +1,52 @@ +import { VideoDescription } from "./main.ts"; + +export function singleVideoDescription(video: VideoDescription): string { + const teachersList = video.teachers.map(v => "[[" + v + "]]").join(" & "); + + return `=== ${video.title} === +Date:{{#time: Y-m-d (D) | ${video.date}}}<br> +Teachers: ${teachersList}<br> +Level: ${video.level} + +[[${video.path}|left|400px|thumb|${video.title}]] + +==== Shown Patterns ==== +${video.patterns} + +==== Notes ==== +${video.notes}`; +} + +export function writeSection(events: VideoDescription[][]): string { + return events.map(v => { + const token = v[0] + const event_name = token.event === token.location ? token.event : token.event + " " + token.location + + // FIXME: This will break with videos in 75 years + const event_date = event_name.match(/\d{2}|20\d{2}/) ? "" : new Date(token.date).getFullYear().toString() + + let r = `== ${event_name} ${event_date} ==\n` + r += `${v.length} Videos\n` + r += v.map(video => singleVideoDescription(video)).join("\n\n") + return r + }).join("\n\n\n") +} + +export function bucketEvents(events: VideoDescription[]): VideoDescription[][] { + const buckets: Record<string, VideoDescription[]> = {} + for (const e of events) { + const tag = e.event + e.location + new Date(e.date).getFullYear().toString() + if (tag in buckets) { + buckets[tag].push(e) + } else { + buckets[tag] = [e] + } + } + + Object.values(buckets) + .forEach(b => + b.sort((a, b) => + new Date(b.date).getTime() - new Date(a.date).getTime())) + + return Object.values(buckets) +} \ No newline at end of file