ugcinc 4.5.4 → 4.5.6

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.
@@ -21,7 +21,7 @@ const definition = (0, types_1.defineNode)({
21
21
  usernameInputType: 'static',
22
22
  time: '9:41',
23
23
  timeInputType: 'static',
24
- profilePicUrl: 'https://ugcinc.co/logo.png',
24
+ profilePicUrl: 'https://app.ugc.inc/logo.png',
25
25
  profilePicInputType: 'static',
26
26
  messages: [
27
27
  { sender: 'user', text: 'Wow, this dm automation is realistic right 🤯' },
@@ -0,0 +1,20 @@
1
+ /**
2
+ * DeduplicationPreview
3
+ *
4
+ * A Remotion composition that renders a live preview of deduplication effects.
5
+ * All visual effects are approximated using CSS filters, SVG, and overlays.
6
+ * Non-visual effects are shown as badges.
7
+ *
8
+ * Used by the webapp's deduplicate modal for real-time preview.
9
+ */
10
+ import type { DeduplicationConfig } from '../types/deduplication';
11
+ export interface DeduplicationPreviewProps {
12
+ /** Source media URL */
13
+ src: string;
14
+ /** Source media type */
15
+ srcType: 'video' | 'image';
16
+ /** Deduplication config */
17
+ config: DeduplicationConfig;
18
+ }
19
+ export declare function DeduplicationPreview({ src, srcType, config, }: DeduplicationPreviewProps): import("react/jsx-runtime").JSX.Element;
20
+ export default DeduplicationPreview;
@@ -0,0 +1,318 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DeduplicationPreview = DeduplicationPreview;
4
+ const jsx_runtime_1 = require("react/jsx-runtime");
5
+ const remotion_1 = require("remotion");
6
+ // =============================================================================
7
+ // Helper: Build CSS filter string from visual adjustments + color filters
8
+ // =============================================================================
9
+ function buildCssFilter(config) {
10
+ const filters = [];
11
+ // Visual adjustments
12
+ const va = config.visual_adjustments;
13
+ if (va) {
14
+ if (va.brightness !== undefined && va.brightness !== 0) {
15
+ // brightness range is -20 to 20, map to CSS brightness (0.8 to 1.2)
16
+ filters.push(`brightness(${1 + va.brightness / 100})`);
17
+ }
18
+ if (va.contrast !== undefined && va.contrast !== 0) {
19
+ filters.push(`contrast(${1 + va.contrast / 100})`);
20
+ }
21
+ if (va.saturation !== undefined && va.saturation !== 0) {
22
+ filters.push(`saturate(${1 + va.saturation / 50})`);
23
+ }
24
+ if (va.gamma !== undefined && va.gamma !== 0) {
25
+ // Approximate gamma with brightness curve
26
+ filters.push(`brightness(${1 + va.gamma / 150})`);
27
+ }
28
+ }
29
+ // Color filters
30
+ const cf = config.color_filter;
31
+ if (cf) {
32
+ if (cf.sepia)
33
+ filters.push('sepia(1)');
34
+ if (cf.blackwhite)
35
+ filters.push('grayscale(1)');
36
+ if (cf.blur)
37
+ filters.push('blur(2px)');
38
+ if (cf.sharpen)
39
+ filters.push('contrast(1.15)');
40
+ if (cf.vintage) {
41
+ filters.push('sepia(0.4)');
42
+ filters.push('contrast(1.1)');
43
+ }
44
+ }
45
+ return filters.length > 0 ? filters.join(' ') : 'none';
46
+ }
47
+ // =============================================================================
48
+ // Helper: Build transform string
49
+ // =============================================================================
50
+ function buildTransform(config) {
51
+ const transforms = [];
52
+ const va = config.visual_adjustments;
53
+ if (va) {
54
+ if (va.horizontal_flip)
55
+ transforms.push('scaleX(-1)');
56
+ if (va.rotate_right)
57
+ transforms.push(`rotate(${va.rotate_right}deg)`);
58
+ if (va.rotate_left)
59
+ transforms.push(`rotate(-${va.rotate_left}deg)`);
60
+ }
61
+ return transforms.length > 0 ? transforms.join(' ') : 'none';
62
+ }
63
+ // =============================================================================
64
+ // Helper: Build clip-path for crop
65
+ // =============================================================================
66
+ function buildClipPath(config) {
67
+ const c = config.crop;
68
+ if (!c)
69
+ return undefined;
70
+ const top = c.crop_top ?? 0;
71
+ const right = c.crop_right ?? 0;
72
+ const bottom = c.crop_bottom ?? 0;
73
+ const left = c.crop_left ?? 0;
74
+ if (top === 0 && right === 0 && bottom === 0 && left === 0)
75
+ return undefined;
76
+ return `inset(${top}px ${right}px ${bottom}px ${left}px)`;
77
+ }
78
+ // =============================================================================
79
+ // Sub-component: Gradient overlay with animation
80
+ // =============================================================================
81
+ function GradientOverlay({ blendMode, opacity, }) {
82
+ const frame = (0, remotion_1.useCurrentFrame)();
83
+ const { fps } = (0, remotion_1.useVideoConfig)();
84
+ const time = frame / fps;
85
+ // Animate gradient angle over time
86
+ const angle = (time * 30) % 360;
87
+ return ((0, jsx_runtime_1.jsx)("div", { style: {
88
+ position: 'absolute',
89
+ inset: 0,
90
+ background: `linear-gradient(${angle}deg, rgba(255,100,50,${opacity}), rgba(50,100,255,${opacity}), rgba(100,255,50,${opacity}))`,
91
+ mixBlendMode: blendMode,
92
+ pointerEvents: 'none',
93
+ } }));
94
+ }
95
+ // =============================================================================
96
+ // Sub-component: Color shift animated overlay
97
+ // =============================================================================
98
+ function ColorShiftOverlay({ opacity, speed, }) {
99
+ const frame = (0, remotion_1.useCurrentFrame)();
100
+ const { fps } = (0, remotion_1.useVideoConfig)();
101
+ const time = frame / fps;
102
+ // Cycle hue over time
103
+ const hue = (time * speed * 60) % 360;
104
+ return ((0, jsx_runtime_1.jsx)("div", { style: {
105
+ position: 'absolute',
106
+ inset: 0,
107
+ backgroundColor: `hsla(${hue}, 100%, 50%, ${opacity / 100})`,
108
+ mixBlendMode: 'overlay',
109
+ pointerEvents: 'none',
110
+ } }));
111
+ }
112
+ // =============================================================================
113
+ // Sub-component: Diagonal / scanline filter overlay
114
+ // =============================================================================
115
+ function DiagonalFilterOverlay({ filterType, }) {
116
+ const getPattern = () => {
117
+ const colorMap = {
118
+ scan_lines: 'rgba(0,0,0,0.15)',
119
+ scan_lines_green: 'rgba(0,255,0,0.1)',
120
+ scan_lines_red: 'rgba(255,0,0,0.1)',
121
+ scan_lines_blue: 'rgba(0,0,255,0.1)',
122
+ };
123
+ switch (filterType) {
124
+ case 'scan_lines':
125
+ case 'scan_lines_green':
126
+ case 'scan_lines_red':
127
+ case 'scan_lines_blue': {
128
+ const color = colorMap[filterType] ?? 'rgba(0,0,0,0.15)';
129
+ return {
130
+ background: `repeating-linear-gradient(0deg, ${color} 0px, ${color} 1px, transparent 1px, transparent 3px)`,
131
+ };
132
+ }
133
+ case 'hexagonal_grid':
134
+ return {
135
+ background: `repeating-linear-gradient(60deg, rgba(0,0,0,0.08) 0px, rgba(0,0,0,0.08) 1px, transparent 1px, transparent 6px),
136
+ repeating-linear-gradient(-60deg, rgba(0,0,0,0.08) 0px, rgba(0,0,0,0.08) 1px, transparent 1px, transparent 6px)`,
137
+ };
138
+ case 'diagonal_square_grid':
139
+ return {
140
+ background: `repeating-linear-gradient(45deg, rgba(0,0,0,0.08) 0px, rgba(0,0,0,0.08) 1px, transparent 1px, transparent 6px),
141
+ repeating-linear-gradient(-45deg, rgba(0,0,0,0.08) 0px, rgba(0,0,0,0.08) 1px, transparent 1px, transparent 6px)`,
142
+ };
143
+ default:
144
+ return {};
145
+ }
146
+ };
147
+ return ((0, jsx_runtime_1.jsx)("div", { style: {
148
+ position: 'absolute',
149
+ inset: 0,
150
+ ...getPattern(),
151
+ pointerEvents: 'none',
152
+ } }));
153
+ }
154
+ // =============================================================================
155
+ // Sub-component: Lens correction via SVG filter
156
+ // =============================================================================
157
+ function LensCorrectionOverlay({ k1, k2, }) {
158
+ // Scale up the effect for visual clarity in preview
159
+ const scale = Math.abs(k1) * 200 + Math.abs(k2) * 400;
160
+ const scaleStr = Math.max(1, scale).toFixed(1);
161
+ return ((0, jsx_runtime_1.jsxs)("svg", { style: {
162
+ position: 'absolute',
163
+ inset: 0,
164
+ width: '100%',
165
+ height: '100%',
166
+ pointerEvents: 'none',
167
+ }, children: [(0, jsx_runtime_1.jsx)("defs", { children: (0, jsx_runtime_1.jsxs)("filter", { id: "lens-distortion", x: "-10%", y: "-10%", width: "120%", height: "120%", children: [(0, jsx_runtime_1.jsx)("feTurbulence", { type: "turbulence", baseFrequency: "0.01", numOctaves: 1, seed: 1, result: "turbulence" }), (0, jsx_runtime_1.jsx)("feDisplacementMap", { in: "SourceGraphic", in2: "turbulence", scale: scaleStr, xChannelSelector: "R", yChannelSelector: "G" })] }) }), (0, jsx_runtime_1.jsx)("rect", { width: "100%", height: "100%", fill: "transparent", filter: "url(#lens-distortion)", style: { opacity: 0.3 } })] }));
168
+ }
169
+ // =============================================================================
170
+ // Sub-component: RGBA channel shift
171
+ // =============================================================================
172
+ function RGBAShiftOverlay({ src, srcType }) {
173
+ const mediaStyle = {
174
+ width: '100%',
175
+ height: '100%',
176
+ objectFit: 'cover',
177
+ };
178
+ const MediaElement = srcType === 'video'
179
+ ? () => (0, jsx_runtime_1.jsx)(remotion_1.Video, { src: src, style: mediaStyle })
180
+ : () => (0, jsx_runtime_1.jsx)(remotion_1.Img, { src: src, style: mediaStyle });
181
+ return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsxs)("div", { style: {
182
+ position: 'absolute',
183
+ inset: 0,
184
+ transform: 'translate(-2px, 0)',
185
+ mixBlendMode: 'screen',
186
+ opacity: 0.3,
187
+ pointerEvents: 'none',
188
+ }, children: [(0, jsx_runtime_1.jsx)("div", { style: { width: '100%', height: '100%', filter: 'grayscale(1) brightness(0.8)', mixBlendMode: 'multiply' }, children: (0, jsx_runtime_1.jsx)(MediaElement, {}) }), (0, jsx_runtime_1.jsx)("div", { style: {
189
+ position: 'absolute',
190
+ inset: 0,
191
+ backgroundColor: 'rgba(255,0,0,0.5)',
192
+ mixBlendMode: 'multiply',
193
+ } })] }), (0, jsx_runtime_1.jsxs)("div", { style: {
194
+ position: 'absolute',
195
+ inset: 0,
196
+ transform: 'translate(2px, 0)',
197
+ mixBlendMode: 'screen',
198
+ opacity: 0.3,
199
+ pointerEvents: 'none',
200
+ }, children: [(0, jsx_runtime_1.jsx)("div", { style: { width: '100%', height: '100%', filter: 'grayscale(1) brightness(0.8)', mixBlendMode: 'multiply' }, children: (0, jsx_runtime_1.jsx)(MediaElement, {}) }), (0, jsx_runtime_1.jsx)("div", { style: {
201
+ position: 'absolute',
202
+ inset: 0,
203
+ backgroundColor: 'rgba(0,0,255,0.5)',
204
+ mixBlendMode: 'multiply',
205
+ } })] })] }));
206
+ }
207
+ // =============================================================================
208
+ // Sub-component: Vintage noise + vignette overlay
209
+ // =============================================================================
210
+ function VintageOverlay() {
211
+ return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("div", { style: {
212
+ position: 'absolute',
213
+ inset: 0,
214
+ background: 'radial-gradient(ellipse at center, transparent 50%, rgba(0,0,0,0.4) 100%)',
215
+ pointerEvents: 'none',
216
+ } }), (0, jsx_runtime_1.jsx)("div", { style: {
217
+ position: 'absolute',
218
+ inset: 0,
219
+ opacity: 0.06,
220
+ backgroundImage: `url("data:image/svg+xml,%3Csvg viewBox='0 0 200 200' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.65' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E")`,
221
+ backgroundSize: '100px 100px',
222
+ pointerEvents: 'none',
223
+ } })] }));
224
+ }
225
+ // =============================================================================
226
+ // Sub-component: Non-visual effect badges
227
+ // =============================================================================
228
+ function BadgeOverlay({ config }) {
229
+ const badges = [];
230
+ // Phone config
231
+ if (config.phone_config?.inject_exif) {
232
+ const model = config.phone_config.phone_model === 'iphone' ? 'iPhone 15 Pro'
233
+ : config.phone_config.phone_model === 'samsung' ? 'Galaxy S24'
234
+ : 'Pixel 8 Pro';
235
+ badges.push(`${model} EXIF`);
236
+ }
237
+ // Trace removal
238
+ if (config.trace_removal?.remove_ffmpeg_signatures) {
239
+ const codec = config.trace_removal.codec ?? 'H265';
240
+ const ext = config.trace_removal.video_extension ?? 'MOV';
241
+ badges.push(`${codec} ${ext}`);
242
+ }
243
+ // Mobile encoding
244
+ if (config.mobile_encoding?.use_gop || config.mobile_encoding?.delete_b_frames) {
245
+ badges.push('Mobile encoding');
246
+ }
247
+ // Speed
248
+ const speed = config.speed?.speed_up ?? config.speed?.slow_down;
249
+ if (speed && speed !== 1) {
250
+ badges.push(`${speed}x speed`);
251
+ }
252
+ // Cutting
253
+ if (config.cutting?.cut_begin_ms || config.cutting?.cut_end_ms || config.cutting?.cut_middle_ms) {
254
+ const total = (config.cutting.cut_begin_ms ?? 0) + (config.cutting.cut_end_ms ?? 0) + (config.cutting.cut_middle_ms ?? 0);
255
+ badges.push(`${total}ms trimmed`);
256
+ }
257
+ // Frame manipulation (non-visual parts)
258
+ if (config.frame_manipulation?.random_skip_frames)
259
+ badges.push('Frame skip');
260
+ if (config.frame_manipulation?.tblend)
261
+ badges.push('Temporal blend');
262
+ // Enhancement
263
+ if (config.enhancement?.enhance_video) {
264
+ badges.push(`${config.enhancement.enhance_video.toUpperCase()} upscale`);
265
+ }
266
+ // Audio
267
+ if (config.audio?.mute_audio)
268
+ badges.push('Muted');
269
+ else {
270
+ if (config.audio?.random_pitch)
271
+ badges.push('Pitch shifted');
272
+ if (config.audio?.white_noise)
273
+ badges.push('White noise');
274
+ }
275
+ if (badges.length === 0)
276
+ return null;
277
+ return ((0, jsx_runtime_1.jsx)("div", { style: {
278
+ position: 'absolute',
279
+ bottom: 16,
280
+ left: 16,
281
+ right: 16,
282
+ display: 'flex',
283
+ flexWrap: 'wrap',
284
+ gap: 6,
285
+ pointerEvents: 'none',
286
+ }, children: badges.map((badge) => ((0, jsx_runtime_1.jsx)("div", { style: {
287
+ padding: '4px 10px',
288
+ borderRadius: 6,
289
+ backgroundColor: 'rgba(0,0,0,0.6)',
290
+ color: 'rgba(255,255,255,0.85)',
291
+ fontSize: 11,
292
+ fontFamily: 'system-ui, -apple-system, sans-serif',
293
+ fontWeight: 500,
294
+ backdropFilter: 'blur(4px)',
295
+ letterSpacing: 0.2,
296
+ }, children: badge }, badge))) }));
297
+ }
298
+ // =============================================================================
299
+ // Main Composition
300
+ // =============================================================================
301
+ function DeduplicationPreview({ src, srcType, config, }) {
302
+ const cssFilter = buildCssFilter(config);
303
+ const transform = buildTransform(config);
304
+ const clipPath = buildClipPath(config);
305
+ const mediaStyle = {
306
+ width: '100%',
307
+ height: '100%',
308
+ objectFit: 'cover',
309
+ };
310
+ return ((0, jsx_runtime_1.jsxs)(remotion_1.AbsoluteFill, { style: { backgroundColor: '#000000' }, children: [(0, jsx_runtime_1.jsx)("div", { style: {
311
+ position: 'absolute',
312
+ inset: 0,
313
+ filter: cssFilter,
314
+ transform,
315
+ clipPath,
316
+ }, children: srcType === 'video' ? ((0, jsx_runtime_1.jsx)(remotion_1.Video, { src: src, style: mediaStyle })) : ((0, jsx_runtime_1.jsx)(remotion_1.Img, { src: src, style: mediaStyle })) }), config.lens_correction && ((0, jsx_runtime_1.jsx)(LensCorrectionOverlay, { k1: config.lens_correction.k1, k2: config.lens_correction.k2 })), config.frame_manipulation?.rgba_shift && ((0, jsx_runtime_1.jsx)(RGBAShiftOverlay, { src: src, srcType: srcType })), config.gradient_overlay?.enabled && ((0, jsx_runtime_1.jsx)(GradientOverlay, { blendMode: config.gradient_overlay.blend_mode ?? 'overlay', opacity: config.gradient_overlay.opacity ?? 0.05 })), config.color_shift?.enabled && ((0, jsx_runtime_1.jsx)(ColorShiftOverlay, { opacity: config.color_shift.color_shift_opacity ?? 30, speed: config.color_shift.color_shift_speed ?? 1 })), config.diagonal_filter?.enabled && ((0, jsx_runtime_1.jsx)(DiagonalFilterOverlay, { filterType: config.diagonal_filter.scan_line_filter })), config.color_filter?.vintage && (0, jsx_runtime_1.jsx)(VintageOverlay, {}), (0, jsx_runtime_1.jsx)(BadgeOverlay, { config: config })] }));
317
+ }
318
+ exports.default = DeduplicationPreview;
@@ -9,4 +9,5 @@ export { InstagramDmComposition, defaultInstagramDmProps, type InstagramDmCompos
9
9
  export { convertPublicToProps, validatePublicInput, type ValidationError, } from './InstagramDmComposition/convertPublicToProps';
10
10
  export { IMessageDmComposition, defaultIMessageDmProps, type IMessageDmCompositionProps, type ImMessage, type ImMessageSender, } from './IMessageDmComposition';
11
11
  export { BaseDmComposition, DebugOverlay, type BaseDmCompositionProps, } from './DmComposition';
12
+ export { DeduplicationPreview, type DeduplicationPreviewProps, } from './DeduplicationPreview';
12
13
  export * from './messaging';
@@ -17,7 +17,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
17
17
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
18
18
  };
