tangled
alpha
login
or
join now
indexx.dev
/
tweets2bsky
forked from
j4ck.xyz/tweets2bsky
0
fork
atom
A simple tool which lets you scrape twitter accounts and crosspost them to bluesky accounts! Comes with a CLI and a webapp for managing profiles! Works with images/videos/link embeds/threads.
0
fork
atom
overview
issues
pulls
pipelines
fix: restore working video post structure and correct syntax
jack
2 months ago
3fcbccff
6c973a4f
+17
-22
1 changed file
expand all
collapse all
unified
split
src
index.ts
+17
-22
src/index.ts
···
437
const variants = media.video_info?.variants || [];
438
const mp4s = variants
439
.filter((v) => v.content_type === 'video/mp4')
440
-
.sort((a, b) => (b.bitrate || 0) - (a.bitrate || 0)); // Largest first
441
442
if (mp4s.length > 0) {
443
-
for (const variant of mp4s) {
444
-
const videoUrl = variant.url;
0
445
try {
446
const { buffer, mimeType } = await downloadMedia(videoUrl);
447
-
if (buffer.length > 95 * 1024 * 1024) continue;
448
-
449
-
const blob = await uploadToBluesky(agent, buffer, mimeType);
450
-
videoBlob = blob;
451
-
videoAspectRatio = aspectRatio;
452
-
453
-
if (media.media_url_https) {
454
-
try {
455
-
const thumb = await downloadMedia(media.media_url_https);
456
-
videoThumbnailBlob = await uploadToBluesky(agent, thumb.buffer, thumb.mimeType);
457
-
} catch (e) {
458
-
console.warn('Failed to upload video thumbnail');
459
-
}
460
}
461
-
break;
0
0
462
} catch (err) {
463
-
console.warn(`Variant failed, trying next:`, (err as Error).message);
0
0
464
}
465
}
466
}
···
513
// Only attach media/quotes to the first chunk
514
if (i === 0) {
515
if (videoBlob) {
516
-
const videoEmbed: any = {
517
$type: 'app.bsky.embed.video',
518
video: videoBlob,
0
519
};
520
-
if (videoAspectRatio) videoEmbed.aspectRatio = videoAspectRatio;
521
-
if (videoThumbnailBlob) videoEmbed.thumbnail = videoThumbnailBlob;
522
-
postRecord.embed = videoEmbed;
523
} else if (images.length > 0) {
524
const imagesEmbed = { $type: 'app.bsky.embed.images', images };
525
if (quoteEmbed) {
···
437
const variants = media.video_info?.variants || [];
438
const mp4s = variants
439
.filter((v) => v.content_type === 'video/mp4')
440
+
.sort((a, b) => (b.bitrate || 0) - (a.bitrate || 0));
441
442
if (mp4s.length > 0) {
443
+
const firstVariant = mp4s[0];
444
+
if (firstVariant) {
445
+
const videoUrl = firstVariant.url;
446
try {
447
const { buffer, mimeType } = await downloadMedia(videoUrl);
448
+
if (buffer.length <= 95 * 1024 * 1024) {
449
+
const blob = await uploadToBluesky(agent, buffer, mimeType);
450
+
videoBlob = blob;
451
+
videoAspectRatio = aspectRatio;
452
+
break;
0
0
0
0
0
0
0
0
453
}
454
+
console.warn('Video too large (>95MB). Linking to tweet.');
455
+
const tweetUrl = `https://twitter.com/${twitterUsername}/status/${tweetId}`;
456
+
if (!text.includes(tweetUrl)) text += `\n${tweetUrl}`;
457
} catch (err) {
458
+
console.error(`Failed to upload video ${videoUrl}:`, (err as Error).message);
459
+
const tweetUrl = `https://twitter.com/${twitterUsername}/status/${tweetId}`;
460
+
if (!text.includes(tweetUrl)) text += `\n${tweetUrl}`;
461
}
462
}
463
}
···
510
// Only attach media/quotes to the first chunk
511
if (i === 0) {
512
if (videoBlob) {
513
+
postRecord.embed = {
514
$type: 'app.bsky.embed.video',
515
video: videoBlob,
516
+
aspectRatio: videoAspectRatio,
517
};
0
0
0
518
} else if (images.length > 0) {
519
const imagesEmbed = { $type: 'app.bsky.embed.images', images };
520
if (quoteEmbed) {