v0.2.3
new: Auto detect and add new post.
This commit is contained in:
parent
1add8ce529
commit
6855e7eca8
1
dist/assets/index-BIoKxl_Q.js
vendored
1
dist/assets/index-BIoKxl_Q.js
vendored
File diff suppressed because one or more lines are too long
@ -1 +1 @@
|
||||
post{display:block}post[filetype=mp4] span.duration,post[filetype=webm] span.duration,post[filetype=zip] span.duration{background-color:#fff;color:#000}post span.duration{position:absolute;background-color:#00000050;bottom:.3rem;right:.3rem;padding:2px 4px;border-radius:4px;font-size:12px;text-transform:uppercase;z-index:2}post img{border-radius:10px;height:100%;width:100%}post video{border-radius:10px;height:100%;width:100%;object-fit:cover;position:absolute}#post section{background-color:#2f2f45;border-radius:20px;padding:20px}#post div.main{width:calc(100vw - 300px - 4rem);padding-right:10px;display:flex;flex-direction:column}@media (max-width: 800px){#post div.main{width:100%}}#post div.main::-webkit-scrollbar{background-color:#000;width:4px}#post div.main::-webkit-scrollbar-thumb{background-color:#aeaeec;border-radius:2px}#post div.main>h3{padding-left:1rem;margin-block:1rem}#post div.main div.viewer{height:calc(100vh - 2rem);display:flex;justify-content:center;align-items:center;background-color:#000;border-radius:20px;overflow:hidden}#post div.main div.viewer img{max-width:100%;max-height:100%}#post div.main div.viewer video{max-width:100%;max-height:100%}#post div.main section.commentary *{text-wrap:wrap;word-break:break-word}#post div.sidebar{position:fixed;top:1rem;right:1rem;display:flex;flex-direction:column;gap:.4rem;width:300px;overflow:scroll;overflow-x:hidden;height:calc(100vh - 2rem);border-radius:20px}@media (max-width: 800px){#post div.sidebar{position:relative;width:100%;overflow:visible;height:100%;padding-inline:1rem;padding-bottom:1rem}}#post div.sidebar::-webkit-scrollbar{background-color:#000;width:0px}#post div.sidebar::-webkit-scrollbar-thumb{background-color:#aeaeec}#post div.sidebar h3{padding-left:1rem;margin-block:.6rem}#post div.sidebar .post-info{background-color:#2f2f45;border-radius:20px;padding:20px;display:flex;flex-direction:column;gap:.4rem}#post div.sidebar div.property{display:flex;gap:.6rem;align-items:center}#post div.sidebar div.property div.property-values{display:flex;gap:.4rem}#post div.sidebar div.property div.property-values span.property-value{background-color:#525278;color:#aeaeec;padding:2px 4px;border-radius:4px}#post div.sidebar div.inline{display:flex;gap:1rem}#post div.sidebar div.post-tags{display:flex;flex-direction:column;gap:.2rem}#post div.sidebar div.post-tags div.tag{align-items:center}#post div.sidebar div.post-tags div.tag a.tag-name{word-break:break-word;color:#d1d1ee;text-decoration:none}#post div.sidebar div.post-tags div.tag span.tag-post-count{background-color:#525278;color:#aeaeec;padding:0 4px;border-radius:4px;font-size:12px;margin-left:.4rem}page#root .loader{text-align:center;padding-block:2rem}body{background-color:#1e1e2c;color:#d1d1ee;margin:0;font-family:Microsoft Yahei;font-size:14px}body::-webkit-scrollbar{background-color:#000;width:8px}body::-webkit-scrollbar-thumb{background-color:#aeaeec;border-radius:2px}app{display:block}app view{display:block}app view page{min-height:100%;padding:1rem;display:block}
|
||||
post{display:block}post[filetype=mp4] span.duration,post[filetype=webm] span.duration,post[filetype=zip] span.duration{background-color:#fff;color:#000}post span.duration{position:absolute;background-color:#00000050;bottom:.3rem;right:.3rem;padding:2px 4px;border-radius:4px;font-size:12px;text-transform:uppercase;z-index:2}post img{border-radius:10px;height:100%;width:100%}post video{border-radius:10px;height:100%;width:100%;object-fit:cover;position:absolute}#post section{background-color:#2f2f45;border-radius:20px;padding:20px}#post div.main{width:calc(100vw - 300px - 4rem);padding-right:10px;display:flex;flex-direction:column}@media (max-width: 800px){#post div.main{width:100%}}#post div.main::-webkit-scrollbar{background-color:#000;width:4px}#post div.main::-webkit-scrollbar-thumb{background-color:#aeaeec;border-radius:2px}#post div.main>h3{padding-left:1rem;margin-block:1rem}#post div.main div.viewer{height:calc(100vh - 2rem);display:flex;justify-content:center;align-items:center;background-color:#000;border-radius:20px;overflow:hidden}#post div.main div.viewer img{max-width:100%;max-height:100%}#post div.main div.viewer video{max-width:100%;max-height:100%}#post div.main section.commentary *{text-wrap:wrap;word-break:break-word}#post div.sidebar{position:fixed;top:1rem;right:1rem;display:flex;flex-direction:column;gap:.4rem;width:300px;overflow:scroll;overflow-x:hidden;height:calc(100vh - 2rem);border-radius:20px}@media (max-width: 800px){#post div.sidebar{position:relative;width:100%;overflow:visible;height:100%;padding-inline:1rem;padding-bottom:1rem}}#post div.sidebar::-webkit-scrollbar{background-color:#000;width:0px}#post div.sidebar::-webkit-scrollbar-thumb{background-color:#aeaeec}#post div.sidebar h3{padding-left:1rem;margin-block:.6rem}#post div.sidebar .post-info{background-color:#2f2f45;border-radius:20px;padding:20px;display:flex;flex-direction:column;gap:.4rem}#post div.sidebar div.property{display:flex;gap:.6rem;align-items:center}#post div.sidebar div.property div.property-values{display:flex;gap:.4rem}#post div.sidebar div.property div.property-values span.property-value{background-color:#525278;color:#aeaeec;padding:2px 4px;border-radius:4px}#post div.sidebar div.inline{display:flex;gap:1rem}#post div.sidebar div.post-tags{display:flex;flex-direction:column;gap:.2rem}#post div.sidebar div.post-tags div.tag{align-items:center}#post div.sidebar div.post-tags div.tag a.tag-name{word-break:break-word;color:#d1d1ee;text-decoration:none}#post div.sidebar div.post-tags div.tag span.tag-post-count{background-color:#525278;color:#aeaeec;padding:0 4px;border-radius:4px;font-size:12px;margin-left:.4rem}page#root layout *{transition:all .3s ease}page#root .loader{text-align:center;padding-block:2rem}html{overflow-x:hidden}body{background-color:#1e1e2c;color:#d1d1ee;margin:0;font-family:Microsoft Yahei;font-size:14px}body::-webkit-scrollbar{background-color:#000;width:8px}body::-webkit-scrollbar-thumb{background-color:#aeaeec;border-radius:2px}app{display:block}app view{display:block}app view page{min-height:100%;padding:1rem;display:block}
|
1
dist/assets/index-DR9E_CfL.js
vendored
Normal file
1
dist/assets/index-DR9E_CfL.js
vendored
Normal file
File diff suppressed because one or more lines are too long
4
dist/index.html
vendored
4
dist/index.html
vendored
@ -5,8 +5,8 @@
|
||||
<!-- <link rel="icon" type="image/svg+xml" href="/vite.svg" /> -->
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Danbooru Viewer v0.1</title>
|
||||
<script type="module" crossorigin src="/assets/index-BIoKxl_Q.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-Cq-5lgfU.css">
|
||||
<script type="module" crossorigin src="/assets/index-DR9E_CfL.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-BMUJRc5c.css">
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
|
@ -1,8 +1,11 @@
|
||||
@import '/src/component/PostGrid/$PostGrid';
|
||||
@import '/src/component/PostTile/$PostTile';
|
||||
@import '/src/route/posts/$post';
|
||||
@import '/src/route/home/$home';
|
||||
@import '/src/route/gallery/$gallery';
|
||||
|
||||
html {
|
||||
overflow-x: hidden;
|
||||
}
|
||||
body {
|
||||
background-color: #1e1e2c;
|
||||
color: #d1d1ee;
|
||||
|
@ -3,7 +3,7 @@ import '@elexis/layout';
|
||||
import '@elexis/router';
|
||||
import { Booru } from './structure/Booru';
|
||||
import { Router } from '@elexis/router';
|
||||
import { home_route } from './route/home/$home';
|
||||
import { home_route } from './route/gallery/$gallery';
|
||||
import { posts_route } from './route/posts/$post';
|
||||
|
||||
export const booru = new Booru({
|
||||
|
84
src/route/gallery/$gallery.ts
Normal file
84
src/route/gallery/$gallery.ts
Normal file
@ -0,0 +1,84 @@
|
||||
import { Route, Router } from "@elexis/router";
|
||||
import { Post } from "../../structure/Post";
|
||||
import { booru } from "../../main";
|
||||
import { $PostGrid } from "../../component/PostGrid/$PostGrid";
|
||||
import { $PostTile } from "../../component/PostTile/$PostTile";
|
||||
const MAX_POST_LENGTH = 100;
|
||||
export const home_route = new Route((path) => {
|
||||
if (path === '/posts' || path === '/') return '/';
|
||||
}, ({record}) => {
|
||||
const $page = $('page').id('root');
|
||||
async function load(tags: string) {
|
||||
const posts = await Post.fetchMultiple(booru, tags.length ? {tags: tags} : undefined, MAX_POST_LENGTH)
|
||||
const filtered_posts = posts.filter(post => post.file_url);
|
||||
const $layout = $('layout').class('post-grid').type('waterfall').column(5).maxHeight(300).gap(10)
|
||||
.content([
|
||||
filtered_posts.map(post => new $PostTile(post))
|
||||
]).on('resize', () => { resizeCheck() });
|
||||
resizeCheck();
|
||||
let FIRST_POST = posts.at(1)!;
|
||||
let LAST_POST = posts.at(-1)!;
|
||||
let SCROLL_LOADED = false;
|
||||
let POST_ENDED = posts.length !== MAX_POST_LENGTH;
|
||||
const $loader = $('div').class('loader').content( POST_ENDED ? `It's End` : 'Loading...');
|
||||
window.addEventListener('scroll', async () => {
|
||||
if (!$layout.inDOM()) return;
|
||||
if (POST_ENDED) return;
|
||||
if (SCROLL_LOADED) return;
|
||||
if (document.documentElement.scrollTop < document.documentElement.scrollHeight - innerHeight * 3) return;
|
||||
SCROLL_LOADED = true;
|
||||
const posts = await Post.fetchMultiple(booru, tags.length ? {tags: tags, id: `..${LAST_POST.id - 1}`} : {id: `..${LAST_POST.id - 1}`}, MAX_POST_LENGTH)
|
||||
$layout.insert(
|
||||
posts.filter(post => post.file_url).map(post => new $PostTile(post))
|
||||
).render();
|
||||
if (posts.length !== MAX_POST_LENGTH) {
|
||||
$loader.content(`It's End`);
|
||||
POST_ENDED = true;
|
||||
}
|
||||
LAST_POST = posts.at(-1)!;
|
||||
SCROLL_LOADED = false;
|
||||
})
|
||||
|
||||
setInterval(async () => {
|
||||
if (!$layout.inDOM()) return;
|
||||
if (document.documentElement.scrollTop !== 0) return;
|
||||
const posts = await Post.fetchMultiple(booru, tags.length ? {tags: tags, id: `${FIRST_POST.id + 2}..`} : {id: `${FIRST_POST.id + 2}..`}, MAX_POST_LENGTH)
|
||||
const filtered_posts = posts.filter(post => post.file_url)
|
||||
if (posts.length) FIRST_POST = posts.at(0)!;
|
||||
if (filtered_posts.length) $layout.insert(filtered_posts.map(post => new $PostTile(post)), 0).render();
|
||||
}, 10_000)
|
||||
|
||||
return {$layout, $loader}
|
||||
|
||||
function resizeCheck() {
|
||||
if (innerWidth < 350) $layout.column(1);
|
||||
else if (innerWidth < 700) $layout.column(2);
|
||||
else {
|
||||
const col = Math.round(innerWidth / 300)
|
||||
$layout.column(col);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const gridManager = new Map<string, $PostGrid>();
|
||||
record.on('open', async () => {
|
||||
const tags = new URL(location.href).searchParams.get('tags') ?? '';
|
||||
const $cacheGrid = gridManager.get(tags);
|
||||
if ($cacheGrid) {
|
||||
$page.content($cacheGrid);
|
||||
$cacheGrid.render();
|
||||
return;
|
||||
} else {
|
||||
$page.clear();
|
||||
}
|
||||
const {$layout, $loader} = await load(tags);
|
||||
$page.content([
|
||||
$layout,
|
||||
$loader
|
||||
]);
|
||||
$layout.render();
|
||||
gridManager.set(tags, $layout);
|
||||
Router.recoveryScrollPosition();
|
||||
})
|
||||
return $page;
|
||||
})
|
@ -1,4 +1,10 @@
|
||||
page#root {
|
||||
|
||||
layout {
|
||||
* {
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
}
|
||||
.loader {
|
||||
text-align: center;
|
||||
padding-block: 2rem;
|
@ -1,72 +0,0 @@
|
||||
import { Route, Router } from "@elexis/router";
|
||||
import { Post } from "../../structure/Post";
|
||||
import { booru } from "../../main";
|
||||
import { $PostGrid } from "../../component/PostGrid/$PostGrid";
|
||||
import { $PostTile } from "../../component/PostTile/$PostTile";
|
||||
|
||||
export const home_route = new Route((path) => {
|
||||
if (path === '/posts' || path === '/') return '/';
|
||||
}, ({record}) => {
|
||||
const $page = $('page').id('root');
|
||||
async function load(tags: string) {
|
||||
const posts = await Post.fetchMultiple(booru, tags.length ? {tags: tags} : undefined, 100)
|
||||
const $grid = new $PostGrid().content([
|
||||
posts.filter(post => post.file_url).map(post => new $PostTile(post))
|
||||
]).on('resize', () => { resizeCheck() });
|
||||
resizeCheck();
|
||||
let last_post = posts.at(-1)!;
|
||||
let loaded = false;
|
||||
let ended = posts.length !== 100;
|
||||
const $loader = $('div').class('loader').content( ended ? `It's End` : 'Loading...');
|
||||
window.addEventListener('scroll', async () => {
|
||||
if (!$grid.inDOM()) return;
|
||||
if (ended) return;
|
||||
if (loaded) return;
|
||||
if (document.documentElement.scrollTop < document.documentElement.scrollHeight - innerHeight * 3) return;
|
||||
loaded = true;
|
||||
const posts = await Post.fetchMultiple(booru, tags.length ? {tags: tags, id: `..${last_post.id - 1}`} : {id: `..${last_post.id - 1}`}, 100)
|
||||
$grid.insert(
|
||||
posts.filter(post => post.file_url).map(post => new $PostTile(post))
|
||||
).render();
|
||||
if (posts.length !== 100) {
|
||||
$loader.content(`It's End`);
|
||||
ended = true;
|
||||
}
|
||||
last_post = posts.at(-1)!;
|
||||
loaded = false;
|
||||
})
|
||||
|
||||
return {$grid, $loader}
|
||||
|
||||
function resizeCheck() {
|
||||
if (innerWidth < 350) $grid.column(1);
|
||||
else if (innerWidth < 700) $grid.column(2);
|
||||
else {
|
||||
const col = Math.round(innerWidth / 300)
|
||||
$grid.column(col);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const gridManager = new Map<string, $PostGrid>();
|
||||
record.on('open', async () => {
|
||||
const tags = new URL(location.href).searchParams.get('tags') ?? '';
|
||||
const $cacheGrid = gridManager.get(tags);
|
||||
if ($cacheGrid) {
|
||||
$page.content($cacheGrid);
|
||||
$cacheGrid.render();
|
||||
return;
|
||||
} else {
|
||||
$page.clear();
|
||||
}
|
||||
const {$grid, $loader} = await load(tags);
|
||||
$page.content([
|
||||
$grid,
|
||||
$loader
|
||||
]);
|
||||
$grid.render();
|
||||
gridManager.set(tags, $grid);
|
||||
Router.recoveryScrollPosition();
|
||||
})
|
||||
return $page;
|
||||
})
|
@ -14,8 +14,8 @@ export const posts_route = new Route('/posts/:id', ({params}) => {
|
||||
$commentary: $('section').class('commentary')
|
||||
}
|
||||
const value = {
|
||||
uploader$: $.state<string|number>('loading...'),
|
||||
approver$: $.state<string|number>('loading...'),
|
||||
uploader$: $.state('loading...'),
|
||||
approver$: $.state('loading...'),
|
||||
date$: $.state('loading...'),
|
||||
size$: $.state('loading...'),
|
||||
dimension$: $.state(`loading...`),
|
||||
@ -39,6 +39,8 @@ export const posts_route = new Route('/posts/:id', ({params}) => {
|
||||
value.score$.set(post.score$)
|
||||
value.ext$.set(post.file_ext.toUpperCase())
|
||||
loadTags();
|
||||
loadCommentary();
|
||||
|
||||
async function loadTags() {
|
||||
const tags = await Tag.fetchMultiple(booru, {name: {_space: post.tag_string}});
|
||||
const [artist_tags, char_tags, gen_tags, meta_tags, copy_tags] = [
|
||||
@ -57,19 +59,17 @@ export const posts_route = new Route('/posts/:id', ({params}) => {
|
||||
])
|
||||
|
||||
function tag_category(category: string, tags: Tag[]) {
|
||||
const INTL_number = new Intl.NumberFormat('en', {notation: 'compact'})
|
||||
return tags.length ? [
|
||||
$('h3').content(category),
|
||||
$('section').content([
|
||||
tags.map(tag => $('div').class('tag').content([
|
||||
$('a').class('tag-name').content(tag.name).href(`/posts?tags=${tag.name}`),
|
||||
$('span').class('tag-post-count').content(`${INTL_number.format(tag.post_count)}`)
|
||||
$('span').class('tag-post-count').content(tag.post_count$)
|
||||
]))
|
||||
])
|
||||
] : null
|
||||
}
|
||||
}
|
||||
loadCommentary();
|
||||
async function loadCommentary() {
|
||||
const commentary = (await ArtistCommentary.fetchMultiple(booru, {post: {_id: post.id}})).at(0);
|
||||
if (!commentary) return ele.$commentary.content('No commentary');
|
||||
@ -99,13 +99,14 @@ export const posts_route = new Route('/posts/:id', ({params}) => {
|
||||
new $Property('favorites').name('Favorites').value(value.favorites$),
|
||||
new $Property('score').name('Score').value(value.score$)
|
||||
]),
|
||||
$('a').content('Copy link').href(`${booru.api}${location.pathname}`).on('click', (e, $a) => {
|
||||
navigator.clipboard.writeText($a.href());
|
||||
$a.content('Copied!');
|
||||
setTimeout(() => {
|
||||
$a.content('Copy link')
|
||||
}, 2000);
|
||||
})
|
||||
$('a').content('Copy link').href(`${booru.api}${location.pathname}`)
|
||||
.on('click', (e, $a) => {
|
||||
navigator.clipboard.writeText($a.href());
|
||||
$a.content('Copied!');
|
||||
setTimeout(() => {
|
||||
$a.content('Copy link')
|
||||
}, 2000);
|
||||
})
|
||||
]),
|
||||
ele.$tags.content('loading...')
|
||||
])
|
||||
|
@ -7,8 +7,8 @@ export interface PostOptions {}
|
||||
export interface Post extends PostData {}
|
||||
export class Post {
|
||||
static manager = new Map<id, Post>();
|
||||
uploader$ = $.state(this.uploader?.name ?? this.uploader_id);
|
||||
approver$ = $.state(this.approver?.name ?? this.approver_id ?? 'None');
|
||||
uploader$ = $.state(this.uploader?.name$ ?? this.uploader_id?.toString());
|
||||
approver$ = $.state(this.approver?.name$ ?? this.approver_id?.toString() ?? 'None');
|
||||
created_date$ = $.state(``);
|
||||
favorites$ = $.state(this.fav_count);
|
||||
score$ = $.state(this.score);
|
||||
@ -18,10 +18,11 @@ export class Post {
|
||||
}
|
||||
|
||||
static async fetch(booru: Booru, id: id) {
|
||||
const req = await fetch(`${booru.api}/posts/${id}.json`);
|
||||
const post = new this(await req.json());
|
||||
User.fetchMultiple(booru, {id: [post.uploader_id, post.approver_id].detype(null)}).then(() => post.update$());
|
||||
return post;
|
||||
const data = await fetch(`${booru.api}/posts/${id}.json`).then(async data => await data.json()) as PostData;
|
||||
const instance = this.manager.get(data.id)?.update(data) ?? new this(data);
|
||||
this.manager.set(instance.id, instance);
|
||||
User.fetchMultiple(booru, {id: [instance.uploader_id, instance.approver_id].detype(null)}).then(() => instance.update$());
|
||||
return instance;
|
||||
}
|
||||
|
||||
static async fetchMultiple(booru: Booru, tags?: Partial<MetaTags> | string, limit = 20) {
|
||||
@ -40,23 +41,30 @@ export class Post {
|
||||
const req = await fetch(`${booru.api}/posts.json?limit=${limit}${tagsQuery}&_method=get`);
|
||||
const dataArray: PostData[] = await req.json();
|
||||
const list = dataArray.map(data => {
|
||||
const instance = new Post(data);
|
||||
const instance = this.manager.get(data.id)?.update(data) ?? new this(data);
|
||||
this.manager.set(instance.id, instance);
|
||||
return instance;
|
||||
});
|
||||
if (!list.length) return list;
|
||||
const userIds = [...new Set(dataArray.map(data => [data.approver_id, data.uploader_id].detype(null)).flat())];
|
||||
User.fetchMultiple(booru, {id: userIds}).then(() => list.forEach(post => post.update$()));
|
||||
return list;
|
||||
}
|
||||
|
||||
update$() {
|
||||
this.uploader$.set(this.uploader?.name ?? this.uploader_id);
|
||||
this.approver$.set(this.approver?.name ?? this.approver_id ?? 'None');
|
||||
this.uploader$.set(this.uploader?.name$ ?? this.uploader_id.toString());
|
||||
this.approver$.set(this.approver?.name$ ?? this.approver_id?.toString() ?? 'None');
|
||||
this.created_date$.set(dateFrom(+new Date(this.created_at)));
|
||||
this.favorites$.set(this.fav_count);
|
||||
this.score$.set(this.score);
|
||||
}
|
||||
|
||||
update(data: PostData) {
|
||||
Object.assign(this, data);
|
||||
this.update$();
|
||||
return this;
|
||||
}
|
||||
|
||||
get pathname() { return `/posts/${this.id}` }
|
||||
get uploader() { return User.manager.get(this.uploader_id); }
|
||||
get approver() { if (this.approver_id) return User.manager.get(this.approver_id); else return null }
|
||||
|
@ -1,17 +1,22 @@
|
||||
import type { Booru } from "./Booru";
|
||||
|
||||
const INTL_number = new Intl.NumberFormat('en', {notation: 'compact'})
|
||||
export interface TagOptions {}
|
||||
export interface Tag extends TagData {}
|
||||
export class Tag {
|
||||
static manager = new Map<id, Tag>();
|
||||
post_count$ = $.state(0, {format: (value) => `${INTL_number.format(value)}`});
|
||||
name$ = $.state('');
|
||||
constructor(data: TagData) {
|
||||
Object.assign(this, data);
|
||||
this.$update();
|
||||
}
|
||||
|
||||
static async fetch(booru: Booru, id: id) {
|
||||
const req = await fetch(`${booru.api}/tags/${id}.json`);
|
||||
const post = new this(await req.json());
|
||||
return post;
|
||||
const data = await fetch(`${booru.api}/tags/${id}.json`).then(async data => await data.json()) as TagData;
|
||||
const instance = this.manager.get(data.id)?.update(data) ?? new this(data);
|
||||
this.manager.set(instance.id, instance);
|
||||
return instance;
|
||||
}
|
||||
|
||||
static async fetchMultiple(booru: Booru, search?: Partial<TagSearchParams>, limit = 1000) {
|
||||
@ -30,12 +35,23 @@ export class Tag {
|
||||
const req = await fetch(`${booru.api}/tags.json?limit=${limit}${searchQuery}`);
|
||||
const dataArray: TagData[] = await req.json();
|
||||
const list = dataArray.map(data => {
|
||||
const instance = new this(data);
|
||||
const instance = this.manager.get(data.id)?.update(data) ?? new this(data);
|
||||
this.manager.set(instance.id, instance);
|
||||
return instance;
|
||||
});
|
||||
return list;
|
||||
}
|
||||
|
||||
update(data: TagData) {
|
||||
Object.assign(this, data);
|
||||
this.$update();
|
||||
return this;
|
||||
}
|
||||
|
||||
$update() {
|
||||
this.post_count$.set(this.post_count);
|
||||
this.name$.set(this.name);
|
||||
}
|
||||
}
|
||||
|
||||
export interface TagData {
|
||||
|
@ -4,14 +4,17 @@ export class UserOptions {}
|
||||
export interface User extends UserOptions, UserData {}
|
||||
export class User {
|
||||
static manager = new Map<id, User>();
|
||||
name$ = $.state('loding...');
|
||||
constructor(data: UserData) {
|
||||
Object.assign(this, data);
|
||||
this.update$();
|
||||
}
|
||||
|
||||
static async fetch(booru: Booru, id: id) {
|
||||
const req = await fetch(`${booru.api}/posts/${id}.json`);
|
||||
const post = new this(await req.json());
|
||||
return post;
|
||||
const data = await fetch(`${booru.api}/users/${id}.json`).then(async data => await data.json()) as UserData;
|
||||
const instance = this.manager.get(data.id)?.update(data) ?? new this(data);
|
||||
this.manager.set(instance.id, instance);
|
||||
return instance;
|
||||
}
|
||||
|
||||
static async fetchMultiple(booru: Booru, search?: Partial<UserSearchParam>, limit = 200) {
|
||||
@ -36,6 +39,16 @@ export class User {
|
||||
});
|
||||
return list;
|
||||
}
|
||||
|
||||
update(data: UserData) {
|
||||
Object.assign(this, data);
|
||||
this.update$();
|
||||
return this;
|
||||
}
|
||||
|
||||
update$() {
|
||||
this.name$.set(this.name);
|
||||
}
|
||||
}
|
||||
|
||||
export interface UserData {
|
||||
|
Loading…
Reference in New Issue
Block a user