+import io
from os import unlink
from tempfile import NamedTemporaryFile
from django.db import models
get_framerate,
mux,
)
+from .thumbnail import create_thumbnail
class YouTube(models.Model):
data = response.json()
audiobook.youtube_id = data['id']
audiobook.save(update_fields=['youtube_id'])
+
+ self.update_thumbnail(audiobook)
return response
def prepare_file(self, input_path, output_path=None):
# license
# selfDeclaredMadeForKids
+ def update_thumbnail(self, audiobook):
+ thumbnail = self.prepare_thumbnail(audiobook)
+ response = youtube_call(
+ "POST",
+ "https://www.googleapis.com/upload/youtube/v3/thumbnails/set",
+ params={'videoId': audiobook.youtube_id},
+ media_data=buf.read(), # Or just data?
+ )
+
+ def prepare_thumbnail(self, audiobook):
+ img = create_thumbnail(
+ self.thumbnail_template.path,
+ self.thumbnail_definition,
+ {}, # TODO proper context
+ lambda name: Font.objects.get(name=name).truetype.path
+ )
+ buf = io.BytesIO()
+ img.save(buf, format='PNG')
+ return buf
+
class Card(models.Model):
youtube = models.ForeignKey(YouTube, models.CASCADE)
class Meta:
ordering = ('order', )
+
+
+class Font(models.Model):
+ name = models.CharField(max_length=255, unique=True)
+ truetype = models.FileField(upload_to='youtube/font')
+
+ def __str__(self):
+ return self.name
--- /dev/null
+import yaml
+from PIL import Image, ImageDraw, ImageFont
+
+
+def drawbox(img, d, context, get_font_path):
+ for version in d['versions']:
+ if draw_version(img, version, context, get_font_path):
+ break
+
+
+def split_to_lines(text, draw, font, max_width):
+ words = text.split()
+ current = ''
+ while words:
+ new_words = []
+ new_words.append(words.pop(0))
+ while len(new_words[-1]) == 1 and words:
+ new_words.append(words.pop(0))
+ new_words = ' '.join(new_words)
+ new_line = ' '.join([current, new_words]).strip()
+ width = draw.textsize(new_line, font=font)[0]
+ if width > max_width:
+ yield current
+ current = new_words
+ else:
+ current = new_line
+ if current:
+ yield current
+
+
+def draw_version(img, d, context, get_font_path):
+ # todo: do this in a subimg
+ newimg = Image.new(
+ 'RGBA',
+ (
+ img.size[0] - d.get('x', 0),
+ d.get('max-height', img.size[1] - d.get('y', 0)),
+ )
+ )
+
+ draw = ImageDraw.Draw(newimg)
+ cursor = 0
+ for item in d['items']:
+ if item.get('vskip'):
+ cursor += item['vskip']
+ text = item['text'].format(**context)
+ if item.get('uppercase'):
+ text = text.upper()
+ font = ImageFont.truetype(get_font_path(item['font-family']), item['font-size'])
+ max_width = item.get('max-width', newimg.size[0])
+
+ for line in split_to_lines(text, draw, font, max_width):
+ realheight = draw.textsize(line, font=font)[1]
+ if cursor + realheight > newimg.size[1]:
+ return False
+ print('x', draw.text((0, cursor), line, font=font, fill=item.get('color')))
+ cursor += item['line-height']
+
+ img.paste(newimg, (d.get('x', 0), d.get('y', 0)), newimg)
+ return True
+
+
+def create_thumbnail(background_path, defn, context, get_font_path):
+ img = Image.open(background_path)
+ d = yaml.load(defn)
+ for boxdef in d['boxes']:
+ drawbox(img, boxdef, context, get_font_path)
+ return img