Made first version work
This commit is contained in:
35
main.ts
35
main.ts
@@ -1,6 +1,7 @@
|
|||||||
import { Mwn, MwnWikitext } from 'npm:mwn'
|
import { Mwn } from 'npm:mwn'
|
||||||
import process from "node:process";
|
import process from "node:process";
|
||||||
import { parseSummary } from "./parse.ts";
|
import { parseSummary } from "./parse.ts";
|
||||||
|
import { bucketEvents, writeSection } from "./write.ts";
|
||||||
|
|
||||||
async function getWorkshopVideos(bot: Mwn): Promise<string[]> {
|
async function getWorkshopVideos(bot: Mwn): Promise<string[]> {
|
||||||
const response = await bot.request({
|
const response = await bot.request({
|
||||||
@@ -26,6 +27,15 @@ export interface VideoDescription {
|
|||||||
date: string
|
date: string
|
||||||
patterns: string
|
patterns: string
|
||||||
notes: string
|
notes: string
|
||||||
|
path: string
|
||||||
|
title: string
|
||||||
|
}
|
||||||
|
|
||||||
|
async function fetchPages(pages: string[], bot: Mwn): Promise<VideoDescription[]> {
|
||||||
|
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({
|
const bot = new Mwn({
|
||||||
apiUrl: 'https://dancing.thasky.one/api.php',
|
apiUrl: 'https://dancing.thasky.one/api.php',
|
||||||
username: process.env.BOTNAME,
|
username: process.env.BOTNAME,
|
||||||
|
|
||||||
password: process.env.BOTPW,
|
password: process.env.BOTPW,
|
||||||
|
|
||||||
userAgent: 'mwn bot',
|
userAgent: 'mwn bot',
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await bot.login();
|
await bot.login();
|
||||||
const relevantFiles = await getWorkshopVideos(bot)
|
// const relevantFiles = await getWorkshopVideos(bot)
|
||||||
const file_content = await bot.read(relevantFiles[0])
|
// const d = await fetchPages(relevantFiles, bot)
|
||||||
if (file_content.revisions === undefined) {
|
// await Deno.writeTextFile("./descriptions.json", JSON.stringify(d));
|
||||||
throw new Error("Page has no revisions")
|
const d = JSON.parse(await Deno.readTextFile('./descriptions.json'));
|
||||||
}
|
const t = writeSection(bucketEvents(d))
|
||||||
const content = file_content.revisions[0].content
|
const response = await bot.save('Video Description (Automated)', "{{TOC|limit=3}}\n\n" + t, 'Generated descriptions');
|
||||||
if (content === undefined) {
|
console.log(response)
|
||||||
throw new Error("Latest revision has no content")
|
|
||||||
}
|
|
||||||
console.log(content)
|
|
||||||
console.dir(bot.Wikitext.parseSections(content)[2])
|
|
||||||
// parseSummary(content, relevantFiles[0])
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error:', error);
|
console.error('Error:', error);
|
||||||
} finally {
|
} finally {
|
||||||
|
|||||||
34
parse.ts
34
parse.ts
@@ -3,19 +3,31 @@ import { VideoDescription } from "./main.ts";
|
|||||||
|
|
||||||
function parseTemplate(description: string): Record<string, string> {
|
function parseTemplate(description: string): Record<string, string> {
|
||||||
|
|
||||||
const r = new Mwn().Wikitext.parseTemplates(description, {
|
const u = new (new Mwn().Wikitext)(description)
|
||||||
|
const r = u.parseTemplates({
|
||||||
namePredicate: (name) => name === "DanceWorkshopDescription",
|
namePredicate: (name) => name === "DanceWorkshopDescription",
|
||||||
})
|
})
|
||||||
if (r.length < 1) {
|
if (r.length < 1) {
|
||||||
throw new Error("Could not find DanceWorkshopDescription")
|
throw new Error("Could not find DanceWorkshopDescription")
|
||||||
}
|
}
|
||||||
|
if (r.length > 1) {
|
||||||
|
console.warn("More than one DanceWorkshopDescription template found")
|
||||||
|
}
|
||||||
const p = r[0]
|
const p = r[0]
|
||||||
const properties = p.parameters.map(v => ({ [v.name]: v.value }))
|
const properties = p.parameters.map(v => ({ [v.name]: v.value }))
|
||||||
return Object.assign({}, ...properties)
|
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*(?<content>(^\\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 {
|
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
|
b.event = properties['event'] || b.location
|
||||||
|
|
||||||
function parseBlock(header: string, text: string): string {
|
|
||||||
const regex = new RegExp(`===\\s*${header}\\s*===\\s*(?<content>(^\\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')) {
|
if (!Object.hasOwn(properties, 'patterns')) {
|
||||||
console.warn(`Page ${name} has old template usage [no 'patterns' key]`)
|
console.warn(`Page ${name} has old template usage [no 'patterns' key]`)
|
||||||
b.patterns = parseBlock("Shown Patterns", description)
|
b.patterns = parseBlock("Shown Patterns", description)
|
||||||
@@ -62,6 +64,8 @@ export function parseSummary(description: string, name: string): VideoDescriptio
|
|||||||
} else {
|
} else {
|
||||||
b.notes = properties['notes']
|
b.notes = properties['notes']
|
||||||
}
|
}
|
||||||
|
b.path = name
|
||||||
|
const titleMatch = name.match(/File:WCS \w+ (?<title>.+)\.[^.]+/)
|
||||||
|
b.title = titleMatch?.groups ? titleMatch.groups['title'] : name
|
||||||
return (b as VideoDescription)
|
return (b as VideoDescription)
|
||||||
}
|
}
|
||||||
|
|||||||
2
run.sh
2
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
|
||||||
|
|||||||
52
write.ts
Normal file
52
write.ts
Normal file
@@ -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)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user