summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/client/components/avatar.vue38
-rw-r--r--src/client/components/drive-file-thumbnail.vue85
-rw-r--r--src/client/components/drive.file.vue12
-rw-r--r--src/client/components/img-with-blurhash.vue78
-rw-r--r--src/client/components/media-image.vue91
-rw-r--r--src/client/components/media-list.vue2
-rw-r--r--src/client/pages/messaging/messaging-room.message.vue3
-rw-r--r--src/client/pages/page-editor/els/page-editor.el.image.vue2
-rw-r--r--src/client/style.scss4
-rw-r--r--src/misc/get-file-info.ts37
-rw-r--r--src/models/entities/drive-file.ts6
-rw-r--r--src/models/entities/user.ts8
-rw-r--r--src/models/repositories/drive-file.ts1
-rw-r--r--src/models/repositories/user.ts10
-rw-r--r--src/remote/activitypub/models/person.ts16
-rw-r--r--src/server/api/endpoints/i/update.ts8
-rw-r--r--src/services/drive/add-file.ts6
17 files changed, 201 insertions, 206 deletions
diff --git a/src/client/components/avatar.vue b/src/client/components/avatar.vue
index 29b457db87..fd4ab78ce1 100644
--- a/src/client/components/avatar.vue
+++ b/src/client/components/avatar.vue
@@ -1,15 +1,9 @@
<template>
-<span class="eiwwqkts" :class="{ cat }" :title="user | acct" v-if="disableLink && !disablePreview" v-user-preview="user.id" @click="onClick">
- <span class="inner" :style="icon"></span>
+<span class="eiwwqkts" :class="{ cat }" :title="user | acct" v-if="disableLink" v-user-preview="disablePreview ? undefined : user.id" @click="onClick">
+ <img class="inner" :src="url"/>
</span>
-<span class="eiwwqkts" :class="{ cat }" :title="user | acct" v-else-if="disableLink && disablePreview" @click="onClick">
- <span class="inner" :style="icon"></span>
-</span>
-<router-link class="eiwwqkts" :class="{ cat }" :to="user | userPage" :title="user | acct" :target="target" v-else-if="!disableLink && !disablePreview" v-user-preview="user.id">
- <span class="inner" :style="icon"></span>
-</router-link>
-<router-link class="eiwwqkts" :class="{ cat }" :to="user | userPage" :title="user | acct" :target="target" v-else-if="!disableLink && disablePreview">
- <span class="inner" :style="icon"></span>
+<router-link class="eiwwqkts" :class="{ cat }" :to="user | userPage" :title="user | acct" :target="target" v-else v-user-preview="disablePreview ? undefined : user.id">
+ <img class="inner" :src="url"/>
</router-link>
</template>
@@ -45,22 +39,6 @@ export default Vue.extend({
? getStaticImageUrl(this.user.avatarUrl)
: this.user.avatarUrl;
},
- icon(): any {
- return {
- backgroundColor: this.user.avatarColor,
- backgroundImage: `url(${this.url})`,
- };
- }
- },
- watch: {
- 'user.avatarColor'() {
- this.$el.style.color = this.user.avatarColor;
- }
- },
- mounted() {
- if (this.user.avatarColor) {
- this.$el.style.color = this.user.avatarColor;
- }
},
methods: {
onClick(e) {
@@ -102,15 +80,17 @@ export default Vue.extend({
}
.inner {
- background-position: center center;
- background-size: cover;
+ position: absolute;
bottom: 0;
left: 0;
- position: absolute;
right: 0;
top: 0;
border-radius: 100%;
z-index: 1;
+ overflow: hidden;
+ object-fit: cover;
+ width: 100%;
+ height: 100%;
}
}
</style>
diff --git a/src/client/components/drive-file-thumbnail.vue b/src/client/components/drive-file-thumbnail.vue
index 3561be0bc5..4bc1e569b7 100644
--- a/src/client/components/drive-file-thumbnail.vue
+++ b/src/client/components/drive-file-thumbnail.vue
@@ -1,36 +1,15 @@
<template>
-<div class="zdjebgpv" :class="{ detail }" ref="thumbnail" :style="`background-color: ${ background }`">
- <img
- :src="file.url"
- :alt="file.name"
- :title="file.name"
- @load="onThumbnailLoaded"
- v-if="detail && is === 'image'"/>
- <video
- :src="file.url"
- ref="volumectrl"
- preload="metadata"
- controls
- v-else-if="detail && is === 'video'"/>
- <img :src="file.thumbnailUrl" @load="onThumbnailLoaded" :style="`object-fit: ${ fit }`" v-else-if="isThumbnailAvailable"/>
+<div class="zdjebgpv" ref="thumbnail">
+ <img-with-blurhash v-if="isThumbnailAvailable" :hash="file.blurhash" :src="file.thumbnailUrl" :alt="file.name" :title="file.name" :style="`object-fit: ${ fit }`"/>
<fa :icon="faFileImage" class="icon" v-else-if="is === 'image'"/>
<fa :icon="faFileVideo" class="icon" v-else-if="is === 'video'"/>
-
- <audio
- :src="file.url"
- ref="volumectrl"
- preload="metadata"
- controls
- v-else-if="detail && is === 'audio'"/>
<fa :icon="faMusic" class="icon" v-else-if="is === 'audio' || is === 'midi'"/>
-
<fa :icon="faFileCsv" class="icon" v-else-if="is === 'csv'"/>
<fa :icon="faFilePdf" class="icon" v-else-if="is === 'pdf'"/>
<fa :icon="faFileAlt" class="icon" v-else-if="is === 'textfile'"/>
<fa :icon="faFileArchive" class="icon" v-else-if="is === 'archive'"/>
<fa :icon="faFile" class="icon" v-else/>
-
- <fa :icon="faFilm" class="icon-sub" v-if="!detail && isThumbnailAvailable && is === 'video'"/>
+ <fa :icon="faFilm" class="icon-sub" v-if="isThumbnailAvailable && is === 'video'"/>
</div>
</template>
@@ -47,8 +26,12 @@ import {
faFileArchive,
faFilm
} from '@fortawesome/free-solid-svg-icons';
+import ImgWithBlurhash from './img-with-blurhash.vue';
export default Vue.extend({
+ components: {
+ ImgWithBlurhash
+ },
props: {
file: {
type: Object,
@@ -59,11 +42,6 @@ export default Vue.extend({
required: false,
default: 'cover'
},
- detail: {
- type: Boolean,
- required: false,
- default: false
- }
},
data() {
return {
@@ -108,20 +86,12 @@ export default Vue.extend({
? (this.is === 'image' || this.is === 'video')
: false;
},
- background(): string {
- return this.file.properties.avgColor || 'transparent';
- }
},
mounted() {
const audioTag = this.$refs.volumectrl as HTMLAudioElement;
if (audioTag) audioTag.volume = this.$store.state.device.mediaVolume;
},
methods: {
- onThumbnailLoaded() {
- if (this.file.properties.avgColor) {
- this.$refs.thumbnail.style.backgroundColor = 'transparent';
- }
- },
volumechange() {
const audioTag = this.$refs.volumectrl as HTMLAudioElement;
this.$store.commit('device/set', { key: 'mediaVolume', value: audioTag.volume });
@@ -132,14 +102,8 @@ export default Vue.extend({
<style lang="scss" scoped>
.zdjebgpv {
- display: flex;
position: relative;
- > img,
- > .icon {
- pointer-events: none;
- }
-
> .icon-sub {
position: absolute;
width: 30%;
@@ -153,37 +117,10 @@ export default Vue.extend({
margin: auto;
}
- &:not(.detail) {
- > img {
- height: 100%;
- width: 100%;
- object-fit: cover;
- }
-
- > .icon {
- height: 65%;
- width: 65%;
- }
-
- > video,
- > audio {
- width: 100%;
- }
- }
-
- &.detail {
- > .icon {
- height: 100px;
- width: 100px;
- margin: 16px;
- }
-
- > *:not(.icon) {
- max-height: 300px;
- max-width: 100%;
- height: 100%;
- object-fit: contain;
- }
+ > .icon {
+ pointer-events: none;
+ height: 65%;
+ width: 65%;
}
}
</style>
diff --git a/src/client/components/drive.file.vue b/src/client/components/drive.file.vue
index 1b24c61df5..b31a4e6375 100644
--- a/src/client/components/drive.file.vue
+++ b/src/client/components/drive.file.vue
@@ -126,17 +126,6 @@ export default Vue.extend({
this.browser.isDragSource = false;
},
- onThumbnailLoaded() {
- if (this.file.properties.avgColor) {
- anime({
- targets: this.$refs.thumbnail,
- backgroundColor: 'transparent', // TODO fade
- duration: 100,
- easing: 'linear'
- });
- }
- },
-
rename() {
this.$root.dialog({
title: this.$t('renameFile'),
@@ -332,7 +321,6 @@ export default Vue.extend({
width: 128px;
height: 128px;
margin: auto;
- color: var(--driveFileIcon);
}
> .name {
diff --git a/src/client/components/img-with-blurhash.vue b/src/client/components/img-with-blurhash.vue
new file mode 100644
index 0000000000..6e6a2a8965
--- /dev/null
+++ b/src/client/components/img-with-blurhash.vue
@@ -0,0 +1,78 @@
+<template>
+<div class="xubzgfgb" :title="title">
+ <canvas ref="canvas" :width="size" :height="size" :title="title" v-if="!loaded"/>
+ <img v-if="src" :src="src" :title="title" :alt="alt" @load="onLoad"/>
+</div>
+</template>
+
+<script lang="ts">
+import Vue from 'vue';
+import { decode } from 'blurhash';
+
+export default Vue.extend({
+ props: {
+ src: {
+ type: String,
+ required: false,
+ default: null
+ },
+ hash: {
+ type: String,
+ required: true
+ },
+ alt: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ title: {
+ type: String,
+ required: false,
+ default: null,
+ },
+ size: {
+ type: Number,
+ required: false,
+ default: 64
+ },
+ },
+
+ data() {
+ return {
+ loaded: false,
+ };
+ },
+
+ mounted() {
+ this.draw();
+ },
+
+ methods: {
+ draw() {
+ const pixels = decode(this.hash, this.size, this.size);
+ const ctx = (this.$refs.canvas as HTMLCanvasElement).getContext('2d');
+ const imageData = ctx!.createImageData(this.size, this.size);
+ imageData.data.set(pixels);
+ ctx!.putImageData(imageData, 0, 0);
+ },
+
+ onLoad() {
+ this.loaded = true;
+ }
+ }
+});
+</script>
+
+<style lang="scss" scoped>
+.xubzgfgb {
+ width: 100%;
+ height: 100%;
+
+ > canvas,
+ > img {
+ width: 100%;
+ height: 100%;
+ object-fit: cover;
+ }
+}
+</style>
diff --git a/src/client/components/media-image.vue b/src/client/components/media-image.vue
index 6d1b5345de..f6ed45daec 100644
--- a/src/client/components/media-image.vue
+++ b/src/client/components/media-image.vue
@@ -1,19 +1,22 @@
<template>
-<div class="qjewsnkgzzxlxtzncydssfbgjibiehcy" v-if="hide" @click="hide = false">
- <div>
- <b><fa :icon="faExclamationTriangle"/> {{ $t('sensitive') }}</b>
- <span>{{ $t('clickToShow') }}</span>
+<div class="qjewsnkg" v-if="hide" @click="hide = false">
+ <img-with-blurhash class="bg" :hash="image.blurhash" :title="image.name"/>
+ <div class="text">
+ <div>
+ <b><fa :icon="faExclamationTriangle"/> {{ $t('sensitive') }}</b>
+ <span>{{ $t('clickToShow') }}</span>
+ </div>
</div>
</div>
-<div class="gqnyydlzavusgskkfvwvjiattxdzsqlf" v-else>
+<div class="gqnyydlz" v-else>
<i><fa :icon="faEyeSlash" @click="hide = true"/></i>
<a
:href="image.url"
- :style="style"
:title="image.name"
@click.prevent="onClick"
>
- <div v-if="image.type === 'image/gif'">GIF</div>
+ <img-with-blurhash :hash="image.blurhash" :src="url" :alt="image.name" :title="image.name"/>
+ <div class="gif" v-if="image.type === 'image/gif'">GIF</div>
</a>
</div>
</template>
@@ -23,8 +26,12 @@ import Vue from 'vue';
import { faExclamationTriangle, faEyeSlash } from '@fortawesome/free-solid-svg-icons';
import { getStaticImageUrl } from '../scripts/get-static-image-url';
import ImageViewer from './image-viewer.vue';
+import ImgWithBlurhash from './img-with-blurhash.vue';
export default Vue.extend({
+ components: {
+ ImgWithBlurhash
+ },
props: {
image: {
type: Object,
@@ -42,23 +49,18 @@ export default Vue.extend({
};
},
computed: {
- style(): any {
- let url = `url(${
- this.$store.state.device.disableShowingAnimatedImages
- ? getStaticImageUrl(this.image.thumbnailUrl)
- : this.image.thumbnailUrl
- })`;
+ url(): any {
+ let url = this.$store.state.device.disableShowingAnimatedImages
+ ? getStaticImageUrl(this.image.thumbnailUrl)
+ : this.image.thumbnailUrl;
if (this.$store.state.device.loadRemoteMedia) {
url = null;
} else if (this.raw || this.$store.state.device.loadRawImages) {
- url = `url(${this.image.url})`;
+ url = this.image.url;
}
- return {
- 'background-color': this.image.properties.avgColor || 'transparent',
- 'background-image': url
- };
+ return url;
}
},
created() {
@@ -82,7 +84,38 @@ export default Vue.extend({
</script>
<style lang="scss" scoped>
-.gqnyydlzavusgskkfvwvjiattxdzsqlf {
+.qjewsnkg {
+ position: relative;
+
+ > .bg {
+ filter: brightness(0.5);
+ }
+
+ > .text {
+ position: absolute;
+ left: 0;
+ top: 0;
+ width: 100%;
+ height: 100%;
+ z-index: 1;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+
+ > div {
+ display: table-cell;
+ text-align: center;
+ font-size: 0.8em;
+ color: #fff;
+
+ > * {
+ display: block;
+ }
+ }
+ }
+}
+
+.gqnyydlz {
position: relative;
> i {
@@ -110,7 +143,7 @@ export default Vue.extend({
background-size: contain;
background-repeat: no-repeat;
- > div {
+ > .gif {
background-color: var(--fg);
border-radius: 6px;
color: var(--accentLighten);
@@ -126,22 +159,4 @@ export default Vue.extend({
}
}
}
-
-.qjewsnkgzzxlxtzncydssfbgjibiehcy {
- display: flex;
- justify-content: center;
- align-items: center;
- background: #111;
- color: #fff;
-
- > div {
- display: table-cell;
- text-align: center;
- font-size: 12px;
-
- > * {
- display: block;
- }
- }
-}
</style>
diff --git a/src/client/components/media-list.vue b/src/client/components/media-list.vue
index c757d80911..fd0035f10c 100644
--- a/src/client/components/media-list.vue
+++ b/src/client/components/media-list.vue
@@ -114,7 +114,7 @@ export default Vue.extend({
> * {
overflow: hidden;
- border-radius: 4px;
+ border-radius: 6px;
}
&[data-count="1"] {
diff --git a/src/client/pages/messaging/messaging-room.message.vue b/src/client/pages/messaging/messaging-room.message.vue
index 58e1e54ad8..4461740df7 100644
--- a/src/client/pages/messaging/messaging-room.message.vue
+++ b/src/client/pages/messaging/messaging-room.message.vue
@@ -10,8 +10,7 @@
<mfm class="text" v-if="message.text" ref="text" :text="message.text" :i="$store.state.i"/>
<div class="file" v-if="message.file">
<a :href="message.file.url" rel="noopener" target="_blank" :title="message.file.name">
- <img v-if="message.file.type.split('/')[0] == 'image'" :src="message.file.url" :alt="message.file.name"
- :style="{ backgroundColor: message.file.properties.avgColor || 'transparent' }"/>
+ <img v-if="message.file.type.split('/')[0] == 'image'" :src="message.file.url" :alt="message.file.name"/>
<p v-else>{{ message.file.name }}</p>
</a>
</div>
diff --git a/src/client/pages/page-editor/els/page-editor.el.image.vue b/src/client/pages/page-editor/els/page-editor.el.image.vue
index dd690da6f1..d26d7f603f 100644
--- a/src/client/pages/page-editor/els/page-editor.el.image.vue
+++ b/src/client/pages/page-editor/els/page-editor.el.image.vue
@@ -8,7 +8,7 @@
</template>
<section class="oyyftmcf">
- <mk-file-thumbnail class="preview" v-if="file" :file="file" :detail="true" fit="contain" @click="choose()"/>
+ <mk-file-thumbnail class="preview" v-if="file" :file="file" fit="contain" @click="choose()"/>
</section>
</x-container>
</template>
diff --git a/src/client/style.scss b/src/client/style.scss
index 972c38338c..c3d3cf2233 100644
--- a/src/client/style.scss
+++ b/src/client/style.scss
@@ -123,10 +123,6 @@ a {
&:hover {
text-decoration: underline;
}
-
- * {
- cursor: pointer;
- }
}
hr {
diff --git a/src/misc/get-file-info.ts b/src/misc/get-file-info.ts
index b838900f61..ce177cc53d 100644
--- a/src/misc/get-file-info.ts
+++ b/src/misc/get-file-info.ts
@@ -6,6 +6,7 @@ import * as fileType from 'file-type';
import isSvg from 'is-svg';
import * as probeImageSize from 'probe-image-size';
import * as sharp from 'sharp';
+import { encode } from 'blurhash';
const pipeline = util.promisify(stream.pipeline);
@@ -18,7 +19,7 @@ export type FileInfo = {
};
width?: number;
height?: number;
- avgColor?: number[];
+ blurhash?: string;
warnings: string[];
};
@@ -71,12 +72,11 @@ export async function getFileInfo(path: string): Promise<FileInfo> {
}
}
- // average color
- let avgColor: number[] | undefined;
+ let blurhash: string | undefined;
if (['image/jpeg', 'image/gif', 'image/png', 'image/apng', 'image/webp', 'image/svg+xml'].includes(type.mime)) {
- avgColor = await calcAvgColor(path).catch(e => {
- warnings.push(`calcAvgColor failed: ${e}`);
+ blurhash = await getBlurhash(path).catch(e => {
+ warnings.push(`getBlurhash failed: ${e}`);
return undefined;
});
}
@@ -87,7 +87,7 @@ export async function getFileInfo(path: string): Promise<FileInfo> {
type,
width,
height,
- avgColor,
+ blurhash,
warnings,
};
}
@@ -173,18 +173,15 @@ async function detectImageSize(path: string): Promise<{
/**
* Calculate average color of image
*/
-async function calcAvgColor(path: string): Promise<number[]> {
- const img = sharp(path);
-
- const info = await (img as any).stats();
-
- if (info.isOpaque) {
- const r = Math.round(info.channels[0].mean);
- const g = Math.round(info.channels[1].mean);
- const b = Math.round(info.channels[2].mean);
-
- return [r, g, b];
- } else {
- return [255, 255, 255];
- }
+function getBlurhash(path: string): Promise<string> {
+ return new Promise((resolve, reject) => {
+ sharp(path)
+ .raw()
+ .ensureAlpha()
+ .resize(64, 64, { fit: 'inside' })
+ .toBuffer((err, buffer, { width, height }) => {
+ if (err) return reject(err);
+ resolve(encode(new Uint8ClampedArray(buffer), width, height, 7, 7));
+ });
+ });
}
diff --git a/src/models/entities/drive-file.ts b/src/models/entities/drive-file.ts
index 067dc1181c..c02b9f3636 100644
--- a/src/models/entities/drive-file.ts
+++ b/src/models/entities/drive-file.ts
@@ -67,6 +67,12 @@ export class DriveFile {
})
public comment: string | null;
+ @Column('varchar', {
+ length: 128, nullable: true,
+ comment: 'The BlurHash string.'
+ })
+ public blurhash: string | null;
+
@Column('jsonb', {
default: {},
comment: 'The any properties of the DriveFile. For example, it includes image width/height.'
diff --git a/src/models/entities/user.ts b/src/models/entities/user.ts
index d3086f43f2..fee5906a3d 100644
--- a/src/models/entities/user.ts
+++ b/src/models/entities/user.ts
@@ -106,14 +106,14 @@ export class User {
public bannerUrl: string | null;
@Column('varchar', {
- length: 32, nullable: true,
+ length: 128, nullable: true,
})
- public avatarColor: string | null;
+ public avatarBlurhash: string | null;
@Column('varchar', {
- length: 32, nullable: true,
+ length: 128, nullable: true,
})
- public bannerColor: string | null;
+ public bannerBlurhash: string | null;
@Column('boolean', {
default: false,
diff --git a/src/models/repositories/drive-file.ts b/src/models/repositories/drive-file.ts
index 28a393cfb4..6bdf62be8b 100644
--- a/src/models/repositories/drive-file.ts
+++ b/src/models/repositories/drive-file.ts
@@ -115,6 +115,7 @@ export class DriveFileRepository extends Repository<DriveFile> {
md5: file.md5,
size: file.size,
isSensitive: file.isSensitive,
+ blurhash: file.blurhash,
properties: file.properties,
url: opts.self ? file.url : this.getPublicUrl(file, false, meta),
thumbnailUrl: this.getPublicUrl(file, true, meta),
diff --git a/src/models/repositories/user.ts b/src/models/repositories/user.ts
index c4c9503e06..bbaafc9050 100644
--- a/src/models/repositories/user.ts
+++ b/src/models/repositories/user.ts
@@ -165,7 +165,8 @@ export class UserRepository extends Repository<User> {
username: user.username,
host: user.host,
avatarUrl: user.avatarUrl ? user.avatarUrl : config.url + '/avatar/' + user.id,
- avatarColor: user.avatarColor,
+ avatarBlurhash: user.avatarBlurhash,
+ avatarColor: null, // 後方互換性のため
isAdmin: user.isAdmin || falsy,
isModerator: user.isModerator || falsy,
isBot: user.isBot || falsy,
@@ -196,7 +197,8 @@ export class UserRepository extends Repository<User> {
createdAt: user.createdAt.toISOString(),
updatedAt: user.updatedAt ? user.updatedAt.toISOString() : null,
bannerUrl: user.bannerUrl,
- bannerColor: user.bannerColor,
+ bannerBlurhash: user.bannerBlurhash,
+ bannerColor: null, // 後方互換性のため
isLocked: user.isLocked,
isModerator: user.isModerator || falsy,
isSilenced: user.isSilenced || falsy,
@@ -331,7 +333,7 @@ export const packedUserSchema = {
format: 'url',
nullable: true as const, optional: false as const,
},
- avatarColor: {
+ avatarBlurhash: {
type: 'any' as const,
nullable: true as const, optional: false as const,
},
@@ -340,7 +342,7 @@ export const packedUserSchema = {
format: 'url',
nullable: true as const, optional: true as const,
},
- bannerColor: {
+ bannerBlurhash: {
type: 'any' as const,
nullable: true as const, optional: true as const,
},
diff --git a/src/remote/activitypub/models/person.ts b/src/remote/activitypub/models/person.ts
index a3093786d0..a213abf474 100644
--- a/src/remote/activitypub/models/person.ts
+++ b/src/remote/activitypub/models/person.ts
@@ -226,24 +226,24 @@ export async function createPerson(uri: string, resolver?: Resolver): Promise<Us
const bannerId = banner ? banner.id : null;
const avatarUrl = avatar ? DriveFiles.getPublicUrl(avatar, true) : null;
const bannerUrl = banner ? DriveFiles.getPublicUrl(banner) : null;
- const avatarColor = avatar && avatar.properties.avgColor ? avatar.properties.avgColor : null;
- const bannerColor = banner && banner.properties.avgColor ? banner.properties.avgColor : null;
+ const avatarBlurhash = avatar ? avatar.blurhash : null;
+ const bannerBlurhash = banner ? banner.blurhash : null;
await Users.update(user!.id, {
avatarId,
bannerId,
avatarUrl,
bannerUrl,
- avatarColor,
- bannerColor
+ avatarBlurhash,
+ bannerBlurhash
});
user!.avatarId = avatarId;
user!.bannerId = bannerId;
user!.avatarUrl = avatarUrl;
user!.bannerUrl = bannerUrl;
- user!.avatarColor = avatarColor;
- user!.bannerColor = bannerColor;
+ user!.avatarBlurhash = avatarBlurhash;
+ user!.bannerBlurhash = bannerBlurhash;
//#endregion
//#region カスタム絵文字取得
@@ -341,13 +341,13 @@ export async function updatePerson(uri: string, resolver?: Resolver | null, hint
if (avatar) {
updates.avatarId = avatar.id;
updates.avatarUrl = DriveFiles.getPublicUrl(avatar, true);
- updates.avatarColor = avatar.properties.avgColor ? avatar.properties.avgColor : null;
+ updates.avatarBlurhash = avatar.blurhash;
}
if (banner) {
updates.bannerId = banner.id;
updates.bannerUrl = DriveFiles.getPublicUrl(banner);
- updates.bannerColor = banner.properties.avgColor ? banner.properties.avgColor : null;
+ updates.bannerBlurhash = banner.blurhash;
}
// Update user
diff --git a/src/server/api/endpoints/i/update.ts b/src/server/api/endpoints/i/update.ts
index b33948ee0e..48b5e48fc2 100644
--- a/src/server/api/endpoints/i/update.ts
+++ b/src/server/api/endpoints/i/update.ts
@@ -210,8 +210,8 @@ export default define(meta, async (ps, user, token) => {
updates.avatarUrl = DriveFiles.getPublicUrl(avatar, true);
- if (avatar.properties.avgColor) {
- updates.avatarColor = avatar.properties.avgColor;
+ if (avatar.blurhash) {
+ updates.avatarBlurhash = avatar.blurhash;
}
}
@@ -223,8 +223,8 @@ export default define(meta, async (ps, user, token) => {
updates.bannerUrl = DriveFiles.getPublicUrl(banner, false);
- if (banner.properties.avgColor) {
- updates.bannerColor = banner.properties.avgColor;
+ if (banner.blurhash) {
+ updates.bannerBlurhash = banner.blurhash;
}
}
diff --git a/src/services/drive/add-file.ts b/src/services/drive/add-file.ts
index cf0951ebad..969dc04069 100644
--- a/src/services/drive/add-file.ts
+++ b/src/services/drive/add-file.ts
@@ -327,7 +327,6 @@ export default async function(
const properties: {
width?: number;
height?: number;
- avgColor?: string;
} = {};
if (info.width) {
@@ -335,10 +334,6 @@ export default async function(
properties['height'] = info.height;
}
- if (info.avgColor) {
- properties['avgColor'] = `rgb(${info.avgColor.join(',')})`;
- }
-
const profile = user ? await UserProfiles.findOne(user.id) : null;
const folder = await fetchFolder();
@@ -351,6 +346,7 @@ export default async function(
file.folderId = folder !== null ? folder.id : null;
file.comment = comment;
file.properties = properties;
+ file.blurhash = info.blurhash || null;
file.isLink = isLink;
file.isSensitive = user
? Users.isLocalUser(user) && profile!.alwaysMarkNsfw ? true :