v0.6.1
change: open in booru site icon appended in anchor element. new: support open graph link preview. fix: post booru link and file link copy wrong url.
This commit is contained in:
parent
acbb242c97
commit
acf412de6b
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
4
dist/index.html
vendored
4
dist/index.html
vendored
@ -16,8 +16,8 @@
|
||||
|
||||
gtag('config', 'G-59HBGP98WR');
|
||||
</script>
|
||||
<script type="module" crossorigin src="/assets/index-B0cSv4EX.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-GbkvssuE.css">
|
||||
<script type="module" crossorigin src="/assets/index-Dg3fAkPK.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-CPDn8S3u.css">
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
|
@ -128,6 +128,12 @@ nav {
|
||||
display: none;
|
||||
}
|
||||
|
||||
a {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
div.account {
|
||||
height: 2rem;
|
||||
width: 2rem;
|
||||
|
@ -2,7 +2,7 @@
|
||||
"name": "danbooru-viewer",
|
||||
"module": "index.ts",
|
||||
"type": "module",
|
||||
"version": "0.6.0",
|
||||
"version": "0.6.1",
|
||||
"devDependencies": {
|
||||
"@types/bun": "latest",
|
||||
"vite": "^5.4.8",
|
||||
@ -15,8 +15,9 @@
|
||||
"typescript": "^5.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"elysia": "^1.1.20",
|
||||
"@elysiajs/cors": "^1.1.1",
|
||||
"cheerio": "^1.0.0"
|
||||
"@elysiajs/html": "^1.1.1",
|
||||
"cheerio": "^1.0.0",
|
||||
"elysia": "^1.1.20"
|
||||
}
|
||||
}
|
83
server.ts
83
server.ts
@ -1,9 +1,69 @@
|
||||
import cors from "@elysiajs/cors";
|
||||
import Elysia from "elysia";
|
||||
import * as cheerio from 'cheerio';
|
||||
import html from "@elysiajs/html";
|
||||
import type { PostData } from "./src/structure/Post";
|
||||
const list_format = new Intl.ListFormat('en', {type: 'conjunction', style: 'long'})
|
||||
const app = new Elysia()
|
||||
.use(cors())
|
||||
.use(html())
|
||||
.get('*', async ({path}) => {
|
||||
return Bun.file('./dist/index.html')
|
||||
const $ = cheerio.load(Buffer.from(await Bun.file('./dist/index.html').arrayBuffer()));
|
||||
if (path.match(/posts\/(\d+)/)) {
|
||||
const post_id = path.match(/posts\/(\d+)/)?.at(1);
|
||||
const data = await fetch(`https://danbooru.donmai.us/posts/${post_id}.json`).then(res => res.json()) as PostData;
|
||||
switch (data.file_ext) {
|
||||
case 'png':
|
||||
case 'webp':
|
||||
case 'jpg':
|
||||
case 'gif': {
|
||||
$('head')
|
||||
.append(og("og:image", data.file_url))
|
||||
.append(og("og:image:secure_url", data.file_url))
|
||||
.append(og('og:image:type', `image/${data.file_ext}`))
|
||||
.append(og('og:image:height', data.image_height.toString()))
|
||||
.append(og('og:image:width', data.image_width.toString()))
|
||||
.append(og('twitter:image', data.file_url))
|
||||
break;
|
||||
}
|
||||
case 'zip': $('head').append(og("og:video", data.media_asset.variants.find(v => v.file_ext === 'webm')?.url ?? '')); break;
|
||||
case 'mp4':
|
||||
case 'webm': {
|
||||
$('head')
|
||||
.append(og("og:video", data.file_url))
|
||||
.append(og("og:video:secure_url", data.file_url))
|
||||
.append(og("og:video:type", `video/${data.file_ext}`))
|
||||
.append(og("og:video:height", data.image_height.toString()))
|
||||
.append(og("og:video:width", data.image_width.toString()))
|
||||
.append(og("og:image", data.media_asset.variants.find(v => v.file_ext === 'webp')?.url ?? ''))
|
||||
break;
|
||||
}
|
||||
}
|
||||
const byArtist = `${list_format.format(data.tag_string_artist.split(' '))}`;
|
||||
const characters = data.tag_string_character.split(' ').map(str => {
|
||||
const matched = str.match(/([a-z-_]+)(?:\((\w+)\))?/)
|
||||
console.debug(str)
|
||||
return matched?.at(1)?.replaceAll('_', ' ')
|
||||
}).filter(str => str !== undefined);
|
||||
const copyrights = data.tag_string_copyright.split(' ').map(str => {
|
||||
const matched = str.match(/([a-z-_]+)(?:\((\w+)\))?/)
|
||||
return matched?.at(1)?.replaceAll('_', ' ')
|
||||
}).filter(str => str !== undefined);
|
||||
const copyright0 = copyrights.at(0);
|
||||
const title = `${list_format.format(characters)}${copyright0 ? ` (${copyright0}${copyrights.length > 1 ? ` and ${copyrights.length - 1} more` : ''})` : '' }${byArtist ? ` drawn by ${byArtist}` : ''} | Danbooru Viewer`;
|
||||
const description = `${data.file_ext.toUpperCase()} | ${data.image_width}x${data.image_height} | ${digitalUnit(data.file_size)}`;
|
||||
$('head')
|
||||
.append(og('og:title', title))
|
||||
.append(og('og:description', description))
|
||||
.append(og('og:site_name', 'Danbooru Viewer'))
|
||||
.append(og('og:type', 'website'))
|
||||
.append(og('og:url', `https://danbooru.defaultkavy.com/${path}`))
|
||||
.append(og('twitter:site', '@defaultkavy_dev'))
|
||||
.append(og('twitter:title', title))
|
||||
.append(og('twitter:description', description))
|
||||
.append(og('twitter:card', 'summary_large_image'))
|
||||
}
|
||||
return $.html()
|
||||
})
|
||||
.get('/assets/*', (res) => {
|
||||
return Bun.file(`./dist/${res.path}`)
|
||||
@ -11,10 +71,29 @@ const app = new Elysia()
|
||||
.group('/api', app => { return app
|
||||
.delete('/favorites/:id', async ({params, query}) => {
|
||||
const data = await fetch(`${query.origin}/favorites/${params.id}.json?login=${query.login}&api_key=${query.api_key}`, {method: "DELETE"}).then(res => res.ok);
|
||||
console.debug(data)
|
||||
return data
|
||||
})
|
||||
})
|
||||
.listen(3030);
|
||||
console.log('Start listening: 3030')
|
||||
export type Server = typeof app;
|
||||
|
||||
function og(property: string, content: string) {
|
||||
return `<meta property=${property} content="${content}">`
|
||||
}
|
||||
|
||||
export function digitalUnit(bytes: number) {
|
||||
if (bytes < 1000) return `${bytes}B`
|
||||
const kb = bytes / 1000;
|
||||
if (kb < 1000) return `${kb.toFixed(2)}kB`;
|
||||
const mb = bytes / (1000 ** 2);
|
||||
if (mb < 1000) return `${mb.toFixed(2)}MB`;
|
||||
const gb = bytes / (1000 ** 3);
|
||||
if (gb < 1000) return `${gb.toFixed(2)}GB`;
|
||||
const tb = bytes / (1000 ** 4);
|
||||
if (tb < 1000) return `${tb.toFixed(2)}TB`;
|
||||
const pb = bytes / (1000 ** 5);
|
||||
if (pb < 1000) return `${pb.toFixed(2)}PB`;
|
||||
const eb = bytes / (1000 * 6);
|
||||
return `${eb.toFixed(2)}EB`;
|
||||
}
|
@ -61,8 +61,7 @@ $(document.body).content([
|
||||
else Booru.set(danbooru);
|
||||
}),
|
||||
// Open Booru
|
||||
$('ion-icon').class('open').name('open-outline').title('Open in Original Site')
|
||||
.on('click', () => $.open(location.href.replace(location.origin, Booru.used.origin))),
|
||||
$('a').content($('ion-icon').class('open').name('open-outline').title('Open in Original Site')).href(location.href.replace(location.origin, Booru.used.origin)).target('_blank'),
|
||||
// Menu Button
|
||||
$('ion-icon').class('menu').name('menu-outline').title('Menu').hide(false)
|
||||
.self(($icon) => { Booru.events.on('login', () => $icon.hide(true)).on('logout', () => $icon.hide(false)) })
|
||||
|
@ -80,17 +80,17 @@ export const post_route = $('route').path('/posts/:id').id('post').builder(({$ro
|
||||
]),
|
||||
new $Property('file-url').name('File').content([
|
||||
$('a').href(post.file_url$).content(post.file_url$.convert((value) => value.replace('https://', ''))).target('_blank'),
|
||||
$('ion-icon').name('clipboard').on('click', (e, $ion) => copyButtonHandler($ion, post.source))
|
||||
$('ion-icon').name('clipboard').on('click', (e, $ion) => copyButtonHandler($ion, post.file_url))
|
||||
]),
|
||||
new $Property('source-url').name('Source').content([
|
||||
$('a').href(post.source$).content(post.source$.convert((value) => value.replace('https://', ''))).target('_blank'),
|
||||
$('ion-icon').name('clipboard').on('click', (e, $ion) => copyButtonHandler($ion, post.source))
|
||||
]),
|
||||
new $Property('booru-url').name(Booru.name$).content([
|
||||
$('a').href(post.url$).content(post.url$.convert((value) => value.replace('https://', ''))).target('_blank'),
|
||||
$('ion-icon').name('clipboard').on('click', (e, $ion) => copyButtonHandler($ion, post.source))
|
||||
$('a').href(post.booruUrl$).content(post.booruUrl$.convert((value) => value.replace('https://', ''))).target('_blank'),
|
||||
$('ion-icon').name('clipboard').on('click', (e, $ion) => copyButtonHandler($ion, post.booruUrl))
|
||||
]),
|
||||
new $Property('booru-url').name('Webm').hide(true).self(async ($property) => {
|
||||
new $Property('webm-url').name('Webm').hide(true).self(async ($property) => {
|
||||
await post.ready;
|
||||
if (post.isUgoria) $property.content($('a').href(post.webm_url$).content(post.webm_url$.convert((value) => value.replace('https://', ''))).target('_blank')).hide(false);
|
||||
}),
|
||||
|
@ -21,7 +21,7 @@ export class Post extends $EventManager<{update: []}> {
|
||||
file_url$ = $.state(LOADING_STRING);
|
||||
source$ = $.state(LOADING_STRING);
|
||||
dimension$ = $.state(LOADING_STRING);
|
||||
url$ = $.state(LOADING_STRING);
|
||||
booruUrl$ = $.state(LOADING_STRING);
|
||||
createdDate = new Date(this.created_at);
|
||||
ready?: Promise<this>;
|
||||
webm_url$ = $.state(LOADING_STRING);
|
||||
@ -84,7 +84,7 @@ export class Post extends $EventManager<{update: []}> {
|
||||
this.file_url$.set(this.file_url);
|
||||
this.source$.set(this.source);
|
||||
this.dimension$.set(`${this.image_width}x${this.image_height}`);
|
||||
this.url$.set(`${this.url}`);
|
||||
this.booruUrl$.set(`${this.booruUrl}`);
|
||||
if (this.isUgoria) this.webm_url$.set(this.large_file_url);
|
||||
this.createdDate = new Date(this.created_at);
|
||||
this.fire('update');
|
||||
@ -133,7 +133,8 @@ export class Post extends $EventManager<{update: []}> {
|
||||
return [...this.booru.tags.values()].filter(tag => tag_list.includes(tag.name))
|
||||
}
|
||||
get previewURL() { return this.media_asset.variants?.find(variant => variant.file_ext === 'webp')?.url ?? this.large_file_url }
|
||||
get url() { return `${this.booru.origin}/posts/${this.id}` }
|
||||
get booruUrl() { return `${this.booru.origin}/posts/${this.id}` }
|
||||
get url() { return `https://danbooru.defaultkavy.com/posts/${this.id}` }
|
||||
get isFileSource() { return this.source.startsWith('file://') }
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user