taslim19 commited on
Commit
b8b8b54
·
1 Parent(s): 90dc4ea

changed thumbnails.py

Browse files
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
- from DragMusic import app
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
- title = ""
 
29
  for i in list:
30
- if len(title) + len(i) < 60:
31
- title += " " + i
32
- return title.strip()
33
-
34
-
35
- async def get_thumb(videoid):
36
- if os.path.isfile(f"/tmp/cache/{videoid}.png"):
37
- return f"/tmp/cache/{videoid}.png"
38
-
39
- url = f"https://www.youtube.com/watch?v={videoid}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
40
  try:
 
 
 
 
41
  results = VideosSearch(url, limit=1)
42
  for result in (await results.next())["result"]:
43
- try:
44
- title = result["title"]
45
- title = re.sub("\\W+", " ", title)
46
- title = title.title()
47
- except:
48
  title = "Unsupported Title"
49
- try:
50
- duration = result["duration"]
51
- except:
52
- duration = "Unknown Mins"
53
- thumbnail = result["thumbnails"][0]["url"].split("?")[0]
54
- try:
55
- views = result["viewCount"]["short"]
56
- except:
 
 
 
 
 
 
57
  views = "Unknown Views"
58
- try:
59
- channel = result["channel"]["name"]
60
- except:
 
 
 
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
- f = await aiofiles.open(f"/tmp/cache/thumb{videoid}.png", mode="wb")
 
 
 
 
 
 
 
 
 
 
67
  await f.write(await resp.read())
68
  await f.close()
69
-
70
- youtube = Image.open(f"/tmp/cache/thumb{videoid}.png")
 
 
 
71
  image1 = changeImageSize(1280, 720, youtube)
 
72
  image2 = image1.convert("RGBA")
73
- background = image2.filter(filter=ImageFilter.BoxBlur(10))
74
  enhancer = ImageEnhance.Brightness(background)
75
- background = enhancer.enhance(0.5)
 
 
 
 
 
 
 
76
  draw = ImageDraw.Draw(background)
77
  arial = ImageFont.truetype("DragMusic/assets/font2.ttf", 30)
78
  font = ImageFont.truetype("DragMusic/assets/font.ttf", 30)
79
- draw.text((1110, 8), unidecode(app.name), fill="white", font=arial)
80
- draw.text(
81
- (55, 560),
82
- f"{channel} | {views[:23]}",
83
- (255, 255, 255),
84
- font=arial,
85
- )
86
- draw.text(
87
- (57, 600),
88
- clear(title),
89
- (255, 255, 255),
90
- font=font,
91
- )
92
- draw.line(
93
- [(55, 660), (1220, 660)],
94
- fill="white",
95
- width=5,
96
- joint="curve",
97
- )
98
- draw.ellipse(
99
- [(918, 648), (942, 672)],
100
- outline="white",
101
- fill="white",
102
- width=15,
103
- )
104
- draw.text(
105
- (36, 685),
106
- "00:00",
107
- (255, 255, 255),
108
- font=arial,
109
- )
110
- draw.text(
111
- (1185, 685),
112
- f"{duration[:23]}",
113
- (255, 255, 255),
114
- font=arial,
115
- )
116
- try:
117
- os.remove(f"/tmp/cache/thumb{videoid}.png")
118
- except:
119
- pass
120
- background.save(f"/tmp/cache/{videoid}.png")
121
- return f"/tmp/cache/{videoid}.png"
122
- except Exception as e:
123
- print(e)
124
- return YOUTUBE_IMG_URL
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
- LOGGER(__name__).error(e)
290
- return ""
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