Use fetch to load images if insecure request enabled.
This commit is contained in:
Generated
+9
-6
@@ -1,17 +1,17 @@
|
||||
{
|
||||
"name": "Materialious",
|
||||
"version": "1.8.10",
|
||||
"version": "1.9.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "Materialious",
|
||||
"version": "1.8.10",
|
||||
"version": "1.9.0",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@capacitor-community/electron": "^5.0.0",
|
||||
"bgutils-js": "^3.2.0",
|
||||
"capacitor-nodejs": "https://github.com/EdenwareApps/Capacitor-NodeJS/releases/download/v1.0.0-beta.7/capacitor6-nodejs.tgz",
|
||||
"capacitor-nodejs": "https://github.com/hampoelz/capacitor-nodejs/releases/download/v1.0.0-beta.8/capacitor-nodejs.tgz",
|
||||
"chokidar": "~4.0.3",
|
||||
"electron-is-dev": "~2.0.0",
|
||||
"electron-serve": "~1.1.0",
|
||||
@@ -1799,10 +1799,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/capacitor-nodejs": {
|
||||
"version": "1.0.0-beta.7",
|
||||
"resolved": "https://github.com/EdenwareApps/Capacitor-NodeJS/releases/download/v1.0.0-beta.7/capacitor6-nodejs.tgz",
|
||||
"integrity": "sha512-7NwSMxE06nqpuFKyQlt3mWo+VG6Od0d6PBxPKVyPmaptE6sSoimzU/uzQXPWoHV5bwbjgcF+R0BSJAZAyy4gsg==",
|
||||
"version": "1.0.0-beta.8",
|
||||
"resolved": "https://github.com/hampoelz/capacitor-nodejs/releases/download/v1.0.0-beta.8/capacitor-nodejs.tgz",
|
||||
"integrity": "sha512-VAMCTBqz+sA3762kFhSyzXS0unm0EpsVSHLmDYsTYPTiXXZaFcGk27vfXakRyyXJexAUG2Y5rZka5BvH6EmeZw==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=20.10"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@capacitor/core": "^6.0.0"
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
"dependencies": {
|
||||
"@capacitor-community/electron": "^5.0.0",
|
||||
"bgutils-js": "^3.2.0",
|
||||
"capacitor-nodejs": "https://github.com/EdenwareApps/Capacitor-NodeJS/releases/download/v1.0.0-beta.7/capacitor6-nodejs.tgz",
|
||||
"capacitor-nodejs": "https://github.com/hampoelz/capacitor-nodejs/releases/download/v1.0.0-beta.8/capacitor-nodejs.tgz",
|
||||
"chokidar": "~4.0.3",
|
||||
"electron-is-dev": "~2.0.0",
|
||||
"electron-serve": "~1.1.0",
|
||||
@@ -44,4 +44,4 @@
|
||||
"capacitor",
|
||||
"electron"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
import { _ } from 'svelte-i18n';
|
||||
import { get } from 'svelte/store';
|
||||
import type { Channel } from '../api/model';
|
||||
import { truncate } from '../misc';
|
||||
import { insecureRequestImageHandler, truncate } from '../misc';
|
||||
import { interfaceLowBandwidthMode } from '../store';
|
||||
|
||||
interface Props {
|
||||
@@ -19,9 +19,9 @@
|
||||
onMount(async () => {
|
||||
if (get(interfaceLowBandwidthMode)) return;
|
||||
|
||||
const img = new Image();
|
||||
img.src = proxyGoogleImage(getBestThumbnail(channel.authorThumbnails));
|
||||
|
||||
const img = await insecureRequestImageHandler(
|
||||
proxyGoogleImage(getBestThumbnail(channel.authorThumbnails))
|
||||
);
|
||||
img.onload = () => {
|
||||
channelPfp = img;
|
||||
};
|
||||
|
||||
@@ -4,7 +4,9 @@
|
||||
import { getBestThumbnail, proxyGoogleImage } from '$lib/images';
|
||||
import { numberWithCommas } from '$lib/numbers';
|
||||
import { interfaceLowBandwidthMode } from '$lib/store';
|
||||
import { onMount } from 'svelte';
|
||||
import CommentSelf from './Comment.svelte';
|
||||
import { insecureRequestImageHandler } from '$lib/misc';
|
||||
|
||||
interface Props {
|
||||
comment: Comment;
|
||||
@@ -36,16 +38,28 @@
|
||||
|
||||
return processedHtml;
|
||||
}
|
||||
|
||||
let userPfp = $state('');
|
||||
onMount(async () => {
|
||||
if ($interfaceLowBandwidthMode) return;
|
||||
const img = await insecureRequestImageHandler(
|
||||
proxyGoogleImage(getBestThumbnail(comment.authorThumbnails))
|
||||
);
|
||||
|
||||
img.onload = () => {
|
||||
userPfp = img.src;
|
||||
};
|
||||
});
|
||||
</script>
|
||||
|
||||
<div class="comment">
|
||||
{#if !$interfaceLowBandwidthMode}
|
||||
<div class="comment-header">
|
||||
<img
|
||||
class="circle small"
|
||||
src={proxyGoogleImage(getBestThumbnail(comment.authorThumbnails))}
|
||||
alt="comment profile"
|
||||
/>
|
||||
{#if userPfp}
|
||||
<img class="circle small" src={userPfp} alt="comment profile" />
|
||||
{:else}
|
||||
<progress class="circle"></progress>
|
||||
{/if}
|
||||
<div class="comment-info">
|
||||
<a href={`/channel/${comment.authorId}`} class="author">
|
||||
<span class="bold" class:channel-owner={comment.authorIsChannelOwner}>
|
||||
|
||||
@@ -9,8 +9,6 @@
|
||||
}
|
||||
|
||||
let { hashtag }: Props = $props();
|
||||
|
||||
let channelPfp: HTMLImageElement | undefined;
|
||||
</script>
|
||||
|
||||
<a href={hashtag.url} class="wave" style="min-width: 100%;min-height: 100%;">
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
import { _ } from 'svelte-i18n';
|
||||
import { get } from 'svelte/store';
|
||||
import type { Playlist } from '../api/model';
|
||||
import { truncate } from '../misc';
|
||||
import { insecureRequestImageHandler, truncate } from '../misc';
|
||||
import { interfaceLowBandwidthMode } from '../store';
|
||||
|
||||
interface Props {
|
||||
@@ -21,20 +21,23 @@
|
||||
|
||||
const playlistLink = `/playlist/${playlist.playlistId}`;
|
||||
|
||||
onMount(() => {
|
||||
onMount(async () => {
|
||||
if (get(interfaceLowBandwidthMode)) return;
|
||||
|
||||
img = new Image();
|
||||
let imgSrc = '';
|
||||
|
||||
if (playlist.videos.length > 0) {
|
||||
img.src = getBestThumbnail(playlist.videos[0].videoThumbnails) || '';
|
||||
imgSrc = getBestThumbnail(playlist.videos[0].videoThumbnails) || '';
|
||||
} else if (playlist.playlistThumbnail) {
|
||||
img.src = playlist.playlistThumbnail;
|
||||
imgSrc = playlist.playlistThumbnail;
|
||||
} else {
|
||||
img.src = '';
|
||||
imgSrc = '';
|
||||
loading = false;
|
||||
return;
|
||||
}
|
||||
|
||||
img = await insecureRequestImageHandler(imgSrc);
|
||||
|
||||
img.onload = () => {
|
||||
loading = false;
|
||||
};
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
interfaceAutoExpandComments,
|
||||
interfaceAutoExpandDesc,
|
||||
interfaceDefaultPage,
|
||||
interfaceDisplayThumbnailAvatars,
|
||||
interfaceForceCase,
|
||||
interfaceLowBandwidthMode,
|
||||
interfaceRegionStore,
|
||||
@@ -171,22 +170,6 @@
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div class="field no-margin">
|
||||
<nav class="no-padding">
|
||||
<div class="max">
|
||||
<div>{$_('layout.displayThumbnailAvatars')}</div>
|
||||
</div>
|
||||
<label class="switch">
|
||||
<input
|
||||
type="checkbox"
|
||||
bind:checked={$interfaceDisplayThumbnailAvatars}
|
||||
onclick={() => interfaceDisplayThumbnailAvatars.set(!$interfaceDisplayThumbnailAvatars)}
|
||||
/>
|
||||
<span></span>
|
||||
</label>
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
<div class="field no-margin">
|
||||
<nav class="no-padding">
|
||||
<div class="max">
|
||||
|
||||
@@ -1,18 +1,17 @@
|
||||
<script lang="ts">
|
||||
import { getBestThumbnail, proxyGoogleImage } from '$lib/images';
|
||||
import { getBestThumbnail } from '$lib/images';
|
||||
import { letterCase } from '$lib/letterCasing';
|
||||
import { cleanNumber, videoLength } from '$lib/numbers';
|
||||
import { onDestroy, onMount } from 'svelte';
|
||||
import { _ } from 'svelte-i18n';
|
||||
import { get } from 'svelte/store';
|
||||
import { getChannel, getDeArrow, getThumbnail, getVideoProgress } from '../api';
|
||||
import { getDeArrow, getThumbnail, getVideoProgress } from '../api';
|
||||
import type { Notification, PlaylistPageVideo, Video, VideoBase } from '../api/model';
|
||||
import { truncate } from '../misc';
|
||||
import { insecureRequestImageHandler, truncate } from '../misc';
|
||||
import type { PlayerEvents } from '../player';
|
||||
import {
|
||||
authStore,
|
||||
deArrowEnabledStore,
|
||||
interfaceDisplayThumbnailAvatars,
|
||||
interfaceLowBandwidthMode,
|
||||
playerSavePlaybackPositionStore,
|
||||
syncPartyConnectionsStore,
|
||||
@@ -29,8 +28,6 @@
|
||||
|
||||
let { video = $bindable(), playlistId = '', sideways = $bindable(false) }: Props = $props();
|
||||
|
||||
let authorImg: HTMLImageElement | undefined = $state();
|
||||
|
||||
let placeholderHeight: number = $state(0);
|
||||
|
||||
let watchUrl = new URL(`${location.origin}/watch/${video.videoId}`);
|
||||
@@ -64,24 +61,9 @@
|
||||
|
||||
if (window.innerWidth <= 1500) {
|
||||
sideways = false;
|
||||
if (typeof authorImg === 'undefined') loadAuthor();
|
||||
} else sideways = true;
|
||||
}
|
||||
|
||||
async function loadAuthor() {
|
||||
if (!get(interfaceDisplayThumbnailAvatars)) return;
|
||||
|
||||
try {
|
||||
const channel = await getChannel(video.authorId, { priority: 'low' });
|
||||
const loadedPfp = new Image();
|
||||
loadedPfp.src = proxyGoogleImage(getBestThumbnail(channel.authorThumbnails, 75, 75));
|
||||
|
||||
loadedPfp.onload = () => {
|
||||
authorImg = loadedPfp;
|
||||
};
|
||||
} catch {}
|
||||
}
|
||||
|
||||
onMount(async () => {
|
||||
calcThumbnailPlaceholderHeight();
|
||||
|
||||
@@ -95,16 +77,9 @@
|
||||
|
||||
if (get(interfaceLowBandwidthMode)) return;
|
||||
|
||||
// Load author details in background.
|
||||
if (!sideways) {
|
||||
loadAuthor();
|
||||
}
|
||||
|
||||
let imageSrc = getBestThumbnail(video.videoThumbnails) as string;
|
||||
|
||||
if (get(deArrowEnabledStore)) {
|
||||
let locatedThumbnail = false;
|
||||
|
||||
try {
|
||||
const deArrow = await getDeArrow(video.videoId);
|
||||
for (const title of deArrow.titles) {
|
||||
@@ -119,16 +94,13 @@
|
||||
if (thumbnail.timestamp !== null) {
|
||||
imageSrc = await getThumbnail(video.videoId, thumbnail.timestamp);
|
||||
}
|
||||
locatedThumbnail = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch {}
|
||||
}
|
||||
|
||||
const img = new Image();
|
||||
img.src = imageSrc;
|
||||
|
||||
const img = await insecureRequestImageHandler(imageSrc);
|
||||
img.onload = () => {
|
||||
thumbnail = img;
|
||||
};
|
||||
@@ -225,15 +197,6 @@
|
||||
</div>
|
||||
|
||||
<div class="thumbnail-details video-title">
|
||||
{#if !sideways && !$interfaceLowBandwidthMode && $interfaceDisplayThumbnailAvatars}
|
||||
<div style="margin-right: 1em;">
|
||||
{#if authorImg}
|
||||
<img src={authorImg.src} alt="Author" class="circle small" />
|
||||
{:else}
|
||||
<progress style="padding: 15px;" class="circle small"></progress>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
<div class="video-title">
|
||||
<a
|
||||
style="padding-left: 1px;"
|
||||
|
||||
@@ -3,7 +3,7 @@ import { page } from '$app/stores';
|
||||
import he from 'he';
|
||||
import type Peer from 'peerjs';
|
||||
import { get } from 'svelte/store';
|
||||
import { instanceStore } from './store';
|
||||
import { instanceStore, interfaceAllowInsecureRequests } from './store';
|
||||
|
||||
export function truncate(value: string, maxLength: number = 50): string {
|
||||
return value.length > maxLength ? `${value.substring(0, maxLength)}...` : value;
|
||||
@@ -16,10 +16,7 @@ export function decodeHtmlCharCodes(str: string): string {
|
||||
|
||||
export function proxyVideoUrl(source: string): string {
|
||||
const rawSrc = new URL(source);
|
||||
rawSrc.host = get(instanceStore).replace('http://', '').replace(
|
||||
'https://',
|
||||
''
|
||||
);
|
||||
rawSrc.host = get(instanceStore).replace('http://', '').replace('https://', '');
|
||||
|
||||
return rawSrc.toString();
|
||||
}
|
||||
@@ -46,14 +43,11 @@ export async function peerJs(peerId: string): Promise<Peer> {
|
||||
if (typeof PeerInstance === 'undefined') {
|
||||
PeerInstance = (await import('peerjs')).Peer;
|
||||
}
|
||||
return new PeerInstance(
|
||||
peerId,
|
||||
{
|
||||
host: import.meta.env.VITE_DEFAULT_PEERJS_HOST || '0.peerjs.com',
|
||||
path: import.meta.env.VITE_DEFAULT_PEERJS_PATH || '/',
|
||||
port: import.meta.env.VITE_DEFAULT_PEERJS_PORT || 443
|
||||
}
|
||||
);
|
||||
return new PeerInstance(peerId, {
|
||||
host: import.meta.env.VITE_DEFAULT_PEERJS_HOST || '0.peerjs.com',
|
||||
path: import.meta.env.VITE_DEFAULT_PEERJS_PATH || '/',
|
||||
port: import.meta.env.VITE_DEFAULT_PEERJS_PORT || 443
|
||||
});
|
||||
}
|
||||
|
||||
export function ensureNoTrailingSlash(url: any): string {
|
||||
@@ -61,3 +55,19 @@ export function ensureNoTrailingSlash(url: any): string {
|
||||
|
||||
return url.endsWith('/') ? url.slice(0, -1) : url;
|
||||
}
|
||||
|
||||
export async function insecureRequestImageHandler(source: string): Promise<HTMLImageElement> {
|
||||
const img = new Image();
|
||||
if (get(interfaceAllowInsecureRequests)) {
|
||||
const imgResp = await fetch(source);
|
||||
if (!imgResp.ok) {
|
||||
img.src = '';
|
||||
}
|
||||
|
||||
img.src = URL.createObjectURL(await imgResp.blob());
|
||||
} else {
|
||||
img.src = source;
|
||||
}
|
||||
|
||||
return img;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user