mirror of
https://github.com/Afilmory/afilmory
synced 2026-04-24 23:05:05 +00:00
feat: sync photos from active storage provider (#135)
Signed-off-by: Innei <tukon479@gmail.com>
This commit is contained in:
@@ -15,9 +15,9 @@ import type { PluginRunState } from '../plugins/manager.js'
|
||||
import { PluginManager } from '../plugins/manager.js'
|
||||
import type {
|
||||
BuilderPluginConfigEntry,
|
||||
BuilderPluginESMImporter,
|
||||
BuilderPluginEventPayloads,
|
||||
} from '../plugins/types.js'
|
||||
import { isPluginReferenceObject } from '../plugins/types.js'
|
||||
import type { StorageProviderFactory } from '../storage/factory.js'
|
||||
import { StorageFactory, StorageManager } from '../storage/index.js'
|
||||
import type { BuilderConfig } from '../types/config.js'
|
||||
@@ -555,14 +555,6 @@ export class AfilmoryBuilder {
|
||||
return
|
||||
}
|
||||
|
||||
if (isPluginReferenceObject(ref)) {
|
||||
const key = ref.resolve
|
||||
if (seen.has(key)) return
|
||||
seen.add(key)
|
||||
references.push(ref)
|
||||
return
|
||||
}
|
||||
|
||||
const pluginName = ref.name
|
||||
if (pluginName) {
|
||||
const key = `plugin:${pluginName}`
|
||||
@@ -576,7 +568,7 @@ export class AfilmoryBuilder {
|
||||
|
||||
const hasPluginWithName = (name: string): boolean => {
|
||||
return references.some((ref) => {
|
||||
if (typeof ref === 'string' || isPluginReferenceObject(ref)) {
|
||||
if (typeof ref === 'string') {
|
||||
return false
|
||||
}
|
||||
return ref.name === name
|
||||
@@ -591,14 +583,16 @@ export class AfilmoryBuilder {
|
||||
this.config.repo.enable &&
|
||||
!hasPluginWithName('afilmory:github-repo-sync')
|
||||
) {
|
||||
addReference('@afilmory/builder/plugins/github-repo-sync')
|
||||
addReference(
|
||||
() => import('@afilmory/builder/plugins/github-repo-sync.js'),
|
||||
)
|
||||
}
|
||||
|
||||
const storagePluginByProvider: Record<string, string> = {
|
||||
s3: '@afilmory/builder/plugins/storage/s3',
|
||||
github: '@afilmory/builder/plugins/storage/github',
|
||||
eagle: '@afilmory/builder/plugins/storage/eagle',
|
||||
local: '@afilmory/builder/plugins/storage/local',
|
||||
const storagePluginByProvider: Record<string, BuilderPluginESMImporter> = {
|
||||
s3: () => import('@afilmory/builder/plugins/storage/s3.js'),
|
||||
github: () => import('@afilmory/builder/plugins/storage/github.js'),
|
||||
eagle: () => import('@afilmory/builder/plugins/storage/eagle.js'),
|
||||
local: () => import('@afilmory/builder/plugins/storage/local.js'),
|
||||
}
|
||||
|
||||
const storageProvider = this.config.storage.provider
|
||||
|
||||
@@ -96,10 +96,7 @@ export async function processImageWithSharp(
|
||||
if (isBitmap(imageBuffer)) {
|
||||
try {
|
||||
// Convert the BMP image to JPEG format and create a new Sharp instance for the converted image.
|
||||
sharpInstance = await convertBmpToJpegSharpInstance(
|
||||
imageBuffer,
|
||||
loggers.image.originalLogger,
|
||||
)
|
||||
sharpInstance = await convertBmpToJpegSharpInstance(imageBuffer)
|
||||
// Update the image buffer to reflect the new JPEG data from the Sharp instance.
|
||||
processedBuffer = await sharpInstance.toBuffer()
|
||||
} catch (error) {
|
||||
@@ -109,10 +106,7 @@ export async function processImageWithSharp(
|
||||
}
|
||||
|
||||
// 获取图片元数据(复用 Sharp 实例)
|
||||
const metadata = await getImageMetadataWithSharp(
|
||||
sharpInstance,
|
||||
loggers.image.originalLogger,
|
||||
)
|
||||
const metadata = await getImageMetadataWithSharp(sharpInstance)
|
||||
if (!metadata) {
|
||||
loggers.image.error(`获取图片元数据失败:${photoKey}`)
|
||||
return null
|
||||
|
||||
@@ -5,10 +5,11 @@ import { pathToFileURL } from 'node:url'
|
||||
import type {
|
||||
BuilderPlugin,
|
||||
BuilderPluginConfigEntry,
|
||||
BuilderPluginESMImporter,
|
||||
BuilderPluginHooks,
|
||||
BuilderPluginReference,
|
||||
} from './types.js'
|
||||
import { isPluginReferenceObject } from './types.js'
|
||||
import { isPluginESMImporter } from './types.js'
|
||||
|
||||
const requireResolver = createRequire(import.meta.url)
|
||||
|
||||
@@ -26,16 +27,12 @@ interface NormalizedDescriptor {
|
||||
|
||||
function normalizeDescriptor(
|
||||
ref: BuilderPluginReference,
|
||||
): NormalizedDescriptor {
|
||||
): NormalizedDescriptor | BuilderPluginESMImporter {
|
||||
if (typeof ref === 'string') {
|
||||
return { specifier: ref }
|
||||
}
|
||||
|
||||
return {
|
||||
specifier: ref.resolve,
|
||||
name: ref.name,
|
||||
options: ref.options,
|
||||
}
|
||||
return ref
|
||||
}
|
||||
|
||||
function resolveSpecifier(
|
||||
@@ -127,8 +124,23 @@ export async function loadPlugins(
|
||||
const results: LoadedPluginDefinition[] = []
|
||||
|
||||
for (const entry of entries) {
|
||||
if (typeof entry === 'string' || isPluginReferenceObject(entry)) {
|
||||
if (typeof entry === 'string') {
|
||||
const descriptor = normalizeDescriptor(entry)
|
||||
|
||||
if (isPluginESMImporter(descriptor)) {
|
||||
const { default: pluginFactoryOrPlugin } = await descriptor()
|
||||
const plugin = await instantiatePlugin(pluginFactoryOrPlugin)
|
||||
const hooks = normalizeHooks(plugin)
|
||||
const name = plugin.name || `lazy-loaded-plugin-${results.length}`
|
||||
|
||||
results.push({
|
||||
name,
|
||||
hooks,
|
||||
pluginOptions: undefined,
|
||||
})
|
||||
continue
|
||||
}
|
||||
|
||||
const { resolvedPath } = resolveSpecifier(descriptor.specifier, baseDir)
|
||||
|
||||
const mod = await importModule(resolvedPath)
|
||||
|
||||
@@ -15,19 +15,10 @@ import type {
|
||||
} from '../types/manifest.js'
|
||||
import type { PhotoManifestItem, ProcessPhotoResult } from '../types/photo.js'
|
||||
|
||||
export type BuilderPluginReference =
|
||||
| string
|
||||
| {
|
||||
resolve: string
|
||||
/**
|
||||
* Optional name override for the plugin. Falls back to the resolved name.
|
||||
*/
|
||||
name?: string
|
||||
/**
|
||||
* Arbitrary configuration passed to the plugin factory.
|
||||
*/
|
||||
options?: unknown
|
||||
}
|
||||
export type BuilderPluginESMImporter = () => Promise<{
|
||||
default: (() => BuilderPlugin | Promise<BuilderPlugin>) | BuilderPlugin
|
||||
}>
|
||||
export type BuilderPluginReference = string | BuilderPluginESMImporter
|
||||
|
||||
export type BuilderPluginConfigEntry = BuilderPluginReference | BuilderPlugin
|
||||
|
||||
@@ -185,8 +176,8 @@ export type BuilderPluginFactory =
|
||||
| (() => BuilderPlugin | Promise<BuilderPlugin>)
|
||||
| ((options: unknown) => BuilderPlugin | Promise<BuilderPlugin>)
|
||||
|
||||
export function isPluginReferenceObject(
|
||||
export function isPluginESMImporter(
|
||||
value: BuilderPluginConfigEntry,
|
||||
): value is Exclude<BuilderPluginReference, string> {
|
||||
return typeof value === 'object' && value !== null && 'resolve' in value
|
||||
): value is BuilderPluginESMImporter {
|
||||
return typeof value === 'function' && value.length === 0
|
||||
}
|
||||
|
||||
12
packages/ui/src/divider/LinearDivider.tsx
Normal file
12
packages/ui/src/divider/LinearDivider.tsx
Normal file
@@ -0,0 +1,12 @@
|
||||
import { clsxm } from '@afilmory/utils'
|
||||
|
||||
export const LinearDivider: Component = ({ className }) => {
|
||||
return (
|
||||
<div
|
||||
className={clsxm(
|
||||
'via-text/20 h-[0.5px] bg-linear-to-r from-transparent to-transparent',
|
||||
className,
|
||||
)}
|
||||
/>
|
||||
)
|
||||
}
|
||||
1
packages/ui/src/divider/index.tsx
Normal file
1
packages/ui/src/divider/index.tsx
Normal file
@@ -0,0 +1 @@
|
||||
export { LinearDivider } from './LinearDivider'
|
||||
@@ -4,6 +4,7 @@ export * from './checkbox'
|
||||
export * from './collapsible'
|
||||
export * from './context-menu'
|
||||
export * from './dialog'
|
||||
export * from './divider'
|
||||
export * from './dropdown-menu'
|
||||
export * from './form'
|
||||
export * from './hover-card'
|
||||
|
||||
Reference in New Issue
Block a user