Script looks like it runs sucessfully, however, i’m implicated with the following error
Error during clip upload: 'NoneType' object has no attribute 'value' poster.py:241
I’ve tried looking through my code, which can be found below, with terminal output as well, doing every debugging method I can think of, and whatever I found on here + google, however, I can’t seem to figure out what is causing this error..
import os
from aiograpi import Client as AiograpiClient
from aiograpi.types import StoryMention, StoryMedia, StoryLink, StoryHashtag
from db import Session, Reel
from datetime import datetime
import config
import auth
import helpers as Helper
from moviepy.editor import VideoFileClip, TextClip, CompositeVideoClip, ColorClip
import logging
from rich.console import Console
from rich.logging import RichHandler
import PIL.Image
import asyncio
# Initialize Rich Console for logging
console = Console()
logging.basicConfig(level=logging.INFO, format="%(message)s", handlers=[RichHandler(console=console)])
# ImageMagick setup
from moviepy.config import change_settings
change_settings({"IMAGEMAGICK_BINARY": os.path.join(config.IMAGEMAGICK_PATH, "magick.exe")})
# Patch to replace ANTIALIAS with LANCZOS
if not hasattr(PIL.Image, 'ANTIALIAS'):
PIL.Image.ANTIALIAS = PIL.Image.LANCZOS
# Function to edit the video (imported from test.py)
def edit_video(input_path, output_path, video_number):
REEL_WIDTH = 720
REEL_HEIGHT = 1280
FINAL_WIDTH = 1080
FINAL_HEIGHT = 1920
console.log(f"[bold yellow]Editing video:[/bold yellow] input_path={input_path}, output_path={output_path}")
try:
# Load the video clip
clip = VideoFileClip(input_path)
original_width, original_height = clip.size
console.log(f"[bold cyan]Loaded video:[/bold cyan] {input_path}")
# Create a background with the final resolution
background = ColorClip(size=(FINAL_WIDTH, FINAL_HEIGHT), color=(0, 0, 0), duration=clip.duration)
# Resize the reel to 720x1280
resized_reel = clip.resize(newsize=(REEL_WIDTH, REEL_HEIGHT))
# Center the resized reel within the final background
centered_reel = resized_reel.set_position('center')
# Calculate the center position manually
center_x = (FINAL_WIDTH - REEL_WIDTH) // 2
center_y = (FINAL_HEIGHT - REEL_HEIGHT) // 2
console.log(f"[bold magenta]Center position:[/bold magenta] x={center_x}, y={center_y}")
# Determine top text based on video number
if video_number % 5 == 0:
top_text_content1 = ""
top_text_content2 = "SAMPLE TEXT"
else:
top_text_content1 = "SAMPLE TEXT 1"
top_text_content2 = "SAMPLE TEXT 2"
top_text_size = 40
font = 'Arial-Bold'
try:
top_text1 = TextClip(top_text_content1, fontsize=top_text_size, color='white', font=font)
top_text2 = TextClip(top_text_content2, fontsize=top_text_size, color='white', font=font)
except Exception as e:
console.log(f"[bold red]Error creating TextClip:[/bold red] {str(e)}")
return
# Debug: Ensure text clips are created correctly
console.log(f"[bold cyan]Top text 1 dimensions:[/bold cyan] {top_text1.size if top_text1 else 'None'}")
console.log(f"[bold cyan]Top text 2 dimensions:[/bold cyan] {top_text2.size if top_text2 else 'None'}")
top_text_x = center_x
top_text_y_position1 = center_y - top_text_size * 2 - 20
top_text_y_position2 = top_text_y_position1 + top_text_size
console.log(f"[bold magenta]Top text 1 position:[/bold magenta] ({top_text_x}, {top_text_y_position1})")
console.log(f"[bold magenta]Top text 2 position:[/bold magenta] ({top_text_x}, {top_text_y_position2})")
top_text1 = top_text1.set_position((top_text_x, top_text_y_position1)).set_duration(clip.duration)
top_text2 = top_text2.set_position((top_text_x, top_text_y_position2)).set_duration(clip.duration)
bottom_text = TextClip("COPYRIGHT TEXT", fontsize=40, color='white', font=font)
bottom_text = bottom_text.set_position(("center", FINAL_HEIGHT - 60)).set_duration(clip.duration)
final_clip = CompositeVideoClip([background, centered_reel, top_text1, top_text2, bottom_text])
final_clip.write_videofile(output_path, codec='libx264')
console.log(f"[bold green]Edited video saved to {output_path}[/bold green]")
except Exception as e:
console.log(f"[bold red]Error in edit_video:[/bold red] {str(e)}")
# Trim Video for story
def trim_video(file_path, output_path, max_duration=15):
clip = VideoFileClip(file_path)
trimmed_clip = clip.subclip(0, max_duration)
trimmed_clip.write_videofile(output_path)
return output_path
# Get Video Duration
def get_video_duration(file_path):
clip = VideoFileClip(file_path)
duration = clip.duration
return duration
# Update is_posted and posted_at field in DB
def update_status(code):
session = Session()
session.query(Reel).filter_by(code=code).update({'is_posted': True, 'posted_at': datetime.now()})
session.commit()
session.close()
# Get Unposted reels from database
# Update get_reel to accept an account parameter
def get_reel(account):
session = Session()
reels = session.query(Reel).filter_by(is_posted=False, account=account).all()
console.log(f"[bold blue]Number of unposted reels found for account {account}:[/bold blue] {len(reels)}")
for reel in reels:
console.log(f"[bold blue]Reel details:[/bold blue] {reel.file_path if reel else 'None'}")
session.close()
if not reels:
console.log(f"[red]Warning: No unposted reels found for account {account}.[/red]")
return reels[0] if reels else None
async def post_to_story(api, media, media_path):
try:
# Retrieve user info and hashtag info
username = await api.user_info_by_username(config.USERNAME)
console.log(f"[bold cyan]User info response:[/bold cyan] {username}")
if username is None:
console.log(f"[red]Error: Unable to retrieve user info for username {config.USERNAME}[/red]")
return
hashtag = await api.hashtag_info('like')
console.log(f"[bold cyan]Hashtag info response:[/bold cyan] {hashtag}")
if hashtag is None:
console.log(f"[red]Error: Unable to retrieve hashtag info for 'like'[/red]")
return
# Determine video duration and trim if necessary
duration = get_video_duration(media_path)
if duration > 15:
media_path = trim_video(media_path, config.DOWNLOAD_DIR + os.sep + media.code + ".mp4")
# Retrieve media_pk and upload video to story
media_pk = await api.media_pk_from_url('https://www.instagram.com/p/' + media.code + '/')
console.log(f"[bold cyan]Media PK response:[/bold cyan] {media_pk}")
if media_pk is None:
console.log(f"[red]Error: Unable to retrieve media_pk for media code {media.code}[/red]")
return
# Check if media object has the expected attributes
if media is None:
console.log(f"[red]Error: Media object is None. Cannot post to story.[/red]")
return
if not hasattr(media, 'value'):
console.log(f"[red]Error: Media object does not have 'value' attribute. Media content: {media}[/red]")
return
# Check if media.value is valid
media_value = media.value
if media_value is None:
console.log(f"[red]Error: Media object has 'value' attribute but value is None.[/red]")
return
# Post to story
await api.video_upload_to_story(
media_path,
"",
mentions=[StoryMention(user=username, x=0.49892962, y=0.703125, width=0.8333333333333334, height=0.125)],
links=[StoryLink(webUri='https://www.instagram.com/p/' + media.code + '/')],
hashtags=[StoryHashtag(hashtag=hashtag, x=0.23, y=0.32, width=0.5, height=0.22)],
medias=[StoryMedia(media_pk=media_pk, x=0.5, y=0.5, width=0.6, height=0.8)],
)
console.log(f"[bold green]Successfully posted video to story[/bold green]")
except Exception as e:
console.log(f"[bold red]Exception {type(e).__name__}: {str(e)}[/bold red]")
# Counter for tracking videos
video_counter = 0
# Main Starts Here
async def main(api):
global video_counter
Helper.load_all_config()
console.log("Started main function")
try:
accounts = config.ACCOUNTS # Fetch accounts from config
if not accounts:
console.log("[bold red]Error: No accounts found in config.ACCOUNTS[/bold red]")
return
for account in accounts:
reel = get_reel(account)
if reel:
video_counter += 1
edited_file = os.path.join(config.DOWNLOAD_DIR, "edited_" + os.path.basename(reel.file_path))
if video_counter % 5 == 0:
edit_video(reel.file_path, edited_file, video_counter)
file_to_upload = edited_file
else:
file_to_upload = reel.file_path
api.delay_range = [1, 3]
console.log("[yellow]Attempting to upload the video clip...[/yellow]")
try:
media = await api.clip_upload(
file_to_upload,
Helper.get_config('HASHTAGS'), # Caption
extra_data={
"like_and_view_counts_disabled": config.LIKE_AND_VIEW_COUNTS_DISABLED,
"disable_comments": config.DISABLE_COMMENTS,
})
console.log(f"[bold yellow]Media object after upload: {media}[/bold yellow]")
console.log(f"[bold yellow]Type of media object: {type(media)}[/bold yellow]")
if isinstance(media, dict):
console.log(f"[bold yellow]Media object keys: {list(media.keys())}[/bold yellow]")
except Exception as e:
console.log(f"[red]Error during clip upload: {str(e)}[/red]")
continue
# Check if media is None
if media is None:
console.log(f"[red]Error: Clip upload failed or returned None for file {file_to_upload}[/red]")
continue
# Check if media has the expected 'value' attribute
if not hasattr(media, 'value'):
console.log(f"[red]Error: Media object does not have 'value' attribute. Media content: {media}[/red]")
continue
# Safely access media.value
try:
media_value = getattr(media, 'value', None)
if media_value is None:
console.log(f"[red]Error: Media object has 'value' attribute but value is None or missing.[/red]")
continue
console.log(f"[green]Media value accessed successfully: {media_value}[/green]")
update_status(reel.code)
if int(config.IS_POST_TO_STORY) == 1:
await post_to_story(api, media, file_to_upload)
except AttributeError as ae:
console.log(f"[bold red]Caught AttributeError when accessing media value: {str(ae)}[/bold red]")
continue
else:
console.log(f"[bold red]No unposted reels found for account {account}![/bold red]")
except Exception as e:
console.log(f"[bold red]Exception {type(e).__name__}: {str(e)}[/bold red]")
if __name__ == "__main__":
api = AiograpiClient()
loop = asyncio.get_event_loop()
loop.run_until_complete(main(api))
Terminal Image:
any help would be greatly appriciated.
Raven is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.