feat: custom transformer composable

This commit is contained in:
taskylizard 2024-08-09 16:37:06 +00:00
parent 5636b5487a
commit 422ffec7e8
No known key found for this signature in database
GPG key ID: 1820131ED1A24120
5 changed files with 295 additions and 210 deletions

View file

@ -1,5 +1,4 @@
import consola from 'consola' import consola from 'consola'
import { basename } from 'pathe'
import UnoCSS from 'unocss/vite' import UnoCSS from 'unocss/vite'
import { defineConfig } from 'vitepress' import { defineConfig } from 'vitepress'
import { import {
@ -13,7 +12,7 @@ import {
import { generateFeed, generateImages, generateMeta } from './hooks' import { generateFeed, generateImages, generateMeta } from './hooks'
import { defs, emojiRender, movePlugin } from './markdown/emoji' import { defs, emojiRender, movePlugin } from './markdown/emoji'
import { toggleStarredPlugin } from './markdown/toggleStarred' import { toggleStarredPlugin } from './markdown/toggleStarred'
import { transformer } from './transformer' import { transforms } from './transformer'
// @unocss-include // @unocss-include
@ -57,7 +56,7 @@ export default defineConfig({
UnoCSS({ UnoCSS({
configFile: '../unocss.config.ts' configFile: '../unocss.config.ts'
}), }),
transformer(), transforms(),
{ {
name: 'custom:adjust-order', name: 'custom:adjust-order',
configResolved(c) { configResolved(c) {

View file

@ -6,7 +6,7 @@ import type { ContentData, SiteConfig } from 'vitepress'
import { type SatoriOptions, satoriVue } from 'x-satori/vue' import { type SatoriOptions, satoriVue } from 'x-satori/vue'
import { renderAsync } from '@resvg/resvg-js' import { renderAsync } from '@resvg/resvg-js'
import consola from 'consola' import consola from 'consola'
import { headers } from '../transformer' import { headers } from '../transformer/constants'
const __dirname = dirname(fileURLToPath(import.meta.url)) const __dirname = dirname(fileURLToPath(import.meta.url))
const __fonts = resolve(__dirname, '../fonts') const __fonts = resolve(__dirname, '../fonts')
@ -71,19 +71,19 @@ async function generateImage({
const _page = getPage(url) const _page = getPage(url)
const title = const title =
frontmatter.layout === 'home' frontmatter.layout === 'home'
? (frontmatter.hero.name ?? frontmatter.title) ? frontmatter.hero.name ?? frontmatter.title
: frontmatter.title : frontmatter.title
? frontmatter.title ? frontmatter.title
: _page?.title : _page?.title
const description = const description =
frontmatter.layout === 'home' frontmatter.layout === 'home'
? (frontmatter.hero.tagline ?? frontmatter.description) ? frontmatter.hero.tagline ?? frontmatter.description
: frontmatter.description : frontmatter.description
? frontmatter.description ? frontmatter.description
: _page?.description : _page?.description
consola.info(url, title, description) // consola.info(url, title, description)
const options: SatoriOptions = { const options: SatoriOptions = {
width: 1200, width: 1200,
height: 628, height: 628,

View file

@ -1,128 +1,9 @@
import { basename } from 'pathe' import { basename } from 'pathe'
import type { Plugin } from 'vitepress' import type { Plugin } from 'vitepress'
import { replaceUnderscore, transformer } from './transformer/core'
import { excluded, getHeader } from './transformer/constants'
interface Header { export function transforms(): Plugin {
[file: string]: { title: string; description: string }
}
export const headers: Header = {
'adblockvpnguide.md': {
title: 'Adblocking / Privacy',
description: "Adblocking, Privacy, VPN's, Proxies, Antivirus"
},
'ai.md': {
title: 'Artificial Intelligence',
description: 'Chat Bots, Text Generators, Image Generators, ChatGPT Tools'
},
'android-iosguide.md': {
title: 'Android / iOS',
description: 'Apps, Jailbreaking, Android Emulators'
},
'audiopiracyguide.md': {
title: 'Music / Podcasts / Radio',
description: 'Stream Audio, Download Audio, Torrent Audio'
},
'beginners-guide.md': {
title: 'Beginners Guide',
description: 'A Guide for Beginners to Piracy'
},
'downloadpiracyguide.md': {
title: 'Downloading',
description: 'Download Sites, Software Sites, Open Directories'
},
'edupiracyguide.md': {
title: 'Educational',
description: 'Courses, Documentaries, Learning Resources'
},
'gamingpiracyguide.md': {
title: 'Gaming / Emulation',
description: 'Download Games, ROMs, Gaming Tools'
},
'linuxguide.md': {
title: 'Linux / MacOS',
description: 'Apps, Software Sites, Gaming'
},
'miscguide.md': {
title: 'Miscellaneous',
description: 'Extensions, Indexes, News, Health, Food, Fun'
},
'nsfwpiracy.md': {
title: 'NSFW',
description: 'NSFW Indexes, Streaming, Downloading'
},
'non-english.md': {
title: 'Non-English',
description: 'International Piracy Sites'
},
'readingpiracyguide.md': {
title: 'Books / Comics / Manga',
description: 'Books, Comics, Magazines, Newspapers'
},
'gaming-tools.md': {
title: 'Gaming Tools',
description: 'Gaming Optimization, Game Launchers, Multiplayer'
},
'devtools.md': {
title: 'Developer Tools',
description: 'Git, Hosting, App Dev, Software Dev'
},
'img-tools.md': {
title: 'Image Tools',
description: 'Image Editors, Generators, Compress'
},
'audio-tools.md': {
title: 'Audio Tools',
description: 'Audio Players, Audio Editors, Audio Downloaders'
},
'system-tools.md': {
title: 'System Tools',
description: 'System Tools, Hardware Tools, Windows ISOs, Customization'
},
'file-tools.md': {
title: 'File Tools',
description: 'Download Managers, File Hosting, File Archivers'
},
'video-tools.md': {
title: 'Video Tools',
description: 'Video Players, Video Editors, Live Streaming, Animation'
},
'text-tools.md': {
title: 'Text Tools',
description: 'Text Editors, Pastebins, Fonts, Translators'
},
'internet-tools.md': {
title: 'Internet Tools',
description: 'Browsers, Extensions, Search Engines'
},
'social-media-tools.md': {
title: 'Social Media Tools',
description: 'Discord Tools, Reddit Tools, YouTube Tools'
},
'storage.md': {
title: 'Storage',
description: 'Sections too big to fit on main pages'
},
'torrentpiracyguide.md': {
title: 'Torrenting',
description: 'Torrent Clients, Torrent Sites, Trackers'
},
'videopiracyguide.md': {
title: 'Movies / TV / Anime',
description: 'Stream Videos, Download Videos, Torrent Videos'
},
'base64.md': {
title: 'Base64',
description: 'Base64 storage'
},
'unsafesites.md': {
title: 'Unsafe Sites',
description: 'Unsafe/harmful sites to avoid.'
}
} as const
const excluded = ['readme.md', 'single-page', 'feedback.md', 'index.md']
export function transformer(): Plugin {
return { return {
name: 'custom:transform-content', name: 'custom:transform-content',
enforce: 'pre', enforce: 'pre',
@ -151,48 +32,56 @@ export function transformer(): Plugin {
} }
} }
function getHeader(id: string) { export const transformGuide = (text: string): string =>
const title = transformer(text)
'<div class="space-y-2 not-prose"><h1 class="text-4xl font-extrabold tracking-tight text-primary underline lg:text-5xl lg:leading-[3.5rem]">' .transform('Beginners Guide', [
{
const description = '<p class="text-black dark:text-text-2">' name: 'TOC',
find: /\[TOC\]\n/gm,
const data = headers[id] replace: ''
let header = '---\n' },
header += `title: "${data.title}"\n` {
header += `description: ${data.description}\n` name: 'TOC2',
header += '---\n' find: /\*\*Table of Contents\*\*\n\[TOC2\]\n/gm,
header += `${title}${data.title}</h1>\n` replace: ''
header += `${description}${data.description}</p></div>\n\n` },
return header {
} name: 'Beginners Guide',
find: /# -> \*\*\*Beginners Guide to Piracy\*\*\* <-\n/gm,
export function transformGuide(text: string): string { replace: ''
const _text = text },
.replace(/\[TOC\]\n/gm, '') {
.replace(/\*\*Table of Contents\*\*\n\[TOC2\]\n/gm, '') name: 'Note',
.replace(/# -> \*\*\*Beginners Guide to Piracy\*\*\* <-\n/gm, '') find: /!!!note\s(.+?)\n/gm,
.replace(/!!!note\s(.+?)\n/gm, '\n:::info\n$1\n:::\n') replace: '\n:::info\n$1\n:::\n'
.replace(/!!!info\s(.+?)\n/gm, '\n:::info\n$1\n:::\n') },
.replace(/!!!warning\s(.+?)\n/gm, ':::warning\n$1\n:::\n') {
.replace(/>\s(.+?)\n/gm, '> $1\n\n') name: 'Info',
.replace(/\*\*\[\^ Back to Top\]\(#beginners-guide-to-piracy\)\*\*/gm, '') find: /!!!info\s(.+?)\n/gm,
.replace(/!!!\s(.+?)\n/gm, ':::info\n$1\n:::\n') replace: '\n:::info\n$1\n:::\n'
.replace(/\n\*\*\[/gm, '\n* **[') },
.replace(/>(.*)\n\n(.*)/gm, ':::details $1\n$2\n:::') {
return _text name: 'Warning',
} find: /!!!warning\s(.+?)\n/gm,
replace: ':::warning\n$1\n:::\n'
function replaceUnderscore(text: string): string { },
const pattern = /\/#[\w\-]+(?:_[\w]+)*/g {
const matches = text.match(pattern) || [] name: 'Quote',
let _text = text find: />\s(.+?)\n/gm,
for (const match of matches) { replace: '> $1\n\n'
const replacement = match.replace(/_/g, '-') },
_text = _text.replace(match, replacement) {
} name: 'Back to Top',
return _text find: /\*\*\[\^ Back to Top\]\(#beginners-guide-to-piracy\)\*\*/gm,
} replace: ''
},
{
name: 'Back to Top',
find: /\*\*\[\^ Back to Top\]\(#beginners-guide-to-piracy\)\*\*/gm,
replace: ''
}
])
.getText()
export function transform(text: string): string { export function transform(text: string): string {
let _text = text let _text = text
@ -362,42 +251,50 @@ export function transform(text: string): string {
return _text return _text
} }
function transformLinks(text: string): string { const transformLinks = (text: string): string =>
const _text = text transformer(text)
// Transform Discord links to icons .transform('Links to Icons', [
.replace( {
/\[Discord\]\(([^\)]*?)\)/gm, name: 'Discord',
'<a target="_blank" href="$1"><div alt="Discord" class="i-carbon:logo-discord" /></a>' find: /\[Discord\]\(([^\)]*?)\)/gm,
) replace:
// Transform GitHub links to icons '<a target="_blank" href="$1"><div alt="Discord" class="i-carbon:logo-discord" /></a>'
.replace( },
/\[GitHub\]\(([^\)]*?)\)/gm, {
'<a target="_blank" href="$1"><div alt="GitHub" class="i-carbon:logo-github mb-1" /></a>' name: 'GitHub',
) find: /\[GitHub\]\(([^\)]*?)\)/gm,
// Fallback for GitHub replace:
.replace( '<a target="_blank" href="$1"><div alt="GitHub" class="i-carbon:logo-github mb-1" /></a>'
/\[Github\]\(([^\)]*?)\)/gm, },
'<a target="_blank" href="$1"><div alt="GitHub" class="i-carbon:logo-github mb-1" /></a>' {
) name: 'GitHub Fallback',
// Transform GitLab links to icons find: /\[Github\]\(([^\)]*?)\)/gm,
.replace( replace:
/\[GitLab\]\(([^\)]*?)\)/gm, '<a target="_blank" href="$1"><div alt="GitHub" class="i-carbon:logo-github mb-1" /></a>'
'<a target="_blank" href="$1"><div alt="GitLab" class="i-carbon:logo-gitlab" /></a>' },
) {
// Fallback for GitLab name: 'GitLab',
.replace( find: /\[GitLab\]\(([^\)]*?)\)/gm,
/\[Gitlab\]\(([^\)]*?)\)/gm, replace:
'<a target="_blank" href="$1"><div alt="GitLab" class="i-carbon:logo-gitlab" /></a>' '<a target="_blank" href="$1"><div alt="GitLab" class="i-carbon:logo-gitlab" /></a>'
) },
// Transform Telegram links to icons {
.replace( name: 'GitLab Fallback',
/\[Telegram\]\(([^\)]*?)\)/gm, find: /\[Gitlab\]\(([^\)]*?)\)/gm,
'<a target="_blank" href="$1"><div alt="Telegram" class="i-mdi:telegram" /></a>' replace:
) '<a target="_blank" href="$1"><div alt="GitLab" class="i-carbon:logo-gitlab" /></a>'
// Transform Subreddit links to icons },
.replace( {
/\[Subreddit\]\(([^\)]*?)\)/gm, name: 'Telegram',
'<a target="_blank" href="$1"><div alt="Reddit" class="i-mdi:reddit" /></a>' find: /\[Telegram\]\(([^\)]*?)\)/gm,
) replace:
return _text '<a target="_blank" href="$1"><div alt="Telegram" class="i-mdi:telegram" /></a>'
} },
{
name: 'Subreddit',
find: /\[Subreddit\]\(([^\)]*?)\)/gm,
replace:
'<a target="_blank" href="$1"><div alt="Reddit" class="i-mdi:reddit" /></a>'
}
])
.getText()

View file

@ -0,0 +1,136 @@
interface Header {
[file: string]: { title: string; description: string }
}
export const headers: Header = {
'adblockvpnguide.md': {
title: 'Adblocking / Privacy',
description: "Adblocking, Privacy, VPN's, Proxies, Antivirus"
},
'ai.md': {
title: 'Artificial Intelligence',
description: 'Chat Bots, Text Generators, Image Generators, ChatGPT Tools'
},
'android-iosguide.md': {
title: 'Android / iOS',
description: 'Apps, Jailbreaking, Android Emulators'
},
'audiopiracyguide.md': {
title: 'Music / Podcasts / Radio',
description: 'Stream Audio, Download Audio, Torrent Audio'
},
'beginners-guide.md': {
title: 'Beginners Guide',
description: 'A Guide for Beginners to Piracy'
},
'downloadpiracyguide.md': {
title: 'Downloading',
description: 'Download Sites, Software Sites, Open Directories'
},
'edupiracyguide.md': {
title: 'Educational',
description: 'Courses, Documentaries, Learning Resources'
},
'gamingpiracyguide.md': {
title: 'Gaming / Emulation',
description: 'Download Games, ROMs, Gaming Tools'
},
'linuxguide.md': {
title: 'Linux / MacOS',
description: 'Apps, Software Sites, Gaming'
},
'miscguide.md': {
title: 'Miscellaneous',
description: 'Extensions, Indexes, News, Health, Food, Fun'
},
'nsfwpiracy.md': {
title: 'NSFW',
description: 'NSFW Indexes, Streaming, Downloading'
},
'non-english.md': {
title: 'Non-English',
description: 'International Piracy Sites'
},
'readingpiracyguide.md': {
title: 'Books / Comics / Manga',
description: 'Books, Comics, Magazines, Newspapers'
},
'gaming-tools.md': {
title: 'Gaming Tools',
description: 'Gaming Optimization, Game Launchers, Multiplayer'
},
'devtools.md': {
title: 'Developer Tools',
description: 'Git, Hosting, App Dev, Software Dev'
},
'img-tools.md': {
title: 'Image Tools',
description: 'Image Editors, Generators, Compress'
},
'audio-tools.md': {
title: 'Audio Tools',
description: 'Audio Players, Audio Editors, Audio Downloaders'
},
'system-tools.md': {
title: 'System Tools',
description: 'System Tools, Hardware Tools, Windows ISOs, Customization'
},
'file-tools.md': {
title: 'File Tools',
description: 'Download Managers, File Hosting, File Archivers'
},
'video-tools.md': {
title: 'Video Tools',
description: 'Video Players, Video Editors, Live Streaming, Animation'
},
'text-tools.md': {
title: 'Text Tools',
description: 'Text Editors, Pastebins, Fonts, Translators'
},
'internet-tools.md': {
title: 'Internet Tools',
description: 'Browsers, Extensions, Search Engines'
},
'social-media-tools.md': {
title: 'Social Media Tools',
description: 'Discord Tools, Reddit Tools, YouTube Tools'
},
'storage.md': {
title: 'Storage',
description: 'Sections too big to fit on main pages'
},
'torrentpiracyguide.md': {
title: 'Torrenting',
description: 'Torrent Clients, Torrent Sites, Trackers'
},
'videopiracyguide.md': {
title: 'Movies / TV / Anime',
description: 'Stream Videos, Download Videos, Torrent Videos'
},
'base64.md': {
title: 'Base64',
description: 'Base64 storage'
},
'unsafesites.md': {
title: 'Unsafe Sites',
description: 'Unsafe/harmful sites to avoid.'
}
} as const
export const excluded = ['readme.md', 'single-page', 'feedback.md', 'index.md']
export function getHeader(id: string) {
const title =
'<div class="space-y-2 not-prose"><h1 class="text-4xl font-extrabold tracking-tight text-primary underline lg:text-5xl lg:leading-[3.5rem]">'
const description = '<p class="text-black dark:text-text-2">'
const data = headers[id]
let header = '---\n'
header += `title: "${data.title}"\n`
header += `description: ${data.description}\n`
header += '---\n'
header += `${title}${data.title}</h1>\n`
header += `${description}${data.description}</p></div>\n\n`
return header
}

View file

@ -0,0 +1,53 @@
import consola from 'consola'
type Transform = {
name: string
find: string | RegExp
replace: string | ((match: string) => string)
}
type TransformerFunc = (name: string, transforms: Transform[]) => Replacer
interface Replacer {
transform: TransformerFunc
getText(): string
}
export const transformer = (text: string) => {
const handler: ProxyHandler<{ text: string }> = {
get(target, prop) {
if (prop === 'transform') {
return (name: string, transforms: Transform[]): Replacer => {
consola.debug(`Starting transform ${name} with ${transforms}`)
transforms.forEach(({ name, find, replace }) => {
consola.debug(`Transforming ${name} with ${find}`)
target.text = target.text.replace(find, replace as any)
})
// @ts-expect-error - Proxy is not typed
return proxy
}
}
if (prop === 'getText') {
return () => target.text
}
return Reflect.get(target, prop)
}
}
const target = { text }
const proxy = new Proxy(target, handler)
return proxy as unknown as Replacer
}
export function replaceUnderscore(text: string): string {
const pattern = /\/#[\w\-]+(?:_[\w]+)*/g
const matches = text.match(pattern) || []
let _text = text
for (const match of matches) {
const replacement = match.replace(/_/g, '-')
_text = _text.replace(match, replacement)
}
return _text
}