19
19
  Object.defineProperty(exports, "__esModule", { value: true });
20
- exports.DebugOverlay = exports.BaseDmComposition = exports.defaultIMessageDmProps = exports.IMessageDmComposition = exports.validatePublicInput = exports.convertPublicToProps = exports.defaultInstagramDmProps = exports.InstagramDmComposition = exports.ScreenshotAnimation = exports.AutoCaptionCompositionWithVideo = exports.AutoCaptionComposition = exports.VideoEditorComposition = exports.ImageEditorComposition = void 0;
20
+ exports.DeduplicationPreview = exports.DebugOverlay = exports.BaseDmComposition = exports.defaultIMessageDmProps = exports.IMessageDmComposition = exports.validatePublicInput = exports.convertPublicToProps = exports.defaultInstagramDmProps = exports.InstagramDmComposition = exports.ScreenshotAnimation = exports.AutoCaptionCompositionWithVideo = exports.AutoCaptionComposition = exports.VideoEditorComposition = exports.ImageEditorComposition = void 0;
21
21
  var ImageEditorComposition_1 = require("./ImageEditorComposition");
22
22
  Object.defineProperty(exports, "ImageEditorComposition", { enumerable: true, get: function () { return ImageEditorComposition_1.ImageEditorComposition; } });
23
23
  var VideoEditorComposition_1 = require("./VideoEditorComposition");
@@ -39,5 +39,7 @@ Object.defineProperty(exports, "defaultIMessageDmProps", { enumerable: true, get
39
39
  var DmComposition_1 = require("./DmComposition");
40
40
  Object.defineProperty(exports, "BaseDmComposition", { enumerable: true, get: function () { return DmComposition_1.BaseDmComposition; } });
41
41
  Object.defineProperty(exports, "DebugOverlay", { enumerable: true, get: function () { return DmComposition_1.DebugOverlay; } });
42
+ var DeduplicationPreview_1 = require("./DeduplicationPreview");
43
+ Object.defineProperty(exports, "DeduplicationPreview", { enumerable: true, get: function () { return DeduplicationPreview_1.DeduplicationPreview; } });
42
44
  // Re-export base messaging types for extensibility
43
45
  __exportStar(require("./messaging"), exports);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ugcinc",
3
- "version": "4.5.4",
3
+ "version": "4.5.6",
4
4
  "description": "TypeScript/JavaScript client for the UGC Inc API",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",