Аватары: убрать инициалы при наличии txId и усилить загрузку старых файлов
This commit is contained in:
parent
4c1aeeeac8
commit
df7f38bd0a
@ -1,2 +1,2 @@
|
|||||||
client.version=1.2.6
|
client.version=1.2.7
|
||||||
server.version=1.2.6
|
server.version=1.2.7
|
||||||
|
|||||||
@ -6,8 +6,8 @@
|
|||||||
<link rel="manifest" href="./manifest.webmanifest" />
|
<link rel="manifest" href="./manifest.webmanifest" />
|
||||||
<title>Shine UI Demo</title>
|
<title>Shine UI Demo</title>
|
||||||
<script>
|
<script>
|
||||||
window.__SHINE_BUILD_HASH__ = '20260426102000';
|
window.__SHINE_BUILD_HASH__ = '20260426105500';
|
||||||
window.__SHINE_CLIENT_VERSION__ = '1.2.6';
|
window.__SHINE_CLIENT_VERSION__ = '1.2.7';
|
||||||
</script>
|
</script>
|
||||||
<script>
|
<script>
|
||||||
(function attachStylesWithBuildHash() {
|
(function attachStylesWithBuildHash() {
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { state } from '../state.js';
|
import { state } from '../state.js';
|
||||||
import { validateArweaveTxId } from '../services/arweave-file-service.js';
|
import { buildArweaveDataUrl, validateArweaveTxId } from '../services/arweave-file-service.js';
|
||||||
import { getCachedAvatarObjectUrl } from '../services/arweave-avatar-cache-service.js';
|
import { getCachedAvatarObjectUrl } from '../services/arweave-avatar-cache-service.js';
|
||||||
|
|
||||||
function normalizeLogin(value) {
|
function normalizeLogin(value) {
|
||||||
@ -52,6 +52,7 @@ export function renderUserAvatar({
|
|||||||
if (!validateArweaveTxId(txId)) {
|
if (!validateArweaveTxId(txId)) {
|
||||||
return wrap;
|
return wrap;
|
||||||
}
|
}
|
||||||
|
fallback.hidden = true;
|
||||||
|
|
||||||
const img = document.createElement('img');
|
const img = document.createElement('img');
|
||||||
img.alt = 'Аватар';
|
img.alt = 'Аватар';
|
||||||
@ -63,25 +64,55 @@ export function renderUserAvatar({
|
|||||||
const gateway = state?.entrySettings?.arweaveServer;
|
const gateway = state?.entrySettings?.arweaveServer;
|
||||||
void getCachedAvatarObjectUrl({ gateway, txId })
|
void getCachedAvatarObjectUrl({ gateway, txId })
|
||||||
.then((objectUrl) => {
|
.then((objectUrl) => {
|
||||||
img.onload = () => {
|
const directUrl = buildArweaveDataUrl({ gateway, txId });
|
||||||
fallback.hidden = true;
|
let triedDirectUrl = false;
|
||||||
img.hidden = false;
|
let objectUrlReleased = false;
|
||||||
|
const releaseObjectUrl = () => {
|
||||||
|
if (objectUrlReleased) return;
|
||||||
|
objectUrlReleased = true;
|
||||||
if (objectUrl.startsWith('blob:')) {
|
if (objectUrl.startsWith('blob:')) {
|
||||||
URL.revokeObjectURL(objectUrl);
|
URL.revokeObjectURL(objectUrl);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
img.onload = () => {
|
||||||
|
fallback.hidden = true;
|
||||||
|
img.hidden = false;
|
||||||
|
releaseObjectUrl();
|
||||||
|
};
|
||||||
img.onerror = () => {
|
img.onerror = () => {
|
||||||
|
if (!triedDirectUrl) {
|
||||||
|
triedDirectUrl = true;
|
||||||
|
releaseObjectUrl();
|
||||||
|
img.src = directUrl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
releaseObjectUrl();
|
||||||
img.hidden = true;
|
img.hidden = true;
|
||||||
fallback.hidden = false;
|
fallback.hidden = false;
|
||||||
if (objectUrl.startsWith('blob:')) {
|
|
||||||
URL.revokeObjectURL(objectUrl);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
img.src = objectUrl;
|
img.src = objectUrl;
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
|
let directUrl = '';
|
||||||
|
try {
|
||||||
|
directUrl = buildArweaveDataUrl({ gateway, txId });
|
||||||
|
} catch {
|
||||||
|
directUrl = '';
|
||||||
|
}
|
||||||
|
if (!directUrl) {
|
||||||
img.hidden = true;
|
img.hidden = true;
|
||||||
fallback.hidden = false;
|
fallback.hidden = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
img.onload = () => {
|
||||||
|
fallback.hidden = true;
|
||||||
|
img.hidden = false;
|
||||||
|
};
|
||||||
|
img.onerror = () => {
|
||||||
|
img.hidden = true;
|
||||||
|
fallback.hidden = false;
|
||||||
|
};
|
||||||
|
img.src = directUrl;
|
||||||
});
|
});
|
||||||
|
|
||||||
return wrap;
|
return wrap;
|
||||||
|
|||||||
@ -103,12 +103,47 @@ async function fetchAvatarBlob({ gateway, txId }) {
|
|||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
throw new Error(`Не удалось загрузить аватар (${response.status} ${response.statusText})`);
|
throw new Error(`Не удалось загрузить аватар (${response.status} ${response.statusText})`);
|
||||||
}
|
}
|
||||||
const blob = await response.blob();
|
const sourceBlob = await response.blob();
|
||||||
const type = String(blob?.type || '').toLowerCase();
|
const sourceType = String(sourceBlob?.type || '').toLowerCase();
|
||||||
if (!type.startsWith('image/')) {
|
if (sourceType.startsWith('image/')) {
|
||||||
throw new Error('Arweave-файл не является изображением');
|
return sourceBlob;
|
||||||
}
|
}
|
||||||
return blob;
|
|
||||||
|
const bytes = new Uint8Array(await sourceBlob.arrayBuffer());
|
||||||
|
const detectedType = detectImageMime(bytes);
|
||||||
|
if (detectedType) {
|
||||||
|
return new Blob([bytes], { type: detectedType });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Старые аватары могли быть загружены без корректного Content-Type.
|
||||||
|
// Возвращаем исходный blob, чтобы браузер попробовал декодировать сам.
|
||||||
|
return sourceBlob;
|
||||||
|
}
|
||||||
|
|
||||||
|
function detectImageMime(bytes) {
|
||||||
|
if (!(bytes instanceof Uint8Array) || bytes.length < 12) return '';
|
||||||
|
if (
|
||||||
|
bytes[0] === 0x89
|
||||||
|
&& bytes[1] === 0x50
|
||||||
|
&& bytes[2] === 0x4e
|
||||||
|
&& bytes[3] === 0x47
|
||||||
|
&& bytes[4] === 0x0d
|
||||||
|
&& bytes[5] === 0x0a
|
||||||
|
&& bytes[6] === 0x1a
|
||||||
|
&& bytes[7] === 0x0a
|
||||||
|
) return 'image/png';
|
||||||
|
if (bytes[0] === 0xff && bytes[1] === 0xd8 && bytes[2] === 0xff) return 'image/jpeg';
|
||||||
|
if (
|
||||||
|
bytes[0] === 0x52
|
||||||
|
&& bytes[1] === 0x49
|
||||||
|
&& bytes[2] === 0x46
|
||||||
|
&& bytes[3] === 0x46
|
||||||
|
&& bytes[8] === 0x57
|
||||||
|
&& bytes[9] === 0x45
|
||||||
|
&& bytes[10] === 0x42
|
||||||
|
&& bytes[11] === 0x50
|
||||||
|
) return 'image/webp';
|
||||||
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getBlobFromCacheOrGateway({ gateway, txId }) {
|
async function getBlobFromCacheOrGateway({ gateway, txId }) {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user