nuxt-media-library 0.0.44

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (164) hide show
  1. package/README.md +243 -0
  2. package/dist/module.d.mts +31 -0
  3. package/dist/module.d.ts +31 -0
  4. package/dist/module.json +9 -0
  5. package/dist/module.mjs +118 -0
  6. package/dist/runtime/components/MLAssetManager/AssetActivity.d.vue.ts +6 -0
  7. package/dist/runtime/components/MLAssetManager/AssetActivity.vue +13 -0
  8. package/dist/runtime/components/MLAssetManager/AssetActivity.vue.d.ts +6 -0
  9. package/dist/runtime/components/MLAssetManager/AssetCard.d.vue.ts +14 -0
  10. package/dist/runtime/components/MLAssetManager/AssetCard.vue +100 -0
  11. package/dist/runtime/components/MLAssetManager/AssetCard.vue.d.ts +14 -0
  12. package/dist/runtime/components/MLAssetManager/AssetDetail.d.vue.ts +14 -0
  13. package/dist/runtime/components/MLAssetManager/AssetDetail.vue +156 -0
  14. package/dist/runtime/components/MLAssetManager/AssetDetail.vue.d.ts +14 -0
  15. package/dist/runtime/components/MLAssetManager/AssetList.d.vue.ts +15 -0
  16. package/dist/runtime/components/MLAssetManager/AssetList.vue +41 -0
  17. package/dist/runtime/components/MLAssetManager/AssetList.vue.d.ts +15 -0
  18. package/dist/runtime/components/MLAssetManager/AssetOverview.d.vue.ts +8 -0
  19. package/dist/runtime/components/MLAssetManager/AssetOverview.vue +321 -0
  20. package/dist/runtime/components/MLAssetManager/AssetOverview.vue.d.ts +8 -0
  21. package/dist/runtime/components/MLAssetManager/AssetPreview.d.vue.ts +10 -0
  22. package/dist/runtime/components/MLAssetManager/AssetPreview.vue +18 -0
  23. package/dist/runtime/components/MLAssetManager/AssetPreview.vue.d.ts +10 -0
  24. package/dist/runtime/components/MLAssetManager/AssetPreviewAudio.d.vue.ts +9 -0
  25. package/dist/runtime/components/MLAssetManager/AssetPreviewAudio.vue +21 -0
  26. package/dist/runtime/components/MLAssetManager/AssetPreviewAudio.vue.d.ts +9 -0
  27. package/dist/runtime/components/MLAssetManager/AssetPreviewDocument.d.vue.ts +9 -0
  28. package/dist/runtime/components/MLAssetManager/AssetPreviewDocument.vue +39 -0
  29. package/dist/runtime/components/MLAssetManager/AssetPreviewDocument.vue.d.ts +9 -0
  30. package/dist/runtime/components/MLAssetManager/AssetPreviewFallback.d.vue.ts +7 -0
  31. package/dist/runtime/components/MLAssetManager/AssetPreviewFallback.vue +41 -0
  32. package/dist/runtime/components/MLAssetManager/AssetPreviewFallback.vue.d.ts +7 -0
  33. package/dist/runtime/components/MLAssetManager/AssetPreviewImage.d.vue.ts +9 -0
  34. package/dist/runtime/components/MLAssetManager/AssetPreviewImage.vue +30 -0
  35. package/dist/runtime/components/MLAssetManager/AssetPreviewImage.vue.d.ts +9 -0
  36. package/dist/runtime/components/MLAssetManager/AssetPreviewSidebar.d.vue.ts +15 -0
  37. package/dist/runtime/components/MLAssetManager/AssetPreviewSidebar.vue +69 -0
  38. package/dist/runtime/components/MLAssetManager/AssetPreviewSidebar.vue.d.ts +15 -0
  39. package/dist/runtime/components/MLAssetManager/AssetPreviewVideo.d.vue.ts +9 -0
  40. package/dist/runtime/components/MLAssetManager/AssetPreviewVideo.vue +148 -0
  41. package/dist/runtime/components/MLAssetManager/AssetPreviewVideo.vue.d.ts +9 -0
  42. package/dist/runtime/components/MLAssetManager/AssetRenditions.d.vue.ts +8 -0
  43. package/dist/runtime/components/MLAssetManager/AssetRenditions.vue +148 -0
  44. package/dist/runtime/components/MLAssetManager/AssetRenditions.vue.d.ts +8 -0
  45. package/dist/runtime/components/MLAssetManager/Processing.d.vue.ts +8 -0
  46. package/dist/runtime/components/MLAssetManager/Processing.vue +84 -0
  47. package/dist/runtime/components/MLAssetManager/Processing.vue.d.ts +8 -0
  48. package/dist/runtime/components/MLAssetManager/SlotCard.d.vue.ts +17 -0
  49. package/dist/runtime/components/MLAssetManager/SlotCard.vue +94 -0
  50. package/dist/runtime/components/MLAssetManager/SlotCard.vue.d.ts +17 -0
  51. package/dist/runtime/components/MLAssetManager/Widget.d.vue.ts +14 -0
  52. package/dist/runtime/components/MLAssetManager/Widget.vue +328 -0
  53. package/dist/runtime/components/MLAssetManager/Widget.vue.d.ts +14 -0
  54. package/dist/runtime/components/MLPreviewProvider.d.vue.ts +31 -0
  55. package/dist/runtime/components/MLPreviewProvider.vue +51 -0
  56. package/dist/runtime/components/MLPreviewProvider.vue.d.ts +31 -0
  57. package/dist/runtime/components/MLProcessing/Forms/ConfigureStepModal.d.vue.ts +13 -0
  58. package/dist/runtime/components/MLProcessing/Forms/ConfigureStepModal.vue +47 -0
  59. package/dist/runtime/components/MLProcessing/Forms/ConfigureStepModal.vue.d.ts +13 -0
  60. package/dist/runtime/components/MLProcessing/Forms/FramePicker.d.vue.ts +11 -0
  61. package/dist/runtime/components/MLProcessing/Forms/FramePicker.vue +162 -0
  62. package/dist/runtime/components/MLProcessing/Forms/FramePicker.vue.d.ts +11 -0
  63. package/dist/runtime/components/MLProcessing/Forms/StepOptionsForm.d.vue.ts +14 -0
  64. package/dist/runtime/components/MLProcessing/Forms/StepOptionsForm.vue +113 -0
  65. package/dist/runtime/components/MLProcessing/Forms/StepOptionsForm.vue.d.ts +14 -0
  66. package/dist/runtime/components/MLProcessing/Pipeline.d.vue.ts +15 -0
  67. package/dist/runtime/components/MLProcessing/Pipeline.vue +178 -0
  68. package/dist/runtime/components/MLProcessing/Pipeline.vue.d.ts +15 -0
  69. package/dist/runtime/components/MLProcessing/PipelineStepItem.d.vue.ts +20 -0
  70. package/dist/runtime/components/MLProcessing/PipelineStepItem.vue +309 -0
  71. package/dist/runtime/components/MLProcessing/PipelineStepItem.vue.d.ts +20 -0
  72. package/dist/runtime/components/MLProcessing/ProgressBar.d.vue.ts +9 -0
  73. package/dist/runtime/components/MLProcessing/ProgressBar.vue +27 -0
  74. package/dist/runtime/components/MLProcessing/ProgressBar.vue.d.ts +9 -0
  75. package/dist/runtime/components/MLProcessing/StepLayout.d.vue.ts +31 -0
  76. package/dist/runtime/components/MLProcessing/StepLayout.vue +36 -0
  77. package/dist/runtime/components/MLProcessing/StepLayout.vue.d.ts +31 -0
  78. package/dist/runtime/components/MLProcessing/Stepper.d.vue.ts +16 -0
  79. package/dist/runtime/components/MLProcessing/Stepper.vue +87 -0
  80. package/dist/runtime/components/MLProcessing/Stepper.vue.d.ts +16 -0
  81. package/dist/runtime/components/MLProcessing/StepperItem.d.vue.ts +16 -0
  82. package/dist/runtime/components/MLProcessing/StepperItem.vue +150 -0
  83. package/dist/runtime/components/MLProcessing/StepperItem.vue.d.ts +16 -0
  84. package/dist/runtime/components/MLProcessing/TopBar.d.vue.ts +21 -0
  85. package/dist/runtime/components/MLProcessing/TopBar.vue +46 -0
  86. package/dist/runtime/components/MLProcessing/TopBar.vue.d.ts +21 -0
  87. package/dist/runtime/components/MLUploader/ButtonUploader.d.vue.ts +55 -0
  88. package/dist/runtime/components/MLUploader/ButtonUploader.vue +211 -0
  89. package/dist/runtime/components/MLUploader/ButtonUploader.vue.d.ts +55 -0
  90. package/dist/runtime/components/MLUploader/Item.d.vue.ts +34 -0
  91. package/dist/runtime/components/MLUploader/Item.vue +242 -0
  92. package/dist/runtime/components/MLUploader/Item.vue.d.ts +34 -0
  93. package/dist/runtime/components/MLUploader/PolicyPopover.d.vue.ts +7 -0
  94. package/dist/runtime/components/MLUploader/PolicyPopover.vue +160 -0
  95. package/dist/runtime/components/MLUploader/PolicyPopover.vue.d.ts +7 -0
  96. package/dist/runtime/components/MLUploader/Widget.d.vue.ts +44 -0
  97. package/dist/runtime/components/MLUploader/Widget.vue +251 -0
  98. package/dist/runtime/components/MLUploader/Widget.vue.d.ts +44 -0
  99. package/dist/runtime/composables/resourcePolicy/mimeUtils.d.ts +4 -0
  100. package/dist/runtime/composables/resourcePolicy/mimeUtils.js +71 -0
  101. package/dist/runtime/composables/resourcePolicy/useMLResourcePolicy.d.ts +17 -0
  102. package/dist/runtime/composables/resourcePolicy/useMLResourcePolicy.js +150 -0
  103. package/dist/runtime/composables/useElapsedTimer.d.ts +13 -0
  104. package/dist/runtime/composables/useElapsedTimer.js +46 -0
  105. package/dist/runtime/composables/useMLAssetLibrary.d.ts +31 -0
  106. package/dist/runtime/composables/useMLAssetLibrary.js +53 -0
  107. package/dist/runtime/composables/useMLAssetManager.d.ts +30 -0
  108. package/dist/runtime/composables/useMLAssetManager.js +229 -0
  109. package/dist/runtime/composables/useMLAssetManagerPreview.d.ts +28 -0
  110. package/dist/runtime/composables/useMLAssetManagerPreview.js +232 -0
  111. package/dist/runtime/composables/useMLAssetPreview.d.ts +23 -0
  112. package/dist/runtime/composables/useMLAssetPreview.js +153 -0
  113. package/dist/runtime/composables/useMLChunkUploader.d.ts +9 -0
  114. package/dist/runtime/composables/useMLChunkUploader.js +22 -0
  115. package/dist/runtime/composables/useMLProcessingPipeline.d.ts +38 -0
  116. package/dist/runtime/composables/useMLProcessingPipeline.js +258 -0
  117. package/dist/runtime/composables/useMLProcessingStatus.d.ts +34 -0
  118. package/dist/runtime/composables/useMLProcessingStatus.js +100 -0
  119. package/dist/runtime/composables/useMLProcessingStepper.d.ts +32 -0
  120. package/dist/runtime/composables/useMLProcessingStepper.js +280 -0
  121. package/dist/runtime/composables/useMLProcessingStrategies.d.ts +7 -0
  122. package/dist/runtime/composables/useMLProcessingStrategies.js +47 -0
  123. package/dist/runtime/composables/useMLRepeater.d.ts +5 -0
  124. package/dist/runtime/composables/useMLRepeater.js +11 -0
  125. package/dist/runtime/css/index.css +1 -0
  126. package/dist/runtime/index.d.ts +13 -0
  127. package/dist/runtime/index.js +13 -0
  128. package/dist/runtime/plugins/asset-direcetive-client.d.ts +2 -0
  129. package/dist/runtime/plugins/asset-direcetive-client.js +64 -0
  130. package/dist/runtime/plugins/config.d.ts +13 -0
  131. package/dist/runtime/plugins/config.js +23 -0
  132. package/dist/runtime/schemas/resource-policy.schema.d.ts +607 -0
  133. package/dist/runtime/schemas/resource-policy.schema.js +117 -0
  134. package/dist/runtime/server/assets-proxy.d.ts +2 -0
  135. package/dist/runtime/server/assets-proxy.js +81 -0
  136. package/dist/runtime/server/create-ml-proxy.d.ts +47 -0
  137. package/dist/runtime/server/create-ml-proxy.js +232 -0
  138. package/dist/runtime/server/delivery-proxy.d.ts +2 -0
  139. package/dist/runtime/server/delivery-proxy.js +74 -0
  140. package/dist/runtime/server/index.d.ts +2 -0
  141. package/dist/runtime/server/index.js +1 -0
  142. package/dist/runtime/server/processing-proxy.d.ts +2 -0
  143. package/dist/runtime/server/processing-proxy.js +55 -0
  144. package/dist/runtime/server/resource-policy-proxy.d.ts +2 -0
  145. package/dist/runtime/server/resource-policy-proxy.js +80 -0
  146. package/dist/runtime/server/tsconfig.json +0 -0
  147. package/dist/runtime/server/uploads-proxy.d.ts +2 -0
  148. package/dist/runtime/server/uploads-proxy.js +99 -0
  149. package/dist/runtime/types/asset.d.ts +174 -0
  150. package/dist/runtime/types/asset.js +7 -0
  151. package/dist/runtime/types/preview.d.ts +20 -0
  152. package/dist/runtime/types/preview.js +0 -0
  153. package/dist/runtime/types/resourcePolicy.d.ts +77 -0
  154. package/dist/runtime/types/resourcePolicy.js +25 -0
  155. package/dist/runtime/types/uploader.d.ts +71 -0
  156. package/dist/runtime/types/uploader.js +0 -0
  157. package/dist/runtime/utils/uploader/checksum.d.ts +21 -0
  158. package/dist/runtime/utils/uploader/checksum.js +23 -0
  159. package/dist/runtime/utils/uploader/chunking.d.ts +8 -0
  160. package/dist/runtime/utils/uploader/chunking.js +21 -0
  161. package/dist/runtime/utils/uploader/uploader.d.ts +20 -0
  162. package/dist/runtime/utils/uploader/uploader.js +206 -0
  163. package/dist/types.d.mts +11 -0
  164. package/package.json +81 -0
