aboutsummaryrefslogtreecommitdiffstats
path: root/cogs/uploader.py
diff options
context:
space:
mode:
authorsalmonik <raisersoft@proton.me>2026-04-20 15:05:51 +0200
committersalmonik <raisersoft@proton.me>2026-04-20 15:05:51 +0200
commitc687d9fa1d89fef8ddc7150d1487dfef07d11abb (patch)
tree61166219a1fe77c22b4623efe9320fcb1b866525 /cogs/uploader.py
parentlil cron fix (diff)
downloadsenator-sperma-c687d9fa1d89fef8ddc7150d1487dfef07d11abb.tar.gz
senator-sperma-c687d9fa1d89fef8ddc7150d1487dfef07d11abb.zip
uploader.py and voice fixes
Signed-off-by: salmonik <raisersoft@proton.me>
Diffstat (limited to 'cogs/uploader.py')
-rw-r--r--cogs/uploader.py154
1 files changed, 154 insertions, 0 deletions
diff --git a/cogs/uploader.py b/cogs/uploader.py
new file mode 100644
index 0000000..68a3938
--- /dev/null
+++ b/cogs/uploader.py
@@ -0,0 +1,154 @@
1# This file is part of Senator Sperma
2# Licensed under the GPL-3.0 License
3# Copyright (C) 2026 Salmonik @ salmonik@tuta.io
4# https://codeberg.org/salmonik/senator-sperma
5
6import os
7import aiofiles
8import requests
9import urllib.parse
10from typing import List, Optional
11import discord
12from discord.ext import commands
13from discord import AutocompleteContext
14from cogs.utils import file_search as search_utils
15import logging
16
17logger = logging.getLogger(__name__)
18
19
20class Uploader(commands.Cog):
21 def __init__(self, bot):
22 from cogs.utils.temp import get_temp_dir
23 self.bot = bot
24 self.temp_dir = get_temp_dir()
25 self._cached_urls = {}
26 self._uploadurl = os.getenv("COPYPARTY_URL_UPLOAD")
27
28 async def _file_autocomplete(self, ctx: AutocompleteContext):
29 query = ctx.value.lower() if ctx.value else ""
30 results = await search_utils.UniversalSearcher.search_copyparty_autocomplete(query, max_results=25)
31
32 user_id = ctx.interaction.user.id
33 self._cached_urls[user_id] = {urllib.parse.unquote(url.split('/')[-1]): url for url in results}
34
35 choices = []
36 for url in results[:25]:
37 filename = urllib.parse.unquote(url.split('/')[-1])
38 display_name = filename[:99] + "…" if len(filename) > 100 else filename
39 choices.append(discord.OptionChoice(name=display_name, value=filename))
40 return choices
41
42 async def _download_from_url(self, url: str) -> Optional[str]:
43 """Download file from copyparty URL and return local path"""
44 try:
45 response = requests.get(url)
46 if response.status_code != 200:
47 return None
48
49 filename = url.split('/')[-1].split('?')[0]
50 file_path = os.path.join(self.temp_dir, filename)
51
52 async with aiofiles.open(file_path, 'wb') as f:
53 await f.write(response.content)
54 return file_path
55 except Exception as e:
56 logger.error(f"Error downloading from {url}: {e}")
57 return None
58
59 async def _upload_to_copyparty(self, file_path: str) -> Optional[str]:
60 """Upload file to copyparty and return download URL"""
61 try:
62 async with aiofiles.open(file_path, 'rb') as f:
63 file_content = await f.read()
64
65 files = {'f': (os.path.basename(file_path), file_content, 'application/octet-stream')}
66 headers = {'Cookie': f'cppwd={os.getenv("COPYPARTY_PASSWORD")}'}
67 params = {'j': '1', 'ck': 'b2'}
68
69 response = requests.post(self._uploadurl, files=files, headers=headers, params=params)
70
71 if response.status_code in [200, 201]:
72 result = response.json()
73 return result.get('fileurl')
74 except Exception as e:
75 logger.error(f"Upload error: {e}")
76 return None
77
78 async def _upload_file(self, file_path: str) -> Optional[str]:
79 """Upload a file and return the URL"""
80 if not self._uploadurl:
81 logger.error("COPYPARTY_URL_UPLOAD not set!")
82 return None
83
84 return await self._upload_to_copyparty(file_path)
85
86 @commands.message_command(
87 name="upload",
88 description="wyślij załączniki na copyparty",
89 )
90 async def message_upload(self, ctx, message: discord.Message):
91 if not message.attachments:
92 await ctx.respond("Brak załączników w wiadomości", ephemeral=True)
93 return
94
95 await ctx.defer()
96
97 uploaded_urls = []
98 failed_count = 0
99
100 for attachment in message.attachments:
101 file_path = os.path.join(self.temp_dir, attachment.filename)
102 await attachment.save(file_path)
103
104 url = await self._upload_file(file_path)
105 if url:
106 uploaded_urls.append(url)
107 else:
108 failed_count += 1
109
110 if os.path.exists(file_path):
111 os.remove(file_path)
112
113 if uploaded_urls:
114 response = f"Wysłano {len(uploaded_urls)} plików:\n" + "\n".join(uploaded_urls)
115 if failed_count > 0:
116 response += f"\n\nNie wysłano {failed_count} plików"
117 await ctx.respond(response)
118 else:
119 await ctx.respond("Nie udało się wysłać żadnych plików", ephemeral=True)
120
121 @commands.slash_command(
122 name="upload",
123 description="wyślij plik na copyparty",
124 )
125 @discord.option(
126 name="zalacznik",
127 description="plik z discorda",
128 required=True,
129 type=discord.Attachment
130 )
131 async def upload(self, ctx, zalacznik: discord.Attachment = None):
132 await ctx.defer()
133
134 file_path = None
135 file_path = os.path.join(self.temp_dir, zalacznik.filename)
136 await zalacznik.save(file_path)
137
138 if not file_path or not os.path.exists(file_path):
139 await ctx.respond("Nie udało się pobrać pliku", ephemeral=True)
140 return
141
142 try:
143 dl_url = await self._upload_file(file_path)
144 if dl_url:
145 await ctx.respond(dl_url)
146 else:
147 await ctx.respond("Nie udało się wysłać pliku", ephemeral=True)
148 finally:
149 if file_path and os.path.exists(file_path):
150 os.remove(file_path)
151
152
153def setup(bot):
154 bot.add_cog(Uploader(bot))