taslim19
commited on
Commit
·
b8b8b54
1
Parent(s):
90dc4ea
changed thumbnails.py
Browse files- DragMusic/assets/font3.ttf +3 -0
- DragMusic/assets/play_icons.png +0 -0
- DragMusic/assets/shuffle_icon.png +0 -0
- DragMusic/utils/thumbnails.py +209 -279
DragMusic/assets/font3.ttf
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:0cb1e335521ccbdcdd2b6b2eb1c3af2518dda2a55b1a2b1a4acef1dc14e0e236
|
3 |
+
size 80716
|
DragMusic/assets/play_icons.png
ADDED
![]() |
DragMusic/assets/shuffle_icon.png
ADDED
![]() |
DragMusic/utils/thumbnails.py
CHANGED
@@ -1,18 +1,13 @@
|
|
|
|
|
|
1 |
import os
|
2 |
import re
|
3 |
-
import textwrap
|
4 |
-
|
5 |
import aiofiles
|
6 |
import aiohttp
|
7 |
from PIL import Image, ImageDraw, ImageEnhance, ImageFilter, ImageFont
|
8 |
-
from unidecode import unidecode
|
9 |
from youtubesearchpython.__future__ import VideosSearch
|
10 |
|
11 |
-
|
12 |
-
from DragMusic.core.mongo import mongodb
|
13 |
-
from config import YOUTUBE_IMG_URL
|
14 |
-
from DragMusic.logging import LOGGER
|
15 |
-
|
16 |
|
17 |
def changeImageSize(maxWidth, maxHeight, image):
|
18 |
widthRatio = maxWidth / image.size[0]
|
@@ -22,296 +17,231 @@ def changeImageSize(maxWidth, maxHeight, image):
|
|
22 |
newImage = image.resize((newWidth, newHeight))
|
23 |
return newImage
|
24 |
|
25 |
-
|
26 |
-
def clear(text):
|
27 |
list = text.split(" ")
|
28 |
-
|
|
|
29 |
for i in list:
|
30 |
-
if len(
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
40 |
try:
|
|
|
|
|
|
|
|
|
41 |
results = VideosSearch(url, limit=1)
|
42 |
for result in (await results.next())["result"]:
|
43 |
-
|
44 |
-
|
45 |
-
title = re.sub("
|
46 |
-
|
47 |
-
except:
|
48 |
title = "Unsupported Title"
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
57 |
views = "Unknown Views"
|
58 |
-
|
59 |
-
|
60 |
-
|
|
|
|
|
|
|
61 |
channel = "Unknown Channel"
|
62 |
|
|
|
63 |
async with aiohttp.ClientSession() as session:
|
64 |
async with session.get(thumbnail) as resp:
|
|
|
|
|
65 |
if resp.status == 200:
|
66 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
67 |
await f.write(await resp.read())
|
68 |
await f.close()
|
69 |
-
|
70 |
-
|
|
|
|
|
|
|
71 |
image1 = changeImageSize(1280, 720, youtube)
|
|
|
72 |
image2 = image1.convert("RGBA")
|
73 |
-
background = image2.filter(filter=ImageFilter.BoxBlur(
|
74 |
enhancer = ImageEnhance.Brightness(background)
|
75 |
-
background = enhancer.enhance(0.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
76 |
draw = ImageDraw.Draw(background)
|
77 |
arial = ImageFont.truetype("DragMusic/assets/font2.ttf", 30)
|
78 |
font = ImageFont.truetype("DragMusic/assets/font.ttf", 30)
|
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 |
-
|
116 |
-
|
117 |
-
|
118 |
-
|
119 |
-
|
120 |
-
|
121 |
-
|
122 |
-
|
123 |
-
|
124 |
-
|
125 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
126 |
|
127 |
-
async def gen_thumb(videoid: str, user_id: int) -> str:
|
128 |
-
if os.path.isfile(f"/tmp/cache/{videoid}.png"):
|
129 |
-
return f"/tmp/cache/{videoid}.png"
|
130 |
-
url = f"https://www.youtube.com/watch?v={videoid}"
|
131 |
-
try:
|
132 |
-
results = VideosSearch(url, limit=1)
|
133 |
-
for result in (await results.next())["result"]:
|
134 |
-
try:
|
135 |
-
title = result["title"]
|
136 |
-
title = re.sub("\\W+", " ", title)
|
137 |
-
title = title.title()
|
138 |
-
except:
|
139 |
-
title = "Unsupported Title"
|
140 |
-
try:
|
141 |
-
duration = result["duration"]
|
142 |
-
except:
|
143 |
-
duration = "Unknown Mins"
|
144 |
-
thumbnail = result["thumbnails"][0]["url"].split("?")[0]
|
145 |
-
try:
|
146 |
-
views = result["viewCount"]["short"]
|
147 |
-
except:
|
148 |
-
views = "Unknown Views"
|
149 |
-
try:
|
150 |
-
channel = result["channel"]["name"]
|
151 |
-
except:
|
152 |
-
channel = "Unknown Channel"
|
153 |
-
|
154 |
-
async with aiohttp.ClientSession() as session:
|
155 |
-
async with session.get(thumbnail) as resp:
|
156 |
-
if resp.status == 200:
|
157 |
-
ctitle = (await app.get_chat(user_id)).title
|
158 |
-
ctitle = await crop_title(ctitle)
|
159 |
-
try:
|
160 |
-
f = await aiofiles.open(f"/tmp/cache/thumb{videoid}.png", mode="wb")
|
161 |
-
await f.write(await resp.read())
|
162 |
-
await f.close()
|
163 |
-
youtube = Image.open(f"/tmp/cache/thumb{videoid}.png")
|
164 |
-
image1 = changeImageSize(1280, 720, youtube)
|
165 |
-
image2 = image1.convert("RGBA")
|
166 |
-
background = image2.filter(filter=ImageFilter.BoxBlur(30))
|
167 |
-
enhancer = ImageEnhance.Brightness(background)
|
168 |
-
background = enhancer.enhance(0.5)
|
169 |
-
draw = ImageDraw.Draw(background)
|
170 |
-
arial = ImageFont.truetype("DragMusic/assets/font2.ttf", 40)
|
171 |
-
font = ImageFont.truetype("DragMusic/assets/font.ttf", 30)
|
172 |
-
draw.text((1110, 8), unidecode(app.name), fill="white", font=arial)
|
173 |
-
draw.text(
|
174 |
-
(55, 560),
|
175 |
-
f"{channel} | {views[:23]}",
|
176 |
-
(255, 255, 255),
|
177 |
-
font=arial,
|
178 |
-
)
|
179 |
-
draw.text(
|
180 |
-
(57, 600),
|
181 |
-
clear(title),
|
182 |
-
(255, 255, 255),
|
183 |
-
font=font,
|
184 |
-
)
|
185 |
-
draw.line(
|
186 |
-
[(55, 660), (1220, 660)],
|
187 |
-
fill="white",
|
188 |
-
width=5,
|
189 |
-
joint="curve",
|
190 |
-
)
|
191 |
-
draw.ellipse(
|
192 |
-
[(918, 648), (942, 672)],
|
193 |
-
outline="white",
|
194 |
-
fill="white",
|
195 |
-
width=15,
|
196 |
-
)
|
197 |
-
draw.text(
|
198 |
-
(36, 685),
|
199 |
-
"00:00",
|
200 |
-
(255, 255, 255),
|
201 |
-
font=arial,
|
202 |
-
)
|
203 |
-
draw.text(
|
204 |
-
(1185, 685),
|
205 |
-
f"{duration[:23]}",
|
206 |
-
(255, 255, 255),
|
207 |
-
font=arial,
|
208 |
-
)
|
209 |
-
except Exception:
|
210 |
-
pass
|
211 |
-
circle = Image.open("DragMusic/assets/circle.png")
|
212 |
-
try:
|
213 |
-
pfp = Image.open(
|
214 |
-
await app.download_media(
|
215 |
-
(await app.get_chat(user_id)).photo.big_file_id,
|
216 |
-
file_name=f"pfp{user_id}.png",
|
217 |
-
)
|
218 |
-
)
|
219 |
-
except Exception:
|
220 |
-
pfp = Image.open("DragMusic/assets/profile.png")
|
221 |
-
pfp = pfp.resize((450, 450))
|
222 |
-
pfp = crop_center(pfp, 450, 450)
|
223 |
-
pfp = mask_circle_solid(pfp, (0, 0, 0, 0), 225)
|
224 |
-
|
225 |
-
#
|
226 |
-
image3 = Image.new("RGBA", (1280, 720))
|
227 |
-
image3.paste(background, (0, 0))
|
228 |
-
image3.paste(youtube, (200, 70), mask=youtube)
|
229 |
-
image3.paste(pfp, (410, 420), mask=pfp)
|
230 |
-
image3.paste(circle, (410, 420), mask=circle)
|
231 |
-
|
232 |
-
# Drawing with Impact Font
|
233 |
-
draw = ImageDraw.Draw(image3)
|
234 |
-
font = ImageFont.truetype("DragMusic/assets/font.ttf", 60)
|
235 |
-
font2 = ImageFont.truetype("DragMusic/assets/font2.ttf", 70)
|
236 |
-
arial = ImageFont.truetype("DragMusic/assets/font2.ttf", 40)
|
237 |
-
gfont = ImageFont.truetype("DragMusic/assets/font2.ttf", 40)
|
238 |
-
para = textwrap.wrap(title, width=32)
|
239 |
-
j = 0
|
240 |
-
try:
|
241 |
-
if para[0]:
|
242 |
-
draw.text(
|
243 |
-
(5, 5),
|
244 |
-
f"{para[0]}",
|
245 |
-
fill="white",
|
246 |
-
stroke_width=3,
|
247 |
-
stroke_fill="black",
|
248 |
-
font=font,
|
249 |
-
)
|
250 |
-
if para[1]:
|
251 |
-
draw.text(
|
252 |
-
(5, 70),
|
253 |
-
f"{para[1]}",
|
254 |
-
fill="white",
|
255 |
-
stroke_width=3,
|
256 |
-
stroke_fill="black",
|
257 |
-
font=font,
|
258 |
-
)
|
259 |
-
except:
|
260 |
-
pass
|
261 |
-
text_w, text_h = draw.textsize(f"Playing on: {ctitle}", font=gfont)
|
262 |
-
draw.text(
|
263 |
-
((1280 - text_w) / 2, 615),
|
264 |
-
f"Playing on: {ctitle}",
|
265 |
-
fill="white",
|
266 |
-
font=gfont,
|
267 |
-
)
|
268 |
-
draw.text((740, 480), "Duration:", fill="white", font=arial)
|
269 |
-
draw.text(
|
270 |
-
(915, 480),
|
271 |
-
f"{duration} Mins",
|
272 |
-
fill="white",
|
273 |
-
font=arial,
|
274 |
-
)
|
275 |
-
draw.text(
|
276 |
-
(740, 530),
|
277 |
-
f"Views : {views}",
|
278 |
-
(255, 255, 255),
|
279 |
-
font=arial,
|
280 |
-
)
|
281 |
-
|
282 |
-
try:
|
283 |
-
os.remove(f"/tmp/cache/thumb{videoid}.png")
|
284 |
-
except:
|
285 |
-
pass
|
286 |
-
background.save(f"/tmp/cache/{videoid}.png")
|
287 |
-
return f"/tmp/cache/{videoid}.png"
|
288 |
except Exception as e:
|
289 |
-
|
290 |
-
|
291 |
-
|
292 |
-
|
293 |
-
def crop_center(pil_img, crop_width, crop_height):
|
294 |
-
img_width, img_height = pil_img.size
|
295 |
-
return pil_img.crop(
|
296 |
-
(
|
297 |
-
(img_width - crop_width) // 2,
|
298 |
-
(img_height - crop_height) // 2,
|
299 |
-
(img_width + crop_width) // 2,
|
300 |
-
(img_height + crop_height) // 2,
|
301 |
-
)
|
302 |
-
)
|
303 |
-
|
304 |
-
|
305 |
-
def mask_circle_solid(im, a, size):
|
306 |
-
output = Image.new("RGBA", (size, size), (0, 0, 0, 0))
|
307 |
-
draw = ImageDraw.Draw(output)
|
308 |
-
draw.ellipse((0, 0, size, size), fill=a)
|
309 |
-
output.putalpha(220)
|
310 |
-
return output
|
311 |
-
|
312 |
-
|
313 |
-
async def crop_title(title):
|
314 |
-
if len(title) > 20:
|
315 |
-
return f"{title[:20]}..."
|
316 |
-
else:
|
317 |
-
return title
|
|
|
1 |
+
import random
|
2 |
+
import logging
|
3 |
import os
|
4 |
import re
|
|
|
|
|
5 |
import aiofiles
|
6 |
import aiohttp
|
7 |
from PIL import Image, ImageDraw, ImageEnhance, ImageFilter, ImageFont
|
|
|
8 |
from youtubesearchpython.__future__ import VideosSearch
|
9 |
|
10 |
+
logging.basicConfig(level=logging.INFO)
|
|
|
|
|
|
|
|
|
11 |
|
12 |
def changeImageSize(maxWidth, maxHeight, image):
|
13 |
widthRatio = maxWidth / image.size[0]
|
|
|
17 |
newImage = image.resize((newWidth, newHeight))
|
18 |
return newImage
|
19 |
|
20 |
+
def truncate(text):
|
|
|
21 |
list = text.split(" ")
|
22 |
+
text1 = ""
|
23 |
+
text2 = ""
|
24 |
for i in list:
|
25 |
+
if len(text1) + len(i) < 30:
|
26 |
+
text1 += " " + i
|
27 |
+
elif len(text2) + len(i) < 30:
|
28 |
+
text2 += " " + i
|
29 |
+
|
30 |
+
text1 = text1.strip()
|
31 |
+
text2 = text2.strip()
|
32 |
+
return [text1,text2]
|
33 |
+
|
34 |
+
def random_color():
|
35 |
+
return (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255))
|
36 |
+
|
37 |
+
def generate_gradient(width, height, start_color, end_color):
|
38 |
+
base = Image.new('RGBA', (width, height), start_color)
|
39 |
+
top = Image.new('RGBA', (width, height), end_color)
|
40 |
+
mask = Image.new('L', (width, height))
|
41 |
+
mask_data = []
|
42 |
+
for y in range(height):
|
43 |
+
mask_data.extend([int(60 * (y / height))] * width)
|
44 |
+
mask.putdata(mask_data)
|
45 |
+
base.paste(top, (0, 0), mask)
|
46 |
+
return base
|
47 |
+
|
48 |
+
def add_border(image, border_width, border_color):
|
49 |
+
width, height = image.size
|
50 |
+
new_width = width + 2 * border_width
|
51 |
+
new_height = height + 2 * border_width
|
52 |
+
new_image = Image.new("RGBA", (new_width, new_height), border_color)
|
53 |
+
new_image.paste(image, (border_width, border_width))
|
54 |
+
return new_image
|
55 |
+
|
56 |
+
def crop_center_circle(img, output_size, border, border_color, crop_scale=1.5):
|
57 |
+
half_the_width = img.size[0] / 2
|
58 |
+
half_the_height = img.size[1] / 2
|
59 |
+
larger_size = int(output_size * crop_scale)
|
60 |
+
img = img.crop(
|
61 |
+
(
|
62 |
+
half_the_width - larger_size/2,
|
63 |
+
half_the_height - larger_size/2,
|
64 |
+
half_the_width + larger_size/2,
|
65 |
+
half_the_height + larger_size/2
|
66 |
+
)
|
67 |
+
)
|
68 |
+
|
69 |
+
img = img.resize((output_size - 2*border, output_size - 2*border))
|
70 |
+
|
71 |
+
|
72 |
+
final_img = Image.new("RGBA", (output_size, output_size), border_color)
|
73 |
+
|
74 |
+
|
75 |
+
mask_main = Image.new("L", (output_size - 2*border, output_size - 2*border), 0)
|
76 |
+
draw_main = ImageDraw.Draw(mask_main)
|
77 |
+
draw_main.ellipse((0, 0, output_size - 2*border, output_size - 2*border), fill=255)
|
78 |
+
|
79 |
+
final_img.paste(img, (border, border), mask_main)
|
80 |
+
|
81 |
+
|
82 |
+
mask_border = Image.new("L", (output_size, output_size), 0)
|
83 |
+
draw_border = ImageDraw.Draw(mask_border)
|
84 |
+
draw_border.ellipse((0, 0, output_size, output_size), fill=255)
|
85 |
+
|
86 |
+
result = Image.composite(final_img, Image.new("RGBA", final_img.size, (0, 0, 0, 0)), mask_border)
|
87 |
+
|
88 |
+
return result
|
89 |
+
|
90 |
+
def draw_text_with_shadow(background, draw, position, text, font, fill, shadow_offset=(3, 3), shadow_blur=5):
|
91 |
+
|
92 |
+
shadow = Image.new('RGBA', background.size, (0, 0, 0, 0))
|
93 |
+
shadow_draw = ImageDraw.Draw(shadow)
|
94 |
+
|
95 |
+
|
96 |
+
shadow_draw.text(position, text, font=font, fill="black")
|
97 |
+
|
98 |
+
|
99 |
+
shadow = shadow.filter(ImageFilter.GaussianBlur(radius=shadow_blur))
|
100 |
+
|
101 |
+
|
102 |
+
background.paste(shadow, shadow_offset, shadow)
|
103 |
+
|
104 |
+
|
105 |
+
draw.text(position, text, font=font, fill=fill)
|
106 |
+
|
107 |
+
async def gen_thumb(videoid: str):
|
108 |
try:
|
109 |
+
if os.path.isfile(f"cache/{videoid}_v4.png"):
|
110 |
+
return f"cache/{videoid}_v4.png"
|
111 |
+
|
112 |
+
url = f"https://www.youtube.com/watch?v={videoid}"
|
113 |
results = VideosSearch(url, limit=1)
|
114 |
for result in (await results.next())["result"]:
|
115 |
+
title = result.get("title")
|
116 |
+
if title:
|
117 |
+
title = re.sub("\W+", " ", title).title()
|
118 |
+
else:
|
|
|
119 |
title = "Unsupported Title"
|
120 |
+
duration = result.get("duration")
|
121 |
+
if not duration:
|
122 |
+
duration = "Live"
|
123 |
+
thumbnail_data = result.get("thumbnails")
|
124 |
+
if thumbnail_data:
|
125 |
+
thumbnail = thumbnail_data[0]["url"].split("?")[0]
|
126 |
+
else:
|
127 |
+
thumbnail = None
|
128 |
+
views_data = result.get("viewCount")
|
129 |
+
if views_data:
|
130 |
+
views = views_data.get("short")
|
131 |
+
if not views:
|
132 |
+
views = "Unknown Views"
|
133 |
+
else:
|
134 |
views = "Unknown Views"
|
135 |
+
channel_data = result.get("channel")
|
136 |
+
if channel_data:
|
137 |
+
channel = channel_data.get("name")
|
138 |
+
if not channel:
|
139 |
+
channel = "Unknown Channel"
|
140 |
+
else:
|
141 |
channel = "Unknown Channel"
|
142 |
|
143 |
+
|
144 |
async with aiohttp.ClientSession() as session:
|
145 |
async with session.get(thumbnail) as resp:
|
146 |
+
|
147 |
+
content = await resp.read()
|
148 |
if resp.status == 200:
|
149 |
+
content_type = resp.headers.get('Content-Type')
|
150 |
+
if 'jpeg' in content_type or 'jpg' in content_type:
|
151 |
+
extension = 'jpg'
|
152 |
+
elif 'png' in content_type:
|
153 |
+
extension = 'png'
|
154 |
+
else:
|
155 |
+
logging.error(f"Unexpected content type: {content_type}")
|
156 |
+
return None
|
157 |
+
|
158 |
+
filepath = f"cache/thumb{videoid}.png"
|
159 |
+
f = await aiofiles.open(filepath, mode="wb")
|
160 |
await f.write(await resp.read())
|
161 |
await f.close()
|
162 |
+
# os.system(f"file {filepath}")
|
163 |
+
|
164 |
+
|
165 |
+
image_path = f"cache/thumb{videoid}.png"
|
166 |
+
youtube = Image.open(image_path)
|
167 |
image1 = changeImageSize(1280, 720, youtube)
|
168 |
+
|
169 |
image2 = image1.convert("RGBA")
|
170 |
+
background = image2.filter(filter=ImageFilter.BoxBlur(20))
|
171 |
enhancer = ImageEnhance.Brightness(background)
|
172 |
+
background = enhancer.enhance(0.6)
|
173 |
+
|
174 |
+
|
175 |
+
start_gradient_color = random_color()
|
176 |
+
end_gradient_color = random_color()
|
177 |
+
gradient_image = generate_gradient(1280, 720, start_gradient_color, end_gradient_color)
|
178 |
+
background = Image.blend(background, gradient_image, alpha=0.2)
|
179 |
+
|
180 |
draw = ImageDraw.Draw(background)
|
181 |
arial = ImageFont.truetype("DragMusic/assets/font2.ttf", 30)
|
182 |
font = ImageFont.truetype("DragMusic/assets/font.ttf", 30)
|
183 |
+
title_font = ImageFont.truetype("DragMusic/assets/font3.ttf", 45)
|
184 |
+
|
185 |
+
|
186 |
+
circle_thumbnail = crop_center_circle(youtube, 400, 20, start_gradient_color)
|
187 |
+
circle_thumbnail = circle_thumbnail.resize((400, 400))
|
188 |
+
circle_position = (120, 160)
|
189 |
+
background.paste(circle_thumbnail, circle_position, circle_thumbnail)
|
190 |
+
|
191 |
+
text_x_position = 565
|
192 |
+
title1 = truncate(title)
|
193 |
+
draw_text_with_shadow(background, draw, (text_x_position, 180), title1[0], title_font, (255, 255, 255))
|
194 |
+
draw_text_with_shadow(background, draw, (text_x_position, 230), title1[1], title_font, (255, 255, 255))
|
195 |
+
draw_text_with_shadow(background, draw, (text_x_position, 320), f"{channel} | {views[:23]}", arial, (255, 255, 255))
|
196 |
+
|
197 |
+
|
198 |
+
line_length = 580
|
199 |
+
line_color = (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255))
|
200 |
+
|
201 |
+
if duration != "Live":
|
202 |
+
color_line_percentage = random.uniform(0.15, 0.85)
|
203 |
+
color_line_length = int(line_length * color_line_percentage)
|
204 |
+
white_line_length = line_length - color_line_length
|
205 |
+
|
206 |
+
start_point_color = (text_x_position, 380)
|
207 |
+
end_point_color = (text_x_position + color_line_length, 380)
|
208 |
+
draw.line([start_point_color, end_point_color], fill=line_color, width=9)
|
209 |
+
|
210 |
+
start_point_white = (text_x_position + color_line_length, 380)
|
211 |
+
end_point_white = (text_x_position + line_length, 380)
|
212 |
+
draw.line([start_point_white, end_point_white], fill="white", width=8)
|
213 |
+
|
214 |
+
circle_radius = 10
|
215 |
+
circle_position = (end_point_color[0], end_point_color[1])
|
216 |
+
draw.ellipse([circle_position[0] - circle_radius, circle_position[1] - circle_radius,
|
217 |
+
circle_position[0] + circle_radius, circle_position[1] + circle_radius], fill=line_color)
|
218 |
+
|
219 |
+
else:
|
220 |
+
line_color = (255, 0, 0)
|
221 |
+
start_point_color = (text_x_position, 380)
|
222 |
+
end_point_color = (text_x_position + line_length, 380)
|
223 |
+
draw.line([start_point_color, end_point_color], fill=line_color, width=9)
|
224 |
+
|
225 |
+
circle_radius = 10
|
226 |
+
circle_position = (end_point_color[0], end_point_color[1])
|
227 |
+
draw.ellipse([circle_position[0] - circle_radius, circle_position[1] - circle_radius,
|
228 |
+
circle_position[0] + circle_radius, circle_position[1] + circle_radius], fill=line_color)
|
229 |
+
|
230 |
+
draw_text_with_shadow(background, draw, (text_x_position, 400), "00:00", arial, (255, 255, 255))
|
231 |
+
draw_text_with_shadow(background, draw, (1080, 400), duration, arial, (255, 255, 255))
|
232 |
+
|
233 |
+
play_icons = Image.open("DragMusic/assets/play_icons.png")
|
234 |
+
play_icons = play_icons.resize((580, 62))
|
235 |
+
background.paste(play_icons, (text_x_position, 450), play_icons)
|
236 |
+
|
237 |
+
os.remove(f"cache/thumb{videoid}.png")
|
238 |
+
|
239 |
+
background_path = f"cache/{videoid}_v4.png"
|
240 |
+
background.save(background_path)
|
241 |
+
|
242 |
+
return background_path
|
243 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
244 |
except Exception as e:
|
245 |
+
logging.error(f"Error generating thumbnail for video {videoid}: {e}")
|
246 |
+
traceback.print_exc()
|
247 |
+
return None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|