@@ -0,0 +1,30 @@
1
+ import { type MaybeRef, type Ref, type ShallowRef, type ComputedRef } from 'vue';
2
+ import type { ProcessingStream } from './useMLProcessingStatus.js';
3
+ import type { AssetDetail, ProcessingTask, Rendition, AvailableSteps, PipelineConfig } from '../types/asset.js';
4
+ export interface UseMLAssetManagerReturn {
5
+ assets: Ref<Map<string, AssetDetail>>;
6
+ loading: Ref<boolean>;
7
+ error: Ref<string | null>;
8
+ selectedAssetId: Ref<string | null>;
9
+ selectedAsset: ComputedRef<AssetDetail | null>;
10
+ select: (assetId: string | null) => void;
11
+ availableSteps: Ref<AvailableSteps | null>;
12
+ selectedPipeline: ComputedRef<PipelineConfig | null>;
13
+ fetchAvailableSteps: () => Promise<void>;
14
+ /** SSE streams for all assets currently being processed */
15
+ processingStreams: Map<string, ProcessingStream>;
16
+ processingTasks: Ref<ProcessingTask[]>;
17
+ processingTasksLoading: Ref<boolean>;
18
+ processingStream: ShallowRef<ProcessingStream | null>;
19
+ fetchProcessingTasks: (assetId: string) => Promise<void>;
20
+ retryTask: (taskId: string) => Promise<void>;
21
+ triggerProcessing: (assetId: string, stepOptions?: Record<string, Record<string, any>>) => Promise<void>;
22
+ renditions: Ref<Rendition[]>;
23
+ renditionsLoading: Ref<boolean>;
24
+ fetchRenditions: (assetId: string) => Promise<void>;
25
+ deleteAsset: (assetId: string) => Promise<void>;
26
+ updateAsset: (assetId: string, patch: Partial<Pick<AssetDetail, 'visibility' | 'title'>> & Record<string, any>) => Promise<void>;
27
+ refresh: (assetId?: string) => Promise<void>;
28
+ cleanup: () => void;
29
+ }
30
+ export declare function useMLAssetManager(assetIds: MaybeRef<string[]>): UseMLAssetManagerReturn;
@@ -0,0 +1,229 @@
1
+ import { computed, onUnmounted, ref, shallowReactive, shallowRef, watch, toValue } from "vue";
2
+ import { $fetch } from "ofetch";
3
+ import { useMLProcessingStatus } from "./useMLProcessingStatus.js";
4
+ export function useMLAssetManager(assetIds) {
5
+ const assets = ref(/* @__PURE__ */ new Map());
6
+ const loading = ref(false);
7
+ const error = ref(null);
8
+ const selectedAssetId = ref(null);
9
+ const selectedAsset = computed(() => {
10
+ if (!selectedAssetId.value) return null;
11
+ return assets.value.get(selectedAssetId.value) ?? null;
12
+ });
13
+ const availableSteps = ref(null);
14
+ const selectedPipeline = computed(() => {
15
+ if (!availableSteps.value || !selectedAsset.value) return null;
16
+ const kind = selectedAsset.value.kind?.toLowerCase();
17
+ return availableSteps.value[kind] ?? null;
18
+ });
19
+ const processingStreams = shallowReactive(/* @__PURE__ */ new Map());
20
+ const processingTasks = ref([]);
21
+ const processingTasksLoading = ref(false);
22
+ const processingStream = shallowRef(null);
23
+ const renditions = ref([]);
24
+ const renditionsLoading = ref(false);
25
+ const { track: trackProcessing, closeAll: closeAllProcessing } = useMLProcessingStatus();
26
+ function syncProcessingStreams() {
27
+ for (const [id, asset] of assets.value) {
28
+ if (asset.status === "processing" && !processingStreams.has(id)) {
29
+ const stream = trackProcessing(id);
30
+ processingStreams.set(id, stream);
31
+ watch(() => stream.isComplete.value, (done) => {
32
+ if (done) {
33
+ processingStreams.delete(id);
34
+ refreshSingle(id);
35
+ }
36
+ });
37
+ watch(() => stream.error.value, (err) => {
38
+ if (err) {
39
+ processingStreams.delete(id);
40
+ refreshSingle(id);
41
+ }
42
+ });
43
+ watch(() => stream.isFailed.value, (failed) => {
44
+ if (failed) {
45
+ processingStreams.delete(id);
46
+ refreshSingle(id);
47
+ }
48
+ });
49
+ }
50
+ }
51
+ for (const [id] of processingStreams) {
52
+ const asset = assets.value.get(id);
53
+ if (!asset || asset.status !== "processing") {
54
+ processingStreams.get(id)?.close();
55
+ processingStreams.delete(id);
56
+ }
57
+ }
58
+ }
59
+ async function fetchAssets(ids) {
60
+ if (!ids.length) return;
61
+ loading.value = true;
62
+ error.value = null;
63
+ try {
64
+ const result = await $fetch("/api/media-library/manage/assets/resolve", {
65
+ method: "POST",
66
+ body: { assetIds: ids }
67
+ });
68
+ for (const item of result.items ?? []) {
69
+ if (item.status === "ok" && item.asset) {
70
+ assets.value.set(item.asset.id, item.asset);
71
+ }
72
+ }
73
+ syncProcessingStreams();
74
+ } catch (err) {
75
+ error.value = err?.message ?? "Failed to load assets";
76
+ } finally {
77
+ loading.value = false;
78
+ }
79
+ }
80
+ async function refreshSingle(assetId) {
81
+ try {
82
+ const asset = await $fetch(`/api/media-library/manage/assets/${encodeURIComponent(assetId)}`);
83
+ assets.value.set(assetId, asset);
84
+ syncProcessingStreams();
85
+ } catch {
86
+ }
87
+ }
88
+ async function refresh(assetId) {
89
+ if (assetId) {
90
+ await refreshSingle(assetId);
91
+ } else {
92
+ await fetchAssets(toValue(assetIds));
93
+ }
94
+ }
95
+ function select(assetId) {
96
+ selectedAssetId.value = assetId;
97
+ }
98
+ async function fetchAvailableSteps() {
99
+ if (availableSteps.value) return;
100
+ try {
101
+ const result = await $fetch(
102
+ "/api/media-library/manage/resource-policies/pipelines/available-steps"
103
+ );
104
+ availableSteps.value = result;
105
+ } catch {
106
+ }
107
+ }
108
+ watch(selectedAssetId, (newId) => {
109
+ processingTasks.value = [];
110
+ renditions.value = [];
111
+ if (newId && processingStreams.has(newId)) {
112
+ processingStream.value = processingStreams.get(newId);
113
+ } else {
114
+ processingStream.value = null;
115
+ }
116
+ });
117
+ async function fetchProcessingTasks(assetId) {
118
+ processingTasksLoading.value = true;
119
+ try {
120
+ const result = await $fetch(
121
+ `/api/media-library/manage/processing/assets/${encodeURIComponent(assetId)}/tasks`
122
+ );
123
+ processingTasks.value = Array.isArray(result) ? result : result.items ?? [];
124
+ } catch {
125
+ processingTasks.value = [];
126
+ } finally {
127
+ processingTasksLoading.value = false;
128
+ }
129
+ }
130
+ async function retryTask(_taskId) {
131
+ if (!selectedAssetId.value) return;
132
+ await $fetch(`/api/media-library/manage/processing/assets/${encodeURIComponent(selectedAssetId.value)}/process`, {
133
+ method: "POST"
134
+ });
135
+ await fetchProcessingTasks(selectedAssetId.value);
136
+ }
137
+ async function triggerProcessing(assetId, stepOptions) {
138
+ await $fetch(`/api/media-library/manage/processing/assets/${encodeURIComponent(assetId)}/process`, {
139
+ method: "POST",
140
+ body: stepOptions ? { stepOptions } : {}
141
+ });
142
+ await fetchProcessingTasks(assetId);
143
+ if (processingStreams.has(assetId)) {
144
+ processingStreams.get(assetId).close();
145
+ }
146
+ const stream = trackProcessing(assetId);
147
+ processingStreams.set(assetId, stream);
148
+ if (assetId === selectedAssetId.value) {
149
+ processingStream.value = stream;
150
+ }
151
+ }
152
+ async function fetchRenditions(assetId) {
153
+ const asset = assets.value.get(assetId);
154
+ renditions.value = asset?.renditions ?? [];
155
+ }
156
+ async function updateAsset(assetId, patch) {
157
+ const updated = await $fetch(
158
+ `/api/media-library/manage/assets/${encodeURIComponent(assetId)}`,
159
+ { method: "PATCH", body: patch }
160
+ );
161
+ if (updated && typeof updated === "object" && "id" in updated) {
162
+ assets.value.set(assetId, updated);
163
+ } else {
164
+ await refreshSingle(assetId);
165
+ }
166
+ }
167
+ async function deleteAsset(assetId) {
168
+ await $fetch(`/api/media-library/manage/assets/${encodeURIComponent(assetId)}`, {
169
+ method: "DELETE"
170
+ });
171
+ assets.value.delete(assetId);
172
+ if (processingStreams.has(assetId)) {
173
+ processingStreams.get(assetId).close();
174
+ processingStreams.delete(assetId);
175
+ }
176
+ if (selectedAssetId.value === assetId) {
177
+ selectedAssetId.value = null;
178
+ processingStream.value = null;
179
+ }
180
+ }
181
+ function cleanup() {
182
+ closeAllProcessing();
183
+ for (const [, stream] of processingStreams) {
184
+ stream.close();
185
+ }
186
+ processingStreams.clear();
187
+ processingStream.value = null;
188
+ }
189
+ watch(() => toValue(assetIds), async (ids) => {
190
+ const newIds = ids.filter((id) => !assets.value.has(id));
191
+ for (const key of assets.value.keys()) {
192
+ if (!ids.includes(key)) assets.value.delete(key);
193
+ }
194
+ if (newIds.length) await fetchAssets(newIds);
195
+ if (selectedAssetId.value && !ids.includes(selectedAssetId.value)) {
196
+ selectedAssetId.value = ids[0] || null;
197
+ }
198
+ if (!selectedAssetId.value && ids.length) {
199
+ selectedAssetId.value = ids[0] || null;
200
+ }
201
+ }, { immediate: true });
202
+ fetchAvailableSteps();
203
+ onUnmounted(cleanup);
204
+ return {
205
+ assets,
206
+ loading,
207
+ error,
208
+ selectedAssetId,
209
+ selectedAsset,
210
+ select,
211
+ availableSteps,
212
+ selectedPipeline,
213
+ fetchAvailableSteps,
214
+ processingStreams,
215
+ processingTasks,
216
+ processingTasksLoading,
217
+ processingStream,
218
+ fetchProcessingTasks,
219
+ retryTask,
220
+ triggerProcessing,
221
+ renditions,
222
+ renditionsLoading,
223
+ fetchRenditions,
224
+ deleteAsset,
225
+ updateAsset,
226
+ refresh,
227
+ cleanup
228
+ };
229
+ }
@@ -0,0 +1,28 @@
1
+ import { type Ref, type ComputedRef } from "vue";
2
+ import type { AssetDetail } from "../types/asset.js";
3
+ export type PreviewSourceKind = "video" | "image" | "audio" | "document" | "fallback";
4
+ export type PreviewSourceType = "hls" | "dash" | "progressive" | "image" | "audio" | "document" | "fallback";
5
+ export interface PreviewSource {
6
+ id: string;
7
+ label: string;
8
+ sublabel?: string;
9
+ kind: PreviewSourceKind;
10
+ type: PreviewSourceType;
11
+ src: string | null;
12
+ thumb: string | null;
13
+ meta?: string;
14
+ group?: string;
15
+ renditionId?: string | null;
16
+ variantName?: string | null;
17
+ }
18
+ export interface UseMLAssetManagerPreviewReturn {
19
+ sources: ComputedRef<PreviewSource[]>;
20
+ groups: ComputedRef<Array<{
21
+ label: string;
22
+ items: PreviewSource[];
23
+ }>>;
24
+ selected: ComputedRef<PreviewSource | null>;
25
+ selectedId: Ref<string | null>;
26
+ select: (id: string) => void;
27
+ }
28
+ export declare function useMLAssetManagerPreview(assetRef: Ref<AssetDetail | null | undefined>): UseMLAssetManagerPreviewReturn;
@@ -0,0 +1,232 @@
1
+ import { computed, ref, watch } from "vue";
2
+ const RENDITION_LABELS = {
3
+ hls: "HLS",
4
+ dash: "DASH",
5
+ mp4: "MP4",
6
+ thumbnail: "Thumbnail",
7
+ web: "Web",
8
+ image_derive: "Image",
9
+ original: "Original",
10
+ backup: "Backup",
11
+ subtitle: "Subtitle",
12
+ transcript: "Transcript"
13
+ };
14
+ const NON_IMAGE_RENDITION_TYPES = /* @__PURE__ */ new Set([
15
+ "hls",
16
+ "dash",
17
+ "mp4",
18
+ "subtitle",
19
+ "transcript",
20
+ "backup",
21
+ "original"
22
+ ]);
23
+ function isImageRendition(r) {
24
+ return !NON_IMAGE_RENDITION_TYPES.has(r.renditionType);
25
+ }
26
+ function isReady(r) {
27
+ const s = (r.status || "").toLowerCase();
28
+ return s === "ready" || s === "completed" || s === "succeeded";
29
+ }
30
+ function readyVariants(r) {
31
+ return (r.variants ?? []).filter((v) => !!v.previewUrl);
32
+ }
33
+ function bestThumb(asset) {
34
+ const thumbRendition = asset.renditions?.find(
35
+ (r) => r.renditionType === "thumbnail" && isReady(r)
36
+ );
37
+ if (!thumbRendition) return null;
38
+ const variant = thumbRendition.variants?.find((v) => v.previewUrl) ?? null;
39
+ return variant?.previewUrl ?? thumbRendition.previewUrl ?? null;
40
+ }
41
+ function kindForOriginal(asset) {
42
+ const k = (asset.kind || "").toLowerCase();
43
+ const mime = (asset.mime_type || asset.mimeType || "").toLowerCase();
44
+ if (k === "image" || mime.startsWith("image/")) return "image";
45
+ if (k === "video" || mime.startsWith("video/")) return "video";
46
+ if (k === "audio" || mime.startsWith("audio/")) return "audio";
47
+ if (k === "document" || mime === "application/pdf" || mime.startsWith("text/") || mime === "application/json") return "document";
48
+ return "fallback";
49
+ }
50
+ function variantMeta(v) {
51
+ const parts = [];
52
+ if (v.width && v.height) parts.push(`${v.width}\xD7${v.height}`);
53
+ if (v.bitrateKbps) parts.push(`${v.bitrateKbps} kbps`);
54
+ return parts.length ? parts.join(" \xB7 ") : void 0;
55
+ }
56
+ function buildSources(asset) {
57
+ if (!asset) return [];
58
+ const out = [];
59
+ const fallbackThumb = bestThumb(asset);
60
+ const renditions = asset.renditions ?? [];
61
+ for (const r of renditions) {
62
+ if (!isReady(r) || !r.previewUrl) continue;
63
+ if (r.renditionType === "hls" || r.renditionType === "dash") {
64
+ out.push({
65
+ id: `${r.id}:master`,
66
+ label: `${RENDITION_LABELS[r.renditionType] ?? r.renditionType.toUpperCase()} (auto)`,
67
+ sublabel: "Adaptive",
68
+ kind: "video",
69
+ type: r.renditionType,
70
+ src: r.previewUrl,
71
+ thumb: fallbackThumb,
72
+ renditionId: r.id
73
+ });
74
+ for (const v of readyVariants(r)) {
75
+ out.push({
76
+ id: `${r.id}:${v.name}`,
77
+ label: `${RENDITION_LABELS[r.renditionType] ?? r.renditionType.toUpperCase()} \xB7 ${v.name}`,
78
+ sublabel: variantMeta(v),
79
+ kind: "video",
80
+ type: r.renditionType,
81
+ src: v.previewUrl,
82
+ thumb: fallbackThumb,
83
+ meta: variantMeta(v),
84
+ renditionId: r.id,
85
+ variantName: v.name
86
+ });
87
+ }
88
+ }
89
+ }
90
+ for (const r of renditions) {
91
+ if (!isReady(r)) continue;
92
+ if (r.renditionType === "mp4") {
93
+ const variants = readyVariants(r);
94
+ if (variants.length) {
95
+ for (const v of variants) {
96
+ out.push({
97
+ id: `${r.id}:${v.name}`,
98
+ label: `MP4 \xB7 ${v.name}`,
99
+ sublabel: variantMeta(v),
100
+ kind: "video",
101
+ type: "progressive",
102
+ src: v.previewUrl,
103
+ thumb: fallbackThumb,
104
+ meta: variantMeta(v),
105
+ renditionId: r.id,
106
+ variantName: v.name
107
+ });
108
+ }
109
+ } else if (r.previewUrl) {
110
+ out.push({
111
+ id: r.id,
112
+ label: "MP4",
113
+ kind: "video",
114
+ type: "progressive",
115
+ src: r.previewUrl,
116
+ thumb: fallbackThumb,
117
+ renditionId: r.id
118
+ });
119
+ }
120
+ }
121
+ }
122
+ const originalKind = kindForOriginal(asset);
123
+ if (asset.previewUrl) {
124
+ const originalType = originalKind === "video" ? "progressive" : originalKind === "image" ? "image" : originalKind === "audio" ? "audio" : originalKind === "document" ? "document" : "fallback";
125
+ out.push({
126
+ id: "original",
127
+ label: "Original",
128
+ sublabel: asset.original_filename ?? void 0,
129
+ kind: originalKind,
130
+ type: originalType,
131
+ src: asset.previewUrl,
132
+ thumb: originalKind === "image" ? asset.previewUrl : fallbackThumb,
133
+ renditionId: null
134
+ });
135
+ }
136
+ for (const r of renditions) {
137
+ if (!isReady(r)) continue;
138
+ if (!isImageRendition(r)) continue;
139
+ const variants = readyVariants(r);
140
+ if (variants.length) {
141
+ for (const v of variants) {
142
+ out.push({
143
+ id: `${r.id}:${v.name}`,
144
+ label: `${RENDITION_LABELS[r.renditionType] ?? r.renditionType} \xB7 ${v.name}`,
145
+ sublabel: variantMeta(v),
146
+ kind: "image",
147
+ type: "image",
148
+ src: v.previewUrl,
149
+ thumb: v.previewUrl,
150
+ meta: variantMeta(v),
151
+ renditionId: r.id,
152
+ variantName: v.name
153
+ });
154
+ }
155
+ } else if (r.previewUrl) {
156
+ out.push({
157
+ id: r.id,
158
+ label: RENDITION_LABELS[r.renditionType] ?? r.renditionType,
159
+ kind: "image",
160
+ type: "image",
161
+ src: r.previewUrl,
162
+ thumb: r.previewUrl,
163
+ renditionId: r.id
164
+ });
165
+ }
166
+ }
167
+ if (!out.length) {
168
+ out.push({
169
+ id: "fallback",
170
+ label: asset.original_filename || asset.title || asset.id.slice(0, 12),
171
+ kind: "fallback",
172
+ type: "fallback",
173
+ src: null,
174
+ thumb: null
175
+ });
176
+ }
177
+ for (const s of out) {
178
+ s.group = groupFor(s);
179
+ }
180
+ return out;
181
+ }
182
+ function groupFor(s) {
183
+ if (s.id === "original") return "Original";
184
+ if (s.kind === "image") return "Images";
185
+ if (s.kind === "video") {
186
+ if (s.type === "hls") return "HLS";
187
+ if (s.type === "dash") return "DASH";
188
+ return "MP4";
189
+ }
190
+ return "Other";
191
+ }
192
+ export function useMLAssetManagerPreview(assetRef) {
193
+ const sources = computed(() => buildSources(assetRef.value));
194
+ const selectedId = ref(null);
195
+ const selected = computed(() => {
196
+ const s = sources.value;
197
+ if (!s.length) return null;
198
+ return s.find((x) => x.id === selectedId.value) ?? s[0] ?? null;
199
+ });
200
+ const groups = computed(() => {
201
+ const map = /* @__PURE__ */ new Map();
202
+ for (const s of sources.value) {
203
+ const key = s.group ?? "Other";
204
+ if (!map.has(key)) map.set(key, []);
205
+ map.get(key).push(s);
206
+ }
207
+ return Array.from(map.entries()).map(([label, items]) => ({ label, items }));
208
+ });
209
+ watch(
210
+ () => assetRef.value?.id,
211
+ () => {
212
+ selectedId.value = null;
213
+ }
214
+ );
215
+ watch(
216
+ sources,
217
+ (s) => {
218
+ if (!s.length) {
219
+ selectedId.value = null;
220
+ return;
221
+ }
222
+ if (!selectedId.value || !s.find((x) => x.id === selectedId.value)) {
223
+ selectedId.value = s[0].id;
224
+ }
225
+ },
226
+ { immediate: true }
227
+ );
228
+ function select(id) {
229
+ if (sources.value.find((s) => s.id === id)) selectedId.value = id;
230
+ }
231
+ return { sources, groups, selected, selectedId, select };
232
+ }
@@ -0,0 +1,23 @@
1
+ import type { AssetPreview } from "../types/preview.js";
2
+ declare function getAsset(id?: string | null): AssetPreview | undefined;
3
+ declare function isBroken(id?: string | null): boolean;
4
+ declare function isForbidden(id?: string | null): boolean;
5
+ declare function markBroken(id?: string | null): void;
6
+ declare function clearBroken(id?: string | null): void;
7
+ declare function ensureAssets(ids: string[]): Promise<void>;
8
+ declare function register(id?: string | null): void;
9
+ export declare const useMLAssetPreview: () => {
10
+ assets: import("vue").Ref<Record<string, AssetPreview>, Record<string, AssetPreview>>;
11
+ pending: import("vue").Ref<Set<string> & Omit<Set<string>, keyof Set<any>>, Set<string> | (Set<string> & Omit<Set<string>, keyof Set<any>>)>;
12
+ broken: import("vue").Ref<Set<string> & Omit<Set<string>, keyof Set<any>>, Set<string> | (Set<string> & Omit<Set<string>, keyof Set<any>>)>;
13
+ forbidden: import("vue").Ref<Set<string> & Omit<Set<string>, keyof Set<any>>, Set<string> | (Set<string> & Omit<Set<string>, keyof Set<any>>)>;
14
+ loading: import("vue").Ref<boolean, boolean>;
15
+ getAsset: typeof getAsset;
16
+ isBroken: typeof isBroken;
17
+ isForbidden: typeof isForbidden;
18
+ markBroken: typeof markBroken;
19
+ clearBroken: typeof clearBroken;
20
+ register: typeof register;
21
+ ensureAssets: typeof ensureAssets;
22
+ };
23
+ export {};
@@ -0,0 +1,153 @@
1
+ import { ref } from "vue";
2
+ import { $fetch } from "ofetch";
3
+ const assets = ref({});
4
+ const pending = ref(/* @__PURE__ */ new Set());
5
+ const broken = ref(/* @__PURE__ */ new Set());
6
+ const forbidden = ref(/* @__PURE__ */ new Set());
7
+ const loading = ref(false);
8
+ function computeSources(asset) {
9
+ const sources = [];
10
+ for (const rendition of asset.renditions ?? []) {
11
+ if (rendition.variants?.length) {
12
+ for (const variant of rendition.variants) {
13
+ if (variant.previewUrl) {
14
+ sources.push({
15
+ url: variant.previewUrl,
16
+ renditionType: rendition.renditionType,
17
+ name: variant.name,
18
+ width: variant.width,
19
+ height: variant.height,
20
+ bitrateKbps: variant.bitrateKbps
21
+ });
22
+ }
23
+ }
24
+ } else if (rendition.previewUrl) {
25
+ sources.push({
26
+ url: rendition.previewUrl,
27
+ renditionType: rendition.renditionType,
28
+ name: null,
29
+ width: null,
30
+ height: null,
31
+ bitrateKbps: null
32
+ });
33
+ }
34
+ }
35
+ return sources;
36
+ }
37
+ let fetchTimer = null;
38
+ function getAsset(id) {
39
+ if (!id) return void 0;
40
+ return assets.value[id];
41
+ }
42
+ function isBroken(id) {
43
+ if (!id) return false;
44
+ return broken.value.has(id);
45
+ }
46
+ function isForbidden(id) {
47
+ if (!id) return false;
48
+ return forbidden.value.has(id);
49
+ }
50
+ function markBroken(id) {
51
+ if (!id) return;
52
+ broken.value.add(id);
53
+ }
54
+ function clearBroken(id) {
55
+ if (!id) return;
56
+ broken.value.delete(id);
57
+ }
58
+ async function fetchAssets(ids) {
59
+ const targetIds = ids.filter((id) => !broken.value.has(id) && !forbidden.value.has(id));
60
+ if (!targetIds.length) return;
61
+ loading.value = true;
62
+ try {
63
+ const result = await $fetch("/api/media-library/delivery/assets/resolve", {
64
+ method: "POST",
65
+ body: { assetIds: targetIds }
66
+ });
67
+ for (const item of result.items ?? []) {
68
+ if (item.status !== "ok" || !item.asset) {
69
+ broken.value.add(item.assetId);
70
+ continue;
71
+ }
72
+ const asset = item.asset;
73
+ assets.value[asset.id] = {
74
+ id: asset.id,
75
+ asset_type: asset.kind,
76
+ url: asset.downloadUrl,
77
+ metadata: asset,
78
+ expiresIn: asset.downloadUrlExpiresIn,
79
+ renditions: asset.renditions ?? [],
80
+ sources: computeSources(asset),
81
+ forbidden: false
82
+ };
83
+ broken.value.delete(asset.id);
84
+ forbidden.value.delete(asset.id);
85
+ }
86
+ } catch (err) {
87
+ const status = err?.status ?? err?.statusCode ?? err?.response?.status;
88
+ if (status === 403) {
89
+ for (const id of targetIds) {
90
+ forbidden.value.add(id);
91
+ assets.value[id] = {
92
+ id,
93
+ asset_type: "",
94
+ url: null,
95
+ metadata: null,
96
+ expiresIn: null,
97
+ renditions: [],
98
+ sources: [],
99
+ forbidden: true
100
+ };
101
+ }
102
+ } else {
103
+ for (const id of targetIds) broken.value.add(id);
104
+ }
105
+ } finally {
106
+ loading.value = false;
107
+ }
108
+ }
109
+ async function ensureAssets(ids) {
110
+ const missing = ids.filter(
111
+ (id) => !assets.value[id] && !broken.value.has(id)
112
+ );
113
+ if (!missing.length) return;
114
+ await fetchAssets(missing);
115
+ }
116
+ function register(id) {
117
+ if (!id) return;
118
+ if (assets.value[id]) return;
119
+ if (broken.value.has(id)) return;
120
+ pending.value.add(id);
121
+ if (import.meta.client) {
122
+ scheduleFetch();
123
+ }
124
+ }
125
+ function scheduleFetch() {
126
+ if (fetchTimer !== null) return;
127
+ fetchTimer = setTimeout(async () => {
128
+ fetchTimer = null;
129
+ await flushPending();
130
+ }, 0);
131
+ }
132
+ async function flushPending() {
133
+ if (!pending.value.size) return;
134
+ const ids = Array.from(pending.value);
135
+ pending.value.clear();
136
+ await fetchAssets(ids);
137
+ }
138
+ export const useMLAssetPreview = () => {
139
+ return {
140
+ assets,
141
+ pending,
142
+ broken,
143
+ forbidden,
144
+ loading,
145
+ getAsset,
146
+ isBroken,
147
+ isForbidden,
148
+ markBroken,
149
+ clearBroken,
150
+ register,
151
+ ensureAssets
152
+ };
153
+ };