@design.estate/dees-wcctools 2.0.0 → 3.0.0
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.
- package/dist_bundle/bundle.js +358 -181
- package/dist_bundle/bundle.js.map +4 -4
- package/dist_ts_web/00_commitinfo_data.js +1 -1
- package/dist_ts_web/elements/wcc-dashboard.d.ts +2 -2
- package/dist_ts_web/elements/wcc-dashboard.js +19 -20
- package/dist_ts_web/elements/wcc-frame.d.ts +1 -1
- package/dist_ts_web/elements/wcc-frame.js +13 -13
- package/dist_ts_web/elements/wcc-properties.d.ts +2 -2
- package/dist_ts_web/elements/wcc-properties.js +30 -25
- package/dist_ts_web/elements/wcc-sidebar.d.ts +1 -1
- package/dist_ts_web/elements/wcc-sidebar.js +11 -11
- package/dist_watch/bundle.js +358 -181
- package/dist_watch/bundle.js.map +4 -4
- package/npmextra.json +12 -6
- package/package.json +13 -12
- package/ts_web/00_commitinfo_data.ts +1 -1
- package/ts_web/elements/wcc-dashboard.ts +17 -12
- package/ts_web/elements/wcc-frame.ts +4 -4
- package/ts_web/elements/wcc-properties.ts +21 -16
- package/ts_web/elements/wcc-sidebar.ts +2 -2
- package/dist_ts_web/services/ffmpeg.service.d.ts +0 -42
- package/dist_ts_web/services/ffmpeg.service.js +0 -276
- package/dist_ts_web/services/mp4.service.d.ts +0 -32
- package/dist_ts_web/services/mp4.service.js +0 -139
package/npmextra.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"
|
|
2
|
+
"@git.zone/cli": {
|
|
3
3
|
"projectType": "wcc",
|
|
4
4
|
"module": {
|
|
5
5
|
"githost": "code.foss.global",
|
|
@@ -21,13 +21,19 @@
|
|
|
21
21
|
"element testing",
|
|
22
22
|
"page development"
|
|
23
23
|
]
|
|
24
|
+
},
|
|
25
|
+
"release": {
|
|
26
|
+
"registries": [
|
|
27
|
+
"https://verdaccio.lossless.digital",
|
|
28
|
+
"https://registry.npmjs.org"
|
|
29
|
+
],
|
|
30
|
+
"accessLevel": "public"
|
|
24
31
|
}
|
|
25
32
|
},
|
|
26
|
-
"
|
|
27
|
-
"npmGlobalTools": [],
|
|
28
|
-
"npmAccessLevel": "public"
|
|
29
|
-
},
|
|
30
|
-
"tsdoc": {
|
|
33
|
+
"@git.zone/tsdoc": {
|
|
31
34
|
"legal": "\n## License and Legal Information\n\nThis repository contains open-source code that is licensed under the MIT License. A copy of the MIT License can be found in the [license](license) file within this repository. \n\n**Please note:** The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file.\n\n### Trademarks\n\nThis project is owned and maintained by Task Venture Capital GmbH. The names and logos associated with Task Venture Capital GmbH and any related products or services are trademarks of Task Venture Capital GmbH and are not included within the scope of the MIT license granted herein. Use of these trademarks must comply with Task Venture Capital GmbH's Trademark Guidelines, and any usage must be approved in writing by Task Venture Capital GmbH.\n\n### Company Information\n\nTask Venture Capital GmbH \nRegistered at District court Bremen HRB 35230 HB, Germany\n\nFor any legal inquiries or if you require further information, please contact us via email at hello@task.vc.\n\nBy using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works.\n"
|
|
35
|
+
},
|
|
36
|
+
"@ship.zone/szci": {
|
|
37
|
+
"npmGlobalTools": []
|
|
32
38
|
}
|
|
33
39
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@design.estate/dees-wcctools",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "A set of web component tools for creating element catalogues, enabling the structured development and documentation of custom elements and pages.",
|
|
6
6
|
"exports": {
|
|
@@ -8,6 +8,12 @@
|
|
|
8
8
|
"./demotools": "./dist_ts_demotools/index.js"
|
|
9
9
|
},
|
|
10
10
|
"type": "module",
|
|
11
|
+
"scripts": {
|
|
12
|
+
"test": "(npm run build)",
|
|
13
|
+
"build": "(tsbuild tsfolders --allowimplicitany && tsbundle element)",
|
|
14
|
+
"watch": "tswatch element",
|
|
15
|
+
"buildDocs": "tsdoc"
|
|
16
|
+
},
|
|
11
17
|
"author": "Lossless GmbH",
|
|
12
18
|
"license": "UNLICENSED",
|
|
13
19
|
"dependencies": {
|
|
@@ -18,13 +24,13 @@
|
|
|
18
24
|
},
|
|
19
25
|
"devDependencies": {
|
|
20
26
|
"@api.global/typedserver": "^7.11.1",
|
|
21
|
-
"@git.zone/tsbuild": "^
|
|
27
|
+
"@git.zone/tsbuild": "^4.0.2",
|
|
22
28
|
"@git.zone/tsbundle": "^2.6.3",
|
|
23
|
-
"@git.zone/tsrun": "^2.0.
|
|
29
|
+
"@git.zone/tsrun": "^2.0.1",
|
|
24
30
|
"@git.zone/tstest": "^3.1.3",
|
|
25
|
-
"@git.zone/tswatch": "^2.3.
|
|
31
|
+
"@git.zone/tswatch": "^2.3.13",
|
|
26
32
|
"@push.rocks/projectinfo": "^5.0.2",
|
|
27
|
-
"@types/node": "^25.0.
|
|
33
|
+
"@types/node": "^25.0.3"
|
|
28
34
|
},
|
|
29
35
|
"files": [
|
|
30
36
|
"ts/**/*",
|
|
@@ -53,10 +59,5 @@
|
|
|
53
59
|
"element testing",
|
|
54
60
|
"page development"
|
|
55
61
|
],
|
|
56
|
-
"
|
|
57
|
-
|
|
58
|
-
"build": "(tsbuild tsfolders --allowimplicitany && tsbundle element)",
|
|
59
|
-
"watch": "tswatch element",
|
|
60
|
-
"buildDocs": "tsdoc"
|
|
61
|
-
}
|
|
62
|
-
}
|
|
62
|
+
"packageManager": "pnpm@10.11.0+sha512.6540583f41cc5f628eb3d9773ecee802f4f9ef9923cc45b69890fb47991d4b092964694ec3a4f738a420c918a333062c8b925d312f42e4f0c263eb603551f977"
|
|
63
|
+
}
|
|
@@ -3,6 +3,6 @@
|
|
|
3
3
|
*/
|
|
4
4
|
export const commitinfo = {
|
|
5
5
|
name: '@design.estate/dees-wcctools',
|
|
6
|
-
version: '
|
|
6
|
+
version: '3.0.0',
|
|
7
7
|
description: 'A set of web component tools for creating element catalogues, enabling the structured development and documentation of custom elements and pages.'
|
|
8
8
|
}
|
|
@@ -34,8 +34,10 @@ export class WccDashboard extends DeesElement {
|
|
|
34
34
|
@property()
|
|
35
35
|
accessor selectedTheme: TTheme = 'dark';
|
|
36
36
|
|
|
37
|
-
|
|
38
|
-
|
|
37
|
+
// Derived from selectedViewport - no need for separate property
|
|
38
|
+
public get isNative(): boolean {
|
|
39
|
+
return this.selectedViewport === 'native';
|
|
40
|
+
}
|
|
39
41
|
|
|
40
42
|
@property()
|
|
41
43
|
accessor pages: Record<string, TTemplateFactory> = {};
|
|
@@ -84,7 +86,7 @@ export class WccDashboard extends DeesElement {
|
|
|
84
86
|
<wcc-sidebar
|
|
85
87
|
.dashboardRef=${this}
|
|
86
88
|
.selectedItem=${this.selectedItem}
|
|
87
|
-
.
|
|
89
|
+
.isNative=${this.isNative}
|
|
88
90
|
@selectedType=${(eventArg) => {
|
|
89
91
|
this.selectedType = eventArg.detail;
|
|
90
92
|
}}
|
|
@@ -101,7 +103,7 @@ export class WccDashboard extends DeesElement {
|
|
|
101
103
|
.selectedItem=${this.selectedItem}
|
|
102
104
|
.selectedViewport=${this.selectedViewport}
|
|
103
105
|
.selectedTheme=${this.selectedTheme}
|
|
104
|
-
.
|
|
106
|
+
.isNative=${this.isNative}
|
|
105
107
|
@selectedViewport=${(eventArg) => {
|
|
106
108
|
this.selectedViewport = eventArg.detail;
|
|
107
109
|
this.scheduleUpdate();
|
|
@@ -116,11 +118,11 @@ export class WccDashboard extends DeesElement {
|
|
|
116
118
|
frame.requestUpdate();
|
|
117
119
|
}
|
|
118
120
|
}}
|
|
119
|
-
@
|
|
120
|
-
this.
|
|
121
|
+
@toggleNative=${() => {
|
|
122
|
+
this.toggleNative();
|
|
121
123
|
}}
|
|
122
124
|
></wcc-properties>
|
|
123
|
-
<wcc-frame id="wccFrame" viewport=${this.selectedViewport} .
|
|
125
|
+
<wcc-frame id="wccFrame" viewport=${this.selectedViewport} .isNative=${this.isNative}>
|
|
124
126
|
</wcc-frame>
|
|
125
127
|
`;
|
|
126
128
|
}
|
|
@@ -135,17 +137,20 @@ export class WccDashboard extends DeesElement {
|
|
|
135
137
|
}
|
|
136
138
|
}
|
|
137
139
|
|
|
138
|
-
public
|
|
139
|
-
|
|
140
|
+
public toggleNative() {
|
|
141
|
+
// Toggle between 'native' and 'desktop' viewports
|
|
142
|
+
this.selectedViewport = this.selectedViewport === 'native' ? 'desktop' : 'native';
|
|
143
|
+
this.buildUrl();
|
|
140
144
|
}
|
|
141
145
|
|
|
142
146
|
public async firstUpdated() {
|
|
143
147
|
this.domtools = await plugins.deesDomtools.DomTools.setupDomTools();
|
|
144
148
|
|
|
145
|
-
// Add ESC key handler for
|
|
149
|
+
// Add ESC key handler for native mode
|
|
146
150
|
document.addEventListener('keydown', (event) => {
|
|
147
|
-
if (event.key === 'Escape' && this.
|
|
148
|
-
this.
|
|
151
|
+
if (event.key === 'Escape' && this.isNative) {
|
|
152
|
+
this.selectedViewport = 'desktop';
|
|
153
|
+
this.buildUrl();
|
|
149
154
|
}
|
|
150
155
|
});
|
|
151
156
|
|
|
@@ -17,7 +17,7 @@ export class WccFrame extends DeesElement {
|
|
|
17
17
|
accessor advancedEditorOpen: boolean = false;
|
|
18
18
|
|
|
19
19
|
@property({ type: Boolean })
|
|
20
|
-
accessor
|
|
20
|
+
accessor isNative: boolean = false;
|
|
21
21
|
|
|
22
22
|
public static styles = [
|
|
23
23
|
css`
|
|
@@ -46,7 +46,7 @@ export class WccFrame extends DeesElement {
|
|
|
46
46
|
return html`
|
|
47
47
|
<style>
|
|
48
48
|
:host {
|
|
49
|
-
${this.
|
|
49
|
+
${this.isNative ? `
|
|
50
50
|
border: none !important;
|
|
51
51
|
left: 0px !important;
|
|
52
52
|
right: 0px !important;
|
|
@@ -58,7 +58,7 @@ export class WccFrame extends DeesElement {
|
|
|
58
58
|
left: 200px;
|
|
59
59
|
`}
|
|
60
60
|
transition: all 0.3s ease;
|
|
61
|
-
${this.
|
|
61
|
+
${this.isNative ? 'padding: 0px;' : (() => {
|
|
62
62
|
switch (this.viewport) {
|
|
63
63
|
case 'desktop':
|
|
64
64
|
return `
|
|
@@ -87,7 +87,7 @@ export class WccFrame extends DeesElement {
|
|
|
87
87
|
}
|
|
88
88
|
|
|
89
89
|
.viewport {
|
|
90
|
-
${!this.
|
|
90
|
+
${!this.isNative && this.viewport !== 'desktop'
|
|
91
91
|
? html` border-right: 1px dotted #444; border-left: 1px dotted #444; `
|
|
92
92
|
: html``
|
|
93
93
|
}
|
|
@@ -35,7 +35,7 @@ export class WccProperties extends DeesElement {
|
|
|
35
35
|
accessor warning: string = null;
|
|
36
36
|
|
|
37
37
|
@property()
|
|
38
|
-
accessor
|
|
38
|
+
accessor isNative: boolean = false;
|
|
39
39
|
|
|
40
40
|
@state()
|
|
41
41
|
accessor propertyContent: TemplateResult[] = [];
|
|
@@ -96,11 +96,11 @@ export class WccProperties extends DeesElement {
|
|
|
96
96
|
overflow: hidden;
|
|
97
97
|
background: var(--background);
|
|
98
98
|
color: var(--foreground);
|
|
99
|
-
display: ${this.
|
|
99
|
+
display: ${this.isNative ? 'none' : 'block'};
|
|
100
100
|
}
|
|
101
101
|
.grid {
|
|
102
102
|
display: grid;
|
|
103
|
-
grid-template-columns: 1fr 150px
|
|
103
|
+
grid-template-columns: 1fr 150px 350px 70px;
|
|
104
104
|
height: 100%;
|
|
105
105
|
}
|
|
106
106
|
.properties {
|
|
@@ -214,6 +214,11 @@ export class WccProperties extends DeesElement {
|
|
|
214
214
|
grid-template-columns: repeat(4, 1fr);
|
|
215
215
|
flex: 1;
|
|
216
216
|
}
|
|
217
|
+
.selectorButtons5 {
|
|
218
|
+
display: grid;
|
|
219
|
+
grid-template-columns: repeat(5, 1fr);
|
|
220
|
+
flex: 1;
|
|
221
|
+
}
|
|
217
222
|
.button {
|
|
218
223
|
display: flex;
|
|
219
224
|
flex-direction: column;
|
|
@@ -623,7 +628,7 @@ export class WccProperties extends DeesElement {
|
|
|
623
628
|
</div>
|
|
624
629
|
<div class="viewportSelector">
|
|
625
630
|
<div class="panelheading">Viewport</div>
|
|
626
|
-
<div class="
|
|
631
|
+
<div class="selectorButtons5">
|
|
627
632
|
<div
|
|
628
633
|
class="button ${this.selectedViewport === 'phone' ? 'selected' : null}"
|
|
629
634
|
@click=${() => {
|
|
@@ -649,23 +654,23 @@ export class WccProperties extends DeesElement {
|
|
|
649
654
|
Tablet<i class="material-symbols-outlined">tablet</i>
|
|
650
655
|
</div>
|
|
651
656
|
<div
|
|
652
|
-
class="button ${this.selectedViewport === 'desktop'
|
|
653
|
-
this.selectedViewport === 'native'
|
|
654
|
-
? 'selected'
|
|
655
|
-
: null}"
|
|
657
|
+
class="button ${this.selectedViewport === 'desktop' ? 'selected' : null}"
|
|
656
658
|
@click=${() => {
|
|
657
|
-
this.selectViewport('
|
|
659
|
+
this.selectViewport('desktop');
|
|
658
660
|
}}
|
|
659
661
|
>
|
|
660
662
|
Desktop<i class="material-symbols-outlined">desktop_windows</i>
|
|
661
663
|
</div>
|
|
664
|
+
<div
|
|
665
|
+
class="button ${this.selectedViewport === 'native' ? 'selected' : null}"
|
|
666
|
+
@click=${() => {
|
|
667
|
+
this.selectViewport('native');
|
|
668
|
+
}}
|
|
669
|
+
>
|
|
670
|
+
Native<i class="material-symbols-outlined">fullscreen</i>
|
|
671
|
+
</div>
|
|
662
672
|
</div>
|
|
663
673
|
</div>
|
|
664
|
-
<div class="docs" @click=${() => this.toggleFullscreen()}>
|
|
665
|
-
<i class="material-symbols-outlined" style="font-size: 20px;">
|
|
666
|
-
${this.isFullscreen ? 'fullscreen_exit' : 'fullscreen'}
|
|
667
|
-
</i>
|
|
668
|
-
</div>
|
|
669
674
|
<!-- Recording Button -->
|
|
670
675
|
<wcc-record-button
|
|
671
676
|
.state=${this.isRecording ? 'recording' : 'idle'}
|
|
@@ -1016,9 +1021,9 @@ export class WccProperties extends DeesElement {
|
|
|
1016
1021
|
);
|
|
1017
1022
|
}
|
|
1018
1023
|
|
|
1019
|
-
private
|
|
1024
|
+
private toggleNative() {
|
|
1020
1025
|
this.dispatchEvent(
|
|
1021
|
-
new CustomEvent('
|
|
1026
|
+
new CustomEvent('toggleNative', {
|
|
1022
1027
|
bubbles: true
|
|
1023
1028
|
})
|
|
1024
1029
|
);
|
|
@@ -18,7 +18,7 @@ export class WccSidebar extends DeesElement {
|
|
|
18
18
|
accessor dashboardRef: WccDashboard;
|
|
19
19
|
|
|
20
20
|
@property()
|
|
21
|
-
accessor
|
|
21
|
+
accessor isNative: boolean = false;
|
|
22
22
|
|
|
23
23
|
// Track which elements are expanded (for multi-demo elements)
|
|
24
24
|
@state()
|
|
@@ -45,7 +45,7 @@ export class WccSidebar extends DeesElement {
|
|
|
45
45
|
--ring: #3b82f6;
|
|
46
46
|
--radius: 4px;
|
|
47
47
|
|
|
48
|
-
display: ${this.
|
|
48
|
+
display: ${this.isNative ? 'none' : 'block'};
|
|
49
49
|
border-right: 1px solid rgba(255, 255, 255, 0.08);
|
|
50
50
|
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif;
|
|
51
51
|
font-size: 14px;
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* FFmpegService - Handles client-side video format conversion using FFmpeg.wasm
|
|
3
|
-
* Uses a custom worker implementation to bypass COEP/CORS issues with the standard library
|
|
4
|
-
*/
|
|
5
|
-
export interface IConversionProgress {
|
|
6
|
-
stage: 'loading' | 'converting' | 'finalizing';
|
|
7
|
-
progress: number;
|
|
8
|
-
message: string;
|
|
9
|
-
}
|
|
10
|
-
export interface IConversionOptions {
|
|
11
|
-
inputBlob: Blob;
|
|
12
|
-
outputFormat: 'mp4' | 'webm';
|
|
13
|
-
onProgress?: (progress: IConversionProgress) => void;
|
|
14
|
-
}
|
|
15
|
-
export declare class FFmpegService {
|
|
16
|
-
private worker;
|
|
17
|
-
private core;
|
|
18
|
-
private loadPromise;
|
|
19
|
-
private messageId;
|
|
20
|
-
private pendingMessages;
|
|
21
|
-
private onLog?;
|
|
22
|
-
private onProgress?;
|
|
23
|
-
/**
|
|
24
|
-
* Lazy load FFmpeg.wasm from CDN using custom worker
|
|
25
|
-
*/
|
|
26
|
-
ensureLoaded(onProgress?: (progress: IConversionProgress) => void): Promise<void>;
|
|
27
|
-
private loadFFmpeg;
|
|
28
|
-
private sendMessage;
|
|
29
|
-
/**
|
|
30
|
-
* Convert WebM blob to MP4
|
|
31
|
-
*/
|
|
32
|
-
convertToMp4(options: IConversionOptions): Promise<Blob>;
|
|
33
|
-
/**
|
|
34
|
-
* Check if FFmpeg is currently loaded
|
|
35
|
-
*/
|
|
36
|
-
get isLoaded(): boolean;
|
|
37
|
-
/**
|
|
38
|
-
* Terminate FFmpeg worker to free resources
|
|
39
|
-
*/
|
|
40
|
-
terminate(): Promise<void>;
|
|
41
|
-
}
|
|
42
|
-
export declare function getFFmpegService(): FFmpegService;
|
|
@@ -1,276 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* FFmpegService - Handles client-side video format conversion using FFmpeg.wasm
|
|
3
|
-
* Uses a custom worker implementation to bypass COEP/CORS issues with the standard library
|
|
4
|
-
*/
|
|
5
|
-
export class FFmpegService {
|
|
6
|
-
worker = null;
|
|
7
|
-
core = null;
|
|
8
|
-
loadPromise = null;
|
|
9
|
-
messageId = 0;
|
|
10
|
-
pendingMessages = new Map();
|
|
11
|
-
onLog;
|
|
12
|
-
onProgress;
|
|
13
|
-
/**
|
|
14
|
-
* Lazy load FFmpeg.wasm from CDN using custom worker
|
|
15
|
-
*/
|
|
16
|
-
async ensureLoaded(onProgress) {
|
|
17
|
-
if (this.worker && this.core)
|
|
18
|
-
return;
|
|
19
|
-
if (this.loadPromise) {
|
|
20
|
-
await this.loadPromise;
|
|
21
|
-
return;
|
|
22
|
-
}
|
|
23
|
-
this.loadPromise = this.loadFFmpeg(onProgress);
|
|
24
|
-
await this.loadPromise;
|
|
25
|
-
}
|
|
26
|
-
async loadFFmpeg(onProgress) {
|
|
27
|
-
console.log('[FFmpeg] Starting FFmpeg load with custom worker...');
|
|
28
|
-
onProgress?.({
|
|
29
|
-
stage: 'loading',
|
|
30
|
-
progress: 0,
|
|
31
|
-
message: 'Loading FFmpeg library...'
|
|
32
|
-
});
|
|
33
|
-
// Import toBlobURL utility
|
|
34
|
-
const { toBlobURL } = await import('@ffmpeg/util');
|
|
35
|
-
// Use jsdelivr CDN (has proper CORS/CORP headers)
|
|
36
|
-
const coreBaseURL = 'https://cdn.jsdelivr.net/npm/@ffmpeg/core@0.12.9/dist/umd';
|
|
37
|
-
onProgress?.({
|
|
38
|
-
stage: 'loading',
|
|
39
|
-
progress: 10,
|
|
40
|
-
message: 'Downloading FFmpeg core (~31MB)...'
|
|
41
|
-
});
|
|
42
|
-
console.log('[FFmpeg] Creating blob URLs...');
|
|
43
|
-
const coreURL = await toBlobURL(`${coreBaseURL}/ffmpeg-core.js`, 'text/javascript');
|
|
44
|
-
const wasmURL = await toBlobURL(`${coreBaseURL}/ffmpeg-core.wasm`, 'application/wasm');
|
|
45
|
-
console.log('[FFmpeg] Blob URLs created');
|
|
46
|
-
onProgress?.({
|
|
47
|
-
stage: 'loading',
|
|
48
|
-
progress: 50,
|
|
49
|
-
message: 'Initializing FFmpeg...'
|
|
50
|
-
});
|
|
51
|
-
// Create custom worker code that bypasses @ffmpeg/ffmpeg wrapper issues
|
|
52
|
-
const workerCode = `
|
|
53
|
-
let ffmpeg = null;
|
|
54
|
-
|
|
55
|
-
self.onmessage = async (e) => {
|
|
56
|
-
const { id, type, data } = e.data;
|
|
57
|
-
|
|
58
|
-
try {
|
|
59
|
-
switch (type) {
|
|
60
|
-
case 'LOAD': {
|
|
61
|
-
const { coreURL, wasmURL } = data;
|
|
62
|
-
console.log('[FFmpeg Worker] Loading core...');
|
|
63
|
-
importScripts(coreURL);
|
|
64
|
-
|
|
65
|
-
console.log('[FFmpeg Worker] Initializing with WASM...');
|
|
66
|
-
ffmpeg = await self.createFFmpegCore({
|
|
67
|
-
mainScriptUrlOrBlob: coreURL + '#' + btoa(JSON.stringify({ wasmURL }))
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
// Set up logging
|
|
71
|
-
ffmpeg.setLogger((log) => {
|
|
72
|
-
console.log('[FFmpeg Worker Log]', log);
|
|
73
|
-
self.postMessage({ type: 'LOG', data: log });
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
// Set up progress - progress is an object { ratio: 0-1, time: seconds }
|
|
77
|
-
ffmpeg.setProgress((progress) => {
|
|
78
|
-
const ratio = typeof progress === 'number' ? progress : (progress.ratio || 0);
|
|
79
|
-
console.log('[FFmpeg Worker Progress]', ratio);
|
|
80
|
-
self.postMessage({ type: 'PROGRESS', data: ratio });
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
console.log('[FFmpeg Worker] Core initialized successfully');
|
|
84
|
-
console.log('[FFmpeg Worker] Available methods:', Object.keys(ffmpeg).join(', '));
|
|
85
|
-
self.postMessage({ id, type: 'LOAD', data: true });
|
|
86
|
-
break;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
case 'EXEC': {
|
|
90
|
-
const { args, timeout = -1 } = data;
|
|
91
|
-
console.log('[FFmpeg Worker] Executing:', args.join(' '));
|
|
92
|
-
|
|
93
|
-
try {
|
|
94
|
-
ffmpeg.setTimeout(timeout);
|
|
95
|
-
ffmpeg.exec(...args);
|
|
96
|
-
const ret = ffmpeg.ret;
|
|
97
|
-
console.log('[FFmpeg Worker] Exec returned:', ret);
|
|
98
|
-
ffmpeg.reset();
|
|
99
|
-
self.postMessage({ id, type: 'EXEC', data: ret });
|
|
100
|
-
} catch (execErr) {
|
|
101
|
-
console.error('[FFmpeg Worker] Exec error:', execErr);
|
|
102
|
-
throw execErr;
|
|
103
|
-
}
|
|
104
|
-
break;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
case 'WRITE_FILE': {
|
|
108
|
-
const { path, fileData } = data;
|
|
109
|
-
console.log('[FFmpeg Worker] Writing file:', path, 'size:', fileData.length);
|
|
110
|
-
ffmpeg.FS.writeFile(path, fileData);
|
|
111
|
-
self.postMessage({ id, type: 'WRITE_FILE', data: true });
|
|
112
|
-
break;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
case 'READ_FILE': {
|
|
116
|
-
const { path } = data;
|
|
117
|
-
console.log('[FFmpeg Worker] Reading file:', path);
|
|
118
|
-
const fileData = ffmpeg.FS.readFile(path);
|
|
119
|
-
console.log('[FFmpeg Worker] Read file size:', fileData.length);
|
|
120
|
-
self.postMessage({ id, type: 'READ_FILE', data: fileData }, [fileData.buffer]);
|
|
121
|
-
break;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
case 'DELETE_FILE': {
|
|
125
|
-
const { path } = data;
|
|
126
|
-
console.log('[FFmpeg Worker] Deleting file:', path);
|
|
127
|
-
ffmpeg.FS.unlink(path);
|
|
128
|
-
self.postMessage({ id, type: 'DELETE_FILE', data: true });
|
|
129
|
-
break;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
default:
|
|
133
|
-
throw new Error('Unknown message type: ' + type);
|
|
134
|
-
}
|
|
135
|
-
} catch (err) {
|
|
136
|
-
console.error('[FFmpeg Worker] Error:', err);
|
|
137
|
-
self.postMessage({ id, type: 'ERROR', data: err.message || String(err) });
|
|
138
|
-
}
|
|
139
|
-
};
|
|
140
|
-
`;
|
|
141
|
-
// Create worker from blob
|
|
142
|
-
const workerBlob = new Blob([workerCode], { type: 'text/javascript' });
|
|
143
|
-
const workerURL = URL.createObjectURL(workerBlob);
|
|
144
|
-
this.worker = new Worker(workerURL);
|
|
145
|
-
// Set up message handler
|
|
146
|
-
this.worker.onmessage = (e) => {
|
|
147
|
-
const { id, type, data } = e.data;
|
|
148
|
-
if (type === 'LOG') {
|
|
149
|
-
console.log('[FFmpeg Log]', data);
|
|
150
|
-
this.onLog?.(data.message || data);
|
|
151
|
-
return;
|
|
152
|
-
}
|
|
153
|
-
if (type === 'PROGRESS') {
|
|
154
|
-
this.onProgress?.(data);
|
|
155
|
-
return;
|
|
156
|
-
}
|
|
157
|
-
const pending = this.pendingMessages.get(id);
|
|
158
|
-
if (pending) {
|
|
159
|
-
this.pendingMessages.delete(id);
|
|
160
|
-
if (type === 'ERROR') {
|
|
161
|
-
pending.reject(new Error(data));
|
|
162
|
-
}
|
|
163
|
-
else {
|
|
164
|
-
pending.resolve(data);
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
};
|
|
168
|
-
this.worker.onerror = (e) => {
|
|
169
|
-
console.error('[FFmpeg] Worker error:', e);
|
|
170
|
-
};
|
|
171
|
-
// Initialize FFmpeg in worker
|
|
172
|
-
console.log('[FFmpeg] Initializing worker...');
|
|
173
|
-
await this.sendMessage('LOAD', { coreURL, wasmURL });
|
|
174
|
-
this.core = true; // Mark as loaded
|
|
175
|
-
console.log('[FFmpeg] Worker initialized successfully');
|
|
176
|
-
onProgress?.({
|
|
177
|
-
stage: 'loading',
|
|
178
|
-
progress: 100,
|
|
179
|
-
message: 'FFmpeg loaded successfully'
|
|
180
|
-
});
|
|
181
|
-
}
|
|
182
|
-
sendMessage(type, data) {
|
|
183
|
-
return new Promise((resolve, reject) => {
|
|
184
|
-
const id = ++this.messageId;
|
|
185
|
-
this.pendingMessages.set(id, { resolve, reject });
|
|
186
|
-
this.worker.postMessage({ id, type, data });
|
|
187
|
-
});
|
|
188
|
-
}
|
|
189
|
-
/**
|
|
190
|
-
* Convert WebM blob to MP4
|
|
191
|
-
*/
|
|
192
|
-
async convertToMp4(options) {
|
|
193
|
-
const { inputBlob, onProgress } = options;
|
|
194
|
-
// Check file size limit (2GB)
|
|
195
|
-
const MAX_FILE_SIZE = 2 * 1024 * 1024 * 1024;
|
|
196
|
-
if (inputBlob.size > MAX_FILE_SIZE) {
|
|
197
|
-
throw new Error('File size exceeds 2GB limit for conversion');
|
|
198
|
-
}
|
|
199
|
-
// Set up progress callback
|
|
200
|
-
this.onProgress = (progress) => {
|
|
201
|
-
const percent = Math.round((progress || 0) * 100);
|
|
202
|
-
console.log('[FFmpeg] Conversion progress:', percent + '%');
|
|
203
|
-
onProgress?.({
|
|
204
|
-
stage: 'converting',
|
|
205
|
-
progress: percent,
|
|
206
|
-
message: `Converting video... ${percent}%`
|
|
207
|
-
});
|
|
208
|
-
};
|
|
209
|
-
await this.ensureLoaded(onProgress);
|
|
210
|
-
onProgress?.({
|
|
211
|
-
stage: 'converting',
|
|
212
|
-
progress: 0,
|
|
213
|
-
message: 'Preparing video for conversion...'
|
|
214
|
-
});
|
|
215
|
-
// Read input blob as Uint8Array
|
|
216
|
-
const inputData = new Uint8Array(await inputBlob.arrayBuffer());
|
|
217
|
-
// Write input file to virtual filesystem
|
|
218
|
-
await this.sendMessage('WRITE_FILE', { path: 'input.webm', fileData: inputData });
|
|
219
|
-
// Execute conversion with optimized settings for web playback
|
|
220
|
-
await this.sendMessage('EXEC', {
|
|
221
|
-
args: [
|
|
222
|
-
'-i', 'input.webm',
|
|
223
|
-
'-c:v', 'libx264',
|
|
224
|
-
'-preset', 'fast',
|
|
225
|
-
'-crf', '23',
|
|
226
|
-
'-c:a', 'aac',
|
|
227
|
-
'-b:a', '128k',
|
|
228
|
-
'-movflags', '+faststart',
|
|
229
|
-
'output.mp4'
|
|
230
|
-
]
|
|
231
|
-
});
|
|
232
|
-
onProgress?.({
|
|
233
|
-
stage: 'finalizing',
|
|
234
|
-
progress: 95,
|
|
235
|
-
message: 'Finalizing video...'
|
|
236
|
-
});
|
|
237
|
-
// Read output file
|
|
238
|
-
const outputData = await this.sendMessage('READ_FILE', { path: 'output.mp4' });
|
|
239
|
-
// Clean up virtual filesystem
|
|
240
|
-
await this.sendMessage('DELETE_FILE', { path: 'input.webm' });
|
|
241
|
-
await this.sendMessage('DELETE_FILE', { path: 'output.mp4' });
|
|
242
|
-
onProgress?.({
|
|
243
|
-
stage: 'finalizing',
|
|
244
|
-
progress: 100,
|
|
245
|
-
message: 'Conversion complete!'
|
|
246
|
-
});
|
|
247
|
-
return new Blob([new Uint8Array(outputData)], { type: 'video/mp4' });
|
|
248
|
-
}
|
|
249
|
-
/**
|
|
250
|
-
* Check if FFmpeg is currently loaded
|
|
251
|
-
*/
|
|
252
|
-
get isLoaded() {
|
|
253
|
-
return this.worker !== null && this.core !== null;
|
|
254
|
-
}
|
|
255
|
-
/**
|
|
256
|
-
* Terminate FFmpeg worker to free resources
|
|
257
|
-
*/
|
|
258
|
-
async terminate() {
|
|
259
|
-
if (this.worker) {
|
|
260
|
-
this.worker.terminate();
|
|
261
|
-
this.worker = null;
|
|
262
|
-
this.core = null;
|
|
263
|
-
this.loadPromise = null;
|
|
264
|
-
this.pendingMessages.clear();
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
// Singleton instance for caching
|
|
269
|
-
let ffmpegServiceInstance = null;
|
|
270
|
-
export function getFFmpegService() {
|
|
271
|
-
if (!ffmpegServiceInstance) {
|
|
272
|
-
ffmpegServiceInstance = new FFmpegService();
|
|
273
|
-
}
|
|
274
|
-
return ffmpegServiceInstance;
|
|
275
|
-
}
|
|
276
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZmZtcGVnLnNlcnZpY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi90c193ZWIvc2VydmljZXMvZmZtcGVnLnNlcnZpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7OztHQUdHO0FBdUJILE1BQU0sT0FBTyxhQUFhO0lBQ2hCLE1BQU0sR0FBa0IsSUFBSSxDQUFDO0lBQzdCLElBQUksR0FBUSxJQUFJLENBQUM7SUFDakIsV0FBVyxHQUF5QixJQUFJLENBQUM7SUFDekMsU0FBUyxHQUFHLENBQUMsQ0FBQztJQUNkLGVBQWUsR0FBeUQsSUFBSSxHQUFHLEVBQUUsQ0FBQztJQUNsRixLQUFLLENBQTZCO0lBQ2xDLFVBQVUsQ0FBOEI7SUFFaEQ7O09BRUc7SUFDSCxLQUFLLENBQUMsWUFBWSxDQUFDLFVBQW9EO1FBQ3JFLElBQUksSUFBSSxDQUFDLE1BQU0sSUFBSSxJQUFJLENBQUMsSUFBSTtZQUFFLE9BQU87UUFFckMsSUFBSSxJQUFJLENBQUMsV0FBVyxFQUFFLENBQUM7WUFDckIsTUFBTSxJQUFJLENBQUMsV0FBVyxDQUFDO1lBQ3ZCLE9BQU87UUFDVCxDQUFDO1FBRUQsSUFBSSxDQUFDLFdBQVcsR0FBRyxJQUFJLENBQUMsVUFBVSxDQUFDLFVBQVUsQ0FBQyxDQUFDO1FBQy9DLE1BQU0sSUFBSSxDQUFDLFdBQVcsQ0FBQztJQUN6QixDQUFDO0lBRU8sS0FBSyxDQUFDLFVBQVUsQ0FBQyxVQUFvRDtRQUMzRSxPQUFPLENBQUMsR0FBRyxDQUFDLHFEQUFxRCxDQUFDLENBQUM7UUFFbkUsVUFBVSxFQUFFLENBQUM7WUFDWCxLQUFLLEVBQUUsU0FBUztZQUNoQixRQUFRLEVBQUUsQ0FBQztZQUNYLE9BQU8sRUFBRSwyQkFBMkI7U0FDckMsQ0FBQyxDQUFDO1FBRUgsMkJBQTJCO1FBQzNCLE1BQU0sRUFBRSxTQUFTLEVBQUUsR0FBRyxNQUFNLE1BQU0sQ0FBQyxjQUFjLENBQUMsQ0FBQztRQUVuRCxrREFBa0Q7UUFDbEQsTUFB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
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* MP4Service - Handles client-side video format conversion using Mediabunny
|
|
3
|
-
* Uses WebCodecs API for hardware-accelerated encoding (10-50x faster than FFmpeg.wasm)
|
|
4
|
-
* @see https://mediabunny.dev/
|
|
5
|
-
*/
|
|
6
|
-
export interface IConversionProgress {
|
|
7
|
-
stage: 'loading' | 'converting' | 'finalizing';
|
|
8
|
-
progress: number;
|
|
9
|
-
message: string;
|
|
10
|
-
}
|
|
11
|
-
export interface IConversionOptions {
|
|
12
|
-
inputBlob: Blob;
|
|
13
|
-
outputFormat: 'mp4' | 'webm';
|
|
14
|
-
onProgress?: (progress: IConversionProgress) => void;
|
|
15
|
-
}
|
|
16
|
-
export declare class MP4Service {
|
|
17
|
-
/**
|
|
18
|
-
* Check if WebCodecs is supported in this browser
|
|
19
|
-
*/
|
|
20
|
-
static isSupported(): boolean;
|
|
21
|
-
/**
|
|
22
|
-
* Check if H.264 encoding is actually available (not just API presence)
|
|
23
|
-
*/
|
|
24
|
-
static isEncodingSupported(): Promise<boolean>;
|
|
25
|
-
/**
|
|
26
|
-
* Convert WebM blob to MP4 using Mediabunny (hardware accelerated via WebCodecs)
|
|
27
|
-
*/
|
|
28
|
-
convertToMp4(options: IConversionOptions): Promise<Blob>;
|
|
29
|
-
}
|
|
30
|
-
export declare function getMP4Service(): MP4Service;
|
|
31
|
-
export { MP4Service as FFmpegService };
|
|
32
|
-
export { getMP4Service as getFFmpegService };
|