Skip to content

Commit

Permalink
Merge pull request #37 from jamesoncollins/devel
Browse files Browse the repository at this point in the history
Devel
  • Loading branch information
jamesoncollins authored Dec 31, 2024
2 parents f9425f3 + dbc8316 commit 291e66e
Show file tree
Hide file tree
Showing 2 changed files with 102 additions and 30 deletions.
63 changes: 44 additions & 19 deletions handlers/twitter_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ def can_handle(self) -> bool:

def get_attachments(self) -> list:
url = self.extract_url(self.input_str)
video_content = download_video(url)
video_content = download_video_with_limit(url)
if video_content:
return [BaseHandler.file_to_base64(video_content)]
return []
Expand All @@ -35,31 +35,56 @@ def get_name() -> str:


def download_video(url: str) -> str:
"""
Downloads the video from a Twitter or X post URL using yt_dlp.
return download_video_with_limit(url)

Args:
url (str): The URL of the Twitter or X post.
def download_video_with_limit(url, max_filesize_mb=90, suggested_filename="downloaded_video.mp4"):
"""
Downloads the best quality video below the specified file size limit.
Returns:
str: The path to the downloaded video file, or an empty string if download fails.
:param url: URL of the video to download
:param max_filesize_mb: Maximum file size in megabytes
:param suggested_filename: Suggested filename for the downloaded video (without extension)
:return: Actual filename of the downloaded video
"""
filename = "downloaded_video.mp4"

class FilesizeLimitError(Exception):
pass

def progress_hook(d):
if d['status'] == 'finished':
print("Download complete. Processing...")

def filesize_limiter(info_dict, *args, **kwargs):
filesize = info_dict.get('filesize', 0) or info_dict.get('filesize_approx', 0)
if filesize and filesize > max_filesize_mb * 1024 * 1024:
raise FilesizeLimitError("File size exceeds limit!")

test = os.listdir("./")
for item in test:
if item.startswith(filename):
os.remove(os.path.join("./", item))
if item.startswith(suggested_filename):
os.remove(os.path.join("./", item))

actual_filename = None
ydl_opts = {
'outtmpl': filename,
'format': 'bestvideo+bestaudio/best',
'quiet': True,
'format': 'best',
'progress_hooks': [progress_hook],
'outtmpl': f'{suggested_filename if suggested_filename else "%(title)s"}.%(ext)s',
'postprocessors': [{
'key': 'FFmpegVideoConvertor',
'preferedformat': 'mp4',
}],
'match_filter': filesize_limiter
}

try:
with yt_dlp.YoutubeDL(ydl_opts) as ydl:
filename_collector = FilenameCollectorPP()
ydl.add_post_processor(filename_collector)
ydl.download([url])
return filename_collector.filenames[0]
result = ydl.extract_info(url, download=True)
actual_filename = ydl.prepare_filename(result)
except FilesizeLimitError as e:
print(f"Skipping download: {e}")
except Exception as e:
print(f"Error downloading video: {e}")
return ""
print(f"An error occurred: {e}")

return actual_filename


69 changes: 58 additions & 11 deletions run.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from handlers.base_handler import BaseHandler
from utils import *
import time
from pickle import NONE

start_time = time.time()

Expand Down Expand Up @@ -50,15 +51,24 @@ async def reply(
):

source = c.message.source
desintation = c.message.raw_message["envelope"]["syncMessage"]["sentMessage"]["destination"]




#fixme: dont use OS var here, get it from the bot
if c.message.group or source != os.environ["BOT_NUMBER"]:
# this was a group message
# do a normal reply
return await c.reply(str, base64_attachments)
else:
# this was a 1on1 message that we send ourselves
# this was a 1on1 message that we send ourselves

# some 1v1 messages are dataMesages, not syncMessages, and they dont have dest info
try:
desintation = c.message.raw_message["envelope"]["syncMessage"]["sentMessage"]["destination"]
except Exception as e:
print(f"Failed to get desintation info, using NOT_NUMBER: {e}")
desintation = os.environ["BOT_NUMBER"]

return await c.bot.send(
desintation,
text,
Expand Down Expand Up @@ -94,30 +104,57 @@ async def handle(self, c: Context):
b64_attachments = c.message.base64_attachments
source_name = c.message.raw_message["envelope"]["sourceName"] # this is a display name, i.e. Bob Smith

# this will be the same as source or group above
recipient = c.message.recipient()

# was this a 1on1 message, or a group message?
if c.message.group == None:
destination = NONE
desintation_uuid = None
if c.message.is_private():
print("Is private message")

# this is not a group message
# see what the destination is
desintation = c.message.raw_message["envelope"]["syncMessage"]["sentMessage"]["destination"]
desintation_uuid = c.message.raw_message["envelope"]["syncMessage"]["sentMessage"]["destinationUuid"]
else:
#
# many 1v1 messages come through as dataMessage, not syncMessage.
# and, they dont have destination info, i assume becuase its implied?
try:
destination = c.message.raw_message["envelope"]["syncMessage"]["sentMessage"]["destination"]
desintation_uuid = c.message.raw_message["envelope"]["syncMessage"]["sentMessage"]["destinationUuid"]
except Exception as e:
print(f"Failed to get desintation info, using NOT_NUMBER: {e}")
desintation = os.environ["BOT_NUMBER"]

elif c.message.is_group():
print("Is group message")
# the message contains the group ID, but not the group name.
# the bot knows all the group names and IDs that the BOT_NUMBER has
# this try-except is just for unittests, becuase it doesn't populate these
# fields correctly
try:
group = find_group_by_internal_id(c.bot.groups, c.message.group)
group_name = group["name"]
if ignore_groups and group_name in ignore_groups:
if ignore_groups != None and ignore_groups and group_name in ignore_groups:
print("Ignored group")
return
if group_name not in group_names and group_names != True:
if group_names != True and group_name not in group_names :
print("group not in group list or group_names isnt True")
return
except Exception as e:
print(f"Failed to get group info: {e}")

else:
print("unknown group/private type")
return

if c.message.type.name == "DATA_MESSAGE":
print("is data message")
elif c.message.type.name == "SYNC_MESSAGE":
print("is sync message")
else:
print("unknown message type")
return

print(f"source {source}, recipient {c.message.recipient()}, dest {destination}, group {group}, message type {c.message.type.name}")

if msg is None:
print("Message was None")
Expand Down Expand Up @@ -162,7 +199,17 @@ async def handle(self, c: Context):
handler.assign_context(c)
if handler.can_handle():
print("Handler Used:", handler_class.get_name())
await c.reply( LOGMSG + handler.get_message(), base64_attachments=handler.get_attachments() )
msg = handler.get_message()
try:
attachments = handler.get_attachments()
except Exception as e:
msg += "\nfailed to download\n"
msg += "Handler {handler_name} exception: {e}"
attachments = []
try:
await c.reply( LOGMSG + msg, base64_attachments=attachments )
except Exception as e:
c.reply( LOGMSG + msg + "failed to send signal message" )
#return
except Exception as e:
print(f"Handler {handler_name} exception: {e}")
Expand Down

0 comments on commit 291e66e

Please sign in to comment.