YouTube support.
[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(blank=True)
22     intro_card_duration = models.FloatField(null=True, blank=True)
23     card = models.FileField(blank=True)
24     loop_video = models.FileField(blank=True)
25     outro_card = models.FileField(blank=True)
26     outro_card_duration = models.FloatField(null=True, blank=True)
27
28     class Meta:
29         verbose_name = _("YouTube configuration")
30         verbose_name_plural = _("YouTube configurations")
31
32     def publish(self, audiobook, path):
33         ctx = Context(dict(audiobook=audiobook))
34         description = Template(self.description_template).render(ctx)
35         title = Template(self.title_template).render(ctx)
36         privacy = 'private'
37
38         data = dict(
39             snippet=dict(
40                 title=title,
41                 description=description,
42                 # tags=tags,
43                 # categoryId=category,
44                 # defaultLanguage
45             ),
46             status=dict(
47                 privacyStatus=privacy,
48                 # license
49                 # selfDeclaredMadeForKids
50             ),
51             # recordingDetails=dict(
52             # recordingDate
53             # ),
54         )
55         part = ",".join(data.keys())
56
57         with open(path, "rb") as f:
58             response = youtube_call(
59                 "POST",
60                 "https://www.googleapis.com/upload/youtube/v3/videos",
61                 params={'part': part},
62                 data=data,
63                 media_data=f.read(),
64             )
65         data = response.json()
66         audiobook.youtube_id = data['id']
67         audiobook.save(update_fields=['youtube_id'])
68         return response
69
70     def prepare_file(self, input_path, output_path=None):
71         duration = get_duration(input_path)
72         video = self.prepare_video(duration)
73         output = mux([video, input_path], output_path=output_path)
74         unlink(video)
75         return output
76
77     def prepare_video(self, duration):
78         concat = []
79         delete = []
80
81         if self.loop_video:
82             fps = get_framerate(self.loop_video.path)
83         else:
84             fps = 25
85
86         loop_duration = duration
87         if self.intro_card and self.intro_card_duration:
88             loop_duration -= self.intro_card_duration
89             intro = video_from_image(
90                 self.intro_card.path, self.intro_card_duration, fps=fps
91             )
92             concat.append(intro)
93             delete.append(intro)
94
95         if self.outro_card and self.outro_card_duration:
96             loop_duration -= self.outro_card_duration
97             outro = video_from_image(
98                 self.outro_card.path, self.outro_card_duration, fps=fps
99             )
100             concat.append(outro)
101             delete.append(outro)
102
103         if self.loop_video:
104             loop_video_duration = get_duration(self.loop_video.path)
105             times_loop = int(loop_duration // loop_video_duration)
106
107             leftover_duration = loop_duration % loop_video_duration
108             leftover = cut_video(self.loop_video.path, leftover_duration)
109             concat[1:1] = [self.loop_video.path] * times_loop + [leftover]
110             delete.append(leftover)
111         else:
112             leftover = video_from_image(self.card.path, loop_duration)
113             concat.insert(1, video_from_image(self.card.path, loop_duration, fps=fps))
114             delete.append(leftover)
115
116         output = concat_videos(concat)
117         for p in delete:
118             unlink(p)
119         return output
120
121     # tags
122     # license
123     # selfDeclaredMadeForKids