-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmedia_manager.py
More file actions
115 lines (102 loc) · 4.6 KB
/
Copy pathmedia_manager.py
File metadata and controls
115 lines (102 loc) · 4.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
import aiohttp
import asyncio
import os
import time
import logging
import discord
import io
import config
logger = logging.getLogger("MacbLogger")
class MediaManager:
def __init__(self):
self.session = None
def initialize(self):
self.session = aiohttp.ClientSession()
async def close(self):
if self.session:
await self.session.close()
async def downloadMedia(self, messageId, url):
if not url or not url.startswith("http"):
return url
try:
filename = url.split("/")[-1].split("?")[0]
if not filename:
filename = "file.dat"
localPath = f"{config.cacheDir}/{messageId}_{filename}"
if os.path.exists(localPath):
return localPath
async with self.session.get(url, timeout=30) as response:
if response.status == 200:
with open(localPath, "wb") as localFile:
async for chunk in response.content.iter_chunked(65536):
localFile.write(chunk)
return localPath
elif response.status == 429:
retryAfter = float(response.headers.get("Retry-After", 2))
await asyncio.sleep(retryAfter)
return await self.downloadMedia(messageId, url)
except Exception as downloadError:
logger.error(f"Error downloading media from {url}: {str(downloadError)}")
return url
async def convertToDiscordFile(self, pathOrUrl):
if not pathOrUrl:
return None
try:
if os.path.exists(pathOrUrl):
filename = pathOrUrl.split("/")[-1]
return discord.File(pathOrUrl, filename=filename)
if pathOrUrl.startswith("http"):
maxRetries = 3
for attempt in range(maxRetries):
try:
async with self.session.get(pathOrUrl, timeout=15) as response:
if response.status == 200:
fileData = await response.read()
filename = pathOrUrl.split("/")[-1].split("?")[0]
if not filename:
filename = "file.dat"
return discord.File(io.BytesIO(fileData), filename=filename)
elif response.status == 429:
await asyncio.sleep(float(response.headers.get("Retry-After", 2)))
else:
await asyncio.sleep(2 ** attempt)
except Exception:
await asyncio.sleep(2 ** attempt)
except Exception as conversionError:
logger.error(f"Error converting to discord file: {str(conversionError)}")
return None
async def cleanCacheTask(self):
while True:
try:
await asyncio.sleep(86400)
if not os.path.exists(config.cacheDir):
continue
currentTime = time.time()
maxAgeSecs = config.maxCacheAgeDays * 86400
totalSize = 0
filesList = []
for entry in os.scandir(config.cacheDir):
if entry.is_file():
fileStat = entry.stat()
fileAge = currentTime - fileStat.st_mtime
if fileAge > maxAgeSecs:
try:
os.remove(entry.path)
except OSError:
pass
else:
totalSize += fileStat.st_size
filesList.append((fileStat.st_mtime, entry.path, fileStat.st_size))
maxSizeBytes = config.maxCacheSizeMb * 1024 * 1024
if totalSize > maxSizeBytes:
filesList.sort(key=lambda x: x[0])
for mtime, path, size in filesList:
try:
os.remove(path)
totalSize -= size
if totalSize <= maxSizeBytes:
break
except OSError:
pass
except Exception as cacheError:
logger.error(f"Error cleaning cache directory: {str(cacheError)}")