Added new yml
This commit is contained in:
@@ -8,6 +8,7 @@ import os
|
||||
from dotenv import load_dotenv
|
||||
from atproto import Client, client_utils, models
|
||||
from playwright.sync_api import sync_playwright
|
||||
from moviepy.editor import VideoFileClip
|
||||
|
||||
# --- Logging Setup ---
|
||||
LOG_PATH = "twitter2bsky.log"
|
||||
@@ -199,7 +200,31 @@ def clean_url(url):
|
||||
return cleaned_url
|
||||
return None
|
||||
|
||||
# --- 4. Formatting & Bluesky Logic ---
|
||||
# --- 4. Video Processing ---
|
||||
def download_and_crop_video(video_url, output_path):
|
||||
"""Downloads the video and crops it to 59 seconds."""
|
||||
try:
|
||||
# Download the video
|
||||
response = httpx.get(video_url, timeout=10)
|
||||
if response.status_code == 200:
|
||||
with open(output_path, 'wb') as f:
|
||||
f.write(response.content)
|
||||
logging.info(f"✅ Video downloaded: {output_path}")
|
||||
|
||||
# Crop the video to 59 seconds
|
||||
video_clip = VideoFileClip(output_path)
|
||||
cropped_clip = video_clip.subclip(0, min(59, video_clip.duration))
|
||||
cropped_clip.write_videofile(output_path, codec='libx264')
|
||||
logging.info(f"✅ Video cropped to 59 seconds: {output_path}")
|
||||
return output_path
|
||||
else:
|
||||
logging.error(f"❌ Failed to download video: {video_url}")
|
||||
return None
|
||||
except Exception as e:
|
||||
logging.error(f"❌ Error processing video: {e}")
|
||||
return None
|
||||
|
||||
# --- 5. Formatting & Bluesky Logic ---
|
||||
def get_last_bsky(client, handle):
|
||||
timeline = client.get_author_feed(handle)
|
||||
for titem in timeline.feed:
|
||||
@@ -288,16 +313,17 @@ def make_rich(content):
|
||||
|
||||
return text_builder
|
||||
|
||||
def get_blob_from_url(image_url, client):
|
||||
def get_blob_from_url(media_url, client):
|
||||
"""Fetches and uploads the media (image or video) and returns the blob."""
|
||||
try:
|
||||
r = httpx.get(image_url, timeout=10)
|
||||
r = httpx.get(media_url, timeout=10)
|
||||
if r.status_code == 200:
|
||||
return client.upload_blob(r.content).blob
|
||||
except Exception as e:
|
||||
logging.warning(f"Could not fetch image {image_url}: {e}")
|
||||
logging.warning(f"Could not fetch media {media_url}: {e}")
|
||||
return None
|
||||
|
||||
# --- 5. Main Sync Function ---
|
||||
# --- 6. Main Sync Function ---
|
||||
def sync_feeds(args):
|
||||
logging.info("🔄 Starting sync cycle...")
|
||||
try:
|
||||
@@ -324,7 +350,8 @@ def sync_feeds(args):
|
||||
for tweet in reversed(tweets):
|
||||
tweet_time = arrow.get(tweet.created_on)
|
||||
|
||||
if tweet_time > last_bsky_time: # Only post new tweets
|
||||
#if tweet_time > last_bsky_time: # Only post new tweets
|
||||
if True: # For testing, post all tweets regardless of time
|
||||
logging.info(f"📝 Found new tweet from {tweet_time}. Posting to Bluesky...")
|
||||
|
||||
raw_text = tweet.text.strip()
|
||||
@@ -365,10 +392,14 @@ def sync_feeds(args):
|
||||
# Inject our dynamic alt text here!
|
||||
images.append(models.AppBskyEmbedImages.Image(alt=dynamic_alt, image=blob))
|
||||
elif media.type == "video":
|
||||
# Handle video uploads if necessary (this part may vary based on your API capabilities)
|
||||
blob = get_blob_from_url(media.media_url_https, bsky_client)
|
||||
if blob:
|
||||
images.append(models.AppBskyEmbedImages.Image(alt=dynamic_alt, image=blob))
|
||||
# Download and crop the video
|
||||
video_path = "temp_video.mp4"
|
||||
cropped_video_path = download_and_crop_video(media.media_url_https, video_path)
|
||||
if cropped_video_path:
|
||||
blob = get_blob_from_url(cropped_video_path, bsky_client)
|
||||
if blob:
|
||||
images.append(models.AppBskyEmbedImages.Image(alt=dynamic_alt, image=blob))
|
||||
os.remove(video_path) # Clean up the temporary video file
|
||||
|
||||
# 🌐 Posting with Catalan language tag
|
||||
try:
|
||||
@@ -389,7 +420,31 @@ def sync_feeds(args):
|
||||
except Exception as e:
|
||||
logging.error(f"❌ Error during sync cycle: {e}")
|
||||
|
||||
# --- 6. Main Execution ---
|
||||
# --- 7. Download and Crop Video Function ---
|
||||
def download_and_crop_video(video_url, output_path):
|
||||
"""Downloads the video and crops it to 59 seconds."""
|
||||
try:
|
||||
# Download the video
|
||||
response = httpx.get(video_url, timeout=10)
|
||||
if response.status_code == 200:
|
||||
with open(output_path, 'wb') as f:
|
||||
f.write(response.content)
|
||||
logging.info(f"✅ Video downloaded: {output_path}")
|
||||
|
||||
# Crop the video to 59 seconds
|
||||
video_clip = VideoFileClip(output_path)
|
||||
cropped_clip = video_clip.subclip(0, min(59, video_clip.duration))
|
||||
cropped_clip.write_videofile(output_path, codec='libx264')
|
||||
logging.info(f"✅ Video cropped to 59 seconds: {output_path}")
|
||||
return output_path
|
||||
else:
|
||||
logging.error(f"❌ Failed to download video: {video_url}")
|
||||
return None
|
||||
except Exception as e:
|
||||
logging.error(f"❌ Error processing video: {e}")
|
||||
return None
|
||||
|
||||
# --- 8. Main Execution ---
|
||||
def main():
|
||||
load_dotenv()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user