mirror of
https://github.com/OpenCut-app/OpenCut.git
synced 2026-07-13 21:52:53 +02:00
refactor services structure
This commit is contained in:
@@ -16,6 +16,16 @@ When implementing new features:
|
|||||||
3. Understand the API surface of your codebase
|
3. Understand the API surface of your codebase
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
|
## apps/web/src/components/editor/timeline
|
||||||
|
|
||||||
|
audio-waveform.tsx
|
||||||
|
export function AudioWaveform({␍
|
||||||
|
audioUrl,␍
|
||||||
|
audioBuffer,␍
|
||||||
|
height = 32,␍
|
||||||
|
className = "",␍
|
||||||
|
}: AudioWaveformProps)
|
||||||
|
|
||||||
## apps/web/src/constants
|
## apps/web/src/constants
|
||||||
|
|
||||||
editor-constants.ts
|
editor-constants.ts
|
||||||
@@ -574,7 +584,7 @@ definitions.ts
|
|||||||
| "selection"␍
|
| "selection"␍
|
||||||
| "history"␍
|
| "history"␍
|
||||||
| "timeline"␍
|
| "timeline"␍
|
||||||
| "controls"
|
| "con...
|
||||||
export interface TActionDefinition {
|
export interface TActionDefinition {
|
||||||
description: string
|
description: string
|
||||||
category: TActionCategory
|
category: TActionCategory
|
||||||
@@ -604,7 +614,7 @@ registry.ts
|
|||||||
types.ts
|
types.ts
|
||||||
export type TActionArgsMap = {␍
|
export type TActionArgsMap = {␍
|
||||||
"seek-forward": { seconds: number } | undefined;␍
|
"seek-forward": { seconds: number } | undefined;␍
|
||||||
"seek-backward": { seconds: number } | undef...
|
"seek-backward": { seconds: number } | und...
|
||||||
export type TActionWithArgs = keyof TActionArgsMap
|
export type TActionWithArgs = keyof TActionArgsMap
|
||||||
export type TActionWithOptionalArgs = | TActionWithNoArgs␍
|
export type TActionWithOptionalArgs = | TActionWithNoArgs␍
|
||||||
| TKeysWithValueUndefined<TActionArgsMap>
|
| TKeysWithValueUndefined<TActionArgsMap>
|
||||||
@@ -614,7 +624,7 @@ types.ts
|
|||||||
: undefined
|
: undefined
|
||||||
export type TActionFunc<A extends TAction> = A extends TActionWithArgs␍
|
export type TActionFunc<A extends TAction> = A extends TActionWithArgs␍
|
||||||
? (arg: TArgOfAction<A>, trigger?: TInvocationTrigger) => void␍
|
? (arg: TArgOfAction<A>, trigger?: TInvocationTrigger) => void␍
|
||||||
: (_?:...
|
: (_...
|
||||||
export type TInvocationTrigger = "keypress" | "mouseclick"
|
export type TInvocationTrigger = "keypress" | "mouseclick"
|
||||||
export type TBoundActionList = {␍
|
export type TBoundActionList = {␍
|
||||||
[A in TAction]?: Array<TActionFunc<A>>;␍
|
[A in TAction]?: Array<TActionFunc<A>>;␍
|
||||||
@@ -673,12 +683,12 @@ parser.ts
|
|||||||
export type GradientOrientation = LinearOrientation | Array<RadialOrientation>
|
export type GradientOrientation = LinearOrientation | Array<RadialOrientation>
|
||||||
export type Color = | { type: "hex"; value: string }␍
|
export type Color = | { type: "hex"; value: string }␍
|
||||||
| { type: "literal"; value: string }␍
|
| { type: "literal"; value: string }␍
|
||||||
| { type: "rgb"; value: A...
|
| { type: "rgb"; value:...
|
||||||
export type ColorStop = Color & { length?: Distance }
|
export type ColorStop = Color & { length?: Distance }
|
||||||
export type GradientAst = {␍
|
export type GradientAst = {␍
|
||||||
type: GradientType;␍
|
type: GradientType;␍
|
||||||
orientation: GradientOrientation | undefined;␍
|
orientation: GradientOrientation | undefined;␍
|
||||||
colorStops: Array<ColorSto...
|
colorStops: Array<Color...
|
||||||
export const parseGradient = ({␍
|
export const parseGradient = ({␍
|
||||||
code,␍
|
code,␍
|
||||||
}: {␍
|
}: {␍
|
||||||
@@ -691,8 +701,7 @@ parser.ts
|
|||||||
audio.ts
|
audio.ts
|
||||||
export type CollectedAudioElement = Omit<␍
|
export type CollectedAudioElement = Omit<␍
|
||||||
AudioElement,␍
|
AudioElement,␍
|
||||||
"type" | "mediaId" | "volume" | "id" | "name" | "sourceType" | "sourceUrl"
|
"type" | "mediaId" | "volume" | "id" | "name" | "sourceType" | "sourceUrl...
|
||||||
...
|
|
||||||
export function createAudioContext(): AudioContext
|
export function createAudioContext(): AudioContext
|
||||||
export interface DecodedAudio {
|
export interface DecodedAudio {
|
||||||
samples: Float32Array
|
samples: Float32Array
|
||||||
@@ -1119,27 +1128,6 @@ caption.ts
|
|||||||
minDuration?: number;␍
|
minDuration?: number;␍
|
||||||
}): CaptionChunk[]
|
}): CaptionChunk[]
|
||||||
|
|
||||||
## apps/web/src/services/media
|
|
||||||
|
|
||||||
video-cache.ts
|
|
||||||
export class VideoCache {
|
|
||||||
sinks
|
|
||||||
initPromises
|
|
||||||
async getFrameAt({
|
|
||||||
mediaId,
|
|
||||||
file,
|
|
||||||
time,
|
|
||||||
}: {
|
|
||||||
mediaId: string;
|
|
||||||
file: File;
|
|
||||||
time: number;
|
|
||||||
}): Promise<WrappedCanvas | null>
|
|
||||||
clearVideo({ mediaId }: { mediaId: string }): void
|
|
||||||
clearAll(): void
|
|
||||||
getStats()
|
|
||||||
}
|
|
||||||
export const videoCache
|
|
||||||
|
|
||||||
## apps/web/src/services/renderer
|
## apps/web/src/services/renderer
|
||||||
|
|
||||||
canvas-renderer.ts
|
canvas-renderer.ts
|
||||||
@@ -1173,7 +1161,7 @@ scene-builder.ts
|
|||||||
canvasSize: TCanvasSize;␍
|
canvasSize: TCanvasSize;␍
|
||||||
tracks: TimelineTrack[];␍
|
tracks: TimelineTrack[];␍
|
||||||
mediaAssets: MediaAsset[];␍
|
mediaAssets: MediaAsset[];␍
|
||||||
duration: numb...
|
duration: ...
|
||||||
export function buildScene(params: BuildSceneParams)
|
export function buildScene(params: BuildSceneParams)
|
||||||
|
|
||||||
scene-exporter.ts
|
scene-exporter.ts
|
||||||
@@ -1183,7 +1171,7 @@ scene-exporter.ts
|
|||||||
progress: [progress: number];␍
|
progress: [progress: number];␍
|
||||||
complete: [buffer: ArrayBuffer];␍
|
complete: [buffer: ArrayBuffer];␍
|
||||||
error: [error: Error];␍
|
error: [error: Error];␍
|
||||||
cance...
|
c...
|
||||||
export class SceneExporter extends EventEmitter<SceneExporterEvents> {
|
export class SceneExporter extends EventEmitter<SceneExporterEvents> {
|
||||||
renderer: CanvasRenderer
|
renderer: CanvasRenderer
|
||||||
format: ExportFormat
|
format: ExportFormat
|
||||||
@@ -1236,7 +1224,7 @@ opfs-adapter.ts
|
|||||||
static isSupported(): boolean
|
static isSupported(): boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
storage-service.ts
|
service.ts
|
||||||
export const storageService
|
export const storageService
|
||||||
|
|
||||||
types.ts
|
types.ts
|
||||||
@@ -1270,11 +1258,10 @@ types.ts
|
|||||||
"createdAt" | "updatedAt"␍
|
"createdAt" | "updatedAt"␍
|
||||||
> & {␍
|
> & {␍
|
||||||
createdAt: string;␍
|
createdAt: string;␍
|
||||||
updatedAt: string;
|
updatedAt: st...
|
||||||
}
|
|
||||||
export type SerializedProject = Omit<TProject, "metadata" | "scenes"> & {␍
|
export type SerializedProject = Omit<TProject, "metadata" | "scenes"> & {␍
|
||||||
metadata: SerializedProjectMetadata;␍
|
metadata: SerializedProjectMetadata;␍
|
||||||
scenes: Serializ...
|
scenes: Serial...
|
||||||
export interface StorageConfig {
|
export interface StorageConfig {
|
||||||
projectsDb: string
|
projectsDb: string
|
||||||
mediaDb: string
|
mediaDb: string
|
||||||
@@ -1284,15 +1271,36 @@ types.ts
|
|||||||
|
|
||||||
## apps/web/src/services/transcription
|
## apps/web/src/services/transcription
|
||||||
|
|
||||||
index.ts
|
service.ts
|
||||||
export const transcriptionService
|
export const transcriptionService
|
||||||
|
|
||||||
worker.ts
|
worker.ts
|
||||||
export type WorkerMessage = | { type: "init"; modelId: string }␍
|
export type WorkerMessage = | { type: "init"; modelId: string }␍
|
||||||
| { type: "transcribe"; audio: Float32Array; language: strin...
|
| { type: "transcribe"; audio: Float32Array; language: stri...
|
||||||
export type WorkerResponse = | { type: "init-progress"; progress: number }␍
|
export type WorkerResponse = | { type: "init-progress"; progress: number }␍
|
||||||
| { type: "init-complete" }␍
|
| { type: "init-complete" }␍
|
||||||
| { type: "init-error...
|
| { type: "init-err...
|
||||||
|
|
||||||
|
## apps/web/src/services/video-cache
|
||||||
|
|
||||||
|
service.ts
|
||||||
|
export class VideoCache {
|
||||||
|
sinks
|
||||||
|
initPromises
|
||||||
|
async getFrameAt({␍
|
||||||
|
mediaId,␍
|
||||||
|
file,␍
|
||||||
|
time,␍
|
||||||
|
}: {␍
|
||||||
|
mediaId: string;␍
|
||||||
|
file: File;␍
|
||||||
|
time: number;␍
|
||||||
|
}): Promise<WrappedCanvas | null>
|
||||||
|
clearVideo({ mediaId }: { mediaId: string }): void
|
||||||
|
clearAll(): void
|
||||||
|
getStats()
|
||||||
|
}
|
||||||
|
export const videoCache
|
||||||
|
|
||||||
## apps/web/src/stores
|
## apps/web/src/stores
|
||||||
|
|
||||||
@@ -1360,13 +1368,13 @@ blog.ts
|
|||||||
title: string;␍
|
title: string;␍
|
||||||
content: string;␍
|
content: string;␍
|
||||||
description: string;␍
|
description: string;␍
|
||||||
coverImage...
|
cove...
|
||||||
export type Pagination = {␍
|
export type Pagination = {␍
|
||||||
limit: number;␍
|
limit: number;␍
|
||||||
currpage: number;␍
|
currpage: number;␍
|
||||||
nextPage: number | null;␍
|
nextPage: number | null;␍
|
||||||
prevPage: number | null;␍
|
prevPage: number | null;␍
|
||||||
totalIt...
|
to...
|
||||||
export type MarblePostList = {␍
|
export type MarblePostList = {␍
|
||||||
posts: Post[];␍
|
posts: Post[];␍
|
||||||
pagination: Pagination;␍
|
pagination: Pagination;␍
|
||||||
@@ -1469,9 +1477,7 @@ keybinding.ts
|
|||||||
| "j"␍
|
| "j"␍
|
||||||
| "k"␍
|
| "k"␍
|
||||||
| "l"␍
|
| "l"␍
|
||||||
| "m"
|
|...
|
||||||
| "n"
|
|
||||||
...
|
|
||||||
export type ModifierBasedShortcutKey = `${ModifierKeys}+${Key}`
|
export type ModifierBasedShortcutKey = `${ModifierKeys}+${Key}`
|
||||||
export type SingleCharacterShortcutKey = `${Key}`
|
export type SingleCharacterShortcutKey = `${Key}`
|
||||||
export type ShortcutKey = ModifierBasedShortcutKey | SingleCharacterShortcutKey
|
export type ShortcutKey = ModifierBasedShortcutKey | SingleCharacterShortcutKey
|
||||||
@@ -1490,8 +1496,7 @@ project.ts
|
|||||||
}␍
|
}␍
|
||||||
| {␍
|
| {␍
|
||||||
type: "blur";␍
|
type: "blur";␍
|
||||||
blurIntensity: number;
|
blurIntensity: number...
|
||||||
}
|
|
||||||
export interface TCanvasSize {
|
export interface TCanvasSize {
|
||||||
width: number
|
width: number
|
||||||
height: number
|
height: number
|
||||||
@@ -1679,7 +1684,7 @@ timeline.ts
|
|||||||
| CreateVideoElement␍
|
| CreateVideoElement␍
|
||||||
| CreateImageElement␍
|
| CreateImageElement␍
|
||||||
| CreateTextElement␍
|
| CreateTextElement␍
|
||||||
| CreateSt...
|
| Crea...
|
||||||
export interface ElementDragState {
|
export interface ElementDragState {
|
||||||
isDragging: boolean
|
isDragging: boolean
|
||||||
elementId: string | null
|
elementId: string | null
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import type {
|
|||||||
TranscriptionLanguage,
|
TranscriptionLanguage,
|
||||||
TranscriptionProgress,
|
TranscriptionProgress,
|
||||||
} from "@/types/transcription";
|
} from "@/types/transcription";
|
||||||
import { transcriptionService } from "@/services/transcription";
|
import { transcriptionService } from "@/services/transcription/service";
|
||||||
import { decodeAudioToFloat32 } from "@/lib/media/audio";
|
import { decodeAudioToFloat32 } from "@/lib/media/audio";
|
||||||
import { buildCaptionChunks } from "@/lib/transcription/caption";
|
import { buildCaptionChunks } from "@/lib/transcription/caption";
|
||||||
import { Spinner } from "@/components/ui/spinner";
|
import { Spinner } from "@/components/ui/spinner";
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
import { createContext, useContext, useEffect, useRef, useState } from "react";
|
import { createContext, useContext, useEffect, useRef, useState } from "react";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import { useEditor } from "@/hooks/use-editor";
|
import { useEditor } from "@/hooks/use-editor";
|
||||||
import { storageService } from "@/services/storage/storage-service";
|
import { storageService } from "@/services/storage/service";
|
||||||
|
|
||||||
interface StorageContextType {
|
interface StorageContextType {
|
||||||
isInitialized: boolean;
|
isInitialized: boolean;
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import type { EditorCore } from "@/core";
|
import type { EditorCore } from "@/core";
|
||||||
import type { MediaAsset } from "@/types/assets";
|
import type { MediaAsset } from "@/types/assets";
|
||||||
import { storageService } from "@/services/storage/storage-service";
|
import { storageService } from "@/services/storage/service";
|
||||||
import { generateUUID } from "@/utils/id";
|
import { generateUUID } from "@/utils/id";
|
||||||
import { videoCache } from "@/services/media/video-cache";
|
import { videoCache } from "@/services/video-cache/service";
|
||||||
import { hasMediaId } from "@/lib/timeline/element-utils";
|
import { hasMediaId } from "@/lib/timeline/element-utils";
|
||||||
|
|
||||||
export class MediaManager {
|
export class MediaManager {
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import type {
|
|||||||
TTimelineViewState,
|
TTimelineViewState,
|
||||||
} from "@/types/project";
|
} from "@/types/project";
|
||||||
import type { ExportOptions, ExportResult } from "@/types/export";
|
import type { ExportOptions, ExportResult } from "@/types/export";
|
||||||
import { storageService } from "@/services/storage/storage-service";
|
import { storageService } from "@/services/storage/service";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import { generateUUID } from "@/utils/id";
|
import { generateUUID } from "@/utils/id";
|
||||||
import { UpdateProjectSettingsCommand } from "@/lib/commands/project";
|
import { UpdateProjectSettingsCommand } from "@/lib/commands/project";
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import type { EditorCore } from "@/core";
|
import type { EditorCore } from "@/core";
|
||||||
import type { TimelineTrack, TScene } from "@/types/timeline";
|
import type { TimelineTrack, TScene } from "@/types/timeline";
|
||||||
import { storageService } from "@/services/storage/storage-service";
|
import { storageService } from "@/services/storage/service";
|
||||||
import {
|
import {
|
||||||
getMainScene,
|
getMainScene,
|
||||||
ensureMainScene,
|
ensureMainScene,
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { Command } from "@/lib/commands/base-command";
|
|||||||
import { EditorCore } from "@/core";
|
import { EditorCore } from "@/core";
|
||||||
import type { MediaAsset } from "@/types/assets";
|
import type { MediaAsset } from "@/types/assets";
|
||||||
import { generateUUID } from "@/utils/id";
|
import { generateUUID } from "@/utils/id";
|
||||||
import { storageService } from "@/services/storage/storage-service";
|
import { storageService } from "@/services/storage/service";
|
||||||
|
|
||||||
export class AddMediaAssetCommand extends Command {
|
export class AddMediaAssetCommand extends Command {
|
||||||
private assetId: string;
|
private assetId: string;
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { Command } from "@/lib/commands/base-command";
|
import { Command } from "@/lib/commands/base-command";
|
||||||
import { EditorCore } from "@/core";
|
import { EditorCore } from "@/core";
|
||||||
import type { MediaAsset } from "@/types/assets";
|
import type { MediaAsset } from "@/types/assets";
|
||||||
import { storageService } from "@/services/storage/storage-service";
|
import { storageService } from "@/services/storage/service";
|
||||||
import { videoCache } from "@/services/media/video-cache";
|
import { videoCache } from "@/services/video-cache/service";
|
||||||
import { hasMediaId } from "@/lib/timeline/element-utils";
|
import { hasMediaId } from "@/lib/timeline/element-utils";
|
||||||
import type { TimelineTrack } from "@/types/timeline";
|
import type { TimelineTrack } from "@/types/timeline";
|
||||||
|
|
||||||
|
|||||||
+1
-7
@@ -333,12 +333,9 @@ class StorageService {
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Utility methods
|
|
||||||
async clearAllData(): Promise<void> {
|
async clearAllData(): Promise<void> {
|
||||||
// Clear all projects
|
|
||||||
await this.projectsAdapter.clear();
|
await this.projectsAdapter.clear();
|
||||||
|
// project-specific media and timelines cleaned up when projects are deleted
|
||||||
// Note: Project-specific media and timelines will be cleaned up when projects are deleted
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async getStorageInfo(): Promise<{
|
async getStorageInfo(): Promise<{
|
||||||
@@ -392,7 +389,6 @@ class StorageService {
|
|||||||
try {
|
try {
|
||||||
const currentData = await this.loadSavedSounds();
|
const currentData = await this.loadSavedSounds();
|
||||||
|
|
||||||
// Check if sound is already saved
|
|
||||||
if (currentData.sounds.some((sound) => sound.id === soundEffect.id)) {
|
if (currentData.sounds.some((sound) => sound.id === soundEffect.id)) {
|
||||||
return; // Already saved
|
return; // Already saved
|
||||||
}
|
}
|
||||||
@@ -456,7 +452,6 @@ class StorageService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check browser support
|
|
||||||
isOPFSSupported(): boolean {
|
isOPFSSupported(): boolean {
|
||||||
return OPFSAdapter.isSupported();
|
return OPFSAdapter.isSupported();
|
||||||
}
|
}
|
||||||
@@ -470,6 +465,5 @@ class StorageService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Export singleton instance
|
|
||||||
export const storageService = new StorageService();
|
export const storageService = new StorageService();
|
||||||
export { StorageService };
|
export { StorageService };
|
||||||
+3
-3
@@ -1,4 +1,5 @@
|
|||||||
import type {
|
import type {
|
||||||
|
TranscriptionLanguage,
|
||||||
TranscriptionResult,
|
TranscriptionResult,
|
||||||
TranscriptionProgress,
|
TranscriptionProgress,
|
||||||
TranscriptionModelId,
|
TranscriptionModelId,
|
||||||
@@ -8,7 +9,6 @@ import {
|
|||||||
TRANSCRIPTION_MODELS,
|
TRANSCRIPTION_MODELS,
|
||||||
} from "@/constants/transcription-constants";
|
} from "@/constants/transcription-constants";
|
||||||
import type { WorkerMessage, WorkerResponse } from "./worker";
|
import type { WorkerMessage, WorkerResponse } from "./worker";
|
||||||
import type { LanguageCode } from "@/types/language";
|
|
||||||
|
|
||||||
type ProgressCallback = (progress: TranscriptionProgress) => void;
|
type ProgressCallback = (progress: TranscriptionProgress) => void;
|
||||||
|
|
||||||
@@ -20,12 +20,12 @@ class TranscriptionService {
|
|||||||
|
|
||||||
async transcribe({
|
async transcribe({
|
||||||
audioData,
|
audioData,
|
||||||
language,
|
language = "auto",
|
||||||
modelId = DEFAULT_TRANSCRIPTION_MODEL,
|
modelId = DEFAULT_TRANSCRIPTION_MODEL,
|
||||||
onProgress,
|
onProgress,
|
||||||
}: {
|
}: {
|
||||||
audioData: Float32Array;
|
audioData: Float32Array;
|
||||||
language?: LanguageCode;
|
language?: TranscriptionLanguage;
|
||||||
modelId?: TranscriptionModelId;
|
modelId?: TranscriptionModelId;
|
||||||
onProgress?: ProgressCallback;
|
onProgress?: ProgressCallback;
|
||||||
}): Promise<TranscriptionResult> {
|
}): Promise<TranscriptionResult> {
|
||||||
+2
@@ -15,6 +15,7 @@ interface VideoSinkData {
|
|||||||
prefetching: boolean;
|
prefetching: boolean;
|
||||||
prefetchPromise: Promise<void> | null;
|
prefetchPromise: Promise<void> | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class VideoCache {
|
export class VideoCache {
|
||||||
private sinks = new Map<string, VideoSinkData>();
|
private sinks = new Map<string, VideoSinkData>();
|
||||||
private initPromises = new Map<string, Promise<void>>();
|
private initPromises = new Map<string, Promise<void>>();
|
||||||
@@ -311,4 +312,5 @@ export class VideoCache {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const videoCache = new VideoCache();
|
export const videoCache = new VideoCache();
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import { create } from "zustand";
|
import { create } from "zustand";
|
||||||
import type { SoundEffect, SavedSound } from "@/types/sounds";
|
import type { SoundEffect, SavedSound } from "@/types/sounds";
|
||||||
import { storageService } from "@/services/storage/storage-service";
|
import { storageService } from "@/services/storage/service";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import { EditorCore } from "@/core";
|
import { EditorCore } from "@/core";
|
||||||
import { buildLibraryAudioElement } from "@/lib/timeline/element-utils";
|
import { buildLibraryAudioElement } from "@/lib/timeline/element-utils";
|
||||||
|
|||||||
Reference in New Issue
Block a user