coomdev
2 years ago
18 changed files with 14092 additions and 12770 deletions
File diff suppressed because it is too large
@ -0,0 +1,129 @@ |
|||
<script lang="ts"> |
|||
import { map } from "lodash"; |
|||
import { each, onMount } from "svelte/internal"; |
|||
|
|||
import type { EmbeddedFile } from "../main"; |
|||
import { appState } from "../stores"; |
|||
import { addToEmbeds, getFileFromHydrus } from "../utils"; |
|||
import Embedding from "./Embedding.svelte"; |
|||
|
|||
import Tag from "./Tag.svelte"; |
|||
|
|||
let tags: string[] = []; |
|||
|
|||
let loading = false; |
|||
|
|||
function removeTag(t: string) { |
|||
tags = tags.filter((e) => e != t); |
|||
update(); |
|||
} |
|||
let maps: [number, EmbeddedFile][] = []; |
|||
|
|||
async function update() { |
|||
loading = true; |
|||
if ($appState.client) { |
|||
try { |
|||
if (tags.length == 0) { |
|||
maps = []; |
|||
loading = false; |
|||
return; |
|||
} |
|||
maps = await getFileFromHydrus( |
|||
$appState.client, |
|||
tags.concat(["system:limit=32"]), |
|||
{ file_sort_type: 4 } |
|||
); |
|||
} catch {} |
|||
} |
|||
loading = false; |
|||
} |
|||
|
|||
onMount(() => { |
|||
return update(); |
|||
}); |
|||
</script> |
|||
|
|||
<div class="cont"> |
|||
<input |
|||
type="text" |
|||
placeholder="Input a tag here, then press enter" |
|||
on:keydown={(ev) => { |
|||
if (ev.key == "Enter") { |
|||
if (ev.currentTarget.value) |
|||
tags = [...tags, ev.currentTarget.value]; |
|||
ev.currentTarget.value = ""; |
|||
update(); |
|||
} |
|||
}} |
|||
/> |
|||
<details> |
|||
<summary>Tips</summary> |
|||
Press enter without entering a tag to refresh. <br /> |
|||
Files are picked randomly <br /> |
|||
Click on a file to embed it <br /> |
|||
</details> |
|||
<div class="tagcont"> |
|||
{#each tags as tag} |
|||
<Tag {tag} on:toggle={() => removeTag(tag)} /> |
|||
{/each} |
|||
</div> |
|||
{#if loading} |
|||
Loading... |
|||
{:else} |
|||
<div class="results"> |
|||
{#each maps as map (map[0])} |
|||
<Embedding |
|||
on:click={() => addToEmbeds(map[1])} |
|||
inhibitExpand={true} |
|||
id={"only"} |
|||
file={map[1]} |
|||
/> |
|||
{/each} |
|||
</div> |
|||
{/if} |
|||
</div> |
|||
|
|||
<style scoped> |
|||
.results { |
|||
display: flex; |
|||
flex-wrap: wrap; |
|||
max-height: 30vh; |
|||
gap: 10px; |
|||
overflow-y: auto; |
|||
align-items: center; |
|||
justify-content: center; |
|||
} |
|||
|
|||
.tagcont { |
|||
display: flex; |
|||
gap: 5px; |
|||
} |
|||
|
|||
.cont { |
|||
display: flex; |
|||
flex-direction: column; |
|||
gap: 10px; |
|||
} |
|||
|
|||
details { |
|||
border: 1px solid #aaa; |
|||
border-radius: 4px; |
|||
padding: 0.5em 0.5em 0; |
|||
} |
|||
|
|||
summary { |
|||
font-weight: bold; |
|||
margin: -0.5em -0.5em 0; |
|||
padding: 0.5em; |
|||
cursor: pointer; |
|||
} |
|||
|
|||
details[open] { |
|||
padding: 0.5em; |
|||
} |
|||
|
|||
details[open] summary { |
|||
border-bottom: 1px solid #aaa; |
|||
margin-bottom: 0.5em; |
|||
} |
|||
</style> |
@ -0,0 +1,100 @@ |
|||
type TagList = (string | TagList)[]; |
|||
|
|||
export interface MyTags { |
|||
0: string[]; |
|||
} |
|||
|
|||
export interface AllKnownTags { |
|||
0: string[]; |
|||
} |
|||
|
|||
export interface ServiceNamesToStatusesToTags { |
|||
'all known tags': AllKnownTags; |
|||
} |
|||
|
|||
export interface MyTags2 { |
|||
0: string[]; |
|||
} |
|||
|
|||
export interface AllKnownTags2 { |
|||
0: string[]; |
|||
} |
|||
|
|||
export interface ServiceNamesToStatusesToDisplayTags { |
|||
'all known tags': AllKnownTags2; |
|||
} |
|||
|
|||
export interface Metadata { |
|||
file_id: number; |
|||
hash: string; |
|||
size: number; |
|||
mime: string; |
|||
ext: string; |
|||
width: number; |
|||
height: number; |
|||
duration?: any; |
|||
num_frames?: any; |
|||
num_words?: any; |
|||
has_audio: boolean; |
|||
time_modified: number; |
|||
is_inbox: boolean; |
|||
is_local: boolean; |
|||
is_trashed: boolean; |
|||
known_urls: string[]; |
|||
service_names_to_statuses_to_tags: ServiceNamesToStatusesToTags; |
|||
service_names_to_statuses_to_display_tags: ServiceNamesToStatusesToDisplayTags; |
|||
} |
|||
|
|||
export interface RootObject { |
|||
metadata: Metadata[]; |
|||
} |
|||
|
|||
export class HydrusClient { |
|||
constructor( |
|||
private ak: string, |
|||
private origin: string = 'http://127.0.0.1', |
|||
private port: number = 45869, |
|||
) { |
|||
} |
|||
|
|||
get baseUrl() { |
|||
return `${this.origin}:${this.port}`; |
|||
} |
|||
|
|||
async get(params: string) { |
|||
return await fetch(this.baseUrl + params, { |
|||
headers: { |
|||
'Hydrus-Client-API-Access-Key': this.ak |
|||
} |
|||
}); |
|||
} |
|||
|
|||
async verify() { |
|||
try { |
|||
const ret = await this.get('/verify_access_key'); |
|||
return !!await ret.json(); |
|||
} catch (e) { |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
async idsByTags(taglist: TagList, args?: object) { |
|||
const req = await this.get('/get_files/search_files?tags=' + encodeURIComponent(JSON.stringify(taglist)) + (args ? '&' + (Object.entries(args).map(e => `${e[0]}=${encodeURIComponent(e[1])}`).join('&')) : '')); |
|||
return await req.json() as { file_ids: number[] }; |
|||
} |
|||
|
|||
async getMetaDataByIds(ids: number[]) { |
|||
const req = await this.get('/get_files/file_metadata?file_ids=' + encodeURIComponent(JSON.stringify(ids))); |
|||
return await req.json() as { metadata: Metadata[] }; |
|||
} |
|||
|
|||
async getFile(id: number) { |
|||
const req = await this.get('/get_files/file?file_id=' + id); |
|||
return await req.arrayBuffer(); |
|||
} |
|||
|
|||
async getThumbnail(id: number) { |
|||
const req = await this.get('/get_files/thumbnail?file_id=' + id); |
|||
return await req.arrayBuffer(); |
|||
} |
|||
} |
Loading…
Reference in new issue