You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
226 lines
6.7 KiB
226 lines
6.7 KiB
<script lang="ts">
|
|
import { fileTypeFromBuffer } from 'file-type';
|
|
import type Embedding from './Embedding.svelte';
|
|
import type Embeddings from './Embeddings.svelte';
|
|
|
|
import { EmbeddedFile, EMBED_TYPES } from './main';
|
|
|
|
import { settings } from './stores'
|
|
|
|
export let id = ''
|
|
export let files: EmbeddedFile[];
|
|
export let inst: Embedding | Embeddings;
|
|
|
|
let isVideo = false
|
|
|
|
inst.$on("fileinfo", (info) => {
|
|
isVideo = isVideo || info.detail.type.mime.startsWith('video/');
|
|
})
|
|
|
|
let visible = false
|
|
function reveal() {
|
|
visible = !visible
|
|
document.dispatchEvent(new CustomEvent('reveal', { detail: { id } }))
|
|
}
|
|
const isNotChrome = !navigator.userAgent.includes("Chrome/");
|
|
|
|
|
|
const opContainer = document.querySelector('.opContainer') as HTMLDivElement;
|
|
const fullId = opContainer?.dataset.fullID ?? "";
|
|
const boardID = fullId?.substring(0, fullId.indexOf('.')) ?? "";
|
|
const opID = fullId?.substring(fullId.indexOf('.') + '.'.length) ?? "";
|
|
|
|
const opSubject = opContainer?.querySelector('.postInfo.desktop .subject')?.textContent ?? "";
|
|
const opComment = opContainer?.querySelector('.postMessage')?.textContent ?? "";
|
|
const opInfo = (opSubject + opComment).substring(0, 46);
|
|
const opTotal = `[${opInfo}]_oID[${opID}]`;
|
|
|
|
const MAX_PATH = 237;
|
|
function downloadName(filename: string) {
|
|
//! TODO add user flag or check for Windows or not, if not remove .substring() calls.
|
|
//MAX Length=(260-12-1) = 247. The trailing minus 1 is for the invisible NUL terminator. (Windows)
|
|
//opera browser max length 243?
|
|
//firefox browser max length 237?
|
|
//style -> '-[]_oID[]_pID[]_[].' = 19 char length
|
|
//style example -> '$boardID-[$name]_opID.[$opID]_postID.[$postID]_[$fileName]'
|
|
|
|
const downloadExt = filename.substring(filename.lastIndexOf("."));
|
|
|
|
const postWrapper = document.querySelector('[alt="'+filename+'"]')?.parentElement?.parentElement?.parentElement?.parentElement;
|
|
const pID = postWrapper?.id.substring(1) ?? "";
|
|
// const pSubject = postWrapper?.querySelector('.subject')?.textContent ?? "";
|
|
// const pComment = postWrapper?.querySelector('.postMessage')?.textContent ?? "";
|
|
// const pInfo = (opSubject + opComment).substring(0, 46);
|
|
// const pTotal = `[${pInfo}]_ID[${pID}]`;
|
|
|
|
// return `${boardID}-${opTotal}_pID[${postID}]_[{3e}${fileName}]`;
|
|
const suffix = ']' + downloadExt;
|
|
const max = MAX_PATH - suffix.length;
|
|
const substringed = `${boardID}-${opTotal}_pID[${pID}]_[{PEE}${filename}`.substring(0, max);
|
|
return substringed + suffix;
|
|
}
|
|
|
|
|
|
|
|
async function downloadFile(file: EmbeddedFile) {
|
|
const a = document.createElement("a") as HTMLAnchorElement;
|
|
document.body.appendChild(a);
|
|
a.style.display = 'none';
|
|
const thumb = (typeof file.data === 'function') ? await file.data() : file.data ;
|
|
if(!(thumb instanceof ArrayBuffer || thumb instanceof Uint8Array)) {
|
|
console.error("Couldn't download File");
|
|
debugger;
|
|
return;
|
|
}
|
|
const type = await fileTypeFromBuffer(thumb);
|
|
const url = URL.createObjectURL(new Blob([thumb], { type: type?.mime }))
|
|
a.href = url;
|
|
|
|
a.download = downloadName(file.filename);
|
|
a.click();
|
|
window.URL.revokeObjectURL(url);
|
|
}
|
|
|
|
let black = new Set<string>();
|
|
settings.subscribe(s => {
|
|
black = new Set(s.blacklist);
|
|
});
|
|
let blackHits = files.filter(file => file.tags?.some(e => black.has(e)) ?? false) ?? [''];
|
|
</script>
|
|
|
|
{#if $settings.eye}
|
|
<span
|
|
on:click={reveal}
|
|
class:fa-eye={!visible}
|
|
class:fa-eye-slash={visible}
|
|
class="fa clickable"
|
|
/>
|
|
{/if}
|
|
{#each files as file}
|
|
<span
|
|
title={file.filename}
|
|
on:click={() => downloadFile(file)}
|
|
class="fa fa-download clickable"
|
|
class:hasembed={file?.embed_type === EMBED_TYPES.MEDIA_EMBED}
|
|
class:hasext={file?.embed_type === EMBED_TYPES.EXTERNAL_BOORU || file?.embed_type === EMBED_TYPES.EXTERNAL_POMF}
|
|
class:hasblack={file?.isBlacklisted === true}
|
|
/> <!-- hasblack is last for it to have greater weight than hasext, to override it -->
|
|
|
|
{#if file.source}
|
|
<!-- svelte-ignore a11y-missing-content -->
|
|
<a
|
|
href={file.source}
|
|
target="_blank"
|
|
class="clickable"
|
|
class:hasembed={file?.embed_type === EMBED_TYPES.MEDIA_EMBED}
|
|
class:hasext={file?.embed_type === EMBED_TYPES.EXTERNAL_BOORU || file?.embed_type === EMBED_TYPES.EXTERNAL_POMF}
|
|
class:hasblack={file?.isBlacklisted === true}
|
|
>Source</a>
|
|
{/if}
|
|
{#if file.page}
|
|
<!-- svelte-ignore a11y-missing-content -->
|
|
<a
|
|
href={file.page.url}
|
|
target="_blank"
|
|
class="clickable"
|
|
class:hasembed={file?.embed_type === EMBED_TYPES.MEDIA_EMBED}
|
|
class:hasext={file?.embed_type === EMBED_TYPES.EXTERNAL_BOORU || file?.embed_type === EMBED_TYPES.EXTERNAL_POMF}
|
|
class:hasblack={file?.isBlacklisted === true}
|
|
>{file.page.title}</a>
|
|
{/if}
|
|
{#if file.tags}
|
|
<!-- svelte-ignore a11y-missing-content -->
|
|
<details class="tags">
|
|
<summary
|
|
class:hasembed={file?.embed_type === EMBED_TYPES.MEDIA_EMBED}
|
|
class:hasext={file?.embed_type === EMBED_TYPES.EXTERNAL_BOORU || file?.embed_type === EMBED_TYPES.EXTERNAL_POMF}
|
|
class:hasblack={file?.isBlacklisted === true}
|
|
>Tags</summary>
|
|
<ul>
|
|
{#each file.tags as tag}
|
|
<li class:hasblack-bg={black.has(tag)}>{tag}</li>
|
|
{/each}
|
|
</ul>
|
|
</details>
|
|
{/if}
|
|
{#if isNotChrome && isVideo}
|
|
<!-- svelte-ignore a11y-missing-attribute -->
|
|
<a on:click={(ev) => { inst.bepis(ev); }}
|
|
alt="By clicking this you agree to stay hydrated"
|
|
class="clickable"
|
|
class:hasembed={file?.embed_type === EMBED_TYPES.MEDIA_EMBED}
|
|
class:hasext={file?.embed_type === EMBED_TYPES.EXTERNAL_BOORU || file?.embed_type === EMBED_TYPES.EXTERNAL_POMF}
|
|
class:hasblack={file?.isBlacklisted === true}
|
|
>[PEE contract]</a
|
|
>
|
|
{/if}
|
|
{/each}
|
|
|
|
<style scoped>
|
|
.clickable {
|
|
cursor: pointer;
|
|
/* margin-left: 5px; */
|
|
|
|
/* Custom */
|
|
margin-left: 2px;
|
|
margin-right: 2px;
|
|
}
|
|
|
|
.hasembed {
|
|
color: deeppink;
|
|
}
|
|
.hasext {
|
|
color: goldenrod;
|
|
}
|
|
.hasblack {
|
|
color: black;
|
|
}
|
|
|
|
/*
|
|
.hasembed-bg {
|
|
background-color: deeppink;
|
|
}
|
|
.hasext-bg {
|
|
background-color: goldenrod;
|
|
}
|
|
*/
|
|
.hasblack-bg {
|
|
background-color: black;
|
|
}
|
|
.clickable:hover {
|
|
text-shadow: 0 0 4px palevioletred;
|
|
}
|
|
a.clickable.hasembed {
|
|
color: deeppink !important;
|
|
}
|
|
a.clickable.hasext {
|
|
color: goldenrod !important;
|
|
}
|
|
a.clickable.hasblack {
|
|
color: black !important;
|
|
}
|
|
|
|
details.tags {
|
|
display: inline-block;
|
|
margin-right: 2px;
|
|
}
|
|
details.tags > summary {
|
|
user-select: none;
|
|
cursor: pointer;
|
|
}
|
|
details.tags > ul {
|
|
position: absolute;
|
|
min-width: 35px;
|
|
|
|
list-style: none;
|
|
margin: 0;
|
|
margin-top: 2px;
|
|
padding: 0;
|
|
background-color: #191a1c;
|
|
z-index: 10;
|
|
}
|
|
details.tags > ul > li {
|
|
padding: 2px 4px;
|
|
/* margin-bottom: 2px; */
|
|
}
|
|
</style>
|
|
|