This commit is contained in:
		
							parent
							
								
									7432de3d33
								
							
						
					
					
						commit
						c3b3b9b9a6
					
				
					 8 changed files with 21 additions and 56 deletions
				
			
		|  | @ -14,7 +14,7 @@ RUN pacman -S --noconfirm pacman | ||||||
| RUN pacman-db-upgrade | RUN pacman-db-upgrade | ||||||
| RUN pacman -S --noconfirm archlinux-keyring | RUN pacman -S --noconfirm archlinux-keyring | ||||||
| RUN pacman -Syyu --noconfirm | RUN pacman -Syyu --noconfirm | ||||||
| RUN pacman -S --noconfirm git nodejs npm mongodb redis imagemagick | RUN pacman -S --noconfirm git nodejs npm mongodb redis | ||||||
| 
 | 
 | ||||||
| COPY misskey.sh /root/misskey.sh | COPY misskey.sh /root/misskey.sh | ||||||
| RUN chmod u+x /root/misskey.sh | RUN chmod u+x /root/misskey.sh | ||||||
|  |  | ||||||
|  | @ -25,7 +25,6 @@ Please install and setup these softwares: | ||||||
| * *Node.js* and *npm* | * *Node.js* and *npm* | ||||||
| * **[MongoDB](https://www.mongodb.com/)** >= 3.6 | * **[MongoDB](https://www.mongodb.com/)** >= 3.6 | ||||||
| * **[Redis](https://redis.io/)** | * **[Redis](https://redis.io/)** | ||||||
| * **[ImageMagick](http://www.imagemagick.org/script/index.php)** >= 7.0 |  | ||||||
| 
 | 
 | ||||||
| ##### Optional | ##### Optional | ||||||
| * [Elasticsearch](https://www.elastic.co/) - used to provide searching feature instead of MongoDB | * [Elasticsearch](https://www.elastic.co/) - used to provide searching feature instead of MongoDB | ||||||
|  |  | ||||||
|  | @ -25,7 +25,6 @@ adduser --disabled-password --disabled-login misskey | ||||||
| * *Node.js* と *npm* | * *Node.js* と *npm* | ||||||
| * **[MongoDB](https://www.mongodb.com/)** (3.6以上) | * **[MongoDB](https://www.mongodb.com/)** (3.6以上) | ||||||
| * **[Redis](https://redis.io/)** | * **[Redis](https://redis.io/)** | ||||||
| * **[ImageMagick](http://www.imagemagick.org/script/index.php)** |  | ||||||
| 
 | 
 | ||||||
| ##### オプション | ##### オプション | ||||||
| * [Elasticsearch](https://www.elastic.co/) - 検索機能を向上させるために用います。 | * [Elasticsearch](https://www.elastic.co/) - 検索機能を向上させるために用います。 | ||||||
|  |  | ||||||
|  | @ -33,7 +33,6 @@ | ||||||
| 		"@types/deep-equal": "1.0.1", | 		"@types/deep-equal": "1.0.1", | ||||||
| 		"@types/elasticsearch": "5.0.25", | 		"@types/elasticsearch": "5.0.25", | ||||||
| 		"@types/file-type": "5.2.1", | 		"@types/file-type": "5.2.1", | ||||||
| 		"@types/gm": "1.18.0", |  | ||||||
| 		"@types/gulp": "3.8.36", | 		"@types/gulp": "3.8.36", | ||||||
| 		"@types/gulp-htmlmin": "1.3.32", | 		"@types/gulp-htmlmin": "1.3.32", | ||||||
| 		"@types/gulp-mocha": "0.0.32", | 		"@types/gulp-mocha": "0.0.32", | ||||||
|  | @ -73,6 +72,7 @@ | ||||||
| 		"@types/request-promise-native": "1.0.15", | 		"@types/request-promise-native": "1.0.15", | ||||||
| 		"@types/rimraf": "2.0.2", | 		"@types/rimraf": "2.0.2", | ||||||
| 		"@types/seedrandom": "2.4.27", | 		"@types/seedrandom": "2.4.27", | ||||||
|  | 		"@types/sharp": "0.17.9", | ||||||
| 		"@types/showdown": "1.7.5", | 		"@types/showdown": "1.7.5", | ||||||
| 		"@types/single-line-log": "1.1.0", | 		"@types/single-line-log": "1.1.0", | ||||||
| 		"@types/speakeasy": "2.0.2", | 		"@types/speakeasy": "2.0.2", | ||||||
|  | @ -108,7 +108,6 @@ | ||||||
| 		"file-loader": "1.1.11", | 		"file-loader": "1.1.11", | ||||||
| 		"file-type": "8.1.0", | 		"file-type": "8.1.0", | ||||||
| 		"fuckadblock": "3.2.1", | 		"fuckadblock": "3.2.1", | ||||||
| 		"gm": "1.23.1", |  | ||||||
| 		"gulp": "3.9.1", | 		"gulp": "3.9.1", | ||||||
| 		"gulp-cssnano": "2.1.3", | 		"gulp-cssnano": "2.1.3", | ||||||
| 		"gulp-htmlmin": "4.0.0", | 		"gulp-htmlmin": "4.0.0", | ||||||
|  | @ -165,7 +164,6 @@ | ||||||
| 		"parse5": "5.0.0", | 		"parse5": "5.0.0", | ||||||
| 		"portscanner": "2.2.0", | 		"portscanner": "2.2.0", | ||||||
| 		"progress-bar-webpack-plugin": "1.11.0", | 		"progress-bar-webpack-plugin": "1.11.0", | ||||||
| 		"prominence": "0.2.0", |  | ||||||
| 		"promise-sequential": "1.1.1", | 		"promise-sequential": "1.1.1", | ||||||
| 		"pug": "2.0.3", | 		"pug": "2.0.3", | ||||||
| 		"punycode": "2.1.1", | 		"punycode": "2.1.1", | ||||||
|  | @ -181,6 +179,7 @@ | ||||||
| 		"s-age": "1.1.2", | 		"s-age": "1.1.2", | ||||||
| 		"sass-loader": "7.0.3", | 		"sass-loader": "7.0.3", | ||||||
| 		"seedrandom": "2.4.3", | 		"seedrandom": "2.4.3", | ||||||
|  | 		"sharp": "0.20.5", | ||||||
| 		"showdown": "1.8.6", | 		"showdown": "1.8.6", | ||||||
| 		"showdown-highlightjs-extension": "0.1.2", | 		"showdown-highlightjs-extension": "0.1.2", | ||||||
| 		"single-line-log": "1.1.2", | 		"single-line-log": "1.1.2", | ||||||
|  |  | ||||||
|  | @ -1,25 +0,0 @@ | ||||||
| import * as stream from 'stream'; |  | ||||||
| import * as Gm from 'gm'; |  | ||||||
| import { IDriveFile, getDriveFileBucket } from '../models/drive-file'; |  | ||||||
| 
 |  | ||||||
| const gm = Gm.subClass({ |  | ||||||
| 	imageMagick: true |  | ||||||
| }); |  | ||||||
| 
 |  | ||||||
| export default async function(file: IDriveFile): Promise<stream.Readable> { |  | ||||||
| 	if (!/^image\/.*$/.test(file.contentType)) return null; |  | ||||||
| 
 |  | ||||||
| 	const bucket = await getDriveFileBucket(); |  | ||||||
| 	const readable = bucket.openDownloadStream(file._id); |  | ||||||
| 
 |  | ||||||
| 	const g = gm(readable); |  | ||||||
| 
 |  | ||||||
| 	const stream = g |  | ||||||
| 		.resize(256, 256) |  | ||||||
| 		.compress('jpeg') |  | ||||||
| 		.quality(70) |  | ||||||
| 		.interlace('line') |  | ||||||
| 		.stream(); |  | ||||||
| 
 |  | ||||||
| 	return stream; |  | ||||||
| } |  | ||||||
|  | @ -11,7 +11,6 @@ export default class { | ||||||
| 	public showAll(): void { | 	public showAll(): void { | ||||||
| 		this.show('MongoDB', 'mongo --version', x => x.match(/^MongoDB shell version:? v(.*)\r?\n/)); | 		this.show('MongoDB', 'mongo --version', x => x.match(/^MongoDB shell version:? v(.*)\r?\n/)); | ||||||
| 		this.show('Redis', 'redis-server --version', x => x.match(/v=([0-9\.]*)/)); | 		this.show('Redis', 'redis-server --version', x => x.match(/v=([0-9\.]*)/)); | ||||||
| 		this.show('ImageMagick', 'magick -version', x => x.match(/^Version: ImageMagick ([^ ]*)/)); |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	public show(serviceName: string, command: string, transform: (x: string) => RegExpMatchArray): void { | 	public show(serviceName: string, command: string, transform: (x: string) => RegExpMatchArray): void { | ||||||
|  |  | ||||||
|  | @ -37,6 +37,7 @@ export type IMetadata = { | ||||||
| 	storage?: string; | 	storage?: string; | ||||||
| 	storageProps?: any; | 	storageProps?: any; | ||||||
| 	isSensitive?: boolean; | 	isSensitive?: boolean; | ||||||
|  | 	isRemote?: boolean; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| export type IDriveFile = { | export type IDriveFile = { | ||||||
|  | @ -160,7 +161,7 @@ export const pack = ( | ||||||
| 
 | 
 | ||||||
| 	_target.url = _file.metadata.url ? _file.metadata.url : `${config.drive_url}/${_target.id}/${encodeURIComponent(_target.name)}`; | 	_target.url = _file.metadata.url ? _file.metadata.url : `${config.drive_url}/${_target.id}/${encodeURIComponent(_target.name)}`; | ||||||
| 	_target.src = _file.metadata.url; | 	_target.src = _file.metadata.url; | ||||||
| 	_target.isRemote = _file.metadata.withoutChunks; | 	_target.isRemote = _file.metadata.isRemote; | ||||||
| 
 | 
 | ||||||
| 	if (_target.properties == null) _target.properties = {}; | 	if (_target.properties == null) _target.properties = {}; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -4,12 +4,11 @@ import * as stream from 'stream'; | ||||||
| 
 | 
 | ||||||
| import * as mongodb from 'mongodb'; | import * as mongodb from 'mongodb'; | ||||||
| import * as crypto from 'crypto'; | import * as crypto from 'crypto'; | ||||||
| import * as _gm from 'gm'; |  | ||||||
| import * as debug from 'debug'; | import * as debug from 'debug'; | ||||||
| import fileType = require('file-type'); | import fileType = require('file-type'); | ||||||
| const prominence = require('prominence'); |  | ||||||
| import * as Minio from 'minio'; | import * as Minio from 'minio'; | ||||||
| import * as uuid from 'uuid'; | import * as uuid from 'uuid'; | ||||||
|  | import * as sharp from 'sharp'; | ||||||
| 
 | 
 | ||||||
| import DriveFile, { IMetadata, getDriveFileBucket, IDriveFile } from '../../models/drive-file'; | import DriveFile, { IMetadata, getDriveFileBucket, IDriveFile } from '../../models/drive-file'; | ||||||
| import DriveFolder from '../../models/drive-folder'; | import DriveFolder from '../../models/drive-folder'; | ||||||
|  | @ -19,10 +18,6 @@ import { isLocalUser, IUser, IRemoteUser } from '../../models/user'; | ||||||
| import delFile from './delete-file'; | import delFile from './delete-file'; | ||||||
| import config from '../../config'; | import config from '../../config'; | ||||||
| 
 | 
 | ||||||
| const gm = _gm.subClass({ |  | ||||||
| 	imageMagick: true |  | ||||||
| }); |  | ||||||
| 
 |  | ||||||
| const log = debug('misskey:drive:add-file'); | const log = debug('misskey:drive:add-file'); | ||||||
| 
 | 
 | ||||||
| async function save(readable: stream.Readable, name: string, type: string, hash: string, size: number, metadata: any): Promise<IDriveFile> { | async function save(readable: stream.Readable, name: string, type: string, hash: string, size: number, metadata: any): Promise<IDriveFile> { | ||||||
|  | @ -53,6 +48,8 @@ async function save(readable: stream.Readable, name: string, type: string, hash: | ||||||
| 			}); | 			}); | ||||||
| 
 | 
 | ||||||
| 			return file; | 			return file; | ||||||
|  | 		} else { | ||||||
|  | 			throw 'unknown storage type'; | ||||||
| 		} | 		} | ||||||
| 	} else { | 	} else { | ||||||
| 		// Get MongoDB GridFS bucket
 | 		// Get MongoDB GridFS bucket
 | ||||||
|  | @ -228,42 +225,37 @@ export default async function( | ||||||
| 
 | 
 | ||||||
| 	let propPromises: Array<Promise<void>> = []; | 	let propPromises: Array<Promise<void>> = []; | ||||||
| 
 | 
 | ||||||
| 	const isImage = ['image/jpeg', 'image/gif', 'image/png'].includes(mime); | 	const isImage = ['image/jpeg', 'image/gif', 'image/png', 'image/webp'].includes(mime); | ||||||
| 
 | 
 | ||||||
| 	if (isImage) { | 	if (isImage) { | ||||||
|  | 		const img = sharp(path); | ||||||
|  | 
 | ||||||
| 		// Calc width and height
 | 		// Calc width and height
 | ||||||
| 		const calcWh = async () => { | 		const calcWh = async () => { | ||||||
| 			log('calculate image width and height...'); | 			log('calculate image width and height...'); | ||||||
| 
 | 
 | ||||||
| 			// Calculate width and height
 | 			// Calculate width and height
 | ||||||
| 			const g = gm(fs.createReadStream(path), name); | 			const meta = await img.metadata(); | ||||||
| 			const size = await prominence(g).size(); |  | ||||||
| 
 | 
 | ||||||
| 			log(`image width and height is calculated: ${size.width}, ${size.height}`); | 			log(`image width and height is calculated: ${meta.width}, ${meta.height}`); | ||||||
| 
 | 
 | ||||||
| 			properties['width'] = size.width; | 			properties['width'] = meta.width; | ||||||
| 			properties['height'] = size.height; | 			properties['height'] = meta.height; | ||||||
| 		}; | 		}; | ||||||
| 
 | 
 | ||||||
| 		// Calc average color
 | 		// Calc average color
 | ||||||
| 		const calcAvg = async () => { | 		const calcAvg = async () => { | ||||||
| 			log('calculate average color...'); | 			log('calculate average color...'); | ||||||
| 
 | 
 | ||||||
| 			const info = await prominence(gm(fs.createReadStream(path), name)).identify(); | 			const info = await (img as any).stats(); | ||||||
| 			const isTransparent = info ? info['Channel depth'].Alpha != null : false; |  | ||||||
| 
 | 
 | ||||||
| 			const buffer = await prominence(gm(fs.createReadStream(path), name) | 			const r = Math.round(info.channels[0].mean); | ||||||
| 				.setFormat('ppm') | 			const g = Math.round(info.channels[1].mean); | ||||||
| 				.resize(1, 1)) // 1pxのサイズに縮小して平均色を取得するというハック
 | 			const b = Math.round(info.channels[2].mean); | ||||||
| 				.toBuffer(); |  | ||||||
| 
 |  | ||||||
| 			const r = buffer.readUInt8(buffer.length - 3); |  | ||||||
| 			const g = buffer.readUInt8(buffer.length - 2); |  | ||||||
| 			const b = buffer.readUInt8(buffer.length - 1); |  | ||||||
| 
 | 
 | ||||||
| 			log(`average color is calculated: ${r}, ${g}, ${b}`); | 			log(`average color is calculated: ${r}, ${g}, ${b}`); | ||||||
| 
 | 
 | ||||||
| 			const value = isTransparent ? [r, g, b, 255] : [r, g, b]; | 			const value = info.isOpaque ? [r, g, b] : [r, g, b, 255]; | ||||||
| 
 | 
 | ||||||
| 			properties['avgColor'] = value; | 			properties['avgColor'] = value; | ||||||
| 		}; | 		}; | ||||||
|  | @ -282,6 +274,7 @@ export default async function( | ||||||
| 		comment: comment, | 		comment: comment, | ||||||
| 		properties: properties, | 		properties: properties, | ||||||
| 		withoutChunks: isLink, | 		withoutChunks: isLink, | ||||||
|  | 		isRemote: isLink, | ||||||
| 		isSensitive: sensitive | 		isSensitive: sensitive | ||||||
| 	} as IMetadata; | 	} as IMetadata; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue