Support uploading larger files

This commit is contained in:
Nexus 2024-05-31 02:23:42 +01:00
parent 38f47b9699
commit 774e8cf3d7
Signed by: nex
GPG key ID: 0FA334385D0B689F
3 changed files with 59 additions and 23 deletions

View file

@ -66,7 +66,8 @@ RUN DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
python3 \ python3 \
python3-pip \ python3-pip \
python3-dev \ python3-dev \
python3-virtualenv python3-virtualenv \
libmagic-dev
RUN virtualenv /app/venv RUN virtualenv /app/venv
RUN /app/venv/bin/pip install --upgrade --no-input pip wheel setuptools RUN /app/venv/bin/pip install --upgrade --no-input pip wheel setuptools

View file

@ -19,3 +19,4 @@ redis~=5.0
beautifulsoup4~=4.12 beautifulsoup4~=4.12
lxml~=5.1 lxml~=5.1
matplotlib~=3.8 matplotlib~=3.8
python-magic~=0.4

View file

@ -2,10 +2,12 @@ import asyncio
import functools import functools
import hashlib import hashlib
import logging import logging
import httpx
import subprocess import subprocess
import tempfile import tempfile
import textwrap import textwrap
import typing import typing
import uuid
from pathlib import Path from pathlib import Path
from urllib.parse import urlparse from urllib.parse import urlparse
@ -205,6 +207,22 @@ class YTDLCog(commands.Cog):
raise RuntimeError(process.stderr.decode()) raise RuntimeError(process.stderr.decode())
return new_file return new_file
@staticmethod
async def upload_to_0x0(name: str, data: typing.BinaryIO[bytes], mime_type: str | None = None) -> str:
if not mime_type:
import magic
mime_type = await asyncio.to_thread(magic.from_buffer, data.read(4096), mime=True)
data.seek(0)
async with httpx.AsyncClient() as client:
response = await client.post(
"https://0x0.st",
files={"file": (name, data, mime_type)},
headers={"User-Agent": "CollegeBot (matrix: @nex:nexy7574.co.uk)"},
)
if response.status_code == 200:
return urlparse(response.text).path[1:]
response.raise_for_status()
@commands.slash_command(name="yt-dl") @commands.slash_command(name="yt-dl")
@commands.max_concurrency(1, wait=False) @commands.max_concurrency(1, wait=False)
# @commands.bot_has_permissions(send_messages=True, embed_links=True, attach_files=True) # @commands.bot_has_permissions(send_messages=True, embed_links=True, attach_files=True)
@ -294,6 +312,7 @@ class YTDLCog(commands.Cog):
description = str(e) description = str(e)
thumbnail_url = webpage_url = None thumbnail_url = webpage_url = None
likes = views = 0 likes = views = 0
chosen_format_id = str(uuid.uuid4())
else: else:
title = extracted_info.get("title", url) title = extracted_info.get("title", url)
title = textwrap.shorten(title, 100) title = textwrap.shorten(title, 100)
@ -305,7 +324,7 @@ class YTDLCog(commands.Cog):
final_extension = extracted_info.get("ext") final_extension = extracted_info.get("ext")
format_note = extracted_info.get("format_note", "%s (%s)" % (chosen_format, chosen_format_id)) format_note = extracted_info.get("format_note", "%s (%s)" % (chosen_format, chosen_format_id))
resolution = extracted_info.get("resolution") resolution = extracted_info.get("resolution")
fps = extracted_info.get("fps") fps = extracted_info.get("fps", 0.0)
vcodec = extracted_info.get("vcodec") vcodec = extracted_info.get("vcodec")
acodec = extracted_info.get("acodec") acodec = extracted_info.get("acodec")
filesize = extracted_info.get("filesize", extracted_info.get("filesize_approx", 1)) filesize = extracted_info.get("filesize", extracted_info.get("filesize_approx", 1))
@ -346,7 +365,7 @@ class YTDLCog(commands.Cog):
.set_footer(text="Downloading (step 2/10)") .set_footer(text="Downloading (step 2/10)")
.set_thumbnail(url=thumbnail_url) .set_thumbnail(url=thumbnail_url)
) )
previous = await self.get_saved(webpage_url, extracted_info["format_id"], snip or "*") previous = await self.get_saved(webpage_url, chosen_format_id, snip or "*")
if previous: if previous:
await ctx.edit( await ctx.edit(
content=previous, content=previous,
@ -375,26 +394,28 @@ class YTDLCog(commands.Cog):
) )
try: try:
if audio_only is False: if audio_only is False:
file = next(temp_dir.glob("*." + extracted_info["ext"])) file: Path = next(temp_dir.glob("*." + extracted_info["ext"]))
else: else:
# can be .opus, .m4a, .mp3, .ogg, .oga # can be .opus, .m4a, .mp3, .ogg, .oga
for _file in temp_dir.iterdir(): for _file in temp_dir.iterdir():
if _file.suffix in (".opus", ".m4a", ".mp3", ".ogg", ".oga", ".aac", ".wav"): if _file.suffix in (".opus", ".m4a", ".mp3", ".ogg", ".oga", ".aac", ".wav"):
file = _file file: Path = _file
break break
else: else:
raise StopIteration raise StopIteration
except StopIteration: except StopIteration:
ext = extracted_info["ext"]
self.log.warning( self.log.warning(
"Failed to locate downloaded file. Was supposed to be looking for a file extension of " "Failed to locate downloaded file. Was supposed to be looking for a file extension of "
"%r amongst files %r, however none were found.", "%r amongst files %r, however none were found.",
extracted_info["ext"], ext,
list(map(str, temp_dir.iterdir())), list(map(str, temp_dir.iterdir())),
) )
return await ctx.edit( return await ctx.edit(
embed=discord.Embed( embed=discord.Embed(
title="Error", title="Error",
description="Failed to locate downloaded video file.\n" description="Failed to locate downloaded video file."
f" Was expecting a file with the extension {ext}.\n"
f"Files: {', '.join(list(map(str, temp_dir.iterdir())))}", f"Files: {', '.join(list(map(str, temp_dir.iterdir())))}",
colour=discord.Colour.red(), colour=discord.Colour.red(),
url=webpage_url, url=webpage_url,
@ -421,7 +442,7 @@ class YTDLCog(commands.Cog):
"-preset", "-preset",
"fast", "fast",
"-crf", "-crf",
"28", "24",
"-deadline", "-deadline",
"realtime", "realtime",
"-cpu-used", "-cpu-used",
@ -464,11 +485,11 @@ class YTDLCog(commands.Cog):
if audio_only and file.suffix != ".m4a": if audio_only and file.suffix != ".m4a":
self.log.info("Converting %r to m4a.", file) self.log.info("Converting %r to m4a.", file)
file = await asyncio.to_thread(self.convert_to_m4a, file) file: Path = await asyncio.to_thread(self.convert_to_m4a, file)
stat = file.stat() stat = file.stat()
size_bytes = stat.st_size size_bytes = stat.st_size
if size_bytes >= ((25 * 1024 * 1024) - 256): if size_bytes >= ((500 * 1024 * 1024) - 256):
return await ctx.edit( return await ctx.edit(
embed=discord.Embed( embed=discord.Embed(
title="Error", title="Error",
@ -477,9 +498,9 @@ class YTDLCog(commands.Cog):
url=webpage_url, url=webpage_url,
) )
) )
size_megabits = (size_bytes * 8) / 1024 / 1024 size_megabits = (size_bytes * 8) / 1024 / 1024
eta_seconds = size_megabits / 20 eta_seconds = size_megabits / 20
upload_file = await asyncio.to_thread(discord.File, file, filename=file.name)
await ctx.edit( await ctx.edit(
embed=discord.Embed( embed=discord.Embed(
title="Uploading...", title="Uploading...",
@ -488,19 +509,32 @@ class YTDLCog(commands.Cog):
timestamp=discord.utils.utcnow(), timestamp=discord.utils.utcnow(),
) )
) )
embed = discord.Embed(
title=f"Downloaded {title}!",
description="Views: {:,} | Likes: {:,}".format(views or 0, likes or 0),
colour=discord.Colour.green(),
timestamp=discord.utils.utcnow(),
url=webpage_url,
)
try: try:
msg = await ctx.edit( if size_bytes >= (20 * 1024 * 1024):
file=upload_file, with file.open("rb") as fb:
embed=discord.Embed( part = await self.upload_to_0x0(
title=f"Downloaded {title}!", file.name,
description="Views: {:,} | Likes: {:,}".format(views or 0, likes or 0), fb
colour=discord.Colour.green(), )
timestamp=discord.utils.utcnow(), await ctx.edit(
url=webpage_url, content="https://embeds.video/0x0/" + part,
), embed=embed
) )
await self.save_link(msg, webpage_url, chosen_format_id, snip=snip or "*") else:
except discord.HTTPException as e: upload_file = await asyncio.to_thread(discord.File, file, filename=file.name)
msg = await ctx.edit(
file=upload_file,
embed=embed
)
await self.save_link(msg, webpage_url, chosen_format_id, snip=snip or "*")
except (discord.HTTPException, ConnectionError, httpx.HTTPStatusError) as e:
self.log.error(e, exc_info=True) self.log.error(e, exc_info=True)
return await ctx.edit( return await ctx.edit(
embed=discord.Embed( embed=discord.Embed(