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

View file

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

View file

@ -1,128 +1,9 @@
import { basename } from 'pathe'
import type { Plugin } from 'vitepress'
import { replaceUnderscore, transformer } from './transformer/core'
import { excluded, getHeader } from './transformer/constants'
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
const excluded = ['readme.md', 'single-page', 'feedback.md', 'index.md']
export function transformer(): Plugin {
export function transforms(): Plugin {
return {
name: 'custom:transform-content',
enforce: 'pre',
@ -151,48 +32,56 @@ export function transformer(): Plugin {
}
}
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
}
export function transformGuide(text: string): string {
const _text = text
.replace(/\[TOC\]\n/gm, '')
.replace(/\*\*Table of Contents\*\*\n\[TOC2\]\n/gm, '')
.replace(/# -> \*\*\*Beginners Guide to Piracy\*\*\* <-\n/gm, '')
.replace(/!!!note\s(.+?)\n/gm, '\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')
.replace(/\*\*\[\^ Back to Top\]\(#beginners-guide-to-piracy\)\*\*/gm, '')
.replace(/!!!\s(.+?)\n/gm, ':::info\n$1\n:::\n')
.replace(/\n\*\*\[/gm, '\n* **[')
.replace(/>(.*)\n\n(.*)/gm, ':::details $1\n$2\n:::')
return _text
}
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
}
export const transformGuide = (text: string): string =>
transformer(text)
.transform('Beginners Guide', [
{
name: 'TOC',
find: /\[TOC\]\n/gm,
replace: ''
},
{
name: 'TOC2',
find: /\*\*Table of Contents\*\*\n\[TOC2\]\n/gm,
replace: ''
},
{
name: 'Beginners Guide',
find: /# -> \*\*\*Beginners Guide to Piracy\*\*\* <-\n/gm,
replace: ''
},
{
name: 'Note',
find: /!!!note\s(.+?)\n/gm,
replace: '\n:::info\n$1\n:::\n'
},
{
name: 'Info',
find: /!!!info\s(.+?)\n/gm,
replace: '\n:::info\n$1\n:::\n'
},
{
name: 'Warning',
find: /!!!warning\s(.+?)\n/gm,
replace: ':::warning\n$1\n:::\n'
},
{
name: 'Quote',
find: />\s(.+?)\n/gm,
replace: '> $1\n\n'
},
{
name: 'Back to Top',
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 {
let _text = text
@ -362,42 +251,50 @@ export function transform(text: string): string {
return _text
}
function transformLinks(text: string): string {
const _text = text
// Transform Discord links to icons
.replace(
/\[Discord\]\(([^\)]*?)\)/gm,
'<a target="_blank" href="$1"><div alt="Discord" class="i-carbon:logo-discord" /></a>'
)
// Transform GitHub links to icons
.replace(
/\[GitHub\]\(([^\)]*?)\)/gm,
'<a target="_blank" href="$1"><div alt="GitHub" class="i-carbon:logo-github mb-1" /></a>'
)
// Fallback for GitHub
.replace(
/\[Github\]\(([^\)]*?)\)/gm,
'<a target="_blank" href="$1"><div alt="GitHub" class="i-carbon:logo-github mb-1" /></a>'
)
// Transform GitLab links to icons
.replace(
/\[GitLab\]\(([^\)]*?)\)/gm,
'<a target="_blank" href="$1"><div alt="GitLab" class="i-carbon:logo-gitlab" /></a>'
)
// Fallback for GitLab
.replace(
/\[Gitlab\]\(([^\)]*?)\)/gm,
'<a target="_blank" href="$1"><div alt="GitLab" class="i-carbon:logo-gitlab" /></a>'
)
// Transform Telegram links to icons
.replace(
/\[Telegram\]\(([^\)]*?)\)/gm,
'<a target="_blank" href="$1"><div alt="Telegram" class="i-mdi:telegram" /></a>'
)
// Transform Subreddit links to icons
.replace(
/\[Subreddit\]\(([^\)]*?)\)/gm,
'<a target="_blank" href="$1"><div alt="Reddit" class="i-mdi:reddit" /></a>'
)
return _text
}
const transformLinks = (text: string): string =>
transformer(text)
.transform('Links to Icons', [
{
name: 'Discord',
find: /\[Discord\]\(([^\)]*?)\)/gm,
replace:
'<a target="_blank" href="$1"><div alt="Discord" class="i-carbon:logo-discord" /></a>'
},
{
name: 'GitHub',
find: /\[GitHub\]\(([^\)]*?)\)/gm,
replace:
'<a target="_blank" href="$1"><div alt="GitHub" class="i-carbon:logo-github mb-1" /></a>'
},
{
name: 'GitHub Fallback',
find: /\[Github\]\(([^\)]*?)\)/gm,
replace:
'<a target="_blank" href="$1"><div alt="GitHub" class="i-carbon:logo-github mb-1" /></a>'
},
{
name: 'GitLab',
find: /\[GitLab\]\(([^\)]*?)\)/gm,
replace:
'<a target="_blank" href="$1"><div alt="GitLab" class="i-carbon:logo-gitlab" /></a>'
},
{
name: 'GitLab Fallback',
find: /\[Gitlab\]\(([^\)]*?)\)/gm,
replace:
'<a target="_blank" href="$1"><div alt="GitLab" class="i-carbon:logo-gitlab" /></a>'
},
{
name: 'Telegram',
find: /\[Telegram\]\(([^\)]*?)\)/gm,
replace:
'<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
}