@gannochenko/staticstripes 0.0.22 → 0.0.24
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/Makefile +8 -0
- package/dist/app-builder.d.ts +18 -0
- package/dist/app-builder.d.ts.map +1 -0
- package/dist/app-builder.js +94 -0
- package/dist/app-builder.js.map +1 -0
- package/dist/cli/commands/filters.d.ts +3 -0
- package/dist/cli/commands/filters.d.ts.map +1 -0
- package/dist/cli/commands/filters.js +21 -0
- package/dist/cli/commands/filters.js.map +1 -0
- package/dist/cli/commands/generate.d.ts.map +1 -1
- package/dist/cli/commands/generate.js +6 -1
- package/dist/cli/commands/generate.js.map +1 -1
- package/dist/cli/instagram/instagram-upload-strategy.d.ts +5 -0
- package/dist/cli/instagram/instagram-upload-strategy.d.ts.map +1 -1
- package/dist/cli/instagram/instagram-upload-strategy.js +46 -3
- package/dist/cli/instagram/instagram-upload-strategy.js.map +1 -1
- package/dist/cli.js +2 -0
- package/dist/cli.js.map +1 -1
- package/dist/ffmpeg.d.ts +32 -0
- package/dist/ffmpeg.d.ts.map +1 -1
- package/dist/ffmpeg.js +118 -0
- package/dist/ffmpeg.js.map +1 -1
- package/dist/html-project-parser.d.ts +36 -1
- package/dist/html-project-parser.d.ts.map +1 -1
- package/dist/html-project-parser.js +332 -15
- package/dist/html-project-parser.js.map +1 -1
- package/dist/project.d.ts +4 -1
- package/dist/project.d.ts.map +1 -1
- package/dist/project.js +50 -1
- package/dist/project.js.map +1 -1
- package/dist/sample-sequences.d.ts.map +1 -1
- package/dist/sample-sequences.js +293 -0
- package/dist/sample-sequences.js.map +1 -1
- package/dist/sequence.d.ts +4 -1
- package/dist/sequence.d.ts.map +1 -1
- package/dist/sequence.js +71 -21
- package/dist/sequence.js.map +1 -1
- package/dist/stream.d.ts +17 -0
- package/dist/stream.d.ts.map +1 -1
- package/dist/stream.js +28 -0
- package/dist/stream.js.map +1 -1
- package/dist/type.d.ts +29 -2
- package/dist/type.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/app-builder.ts +113 -0
- package/src/cli/commands/filters.ts +21 -0
- package/src/cli/commands/generate.ts +10 -1
- package/src/cli/instagram/instagram-upload-strategy.ts +61 -1
- package/src/cli.ts +2 -0
- package/src/ffmpeg.ts +161 -0
- package/src/html-project-parser.ts +410 -28
- package/src/project.ts +62 -0
- package/src/sample-sequences.ts +300 -0
- package/src/sequence.ts +78 -22
- package/src/stream.ts +50 -0
- package/src/type.ts +31 -2
|
@@ -820,6 +820,7 @@ class HTMLProjectParser {
|
|
|
820
820
|
let thumbOffset;
|
|
821
821
|
let coverUrl;
|
|
822
822
|
let videoUrl;
|
|
823
|
+
let locationId;
|
|
823
824
|
const localTags = [];
|
|
824
825
|
if ('children' in element && element.children) {
|
|
825
826
|
for (const child of element.children) {
|
|
@@ -891,6 +892,21 @@ class HTMLProjectParser {
|
|
|
891
892
|
}
|
|
892
893
|
break;
|
|
893
894
|
}
|
|
895
|
+
case 'location': {
|
|
896
|
+
const id = childAttrs.get('id');
|
|
897
|
+
const city = childAttrs.get('city');
|
|
898
|
+
const country = childAttrs.get('country');
|
|
899
|
+
if (id) {
|
|
900
|
+
// Explicit location ID provided
|
|
901
|
+
locationId = id;
|
|
902
|
+
}
|
|
903
|
+
else if (city && country) {
|
|
904
|
+
// Store search query for later resolution
|
|
905
|
+
// Format: "search:City, Country"
|
|
906
|
+
locationId = `search:${city}, ${country}`;
|
|
907
|
+
}
|
|
908
|
+
break;
|
|
909
|
+
}
|
|
894
910
|
}
|
|
895
911
|
}
|
|
896
912
|
}
|
|
@@ -914,6 +930,7 @@ class HTMLProjectParser {
|
|
|
914
930
|
thumbOffset,
|
|
915
931
|
coverUrl,
|
|
916
932
|
videoUrl,
|
|
933
|
+
locationId,
|
|
917
934
|
},
|
|
918
935
|
};
|
|
919
936
|
}
|
|
@@ -1300,16 +1317,28 @@ class HTMLProjectParser {
|
|
|
1300
1317
|
// 4. Extract container or app if present (first one only, mutually exclusive)
|
|
1301
1318
|
const container = this.extractFragmentContainer(element);
|
|
1302
1319
|
const app = container ? undefined : this.extractFragmentApp(element);
|
|
1303
|
-
//
|
|
1304
|
-
const
|
|
1305
|
-
//
|
|
1306
|
-
const
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
//
|
|
1310
|
-
const
|
|
1311
|
-
|
|
1312
|
-
|
|
1320
|
+
// 4b. Parse data-timing attribute (short syntax) - takes precedence over CSS
|
|
1321
|
+
const dataTiming = this.parseDataTiming(attrs.get('data-timing'));
|
|
1322
|
+
// 5. Parse trimLeft from data-timing or -trim-start property
|
|
1323
|
+
const trimLeft = dataTiming.trimStart !== undefined
|
|
1324
|
+
? dataTiming.trimStart
|
|
1325
|
+
: this.parseTrimStart(styles['-trim-start']);
|
|
1326
|
+
// 5b. Parse trimRight from data-timing or -trim-end property
|
|
1327
|
+
const trimRight = dataTiming.trimEnd !== undefined
|
|
1328
|
+
? dataTiming.trimEnd
|
|
1329
|
+
: this.parseTrimEnd(styles['-trim-end']);
|
|
1330
|
+
// 6. Parse duration from data-timing or -duration property
|
|
1331
|
+
const duration = dataTiming.duration !== undefined
|
|
1332
|
+
? dataTiming.duration
|
|
1333
|
+
: this.parseDurationProperty(styles['-duration'], assetName, assets, trimLeft, trimRight);
|
|
1334
|
+
// 7. Parse overlayLeft from data-timing or -offset-start property
|
|
1335
|
+
const overlayLeft = dataTiming.offsetStart !== undefined
|
|
1336
|
+
? dataTiming.offsetStart
|
|
1337
|
+
: this.parseOffsetStart(styles['-offset-start']);
|
|
1338
|
+
// 8. Parse overlayRight from data-timing or -offset-end property
|
|
1339
|
+
const overlayRight = dataTiming.offsetEnd !== undefined
|
|
1340
|
+
? dataTiming.offsetEnd
|
|
1341
|
+
: this.parseOffsetEnd(styles['-offset-end']);
|
|
1313
1342
|
// 9. Parse -overlay-start-z-index for overlayZIndex
|
|
1314
1343
|
const overlayZIndex = this.parseZIndex(styles['-overlay-start-z-index']);
|
|
1315
1344
|
// 10. Parse -overlay-end-z-index for overlayZIndexRight (temporary)
|
|
@@ -1322,9 +1351,13 @@ class HTMLProjectParser {
|
|
|
1322
1351
|
const objectFitData = this.parseObjectFitProperty(styles['-object-fit']);
|
|
1323
1352
|
// 14. Parse -chromakey
|
|
1324
1353
|
const chromakeyData = this.parseChromakeyProperty(styles['-chromakey']);
|
|
1354
|
+
// 14b. Parse -object-fit-ken-burns
|
|
1355
|
+
const kenBurnsData = this.parseKenBurnsProperty(styles['-object-fit-ken-burns']);
|
|
1325
1356
|
// 15. Parse filter (for visual filters)
|
|
1326
1357
|
const visualFilter = this.parseVisualFilterProperty(styles['filter']);
|
|
1327
|
-
// 16.
|
|
1358
|
+
// 16. Parse sound property (on/off)
|
|
1359
|
+
const sound = this.parseSoundProperty(styles['-sound']);
|
|
1360
|
+
// 17. Extract timecode label from data-timecode attribute
|
|
1328
1361
|
const timecodeLabel = attrs.get('data-timecode') || undefined;
|
|
1329
1362
|
return {
|
|
1330
1363
|
id,
|
|
@@ -1350,6 +1383,17 @@ class HTMLProjectParser {
|
|
|
1350
1383
|
chromakeyBlend: chromakeyData.chromakeyBlend,
|
|
1351
1384
|
chromakeySimilarity: chromakeyData.chromakeySimilarity,
|
|
1352
1385
|
chromakeyColor: chromakeyData.chromakeyColor,
|
|
1386
|
+
objectFitKenBurns: kenBurnsData.objectFitKenBurns,
|
|
1387
|
+
objectFitKenBurnsZoom: kenBurnsData.objectFitKenBurnsZoom,
|
|
1388
|
+
objectFitKenBurnsEffectDuration: kenBurnsData.objectFitKenBurnsEffectDuration,
|
|
1389
|
+
objectFitKenBurnsEasing: kenBurnsData.objectFitKenBurnsEasing,
|
|
1390
|
+
objectFitKenBurnsFocalX: kenBurnsData.objectFitKenBurnsFocalX,
|
|
1391
|
+
objectFitKenBurnsFocalY: kenBurnsData.objectFitKenBurnsFocalY,
|
|
1392
|
+
objectFitKenBurnsPanStartX: kenBurnsData.objectFitKenBurnsPanStartX,
|
|
1393
|
+
objectFitKenBurnsPanStartY: kenBurnsData.objectFitKenBurnsPanStartY,
|
|
1394
|
+
objectFitKenBurnsPanEndX: kenBurnsData.objectFitKenBurnsPanEndX,
|
|
1395
|
+
objectFitKenBurnsPanEndY: kenBurnsData.objectFitKenBurnsPanEndY,
|
|
1396
|
+
sound,
|
|
1353
1397
|
...(visualFilter && { visualFilter }), // Add visualFilter if present
|
|
1354
1398
|
...(container && { container }), // Add container if present
|
|
1355
1399
|
...(app && { app }), // Add app if present
|
|
@@ -1370,6 +1414,21 @@ class HTMLProjectParser {
|
|
|
1370
1414
|
// Validation will happen in the Stream.filter() method
|
|
1371
1415
|
return trimmed || undefined;
|
|
1372
1416
|
}
|
|
1417
|
+
/**
|
|
1418
|
+
* Parses -sound property
|
|
1419
|
+
* Can be: "on" (default) or "off"
|
|
1420
|
+
* When "off", replaces audio stream with silence
|
|
1421
|
+
*/
|
|
1422
|
+
parseSoundProperty(sound) {
|
|
1423
|
+
if (!sound) {
|
|
1424
|
+
return 'on'; // Default: use audio
|
|
1425
|
+
}
|
|
1426
|
+
const trimmed = sound.trim().toLowerCase();
|
|
1427
|
+
if (trimmed === 'off') {
|
|
1428
|
+
return 'off';
|
|
1429
|
+
}
|
|
1430
|
+
return 'on'; // Default for any other value
|
|
1431
|
+
}
|
|
1373
1432
|
/**
|
|
1374
1433
|
* Extracts the first <container> child from a fragment element
|
|
1375
1434
|
*/
|
|
@@ -1540,9 +1599,14 @@ class HTMLProjectParser {
|
|
|
1540
1599
|
}
|
|
1541
1600
|
return Math.max(0, asset.duration - trimLeft - trimRight);
|
|
1542
1601
|
}
|
|
1602
|
+
const trimmed = duration.trim();
|
|
1603
|
+
// Check if it's a calc() expression
|
|
1604
|
+
if (trimmed.startsWith('calc(')) {
|
|
1605
|
+
return (0, expression_parser_1.parseValueLazy)(trimmed);
|
|
1606
|
+
}
|
|
1543
1607
|
// Handle percentage (e.g., "100%", "50%")
|
|
1544
|
-
if (
|
|
1545
|
-
const percentage = parseFloat(
|
|
1608
|
+
if (trimmed.endsWith('%')) {
|
|
1609
|
+
const percentage = parseFloat(trimmed);
|
|
1546
1610
|
if (isNaN(percentage)) {
|
|
1547
1611
|
return 0;
|
|
1548
1612
|
}
|
|
@@ -1554,11 +1618,11 @@ class HTMLProjectParser {
|
|
|
1554
1618
|
return Math.round((asset.duration * percentage) / 100);
|
|
1555
1619
|
}
|
|
1556
1620
|
// Handle time value (e.g., "5000ms", "5s")
|
|
1557
|
-
return this.parseMilliseconds(
|
|
1621
|
+
return this.parseMilliseconds(trimmed);
|
|
1558
1622
|
}
|
|
1559
1623
|
/**
|
|
1560
1624
|
* Parses time value into milliseconds
|
|
1561
|
-
* Supports: "5s", "5000ms", "1.5s",
|
|
1625
|
+
* Supports: "5s", "5000ms", "1.5s", or raw numbers (defaults to milliseconds)
|
|
1562
1626
|
*/
|
|
1563
1627
|
parseMilliseconds(value) {
|
|
1564
1628
|
if (!value) {
|
|
@@ -1579,6 +1643,11 @@ class HTMLProjectParser {
|
|
|
1579
1643
|
return Math.round(seconds * 1000);
|
|
1580
1644
|
}
|
|
1581
1645
|
}
|
|
1646
|
+
// Handle raw numbers (default to milliseconds)
|
|
1647
|
+
const num = parseFloat(trimmed);
|
|
1648
|
+
if (!isNaN(num)) {
|
|
1649
|
+
return Math.round(num);
|
|
1650
|
+
}
|
|
1582
1651
|
return 0;
|
|
1583
1652
|
}
|
|
1584
1653
|
/**
|
|
@@ -1613,6 +1682,62 @@ class HTMLProjectParser {
|
|
|
1613
1682
|
// Otherwise parse as time value
|
|
1614
1683
|
return this.parseMilliseconds(trimmed);
|
|
1615
1684
|
}
|
|
1685
|
+
/**
|
|
1686
|
+
* Parses data-timing attribute with short syntax
|
|
1687
|
+
* Format: "ts=3000,te=5000,d=2000,os=1000,oe=7000"
|
|
1688
|
+
* Where:
|
|
1689
|
+
* ts = -trim-start
|
|
1690
|
+
* te = -trim-end
|
|
1691
|
+
* d = -duration
|
|
1692
|
+
* os = -offset-start
|
|
1693
|
+
* oe = -offset-end
|
|
1694
|
+
* Values default to milliseconds if no unit specified
|
|
1695
|
+
* Supports calc() expressions: ts=calc(url(#id.time.start))
|
|
1696
|
+
*/
|
|
1697
|
+
parseDataTiming(dataTiming) {
|
|
1698
|
+
const result = {};
|
|
1699
|
+
if (!dataTiming) {
|
|
1700
|
+
return result;
|
|
1701
|
+
}
|
|
1702
|
+
// Split by comma and parse each key-value pair
|
|
1703
|
+
const pairs = dataTiming.split(',').map((pair) => pair.trim());
|
|
1704
|
+
for (const pair of pairs) {
|
|
1705
|
+
const [key, value] = pair.split('=').map((s) => s.trim());
|
|
1706
|
+
if (!key || !value) {
|
|
1707
|
+
continue;
|
|
1708
|
+
}
|
|
1709
|
+
// Parse value - check if it's a calc() expression or a simple value
|
|
1710
|
+
let parsedValue;
|
|
1711
|
+
if (value.startsWith('calc(')) {
|
|
1712
|
+
// It's a calc() expression
|
|
1713
|
+
parsedValue = (0, expression_parser_1.parseValueLazy)(value);
|
|
1714
|
+
}
|
|
1715
|
+
else {
|
|
1716
|
+
// It's a simple time value - parse with parseMilliseconds
|
|
1717
|
+
// which handles units like 's' and 'ms', defaulting to ms
|
|
1718
|
+
parsedValue = this.parseMilliseconds(value);
|
|
1719
|
+
}
|
|
1720
|
+
// Map short names to result properties
|
|
1721
|
+
switch (key) {
|
|
1722
|
+
case 'ts':
|
|
1723
|
+
result.trimStart = parsedValue;
|
|
1724
|
+
break;
|
|
1725
|
+
case 'te':
|
|
1726
|
+
result.trimEnd = parsedValue;
|
|
1727
|
+
break;
|
|
1728
|
+
case 'd':
|
|
1729
|
+
result.duration = parsedValue;
|
|
1730
|
+
break;
|
|
1731
|
+
case 'os':
|
|
1732
|
+
result.offsetStart = parsedValue;
|
|
1733
|
+
break;
|
|
1734
|
+
case 'oe':
|
|
1735
|
+
result.offsetEnd = parsedValue;
|
|
1736
|
+
break;
|
|
1737
|
+
}
|
|
1738
|
+
}
|
|
1739
|
+
return result;
|
|
1740
|
+
}
|
|
1616
1741
|
/**
|
|
1617
1742
|
* Parses z-index values (-overlay-start-z-index, -overlay-end-z-index)
|
|
1618
1743
|
*/
|
|
@@ -1674,6 +1799,10 @@ class HTMLProjectParser {
|
|
|
1674
1799
|
if (type === 'cover') {
|
|
1675
1800
|
return { ...defaults, objectFit: 'cover' };
|
|
1676
1801
|
}
|
|
1802
|
+
// Handle "ken-burns"
|
|
1803
|
+
if (type === 'ken-burns') {
|
|
1804
|
+
return { ...defaults, objectFit: 'ken-burns' };
|
|
1805
|
+
}
|
|
1677
1806
|
// Handle "contain" with sub-options
|
|
1678
1807
|
if (type === 'contain') {
|
|
1679
1808
|
const subType = parts[1];
|
|
@@ -1780,6 +1909,194 @@ class HTMLProjectParser {
|
|
|
1780
1909
|
chromakeyColor: color,
|
|
1781
1910
|
};
|
|
1782
1911
|
}
|
|
1912
|
+
/**
|
|
1913
|
+
* Parses -object-fit-ken-burns property
|
|
1914
|
+
* Format:
|
|
1915
|
+
* Zoom effects: "<effect> <focal-x> <focal-y> <zoom%> <duration> [easing]"
|
|
1916
|
+
* Pan effects: "<effect> <zoom-factor> [easing]"
|
|
1917
|
+
* Examples:
|
|
1918
|
+
* - "zoom-in 50% 50% 30% 1000ms ease-in-out" - zoom 30% over 1s
|
|
1919
|
+
* - "zoom-out 30% 30% 50% 2000ms ease-out" - zoom out 50% over 2s
|
|
1920
|
+
* - "pan-left 1.3 linear" - pan with 1.3x zoom
|
|
1921
|
+
* Effects: zoom-in, zoom-out (require focal points + zoom% + duration)
|
|
1922
|
+
* pan-left, pan-right, pan-top, pan-bottom (require zoom factor only)
|
|
1923
|
+
* Zoom: for zoom effects: percentage (30 = 30%), for pan: factor (1.3)
|
|
1924
|
+
* Duration: effect duration in milliseconds (zoom effects only)
|
|
1925
|
+
* Easing: linear, ease-in, ease-out, ease-in-out (default: linear)
|
|
1926
|
+
*/
|
|
1927
|
+
parseKenBurnsProperty(kenBurns) {
|
|
1928
|
+
// Defaults
|
|
1929
|
+
const defaults = {
|
|
1930
|
+
objectFitKenBurns: 'zoom-in',
|
|
1931
|
+
objectFitKenBurnsZoom: 30, // 30% zoom
|
|
1932
|
+
objectFitKenBurnsEffectDuration: 0, // 0 = use fragment duration
|
|
1933
|
+
objectFitKenBurnsEasing: 'linear',
|
|
1934
|
+
objectFitKenBurnsFocalX: 50, // center (for zoom effects)
|
|
1935
|
+
objectFitKenBurnsFocalY: 50, // center (for zoom effects)
|
|
1936
|
+
objectFitKenBurnsPanStartX: 0, // left edge (for horizontal pan)
|
|
1937
|
+
objectFitKenBurnsPanStartY: 0, // top edge (for vertical pan)
|
|
1938
|
+
objectFitKenBurnsPanEndX: 100, // right edge (for horizontal pan)
|
|
1939
|
+
objectFitKenBurnsPanEndY: 100, // bottom edge (for vertical pan)
|
|
1940
|
+
};
|
|
1941
|
+
if (!kenBurns) {
|
|
1942
|
+
return defaults;
|
|
1943
|
+
}
|
|
1944
|
+
const trimmed = kenBurns.trim();
|
|
1945
|
+
const parts = this.splitCssValue(trimmed);
|
|
1946
|
+
if (parts.length === 0) {
|
|
1947
|
+
return defaults;
|
|
1948
|
+
}
|
|
1949
|
+
// Parse effect (first part)
|
|
1950
|
+
const effect = parts[0];
|
|
1951
|
+
const validEffects = ['zoom-in', 'zoom-out', 'pan-left', 'pan-right', 'pan-top', 'pan-bottom'];
|
|
1952
|
+
if (!validEffects.includes(effect)) {
|
|
1953
|
+
return defaults;
|
|
1954
|
+
}
|
|
1955
|
+
let focalX = defaults.objectFitKenBurnsFocalX;
|
|
1956
|
+
let focalY = defaults.objectFitKenBurnsFocalY;
|
|
1957
|
+
let zoom = defaults.objectFitKenBurnsZoom;
|
|
1958
|
+
let effectDuration = defaults.objectFitKenBurnsEffectDuration;
|
|
1959
|
+
let easing = defaults.objectFitKenBurnsEasing;
|
|
1960
|
+
let panStartX = defaults.objectFitKenBurnsPanStartX;
|
|
1961
|
+
let panStartY = defaults.objectFitKenBurnsPanStartY;
|
|
1962
|
+
let panEndX = defaults.objectFitKenBurnsPanEndX;
|
|
1963
|
+
let panEndY = defaults.objectFitKenBurnsPanEndY;
|
|
1964
|
+
const isZoomEffect = effect === 'zoom-in' || effect === 'zoom-out';
|
|
1965
|
+
const isPanEffect = effect === 'pan-left' || effect === 'pan-right' || effect === 'pan-top' || effect === 'pan-bottom';
|
|
1966
|
+
// Parse remaining parts based on effect type
|
|
1967
|
+
let nextIndex = 1;
|
|
1968
|
+
if (isZoomEffect) {
|
|
1969
|
+
// Zoom effects: "<effect> <focal-x%> <focal-y%> <zoom%> <duration> [easing]"
|
|
1970
|
+
// Parse focal points
|
|
1971
|
+
if (parts.length >= 3 && parts[1].includes('%') && parts[2].includes('%')) {
|
|
1972
|
+
const focalXStr = parts[1].split('%')[0];
|
|
1973
|
+
const focalYStr = parts[2].split('%')[0];
|
|
1974
|
+
const parsedX = parseFloat(focalXStr);
|
|
1975
|
+
const parsedY = parseFloat(focalYStr);
|
|
1976
|
+
if (!isNaN(parsedX) && !isNaN(parsedY)) {
|
|
1977
|
+
focalX = Math.max(0, Math.min(100, parsedX));
|
|
1978
|
+
focalY = Math.max(0, Math.min(100, parsedY));
|
|
1979
|
+
nextIndex = 3;
|
|
1980
|
+
// Check if parts[2] had a concatenated value after '%'
|
|
1981
|
+
const remainder = parts[2].split('%')[1];
|
|
1982
|
+
if (remainder && remainder.trim()) {
|
|
1983
|
+
parts.splice(3, 0, remainder.trim());
|
|
1984
|
+
}
|
|
1985
|
+
}
|
|
1986
|
+
}
|
|
1987
|
+
// Parse zoom percentage (required)
|
|
1988
|
+
if (parts.length > nextIndex && parts[nextIndex].includes('%')) {
|
|
1989
|
+
const zoomStr = parts[nextIndex].split('%')[0];
|
|
1990
|
+
const parsedZoom = parseFloat(zoomStr);
|
|
1991
|
+
if (!isNaN(parsedZoom) && parsedZoom >= 0) {
|
|
1992
|
+
zoom = parsedZoom; // Store as percentage (e.g., 30 for 30%)
|
|
1993
|
+
nextIndex++;
|
|
1994
|
+
// Check for concatenated value after '%'
|
|
1995
|
+
const remainder = parts[nextIndex - 1].split('%')[1];
|
|
1996
|
+
if (remainder && remainder.trim()) {
|
|
1997
|
+
parts.splice(nextIndex, 0, remainder.trim());
|
|
1998
|
+
}
|
|
1999
|
+
}
|
|
2000
|
+
}
|
|
2001
|
+
// Parse effect duration (required)
|
|
2002
|
+
if (parts.length > nextIndex) {
|
|
2003
|
+
const durationStr = parts[nextIndex];
|
|
2004
|
+
// Simple inline parser for "1000ms" or "1s" format
|
|
2005
|
+
const match = durationStr.match(/^(\d+(?:\.\d+)?)(ms|s)$/);
|
|
2006
|
+
if (match) {
|
|
2007
|
+
const value = parseFloat(match[1]);
|
|
2008
|
+
const parsedDuration = match[2] === 's' ? value * 1000 : value;
|
|
2009
|
+
if (parsedDuration > 0) {
|
|
2010
|
+
effectDuration = parsedDuration;
|
|
2011
|
+
nextIndex++;
|
|
2012
|
+
}
|
|
2013
|
+
}
|
|
2014
|
+
}
|
|
2015
|
+
// Parse easing (optional)
|
|
2016
|
+
if (parts.length > nextIndex) {
|
|
2017
|
+
const easingStr = parts[nextIndex];
|
|
2018
|
+
if (['linear', 'ease-in', 'ease-out', 'ease-in-out'].includes(easingStr)) {
|
|
2019
|
+
easing = easingStr;
|
|
2020
|
+
}
|
|
2021
|
+
}
|
|
2022
|
+
}
|
|
2023
|
+
else if (isPanEffect) {
|
|
2024
|
+
// Pan effects: "<effect> <zoom%> <start%> <end%> <duration> [easing]"
|
|
2025
|
+
// Example: pan-left 50% 20% 80% 2000ms ease-in
|
|
2026
|
+
// Parse zoom percentage (required)
|
|
2027
|
+
if (parts.length > nextIndex && parts[nextIndex].includes('%')) {
|
|
2028
|
+
const zoomStr = parts[nextIndex].split('%')[0];
|
|
2029
|
+
const parsedZoom = parseFloat(zoomStr);
|
|
2030
|
+
if (!isNaN(parsedZoom) && parsedZoom >= 0) {
|
|
2031
|
+
zoom = parsedZoom; // Store as percentage (e.g., 50 for 50%)
|
|
2032
|
+
nextIndex++;
|
|
2033
|
+
}
|
|
2034
|
+
}
|
|
2035
|
+
// Parse start position percentage (required)
|
|
2036
|
+
if (parts.length > nextIndex && parts[nextIndex].includes('%')) {
|
|
2037
|
+
const startStr = parts[nextIndex].split('%')[0];
|
|
2038
|
+
const parsedStart = parseFloat(startStr);
|
|
2039
|
+
if (!isNaN(parsedStart) && parsedStart >= 0 && parsedStart <= 100) {
|
|
2040
|
+
// Store in appropriate variable based on pan direction
|
|
2041
|
+
if (effect === 'pan-left' || effect === 'pan-right') {
|
|
2042
|
+
panStartX = parsedStart;
|
|
2043
|
+
}
|
|
2044
|
+
else {
|
|
2045
|
+
panStartY = parsedStart;
|
|
2046
|
+
}
|
|
2047
|
+
nextIndex++;
|
|
2048
|
+
}
|
|
2049
|
+
}
|
|
2050
|
+
// Parse end position percentage (required)
|
|
2051
|
+
if (parts.length > nextIndex && parts[nextIndex].includes('%')) {
|
|
2052
|
+
const endStr = parts[nextIndex].split('%')[0];
|
|
2053
|
+
const parsedEnd = parseFloat(endStr);
|
|
2054
|
+
if (!isNaN(parsedEnd) && parsedEnd >= 0 && parsedEnd <= 100) {
|
|
2055
|
+
// Store in appropriate variable based on pan direction
|
|
2056
|
+
if (effect === 'pan-left' || effect === 'pan-right') {
|
|
2057
|
+
panEndX = parsedEnd;
|
|
2058
|
+
}
|
|
2059
|
+
else {
|
|
2060
|
+
panEndY = parsedEnd;
|
|
2061
|
+
}
|
|
2062
|
+
nextIndex++;
|
|
2063
|
+
}
|
|
2064
|
+
}
|
|
2065
|
+
// Parse effect duration (required)
|
|
2066
|
+
if (parts.length > nextIndex) {
|
|
2067
|
+
const durationStr = parts[nextIndex];
|
|
2068
|
+
// Simple inline parser for "1000ms" or "1s" format
|
|
2069
|
+
const match = durationStr.match(/^(\d+(?:\.\d+)?)(ms|s)$/);
|
|
2070
|
+
if (match) {
|
|
2071
|
+
const value = parseFloat(match[1]);
|
|
2072
|
+
const parsedDuration = match[2] === 's' ? value * 1000 : value;
|
|
2073
|
+
if (parsedDuration > 0) {
|
|
2074
|
+
effectDuration = parsedDuration;
|
|
2075
|
+
nextIndex++;
|
|
2076
|
+
}
|
|
2077
|
+
}
|
|
2078
|
+
}
|
|
2079
|
+
// Parse easing (optional)
|
|
2080
|
+
if (parts.length > nextIndex) {
|
|
2081
|
+
const easingStr = parts[nextIndex];
|
|
2082
|
+
if (['linear', 'ease-in', 'ease-out', 'ease-in-out'].includes(easingStr)) {
|
|
2083
|
+
easing = easingStr;
|
|
2084
|
+
}
|
|
2085
|
+
}
|
|
2086
|
+
}
|
|
2087
|
+
return {
|
|
2088
|
+
objectFitKenBurns: effect,
|
|
2089
|
+
objectFitKenBurnsZoom: zoom,
|
|
2090
|
+
objectFitKenBurnsEffectDuration: effectDuration,
|
|
2091
|
+
objectFitKenBurnsEasing: easing,
|
|
2092
|
+
objectFitKenBurnsFocalX: focalX,
|
|
2093
|
+
objectFitKenBurnsFocalY: focalY,
|
|
2094
|
+
objectFitKenBurnsPanStartX: panStartX,
|
|
2095
|
+
objectFitKenBurnsPanStartY: panStartY,
|
|
2096
|
+
objectFitKenBurnsPanEndX: panEndX,
|
|
2097
|
+
objectFitKenBurnsPanEndY: panEndY,
|
|
2098
|
+
};
|
|
2099
|
+
}
|
|
1783
2100
|
}
|
|
1784
2101
|
exports.HTMLProjectParser = HTMLProjectParser;
|
|
1785
2102
|
//# sourceMappingURL=html-project-parser.js.map
|