mirror of
https://github.com/Afilmory/afilmory
synced 2026-02-01 22:48:17 +00:00
refactor: streamline logging in image processing and EXIF extraction
- Removed optional logger parameters in several functions, replacing them with global loggers for consistency. - Updated logging statements to ensure they are always executed, enhancing the visibility of processing steps and errors. - Cleaned up unused imports and commented-out code to improve code clarity and maintainability. Signed-off-by: Innei <tukon479@gmail.com>
This commit is contained in:
@@ -8,7 +8,7 @@ import { exiftool } from 'exiftool-vendored'
|
||||
import type { Metadata } from 'sharp'
|
||||
import sharp from 'sharp'
|
||||
|
||||
import type { Logger } from '../logger/index.js'
|
||||
import { getGlobalLoggers } from '../photo/logger-adapter.js'
|
||||
import type { PickedExif } from '../types/photo.js'
|
||||
|
||||
const baseImageBuffer = sharp({
|
||||
@@ -26,28 +26,27 @@ const baseImageBuffer = sharp({
|
||||
export async function extractExifData(
|
||||
imageBuffer: Buffer,
|
||||
originalBuffer?: Buffer,
|
||||
exifLogger?: Logger['exif'],
|
||||
): Promise<PickedExif | null> {
|
||||
const log = exifLogger
|
||||
const log = getGlobalLoggers().exif
|
||||
|
||||
try {
|
||||
log?.info('开始提取 EXIF 数据')
|
||||
log.info('开始提取 EXIF 数据')
|
||||
|
||||
// 首先尝试从处理后的图片中提取 EXIF
|
||||
let metadata = await sharp(imageBuffer).metadata()
|
||||
|
||||
// 如果处理后的图片没有 EXIF 数据,且提供了原始 buffer,尝试从原始图片提取
|
||||
if (!metadata.exif && originalBuffer) {
|
||||
log?.info('处理后的图片缺少 EXIF 数据,尝试从原始图片提取')
|
||||
log.info('处理后的图片缺少 EXIF 数据,尝试从原始图片提取')
|
||||
try {
|
||||
metadata = await sharp(originalBuffer).metadata()
|
||||
} catch (error) {
|
||||
log?.warn('从原始图片提取 EXIF 失败,可能是不支持的格式:', error)
|
||||
log.warn('从原始图片提取 EXIF 失败,可能是不支持的格式:', error)
|
||||
}
|
||||
}
|
||||
|
||||
if (!metadata.exif) {
|
||||
log?.warn('未找到 EXIF 数据')
|
||||
log.warn('未找到 EXIF 数据')
|
||||
return null
|
||||
}
|
||||
|
||||
@@ -89,21 +88,11 @@ export async function extractExifData(
|
||||
|
||||
const exifData = await exiftool.read(tempImagePath)
|
||||
const result = handleExifData(exifData, metadata)
|
||||
// const makerNote = exifReader(exifBuffer).Photo?.MakerNote
|
||||
|
||||
// if (makerNote) {
|
||||
// const recipe = getRecipe(makerNote)
|
||||
|
||||
// if (recipe) {
|
||||
// ;(exifData as any).FujiRecipe = recipe
|
||||
// log?.info('检测到富士胶片配方信息')
|
||||
// }
|
||||
// }
|
||||
|
||||
await unlink(tempImagePath).catch(noop)
|
||||
|
||||
if (!exifData) {
|
||||
log?.warn('EXIF 数据解析失败')
|
||||
log.warn('EXIF 数据解析失败')
|
||||
return null
|
||||
}
|
||||
|
||||
@@ -112,12 +101,10 @@ export async function extractExifData(
|
||||
delete exifData.warnings
|
||||
delete exifData.errors
|
||||
|
||||
// const cleanedExifData = cleanExifData(exifData)
|
||||
|
||||
log?.success('EXIF 数据提取完成')
|
||||
log.success('EXIF 数据提取完成')
|
||||
return result
|
||||
} catch (error) {
|
||||
log?.error('提取 EXIF 数据失败:', error)
|
||||
log.error('提取 EXIF 数据失败:', error)
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import sharp from 'sharp'
|
||||
|
||||
import { HEIC_FORMATS } from '../constants/index.js'
|
||||
import type { Logger } from '../logger/index.js'
|
||||
import { getGlobalLoggers } from '../photo/logger-adapter.js'
|
||||
import type { ImageMetadata } from '../types/photo.js'
|
||||
|
||||
// 获取图片元数据(复用 Sharp 实例)
|
||||
@@ -86,9 +87,8 @@ export async function convertHeicToJpeg(
|
||||
export async function preprocessImageBuffer(
|
||||
buffer: Buffer,
|
||||
key: string,
|
||||
imageLogger?: Logger['image'],
|
||||
): Promise<Buffer> {
|
||||
const log = imageLogger
|
||||
const log = getGlobalLoggers().image.originalLogger
|
||||
const ext = path.extname(key).toLowerCase()
|
||||
|
||||
// 如果是 HEIC/HEIF 格式,先转换为 JPEG
|
||||
@@ -135,9 +135,9 @@ export async function convertBmpToJpegSharpInstance(
|
||||
|
||||
// 创建 Sharp 实例
|
||||
// Calculate the number of channels in the BMP image
|
||||
const channels = bmpImage.data.length / (bmpImage.width * bmpImage.height);
|
||||
const channels = bmpImage.data.length / (bmpImage.width * bmpImage.height)
|
||||
if (channels !== 3 && channels !== 4) {
|
||||
throw new Error(`Unsupported BMP channel count: ${channels}`);
|
||||
throw new Error(`Unsupported BMP channel count: ${channels}`)
|
||||
}
|
||||
|
||||
// Create Sharp instance with the correct channel count
|
||||
|
||||
@@ -19,7 +19,6 @@ export type {
|
||||
|
||||
// S3 操作
|
||||
export { generateBlurhash } from './image/blurhash.js'
|
||||
export { extractExifData } from './image/exif.js'
|
||||
export {
|
||||
getImageMetadataWithSharp,
|
||||
preprocessImageBuffer,
|
||||
|
||||
@@ -63,7 +63,7 @@ export async function saveManifest(items: PhotoManifestItem[]): Promise<void> {
|
||||
),
|
||||
)
|
||||
|
||||
logger.fs.info(`📁 Manifest 保存至:${manifestPath}`)
|
||||
logger.fs.info(`📁 Manifest 保存至: ${manifestPath}`)
|
||||
}
|
||||
|
||||
// 检测并处理已删除的图片
|
||||
|
||||
@@ -119,11 +119,7 @@ export async function processExifData(
|
||||
const ext = path.extname(photoKey).toLowerCase()
|
||||
const originalBuffer = HEIC_FORMATS.has(ext) ? rawImageBuffer : undefined
|
||||
|
||||
return await extractExifData(
|
||||
imageBuffer,
|
||||
originalBuffer,
|
||||
loggers.exif.originalLogger,
|
||||
)
|
||||
return await extractExifData(imageBuffer, originalBuffer)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -57,11 +57,7 @@ export async function preprocessImage(
|
||||
// 预处理图片(处理 HEIC/HEIF 格式)
|
||||
let imageBuffer: Buffer
|
||||
try {
|
||||
imageBuffer = await preprocessImageBuffer(
|
||||
rawImageBuffer,
|
||||
photoKey,
|
||||
loggers.image.originalLogger,
|
||||
)
|
||||
imageBuffer = await preprocessImageBuffer(rawImageBuffer, photoKey)
|
||||
} catch (error) {
|
||||
loggers.image.error(`预处理图片失败:${photoKey}`, error)
|
||||
return null
|
||||
@@ -182,11 +178,7 @@ export async function executePhotoProcessingPipeline(
|
||||
)
|
||||
|
||||
// 6. 提取照片信息
|
||||
const photoInfo = extractPhotoInfo(
|
||||
photoKey,
|
||||
exifData,
|
||||
loggers.image.originalLogger,
|
||||
)
|
||||
const photoInfo = extractPhotoInfo(photoKey, exifData)
|
||||
|
||||
// 7. 处理 Live Photo
|
||||
const livePhotoResult = processLivePhoto(photoKey, livePhotoMap)
|
||||
|
||||
@@ -2,18 +2,6 @@
|
||||
export type { PhotoProcessorOptions } from './processor.js'
|
||||
export { processPhoto } from './processor.js'
|
||||
|
||||
// 图片处理管道
|
||||
export type {
|
||||
PhotoProcessingContext,
|
||||
ProcessedImageData,
|
||||
} from './image-pipeline.js'
|
||||
export {
|
||||
executePhotoProcessingPipeline,
|
||||
preprocessImage,
|
||||
processImageWithSharp,
|
||||
processPhotoWithPipeline,
|
||||
} from './image-pipeline.js'
|
||||
|
||||
// 缓存管理
|
||||
export type { CacheableData, ThumbnailResult } from './cache-manager.js'
|
||||
export {
|
||||
@@ -27,9 +15,6 @@ export {
|
||||
export type { LivePhotoResult } from './live-photo-handler.js'
|
||||
export { createLivePhotoMap, processLivePhoto } from './live-photo-handler.js'
|
||||
|
||||
// 信息提取
|
||||
export { extractPhotoInfo } from './info-extractor.js'
|
||||
|
||||
// Logger 适配器
|
||||
export type { PhotoLogger, PhotoProcessingLoggers } from './logger-adapter.js'
|
||||
export {
|
||||
|
||||
@@ -2,18 +2,17 @@ import path from 'node:path'
|
||||
|
||||
import { env } from '@env'
|
||||
|
||||
import type { Logger } from '../logger/index.js'
|
||||
import type { PhotoInfo, PickedExif } from '../types/photo.js'
|
||||
import { getGlobalLoggers } from './logger-adapter.js'
|
||||
|
||||
// 从文件名提取照片信息
|
||||
export function extractPhotoInfo(
|
||||
key: string,
|
||||
exifData?: PickedExif | null,
|
||||
imageLogger?: Logger['image'],
|
||||
): PhotoInfo {
|
||||
const log = imageLogger
|
||||
const log = getGlobalLoggers().image
|
||||
|
||||
log?.debug(`提取照片信息:${key}`)
|
||||
log.info(`提取照片信息:${key}`)
|
||||
|
||||
const fileName = path.basename(key, path.extname(key))
|
||||
|
||||
@@ -42,7 +41,7 @@ export function extractPhotoInfo(
|
||||
.filter((part) => part.trim() !== '')
|
||||
tags = pathParts.map((part) => part.trim())
|
||||
|
||||
log?.debug(`从路径提取标签:[${tags.join(', ')}]`)
|
||||
log.info(`从路径提取标签:[${tags.join(', ')}]`)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,7 +53,7 @@ export function extractPhotoInfo(
|
||||
// 如果是 Date 对象,直接使用
|
||||
if (dateTimeOriginal instanceof Date) {
|
||||
dateTaken = dateTimeOriginal.toISOString()
|
||||
log?.debug('使用 EXIF Date 对象作为拍摄时间')
|
||||
log.info('使用 EXIF Date 对象作为拍摄时间')
|
||||
} else {
|
||||
log?.warn(
|
||||
`未知的 DateTimeOriginal 类型:${typeof dateTimeOriginal}`,
|
||||
@@ -72,7 +71,7 @@ export function extractPhotoInfo(
|
||||
const dateMatch = fileName.match(/(\d{4}-\d{2}-\d{2})/)
|
||||
if (dateMatch) {
|
||||
dateTaken = new Date(dateMatch[1]).toISOString()
|
||||
log?.debug(`从文件名提取拍摄时间:${dateMatch[1]}`)
|
||||
log.info(`从文件名提取拍摄时间:${dateMatch[1]}`)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,7 +79,7 @@ export function extractPhotoInfo(
|
||||
const viewsMatch = fileName.match(/(\d+)views?/i)
|
||||
if (viewsMatch) {
|
||||
views = Number.parseInt(viewsMatch[1])
|
||||
log?.debug(`从文件名提取浏览次数:${views}`)
|
||||
log.info(`从文件名提取浏览次数:${views}`)
|
||||
}
|
||||
|
||||
// 从文件名中提取标题(移除日期和浏览次数)
|
||||
@@ -95,7 +94,7 @@ export function extractPhotoInfo(
|
||||
title = path.basename(key, path.extname(key))
|
||||
}
|
||||
|
||||
log?.debug(`照片信息提取完成:"${title}"`)
|
||||
log.info(`照片信息提取完成:"${title}"`)
|
||||
|
||||
return {
|
||||
title,
|
||||
|
||||
@@ -4,7 +4,7 @@ import type { _Object } from '@aws-sdk/client-s3'
|
||||
import { GetObjectCommand, ListObjectsV2Command } from '@aws-sdk/client-s3'
|
||||
|
||||
import { SUPPORTED_FORMATS } from '../../constants/index.js'
|
||||
import type { Logger } from '../../logger/index.js'
|
||||
import { logger } from '../../logger/index.js'
|
||||
import { s3Client } from '../../s3/client.js'
|
||||
import type { S3Config, StorageObject, StorageProvider } from '../interfaces'
|
||||
|
||||
@@ -25,11 +25,9 @@ export class S3StorageProvider implements StorageProvider {
|
||||
this.config = config
|
||||
}
|
||||
|
||||
async getFile(key: string, logger?: Logger['s3']): Promise<Buffer | null> {
|
||||
const log = logger
|
||||
|
||||
async getFile(key: string): Promise<Buffer | null> {
|
||||
try {
|
||||
log?.info(`下载文件:${key}`)
|
||||
logger.s3.info(`下载文件:${key}`)
|
||||
const startTime = Date.now()
|
||||
|
||||
const command = new GetObjectCommand({
|
||||
@@ -40,7 +38,7 @@ export class S3StorageProvider implements StorageProvider {
|
||||
const response = await s3Client.send(command)
|
||||
|
||||
if (!response.Body) {
|
||||
log?.error(`S3 响应中没有 Body: ${key}`)
|
||||
logger.s3.error(`S3 响应中没有 Body: ${key}`)
|
||||
return null
|
||||
}
|
||||
|
||||
@@ -48,7 +46,7 @@ export class S3StorageProvider implements StorageProvider {
|
||||
if (response.Body instanceof Buffer) {
|
||||
const duration = Date.now() - startTime
|
||||
const sizeKB = Math.round(response.Body.length / 1024)
|
||||
log?.success(`下载完成:${key} (${sizeKB}KB, ${duration}ms)`)
|
||||
logger.s3.success(`下载完成:${key} (${sizeKB}KB, ${duration}ms)`)
|
||||
return response.Body
|
||||
}
|
||||
|
||||
@@ -65,17 +63,17 @@ export class S3StorageProvider implements StorageProvider {
|
||||
const buffer = Buffer.concat(chunks)
|
||||
const duration = Date.now() - startTime
|
||||
const sizeKB = Math.round(buffer.length / 1024)
|
||||
log?.success(`下载完成:${key} (${sizeKB}KB, ${duration}ms)`)
|
||||
logger.s3.success(`下载完成:${key} (${sizeKB}KB, ${duration}ms)`)
|
||||
resolve(buffer)
|
||||
})
|
||||
|
||||
stream.on('error', (error) => {
|
||||
log?.error(`下载失败:${key}`, error)
|
||||
logger.s3.error(`下载失败:${key}`, error)
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
} catch (error) {
|
||||
log?.error(`下载失败:${key}`, error)
|
||||
logger.s3.error(`下载失败:${key}`, error)
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user