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