985723346f87a3e9b6db1f65ef27544097bd3ed1
[audio.git] / src / youtube / models.py
1 from os import unlink
2 from tempfile import NamedTemporaryFile
3 from django.db import models
4 from django.utils.translation import gettext_lazy as _
5 from django.template import Template, Context
6 from apiclient import youtube_call
7 from .utils import (
8     video_from_image,
9     cut_video,
10     concat_videos,
11     get_duration,
12     get_framerate,
13     mux,
14 )
15
16
17 class YouTube(models.Model):
18     title_template = models.CharField(max_length=1024, blank=True)
19     description_template = models.TextField(blank=True)
20     category = models.IntegerField(null=True, blank=True)  # get categories
21     intro_card = models.FileField(upload_to='youtube/intro_card', blank=True)
22     intro_card_duration = models.FloatField(null=True, blank=True)
23     card = models.FileField(upload_to='youtube/card', blank=True)
24     loop_video = models.FileField(upload_to='youtube/loop_video', blank=True)
25     outro_card = models.FileField(upload_to='youtube/outro_card', blank=True)
26     outro_card_duration = models.FloatField(null=True, blank=True)
27     thumbnail_template = models.FileField(upload_to='youtube/thumbnail', blank=True)
28     genres = models.CharField(max_length=2048, blank=True)
29
30     class Meta:
31         verbose_name = _("YouTube configuration")
32         verbose_name_plural = _("YouTube configurations")
33
34     def publish(self, audiobook, path):
35         ctx = Context(dict(audiobook=audiobook))
36         description = Template(self.description_template).render(ctx)
37         title = Template(self.title_template).render(ctx)
38         privacy = 'private'
39
40         data = dict(
41             snippet=dict(
42                 title=title,
43                 description=description,
44                 # tags=tags,
45                 # categoryId=category,
46                 # defaultLanguage
47             ),
48             status=dict(
49                 privacyStatus=privacy,
50                 # license
51                 # selfDeclaredMadeForKids
52             ),
53             # recordingDetails=dict(
54             # recordingDate
55             # ),
56         )
57         part = ",".join(data.keys())
58
59         with open(path, "rb") as f:
60             response = youtube_call(
61                 "POST",
62                 "https://www.googleapis.com/upload/youtube/v3/videos",
63                 params={'part': part},
64                 data=data,
65                 media_data=f.read(),
66             )
67         data = response.json()
68         audiobook.youtube_id = data['id']
69         audiobook.save(update_fields=['youtube_id'])
70         return response
71
72     def prepare_file(self, input_path, output_path=None):
73         duration = get_duration(input_path)
74         video = self.prepare_video(duration)
75         output = mux([video, input_path], output_path=output_path)
76         unlink(video)
77         return output
78
79     def prepare_video(self, duration):
80         concat = []
81         delete = []
82
83         if self.loop_video:
84             fps = get_framerate(self.loop_video.path)
85         else:
86             fps = 25
87
88         loop_duration = duration
89         if self.intro_card and self.intro_card_duration:
90             loop_duration -= self.intro_card_duration
91             intro = video_from_image(
92                 self.intro_card.path, self.intro_card_duration, fps=fps
93             )
94             concat.append(intro)
95             delete.append(intro)
96
97         if self.outro_card and self.outro_card_duration:
98             loop_duration -= self.outro_card_duration
99             outro = video_from_image(
100                 self.outro_card.path, self.outro_card_duration, fps=fps
101             )
102             concat.append(outro)
103             delete.append(outro)
104
105         if self.loop_video:
106             loop_video_duration = get_duration(self.loop_video.path)
107             times_loop = int(loop_duration // loop_video_duration)
108
109             leftover_duration = loop_duration % loop_video_duration
110             leftover = cut_video(self.loop_video.path, leftover_duration)
111             concat[1:1] = [self.loop_video.path] * times_loop + [leftover]
112             delete.append(leftover)
113         else:
114             leftover = video_from_image(self.card.path, loop_duration)
115             concat.insert(1, video_from_image(self.card.path, loop_duration, fps=fps))
116             delete.append(leftover)
117
118         output = concat_videos(concat)
119         for p in delete:
120             unlink(p)
121         return output
122
123     # tags
124     # license
125     # selfDeclaredMadeForKids