@gannochenko/staticstripes 0.0.15 → 0.0.16
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/cli/ai-music-api-ai/ai-music-api-ai-generation-strategy.d.ts +3 -4
- package/dist/cli/ai-music-api-ai/ai-music-api-ai-generation-strategy.d.ts.map +1 -1
- package/dist/cli/ai-music-api-ai/ai-music-api-ai-generation-strategy.js +22 -32
- package/dist/cli/ai-music-api-ai/ai-music-api-ai-generation-strategy.js.map +1 -1
- package/dist/cli/credentials.d.ts +81 -0
- package/dist/cli/credentials.d.ts.map +1 -0
- package/dist/cli/credentials.js +109 -0
- package/dist/cli/credentials.js.map +1 -0
- package/dist/cli/instagram/instagram-upload-strategy.d.ts +3 -1
- package/dist/cli/instagram/instagram-upload-strategy.d.ts.map +1 -1
- package/dist/cli/instagram/instagram-upload-strategy.js +37 -26
- package/dist/cli/instagram/instagram-upload-strategy.js.map +1 -1
- package/dist/cli/s3/s3-upload-strategy.d.ts +3 -1
- package/dist/cli/s3/s3-upload-strategy.d.ts.map +1 -1
- package/dist/cli/s3/s3-upload-strategy.js +91 -44
- package/dist/cli/s3/s3-upload-strategy.js.map +1 -1
- package/dist/cli/youtube/youtube-upload-strategy.d.ts +3 -0
- package/dist/cli/youtube/youtube-upload-strategy.d.ts.map +1 -1
- package/dist/cli/youtube/youtube-upload-strategy.js +22 -20
- package/dist/cli/youtube/youtube-upload-strategy.js.map +1 -1
- package/dist/html-project-parser.d.ts +8 -0
- package/dist/html-project-parser.d.ts.map +1 -1
- package/dist/html-project-parser.js +71 -5
- package/dist/html-project-parser.js.map +1 -1
- package/dist/project.d.ts +3 -1
- package/dist/project.d.ts.map +1 -1
- package/dist/project.js +6 -1
- package/dist/project.js.map +1 -1
- package/dist/type.d.ts +1 -1
- package/dist/type.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/cli/ai-music-api-ai/ai-music-api-ai-generation-strategy.ts +24 -55
- package/src/cli/credentials.ts +171 -0
- package/src/cli/instagram/instagram-upload-strategy.ts +38 -39
- package/src/cli/s3/s3-upload-strategy.ts +102 -57
- package/src/cli/youtube/youtube-upload-strategy.ts +22 -23
- package/src/html-project-parser.ts +84 -4
- package/src/project.ts +5 -0
- package/src/type.ts +1 -1
|
@@ -3,13 +3,16 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.S3UploadStrategy = void 0;
|
|
4
4
|
const client_s3_1 = require("@aws-sdk/client-s3");
|
|
5
5
|
const fs_1 = require("fs");
|
|
6
|
-
const
|
|
6
|
+
const credentials_1 = require("../credentials");
|
|
7
7
|
/**
|
|
8
8
|
* S3 upload strategy implementation
|
|
9
9
|
* Supports generic S3-compatible storage (AWS S3, DigitalOcean Spaces, etc.)
|
|
10
10
|
*/
|
|
11
11
|
class S3UploadStrategy {
|
|
12
|
-
|
|
12
|
+
credentialsManager;
|
|
13
|
+
constructor(credentialsManager) {
|
|
14
|
+
this.credentialsManager = credentialsManager;
|
|
15
|
+
}
|
|
13
16
|
getTag() {
|
|
14
17
|
return 's3';
|
|
15
18
|
}
|
|
@@ -21,7 +24,11 @@ class S3UploadStrategy {
|
|
|
21
24
|
if (!upload.s3) {
|
|
22
25
|
throw new Error(`❌ Error: S3 configuration missing for upload "${upload.name}"`);
|
|
23
26
|
}
|
|
24
|
-
const { endpoint, region, bucket,
|
|
27
|
+
const { endpoint, region, bucket, paths, acl } = upload.s3;
|
|
28
|
+
// Validate that we have a "file" path
|
|
29
|
+
if (!paths.has('file')) {
|
|
30
|
+
throw new Error(`❌ Error: S3 upload "${upload.name}" missing required <path name="file"> element`);
|
|
31
|
+
}
|
|
25
32
|
// Validate ACL value if specified
|
|
26
33
|
const allowedAcls = ['private', 'public-read', 'authenticated-read'];
|
|
27
34
|
if (acl && !allowedAcls.includes(acl)) {
|
|
@@ -29,13 +36,21 @@ class S3UploadStrategy {
|
|
|
29
36
|
`Allowed values: ${allowedAcls.join(', ')}\n` +
|
|
30
37
|
`Note: "public-read-write" is not supported for security reasons.`);
|
|
31
38
|
}
|
|
32
|
-
// Load credentials from .auth/<upload-name>.json
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
+
// Load credentials from local .auth/<upload-name>.json or global ~/.staticstripes/auth/<upload-name>.json
|
|
40
|
+
const manager = this.credentialsManager ||
|
|
41
|
+
new credentials_1.CredentialsManager(projectPath, upload.name);
|
|
42
|
+
let credentials;
|
|
43
|
+
try {
|
|
44
|
+
credentials = manager.load([
|
|
45
|
+
'accessKeyId',
|
|
46
|
+
'secretAccessKey',
|
|
47
|
+
]);
|
|
48
|
+
}
|
|
49
|
+
catch (error) {
|
|
50
|
+
// Add helpful context about S3 credentials format
|
|
51
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
52
|
+
throw new Error(`${errorMessage}\n\n` +
|
|
53
|
+
`💡 S3 credentials file should contain:\n` +
|
|
39
54
|
`{\n` +
|
|
40
55
|
` "accessKeyId": "YOUR_ACCESS_KEY",\n` +
|
|
41
56
|
` "secretAccessKey": "YOUR_SECRET_KEY"\n` +
|
|
@@ -44,20 +59,6 @@ class S3UploadStrategy {
|
|
|
44
59
|
` • AWS: IAM → Users → Security Credentials\n` +
|
|
45
60
|
` • DigitalOcean: API → Spaces Keys\n`);
|
|
46
61
|
}
|
|
47
|
-
console.log(`🔐 Loading credentials from: ${credentialsPath}`);
|
|
48
|
-
let credentials;
|
|
49
|
-
try {
|
|
50
|
-
const credentialsJson = (0, fs_1.readFileSync)(credentialsPath, 'utf-8');
|
|
51
|
-
credentials = JSON.parse(credentialsJson);
|
|
52
|
-
if (!credentials.accessKeyId || !credentials.secretAccessKey) {
|
|
53
|
-
throw new Error('Missing accessKeyId or secretAccessKey');
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
catch (error) {
|
|
57
|
-
throw new Error(`❌ Error: Failed to parse S3 credentials from ${credentialsPath}\n` +
|
|
58
|
-
`Ensure the file contains valid JSON with accessKeyId and secretAccessKey.\n` +
|
|
59
|
-
`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
60
|
-
}
|
|
61
62
|
// Get the output file
|
|
62
63
|
const output = project.getOutput(upload.outputName);
|
|
63
64
|
if (!output) {
|
|
@@ -67,20 +68,34 @@ class S3UploadStrategy {
|
|
|
67
68
|
throw new Error(`❌ Error: Output file not found: ${output.path}\n` +
|
|
68
69
|
'💡 Please generate the video first');
|
|
69
70
|
}
|
|
70
|
-
//
|
|
71
|
+
// Prepare interpolation variables
|
|
71
72
|
const slug = this.slugify(project.getTitle());
|
|
72
73
|
const outputName = output.name;
|
|
73
|
-
const
|
|
74
|
-
|
|
75
|
-
|
|
74
|
+
const date = project.getDate() || '';
|
|
75
|
+
const title = project.getTitle();
|
|
76
|
+
const tags = upload.tags;
|
|
77
|
+
// Helper function to interpolate path variables
|
|
78
|
+
const interpolatePath = (pathTemplate) => {
|
|
79
|
+
return pathTemplate
|
|
80
|
+
.replace(/\$\{slug\}/g, slug)
|
|
81
|
+
.replace(/\$\{output\}/g, outputName)
|
|
82
|
+
.replace(/\$\{date\}/g, date);
|
|
83
|
+
};
|
|
84
|
+
// Get and interpolate the file path
|
|
85
|
+
const filePath = interpolatePath(paths.get('file'));
|
|
76
86
|
console.log(`\n📦 Preparing S3 upload...`);
|
|
77
87
|
console.log(` Bucket: ${bucket}`);
|
|
78
88
|
console.log(` Region: ${region}`);
|
|
79
89
|
if (endpoint) {
|
|
80
90
|
console.log(` Endpoint: ${endpoint}`);
|
|
81
91
|
}
|
|
82
|
-
console.log(`
|
|
83
|
-
console.log(`
|
|
92
|
+
console.log(` File path: ${filePath}`);
|
|
93
|
+
console.log(` Video file: ${output.path}`);
|
|
94
|
+
if (paths.has('metadata')) {
|
|
95
|
+
const metadataPath = interpolatePath(paths.get('metadata'));
|
|
96
|
+
console.log(` Metadata path: ${metadataPath}`);
|
|
97
|
+
}
|
|
98
|
+
console.log('');
|
|
84
99
|
// Configure S3 client
|
|
85
100
|
const s3Config = {
|
|
86
101
|
region,
|
|
@@ -98,36 +113,68 @@ class S3UploadStrategy {
|
|
|
98
113
|
s3Config.forcePathStyle = false;
|
|
99
114
|
}
|
|
100
115
|
const s3Client = new client_s3_1.S3Client(s3Config);
|
|
101
|
-
//
|
|
102
|
-
console.log(`📤 Uploading
|
|
116
|
+
// Upload video file
|
|
117
|
+
console.log(`📤 Uploading video file...`);
|
|
103
118
|
const fileBuffer = (0, fs_1.readFileSync)(output.path);
|
|
104
|
-
|
|
105
|
-
const uploadParams = {
|
|
119
|
+
const fileUploadParams = {
|
|
106
120
|
Bucket: bucket,
|
|
107
|
-
Key:
|
|
121
|
+
Key: filePath,
|
|
108
122
|
Body: fileBuffer,
|
|
109
123
|
ContentType: 'video/mp4',
|
|
110
124
|
};
|
|
111
125
|
// Add ACL if specified in configuration
|
|
112
126
|
if (acl) {
|
|
113
|
-
|
|
127
|
+
fileUploadParams.ACL = acl;
|
|
114
128
|
}
|
|
115
|
-
const command = new client_s3_1.PutObjectCommand(uploadParams);
|
|
116
129
|
try {
|
|
117
|
-
await s3Client.send(
|
|
118
|
-
// Construct public URL
|
|
119
|
-
let
|
|
130
|
+
await s3Client.send(new client_s3_1.PutObjectCommand(fileUploadParams));
|
|
131
|
+
// Construct public URL for video
|
|
132
|
+
let fileUrl;
|
|
120
133
|
if (endpoint) {
|
|
121
134
|
// For DigitalOcean Spaces and similar services
|
|
122
135
|
// Format: https://{bucket}.{region}.{endpoint}/{path}
|
|
123
|
-
|
|
136
|
+
fileUrl = `https://${bucket}.${region}.${endpoint}/${filePath}`;
|
|
124
137
|
}
|
|
125
138
|
else {
|
|
126
139
|
// For AWS S3
|
|
127
|
-
|
|
140
|
+
fileUrl = `https://${bucket}.s3.${region}.amazonaws.com/${filePath}`;
|
|
141
|
+
}
|
|
142
|
+
console.log(`✅ Video uploaded successfully!`);
|
|
143
|
+
console.log(`🔗 Video URL: ${fileUrl}`);
|
|
144
|
+
// Upload metadata file if specified
|
|
145
|
+
if (paths.has('metadata')) {
|
|
146
|
+
console.log(`\n📤 Uploading metadata file...`);
|
|
147
|
+
const metadataPath = interpolatePath(paths.get('metadata'));
|
|
148
|
+
// Create metadata JSON
|
|
149
|
+
const metadata = {
|
|
150
|
+
title,
|
|
151
|
+
date: date || null,
|
|
152
|
+
tags,
|
|
153
|
+
};
|
|
154
|
+
const metadataBuffer = Buffer.from(JSON.stringify(metadata, null, 2), 'utf-8');
|
|
155
|
+
const metadataUploadParams = {
|
|
156
|
+
Bucket: bucket,
|
|
157
|
+
Key: metadataPath,
|
|
158
|
+
Body: metadataBuffer,
|
|
159
|
+
ContentType: 'application/json',
|
|
160
|
+
};
|
|
161
|
+
// Add ACL if specified
|
|
162
|
+
if (acl) {
|
|
163
|
+
metadataUploadParams.ACL = acl;
|
|
164
|
+
}
|
|
165
|
+
await s3Client.send(new client_s3_1.PutObjectCommand(metadataUploadParams));
|
|
166
|
+
// Construct public URL for metadata
|
|
167
|
+
let metadataUrl;
|
|
168
|
+
if (endpoint) {
|
|
169
|
+
metadataUrl = `https://${bucket}.${region}.${endpoint}/${metadataPath}`;
|
|
170
|
+
}
|
|
171
|
+
else {
|
|
172
|
+
metadataUrl = `https://${bucket}.s3.${region}.amazonaws.com/${metadataPath}`;
|
|
173
|
+
}
|
|
174
|
+
console.log(`✅ Metadata uploaded successfully!`);
|
|
175
|
+
console.log(`🔗 Metadata URL: ${metadataUrl}`);
|
|
128
176
|
}
|
|
129
|
-
console.log(
|
|
130
|
-
console.log(`🔗 Public URL: ${publicUrl}\n`);
|
|
177
|
+
console.log('');
|
|
131
178
|
}
|
|
132
179
|
catch (error) {
|
|
133
180
|
throw new Error(`❌ Error: Failed to upload to S3\n` +
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"s3-upload-strategy.js","sourceRoot":"","sources":["../../../src/cli/s3/s3-upload-strategy.ts"],"names":[],"mappings":";;;AAGA,kDAAgE;AAChE,2BAA8C;AAC9C
|
|
1
|
+
{"version":3,"file":"s3-upload-strategy.js","sourceRoot":"","sources":["../../../src/cli/s3/s3-upload-strategy.ts"],"names":[],"mappings":";;;AAGA,kDAAgE;AAChE,2BAA8C;AAC9C,gDAAmE;AAEnE;;;GAGG;AACH,MAAa,gBAAgB;IACP;IAApB,YAAoB,kBAAuC;QAAvC,uBAAkB,GAAlB,kBAAkB,CAAqB;IAAG,CAAC;IAE/D,MAAM;QACJ,OAAO,IAAI,CAAC;IACd,CAAC;IAED,QAAQ;QACN,8DAA8D;IAChE,CAAC;IAED,KAAK,CAAC,OAAO,CACX,OAAgB,EAChB,MAAc,EACd,WAAmB;QAEnB,mCAAmC;QACnC,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC;YACf,MAAM,IAAI,KAAK,CACb,iDAAiD,MAAM,CAAC,IAAI,GAAG,CAChE,CAAC;QACJ,CAAC;QAED,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,MAAM,CAAC,EAAE,CAAC;QAE3D,sCAAsC;QACtC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;YACvB,MAAM,IAAI,KAAK,CACb,uBAAuB,MAAM,CAAC,IAAI,+CAA+C,CAClF,CAAC;QACJ,CAAC;QAED,kCAAkC;QAClC,MAAM,WAAW,GAAG,CAAC,SAAS,EAAE,aAAa,EAAE,oBAAoB,CAAC,CAAC;QACrE,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YACtC,MAAM,IAAI,KAAK,CACb,+BAA+B,GAAG,iBAAiB,MAAM,CAAC,IAAI,OAAO;gBACnE,mBAAmB,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI;gBAC7C,kEAAkE,CACrE,CAAC;QACJ,CAAC;QAED,0GAA0G;QAC1G,MAAM,OAAO,GACX,IAAI,CAAC,kBAAkB;YACvB,IAAI,gCAAkB,CAAC,WAAW,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC;QAEnD,IAAI,WAA0B,CAAC;QAC/B,IAAI,CAAC;YACH,WAAW,GAAG,OAAO,CAAC,IAAI,CAAgB;gBACxC,aAAa;gBACb,iBAAiB;aAClB,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,kDAAkD;YAClD,MAAM,YAAY,GAChB,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YACzD,MAAM,IAAI,KAAK,CACb,GAAG,YAAY,MAAM;gBACnB,0CAA0C;gBAC1C,KAAK;gBACL,uCAAuC;gBACvC,0CAA0C;gBAC1C,OAAO;gBACP,4BAA4B;gBAC5B,gDAAgD;gBAChD,wCAAwC,CAC3C,CAAC;QACJ,CAAC;QAED,sBAAsB;QACtB,MAAM,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;QACpD,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,MAAM,IAAI,KAAK,CAAC,oBAAoB,MAAM,CAAC,UAAU,aAAa,CAAC,CAAC;QACtE,CAAC;QAED,IAAI,CAAC,IAAA,eAAU,EAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;YAC7B,MAAM,IAAI,KAAK,CACb,mCAAmC,MAAM,CAAC,IAAI,IAAI;gBAChD,oCAAoC,CACvC,CAAC;QACJ,CAAC;QAED,kCAAkC;QAClC,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;QAC9C,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC;QAC/B,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC;QACrC,MAAM,KAAK,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC;QACjC,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC;QAEzB,gDAAgD;QAChD,MAAM,eAAe,GAAG,CAAC,YAAoB,EAAU,EAAE;YACvD,OAAO,YAAY;iBAChB,OAAO,CAAC,aAAa,EAAE,IAAI,CAAC;iBAC5B,OAAO,CAAC,eAAe,EAAE,UAAU,CAAC;iBACpC,OAAO,CAAC,aAAa,EAAE,IAAI,CAAC,CAAC;QAClC,CAAC,CAAC;QAEF,oCAAoC;QACpC,MAAM,QAAQ,GAAG,eAAe,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAE,CAAC,CAAC;QAErD,OAAO,CAAC,GAAG,CAAC,6BAA6B,CAAC,CAAC;QAC3C,OAAO,CAAC,GAAG,CAAC,cAAc,MAAM,EAAE,CAAC,CAAC;QACpC,OAAO,CAAC,GAAG,CAAC,cAAc,MAAM,EAAE,CAAC,CAAC;QACpC,IAAI,QAAQ,EAAE,CAAC;YACb,OAAO,CAAC,GAAG,CAAC,gBAAgB,QAAQ,EAAE,CAAC,CAAC;QAC1C,CAAC;QACD,OAAO,CAAC,GAAG,CAAC,iBAAiB,QAAQ,EAAE,CAAC,CAAC;QACzC,OAAO,CAAC,GAAG,CAAC,kBAAkB,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;QAC7C,IAAI,KAAK,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC;YAC1B,MAAM,YAAY,GAAG,eAAe,CAAC,KAAK,CAAC,GAAG,CAAC,UAAU,CAAE,CAAC,CAAC;YAC7D,OAAO,CAAC,GAAG,CAAC,qBAAqB,YAAY,EAAE,CAAC,CAAC;QACnD,CAAC;QACD,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAEhB,sBAAsB;QACtB,MAAM,QAAQ,GAAQ;YACpB,MAAM;YACN,WAAW,EAAE;gBACX,WAAW,EAAE,WAAW,CAAC,WAAW;gBACpC,eAAe,EAAE,WAAW,CAAC,eAAe;aAC7C;SACF,CAAC;QAEF,6EAA6E;QAC7E,IAAI,QAAQ,EAAE,CAAC;YACb,oEAAoE;YACpE,8DAA8D;YAC9D,QAAQ,CAAC,QAAQ,GAAG,WAAW,MAAM,IAAI,QAAQ,EAAE,CAAC;YACpD,mEAAmE;YACnE,QAAQ,CAAC,cAAc,GAAG,KAAK,CAAC;QAClC,CAAC;QAED,MAAM,QAAQ,GAAG,IAAI,oBAAQ,CAAC,QAAQ,CAAC,CAAC;QAExC,oBAAoB;QACpB,OAAO,CAAC,GAAG,CAAC,4BAA4B,CAAC,CAAC;QAC1C,MAAM,UAAU,GAAG,IAAA,iBAAY,EAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAE7C,MAAM,gBAAgB,GAAQ;YAC5B,MAAM,EAAE,MAAM;YACd,GAAG,EAAE,QAAQ;YACb,IAAI,EAAE,UAAU;YAChB,WAAW,EAAE,WAAW;SACzB,CAAC;QAEF,wCAAwC;QACxC,IAAI,GAAG,EAAE,CAAC;YACR,gBAAgB,CAAC,GAAG,GAAG,GAAG,CAAC;QAC7B,CAAC;QAED,IAAI,CAAC;YACH,MAAM,QAAQ,CAAC,IAAI,CAAC,IAAI,4BAAgB,CAAC,gBAAgB,CAAC,CAAC,CAAC;YAE5D,iCAAiC;YACjC,IAAI,OAAe,CAAC;YACpB,IAAI,QAAQ,EAAE,CAAC;gBACb,+CAA+C;gBAC/C,sDAAsD;gBACtD,OAAO,GAAG,WAAW,MAAM,IAAI,MAAM,IAAI,QAAQ,IAAI,QAAQ,EAAE,CAAC;YAClE,CAAC;iBAAM,CAAC;gBACN,aAAa;gBACb,OAAO,GAAG,WAAW,MAAM,OAAO,MAAM,kBAAkB,QAAQ,EAAE,CAAC;YACvE,CAAC;YAED,OAAO,CAAC,GAAG,CAAC,gCAAgC,CAAC,CAAC;YAC9C,OAAO,CAAC,GAAG,CAAC,iBAAiB,OAAO,EAAE,CAAC,CAAC;YAExC,oCAAoC;YACpC,IAAI,KAAK,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC;gBAC1B,OAAO,CAAC,GAAG,CAAC,iCAAiC,CAAC,CAAC;gBAC/C,MAAM,YAAY,GAAG,eAAe,CAAC,KAAK,CAAC,GAAG,CAAC,UAAU,CAAE,CAAC,CAAC;gBAE7D,uBAAuB;gBACvB,MAAM,QAAQ,GAAG;oBACf,KAAK;oBACL,IAAI,EAAE,IAAI,IAAI,IAAI;oBAClB,IAAI;iBACL,CAAC;gBAEF,MAAM,cAAc,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;gBAE/E,MAAM,oBAAoB,GAAQ;oBAChC,MAAM,EAAE,MAAM;oBACd,GAAG,EAAE,YAAY;oBACjB,IAAI,EAAE,cAAc;oBACpB,WAAW,EAAE,kBAAkB;iBAChC,CAAC;gBAEF,uBAAuB;gBACvB,IAAI,GAAG,EAAE,CAAC;oBACR,oBAAoB,CAAC,GAAG,GAAG,GAAG,CAAC;gBACjC,CAAC;gBAED,MAAM,QAAQ,CAAC,IAAI,CAAC,IAAI,4BAAgB,CAAC,oBAAoB,CAAC,CAAC,CAAC;gBAEhE,oCAAoC;gBACpC,IAAI,WAAmB,CAAC;gBACxB,IAAI,QAAQ,EAAE,CAAC;oBACb,WAAW,GAAG,WAAW,MAAM,IAAI,MAAM,IAAI,QAAQ,IAAI,YAAY,EAAE,CAAC;gBAC1E,CAAC;qBAAM,CAAC;oBACN,WAAW,GAAG,WAAW,MAAM,OAAO,MAAM,kBAAkB,YAAY,EAAE,CAAC;gBAC/E,CAAC;gBAED,OAAO,CAAC,GAAG,CAAC,mCAAmC,CAAC,CAAC;gBACjD,OAAO,CAAC,GAAG,CAAC,oBAAoB,WAAW,EAAE,CAAC,CAAC;YACjD,CAAC;YAED,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAClB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,IAAI,KAAK,CACb,mCAAmC;gBACjC,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAC9D,CAAC;QACJ,CAAC;IACH,CAAC;IAED;;OAEG;IACK,OAAO,CAAC,IAAY;QAC1B,OAAO,IAAI;aACR,QAAQ,EAAE;aACV,WAAW,EAAE;aACb,IAAI,EAAE;aACN,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,wBAAwB;aAC7C,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC,wBAAwB;aACjD,OAAO,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,mCAAmC;aAC1D,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,oBAAoB;aACvC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC,kBAAkB;IAC3C,CAAC;CACF;AAvOD,4CAuOC"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { UploadStrategy } from '../upload-strategy';
|
|
2
2
|
import { Project } from '../../project';
|
|
3
3
|
import { YouTubeUpload } from '../../type';
|
|
4
|
+
import { CredentialsManager } from '../credentials';
|
|
4
5
|
export interface YouTubeUploadOptions {
|
|
5
6
|
uploadName: string;
|
|
6
7
|
projectPath: string;
|
|
@@ -11,6 +12,8 @@ export interface YouTubeUploadOptions {
|
|
|
11
12
|
* YouTube upload strategy implementation
|
|
12
13
|
*/
|
|
13
14
|
export declare class YouTubeUploadStrategy implements UploadStrategy {
|
|
15
|
+
private credentialsManager?;
|
|
16
|
+
constructor(credentialsManager?: CredentialsManager | undefined);
|
|
14
17
|
getTag(): string;
|
|
15
18
|
validate(): void;
|
|
16
19
|
execute(project: Project, upload: YouTubeUpload, projectPath: string): Promise<void>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"youtube-upload-strategy.d.ts","sourceRoot":"","sources":["../../../src/cli/youtube/youtube-upload-strategy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACxC,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"youtube-upload-strategy.d.ts","sourceRoot":"","sources":["../../../src/cli/youtube/youtube-upload-strategy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACxC,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAI3C,OAAO,EAAE,kBAAkB,EAAsB,MAAM,gBAAgB,CAAC;AAExE,MAAM,WAAW,oBAAoB;IACnC,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED;;GAEG;AACH,qBAAa,qBAAsB,YAAW,cAAc;IAC9C,OAAO,CAAC,kBAAkB,CAAC;gBAAnB,kBAAkB,CAAC,EAAE,kBAAkB,YAAA;IAE3D,MAAM,IAAI,MAAM;IAIhB,QAAQ,IAAI,IAAI;IAIV,OAAO,CACX,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE,aAAa,EACrB,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,IAAI,CAAC;CAiCjB;AAED;;GAEG;AACH,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC,IAAI,CAAC,CAkGf"}
|
|
@@ -8,11 +8,15 @@ exports.handleYouTubeUpload = handleYouTubeUpload;
|
|
|
8
8
|
const path_1 = require("path");
|
|
9
9
|
const youtube_uploader_1 = require("../../youtube-uploader");
|
|
10
10
|
const ejs_1 = __importDefault(require("ejs"));
|
|
11
|
-
const
|
|
11
|
+
const credentials_1 = require("../credentials");
|
|
12
12
|
/**
|
|
13
13
|
* YouTube upload strategy implementation
|
|
14
14
|
*/
|
|
15
15
|
class YouTubeUploadStrategy {
|
|
16
|
+
credentialsManager;
|
|
17
|
+
constructor(credentialsManager) {
|
|
18
|
+
this.credentialsManager = credentialsManager;
|
|
19
|
+
}
|
|
16
20
|
getTag() {
|
|
17
21
|
return 'youtube';
|
|
18
22
|
}
|
|
@@ -20,29 +24,24 @@ class YouTubeUploadStrategy {
|
|
|
20
24
|
// Validation now happens in execute() when we read credentials
|
|
21
25
|
}
|
|
22
26
|
async execute(project, upload, projectPath) {
|
|
23
|
-
//
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
if (!(0, fs_1.existsSync)(credentialsPath)) {
|
|
27
|
-
throw new Error(`❌ Error: YouTube credentials not found\n\n` +
|
|
28
|
-
`Expected location: ${credentialsPath}\n\n` +
|
|
29
|
-
`💡 Run authentication wizard:\n` +
|
|
30
|
-
` staticstripes auth --upload-name ${upload.name}\n\n` +
|
|
31
|
-
`📖 Or view setup instructions:\n` +
|
|
32
|
-
` staticstripes auth-help youtube\n`);
|
|
33
|
-
}
|
|
27
|
+
// Load credentials from local .auth/<upload-name>.json or global ~/.staticstripes/auth/<upload-name>.json
|
|
28
|
+
const manager = this.credentialsManager ||
|
|
29
|
+
new credentials_1.CredentialsManager(projectPath, upload.name);
|
|
34
30
|
let credentials;
|
|
35
31
|
try {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
}
|
|
32
|
+
credentials = manager.load([
|
|
33
|
+
'clientId',
|
|
34
|
+
'clientSecret',
|
|
35
|
+
]);
|
|
41
36
|
}
|
|
42
37
|
catch (error) {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
38
|
+
// Add helpful context about YouTube credentials
|
|
39
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
40
|
+
throw new Error(`${errorMessage}\n\n` +
|
|
41
|
+
`💡 Run authentication wizard:\n` +
|
|
42
|
+
` staticstripes auth --upload-name ${upload.name}\n\n` +
|
|
43
|
+
`📖 Or view setup instructions:\n` +
|
|
44
|
+
` staticstripes auth-help youtube\n`);
|
|
46
45
|
}
|
|
47
46
|
// Delegate to existing handler
|
|
48
47
|
await handleYouTubeUpload(project, {
|
|
@@ -83,6 +82,8 @@ async function handleYouTubeUpload(project, options) {
|
|
|
83
82
|
// Determine title (use upload-specific title or fall back to project title)
|
|
84
83
|
const title = upload.title || project.getTitle();
|
|
85
84
|
console.log(`📝 Title: ${title}\n`);
|
|
85
|
+
// Get date from project
|
|
86
|
+
const date = project.getDate();
|
|
86
87
|
// Build the project to populate fragment times (needed for timecodes)
|
|
87
88
|
console.log('🔨 Building project to calculate timecodes...');
|
|
88
89
|
await project.build(upload.outputName);
|
|
@@ -94,6 +95,7 @@ async function handleYouTubeUpload(project, options) {
|
|
|
94
95
|
const ejsDescription = upload.description.replace(/\$\{(\w+)\}/g, '<%= $1 %>');
|
|
95
96
|
const processedDescription = ejs_1.default.render(ejsDescription, {
|
|
96
97
|
title,
|
|
98
|
+
date,
|
|
97
99
|
tags: formattedTags,
|
|
98
100
|
timecodes: timecodes.join('\n'),
|
|
99
101
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"youtube-upload-strategy.js","sourceRoot":"","sources":["../../../src/cli/youtube/youtube-upload-strategy.ts"],"names":[],"mappings":";;;;;;
|
|
1
|
+
{"version":3,"file":"youtube-upload-strategy.js","sourceRoot":"","sources":["../../../src/cli/youtube/youtube-upload-strategy.ts"],"names":[],"mappings":"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"}
|
|
@@ -134,10 +134,18 @@ export declare class HTMLProjectParser {
|
|
|
134
134
|
* Processes the title from the parsed HTML
|
|
135
135
|
*/
|
|
136
136
|
private processTitle;
|
|
137
|
+
/**
|
|
138
|
+
* Processes the date from the parsed HTML
|
|
139
|
+
*/
|
|
140
|
+
private processDate;
|
|
137
141
|
/**
|
|
138
142
|
* Finds all title elements in the HTML (top-level only, not inside uploads)
|
|
139
143
|
*/
|
|
140
144
|
private findTitleElements;
|
|
145
|
+
/**
|
|
146
|
+
* Finds all date elements in the HTML (top-level only)
|
|
147
|
+
*/
|
|
148
|
+
private findDateElements;
|
|
141
149
|
/**
|
|
142
150
|
* Finds all uploads elements in the HTML
|
|
143
151
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"html-project-parser.d.ts","sourceRoot":"","sources":["../src/html-project-parser.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,EAUV,UAAU,EACX,MAAM,QAAQ,CAAC;AAKhB,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAkBpC,qBAAa,iBAAiB;IAI1B,OAAO,CAAC,IAAI;IACZ,OAAO,CAAC,WAAW;IAJrB,OAAO,CAAC,UAAU,CAAS;gBAGjB,IAAI,EAAE,UAAU,EAChB,WAAW,EAAE,MAAM;IAK7B;;;OAGG;IACI,+BAA+B,IAAI;QACxC,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;QACnC,gBAAgB,EAAE,KAAK,CAAC;YACtB,IAAI,EAAE,MAAM,CAAC;YACb,IAAI,EAAE,MAAM,CAAC;YACb,eAAe,EAAE,MAAM,CAAC;YACxB,MAAM,EAAE,MAAM,CAAC;YACf,QAAQ,CAAC,EAAE,MAAM,CAAC;SACnB,CAAC,CAAC;KACJ;IAuCY,KAAK,IAAI,OAAO,CAAC,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"html-project-parser.d.ts","sourceRoot":"","sources":["../src/html-project-parser.ts"],"names":[],"mappings":"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"}
|
|
@@ -67,11 +67,12 @@ class HTMLProjectParser {
|
|
|
67
67
|
const outputs = this.processOutputs();
|
|
68
68
|
const ffmpegOptions = this.processFfmpegOptions();
|
|
69
69
|
const title = this.processTitle();
|
|
70
|
+
const date = this.processDate();
|
|
70
71
|
const globalTags = this.processGlobalTags();
|
|
71
72
|
const uploads = this.processUploads(title, globalTags);
|
|
72
73
|
const sequences = this.processSequences(assets);
|
|
73
74
|
const cssText = this.html.cssText;
|
|
74
|
-
return new project_1.Project(sequences, assets, outputs, ffmpegOptions, uploads, aiProviders, title, cssText, this.projectPath);
|
|
75
|
+
return new project_1.Project(sequences, assets, outputs, ffmpegOptions, uploads, aiProviders, title, date, cssText, this.projectPath);
|
|
75
76
|
}
|
|
76
77
|
/**
|
|
77
78
|
* Validates that all asset files exist on the filesystem
|
|
@@ -707,7 +708,7 @@ class HTMLProjectParser {
|
|
|
707
708
|
let endpoint;
|
|
708
709
|
let region = '';
|
|
709
710
|
let bucket = '';
|
|
710
|
-
|
|
711
|
+
const paths = new Map();
|
|
711
712
|
let acl;
|
|
712
713
|
if ('children' in element && element.children) {
|
|
713
714
|
for (const child of element.children) {
|
|
@@ -728,7 +729,21 @@ class HTMLProjectParser {
|
|
|
728
729
|
break;
|
|
729
730
|
}
|
|
730
731
|
case 'path': {
|
|
731
|
-
path
|
|
732
|
+
// Extract path name from name attribute
|
|
733
|
+
const pathName = childAttrs.get('name') || 'file';
|
|
734
|
+
// Extract path value from text content
|
|
735
|
+
let pathValue = '';
|
|
736
|
+
if ('children' in childElement && childElement.children) {
|
|
737
|
+
for (const textNode of childElement.children) {
|
|
738
|
+
if (textNode.type === 'text' && 'data' in textNode) {
|
|
739
|
+
pathValue += textNode.data;
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
pathValue = pathValue.trim();
|
|
744
|
+
if (pathValue) {
|
|
745
|
+
paths.set(pathName, pathValue);
|
|
746
|
+
}
|
|
732
747
|
break;
|
|
733
748
|
}
|
|
734
749
|
case 'acl': {
|
|
@@ -740,7 +755,7 @@ class HTMLProjectParser {
|
|
|
740
755
|
}
|
|
741
756
|
}
|
|
742
757
|
// Validate required fields
|
|
743
|
-
if (!region || !bucket ||
|
|
758
|
+
if (!region || !bucket || paths.size === 0) {
|
|
744
759
|
console.warn(`S3 upload "${name}" missing required fields (region, bucket, or path)`);
|
|
745
760
|
return null;
|
|
746
761
|
}
|
|
@@ -758,7 +773,7 @@ class HTMLProjectParser {
|
|
|
758
773
|
endpoint,
|
|
759
774
|
region,
|
|
760
775
|
bucket,
|
|
761
|
-
|
|
776
|
+
paths,
|
|
762
777
|
acl,
|
|
763
778
|
},
|
|
764
779
|
};
|
|
@@ -1010,6 +1025,26 @@ class HTMLProjectParser {
|
|
|
1010
1025
|
}
|
|
1011
1026
|
return title.trim() || 'Untitled Project';
|
|
1012
1027
|
}
|
|
1028
|
+
/**
|
|
1029
|
+
* Processes the date from the parsed HTML
|
|
1030
|
+
*/
|
|
1031
|
+
processDate() {
|
|
1032
|
+
const dateElements = this.findDateElements();
|
|
1033
|
+
if (dateElements.length === 0) {
|
|
1034
|
+
return undefined;
|
|
1035
|
+
}
|
|
1036
|
+
// Get text content from first date element
|
|
1037
|
+
const dateElement = dateElements[0];
|
|
1038
|
+
let date = '';
|
|
1039
|
+
if ('children' in dateElement && dateElement.children) {
|
|
1040
|
+
for (const textNode of dateElement.children) {
|
|
1041
|
+
if (textNode.type === 'text' && 'data' in textNode) {
|
|
1042
|
+
date += textNode.data;
|
|
1043
|
+
}
|
|
1044
|
+
}
|
|
1045
|
+
}
|
|
1046
|
+
return date.trim() || undefined;
|
|
1047
|
+
}
|
|
1013
1048
|
/**
|
|
1014
1049
|
* Finds all title elements in the HTML (top-level only, not inside uploads)
|
|
1015
1050
|
*/
|
|
@@ -1039,6 +1074,37 @@ class HTMLProjectParser {
|
|
|
1039
1074
|
traverse(this.html.ast);
|
|
1040
1075
|
return results;
|
|
1041
1076
|
}
|
|
1077
|
+
/**
|
|
1078
|
+
* Finds all date elements in the HTML (top-level only)
|
|
1079
|
+
*/
|
|
1080
|
+
findDateElements() {
|
|
1081
|
+
const results = [];
|
|
1082
|
+
const traverse = (node, insideProject = false) => {
|
|
1083
|
+
if (node.type === 'tag') {
|
|
1084
|
+
const element = node;
|
|
1085
|
+
// Find top-level <date> tags (not inside <project>, <uploads>, etc.)
|
|
1086
|
+
if (element.name === 'date' && !insideProject) {
|
|
1087
|
+
results.push(element);
|
|
1088
|
+
}
|
|
1089
|
+
// Mark that we're inside a project/uploads/outputs section
|
|
1090
|
+
const isProjectSection = element.name === 'project' ||
|
|
1091
|
+
element.name === 'uploads' ||
|
|
1092
|
+
element.name === 'outputs';
|
|
1093
|
+
if ('children' in node && node.children) {
|
|
1094
|
+
for (const child of node.children) {
|
|
1095
|
+
traverse(child, insideProject || isProjectSection);
|
|
1096
|
+
}
|
|
1097
|
+
}
|
|
1098
|
+
}
|
|
1099
|
+
else if ('children' in node && node.children) {
|
|
1100
|
+
for (const child of node.children) {
|
|
1101
|
+
traverse(child, insideProject);
|
|
1102
|
+
}
|
|
1103
|
+
}
|
|
1104
|
+
};
|
|
1105
|
+
traverse(this.html.ast);
|
|
1106
|
+
return results;
|
|
1107
|
+
}
|
|
1042
1108
|
/**
|
|
1043
1109
|
* Finds all uploads elements in the HTML
|
|
1044
1110
|
*/
|