topic-video-progress.service.ts 2.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465
  1. import { Injectable } from '@angular/core';
  2. export type TopicVideoStage = 'idle' | 'scripting' | 'imaging' | 'videoing' | 'composing' | 'done' | 'failed';
  3. export type TopicVideoMediaMode = 'image' | 'video';
  4. export interface TopicVideoProgressInput {
  5. quickMode: boolean;
  6. stage: TopicVideoStage;
  7. mediaMode: TopicVideoMediaMode;
  8. imageProgress: number;
  9. videoProgress: number;
  10. composeProgress: number;
  11. }
  12. interface SceneLike {
  13. state?: string;
  14. imageUrl?: string;
  15. videoUrl?: string;
  16. }
  17. @Injectable({ providedIn: 'root' })
  18. export class TopicVideoProgressService {
  19. calculateTotalProgress(input: TopicVideoProgressInput): number {
  20. if (!input.quickMode) {
  21. return input.stage === 'composing' ? input.composeProgress : (input.stage === 'done' ? 100 : 0);
  22. }
  23. const SCRIPT_W = 5;
  24. const IMAGE_W = 30;
  25. const COMPOSE_W = 40;
  26. const videoW = input.mediaMode === 'video' ? 25 : 0;
  27. const remain = 100 - SCRIPT_W - IMAGE_W - videoW - COMPOSE_W;
  28. const composeW = COMPOSE_W + remain;
  29. const script = input.stage === 'idle' ? 0 : (input.stage === 'scripting' ? 2 : SCRIPT_W);
  30. const image = Math.round((input.imageProgress / 100) * IMAGE_W);
  31. const video = Math.round((input.videoProgress / 100) * videoW);
  32. const compose = Math.round((input.composeProgress / 100) * composeW);
  33. return Math.min(script + image + video + compose, 100);
  34. }
  35. readyCount(scenes: SceneLike[]): number {
  36. return scenes.filter((scene) => scene.state === 'image-done' || scene.state === 'video-done').length;
  37. }
  38. videoReadyCount(scenes: SceneLike[]): number {
  39. return scenes.filter((scene) => !!scene.videoUrl).length;
  40. }
  41. caseSummary(scenes: SceneLike[]): { C: number; D: number; total: number } {
  42. const summary = { C: 0, D: 0, total: 0 };
  43. for (const scene of scenes) {
  44. if (scene.videoUrl) summary.C++;
  45. else if (scene.imageUrl) summary.D++;
  46. }
  47. summary.total = summary.C + summary.D;
  48. return summary;
  49. }
  50. formatSize(bytes: number): string {
  51. if (bytes < 1024) return `${bytes} B`;
  52. if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
  53. return `${(bytes / 1024 / 1024).toFixed(2)} MB`;
  54. }
  55. }