• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

EsupPortail / Esup-Pod / 13964928276

20 Mar 2025 08:26AM UTC coverage: 70.106%. First build
13964928276

Pull #1280

github

web-flow
Merge a06fb2670 into 749de494a
Pull Request #1280: Replace credit_videofile by credit_video_dir

83 of 105 new or added lines in 12 files covered. (79.05%)

11984 of 17094 relevant lines covered (70.11%)

0.7 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

70.9
/pod/video_encode_transcript/encode.py
1
"""Esup-Pod module to handle video encoding with CPU."""
2

3
from django.conf import settings
1✔
4
from webpush.models import PushInformation
1✔
5

6
from pod.video.models import Video
1✔
7
from .Encoding_video_model import Encoding_video_model
1✔
8
from .encoding_studio import start_encode_video_studio
1✔
9
from .models import EncodingLog
1✔
10

11
from pod.cut.models import CutVideo
1✔
12
from pod.dressing.models import Dressing
1✔
13
from pod.dressing.utils import get_dressing_input
1✔
14
from pod.main.tasks import task_start_encode, task_start_encode_studio
1✔
15
from pod.recorder.models import Recording
1✔
16
from .encoding_settings import FFMPEG_DRESSING_INPUT
1✔
17
from .utils import (
1✔
18
    change_encoding_step,
19
    check_file,
20
    add_encoding_log,
21
    send_email,
22
    send_email_encoding,
23
    send_email_recording,
24
    send_notification_encoding,
25
    time_to_seconds,
26
)
27
import logging
1✔
28
import time
1✔
29
import threading
1✔
30

31
__license__ = "LGPL v3"
1✔
32
log = logging.getLogger(__name__)
1✔
33

34
USE_TRANSCRIPTION = getattr(settings, "USE_TRANSCRIPTION", False)
1✔
35
USE_NOTIFICATIONS = getattr(settings, "USE_NOTIFICATIONS", False)
1✔
36
if USE_TRANSCRIPTION:
1✔
37
    from . import transcript
1✔
38

39
    TRANSCRIPT_VIDEO = getattr(settings, "TRANSCRIPT_VIDEO", "start_transcript")
1✔
40

41
CELERY_TO_ENCODE = getattr(settings, "CELERY_TO_ENCODE", False)
1✔
42
EMAIL_ON_ENCODING_COMPLETION = getattr(settings, "EMAIL_ON_ENCODING_COMPLETION", True)
1✔
43

44
USE_REMOTE_ENCODING_TRANSCODING = getattr(
1✔
45
    settings, "USE_REMOTE_ENCODING_TRANSCODING", False
46
)
47
if USE_REMOTE_ENCODING_TRANSCODING:
1✔
48
    from .encoding_tasks import start_encoding_task
1✔
49
    from .encoding_tasks import start_studio_task
1✔
50

51
FFMPEG_DRESSING_INPUT = getattr(settings, "FFMPEG_DRESSING_INPUT", FFMPEG_DRESSING_INPUT)
1✔
52

53
# ##########################################################################
54
# ENCODE VIDEO: THREAD TO LAUNCH ENCODE
55
# ##########################################################################
56

57
# Disable for the moment, will be reactivated in future version
58

59

60
def start_encode(video_id: int, threaded=True) -> None:
1✔
61
    """Start video encoding."""
62
    if threaded:
1✔
63
        if CELERY_TO_ENCODE:
1✔
64
            task_start_encode.delay(video_id)
×
65
        else:
66
            log.info("START ENCODE VIDEO ID %s" % video_id)
1✔
67
            t = threading.Thread(target=encode_video, args=[video_id])
1✔
68
            t.daemon = True
1✔
69
            t.start()
1✔
70
    else:
71
        encode_video(video_id)
1✔
72

73

74
def start_encode_studio(
1✔
75
    recording_id, video_output, videos, subtime, presenter, threaded=True
76
) -> None:
77
    """Start studio encoding."""
78
    if threaded:
×
79
        if CELERY_TO_ENCODE:
×
80
            task_start_encode_studio.delay(
×
81
                recording_id, video_output, videos, subtime, presenter
82
            )
83
        else:
84
            log.info("START ENCODE VIDEO ID %s" % recording_id)
×
85
            t = threading.Thread(
×
86
                target=encode_video_studio,
87
                args=[recording_id, video_output, videos, subtime, presenter],
88
            )
89
            t.daemon = True
×
90
            t.start()
×
91
    else:
92
        encode_video_studio(recording_id, video_output, videos, subtime, presenter)
×
93

94

95
def encode_video_studio(recording_id, video_output, videos, subtime, presenter) -> None:
1✔
96
    """ENCODE STUDIO: MAIN FUNCTION."""
97
    msg = ""
×
98
    if USE_REMOTE_ENCODING_TRANSCODING:
×
99
        start_studio_task.delay(recording_id, video_output, videos, subtime, presenter)
×
100
    else:
101
        msg = start_encode_video_studio(video_output, videos, subtime, presenter)
×
102
        store_encoding_studio_info(recording_id, video_output, msg)
×
103

104

105
def store_encoding_studio_info(recording_id, video_output, msg) -> None:
1✔
106
    recording = Recording.objects.get(id=recording_id)
×
107
    recording.comment += msg
×
108
    recording.save()
×
109
    if check_file(video_output):
×
110
        from pod.recorder.plugins.type_studio import save_basic_video
×
111

112
        video = save_basic_video(recording, video_output)
×
113
        encode_video(video.id)
×
114
    else:
115
        msg = "Wrong file or path:\n%s" % video_output
×
116
        send_email_recording(msg, recording_id)
×
117

118

119
def encode_video(video_id: int) -> None:
1✔
120
    """ENCODE VIDEO: MAIN FUNCTION."""
121
    start = "Start at: %s" % time.ctime()
1✔
122

123
    video_to_encode = Video.objects.get(id=video_id)
1✔
124
    video_to_encode.encoding_in_progress = True
1✔
125
    video_to_encode.save()
1✔
126

127
    if not check_file(video_to_encode.video.path):
1✔
128
        msg = "Wrong file or path:\n%s" % video_to_encode.video.path
1✔
129
        add_encoding_log(video_id, msg)
1✔
130
        change_encoding_step(video_id, -1, msg)
1✔
131
        send_email(msg, video_id)
1✔
132
        return
1✔
133

134
    change_encoding_step(video_id, 0, "start")
1✔
135
    # start and stop cut?
136
    encoding_video = get_encoding_video(video_to_encode)
1✔
137
    encoding_video.add_encoding_log("start_time", "", True, start)
1✔
138
    change_encoding_step(video_id, 1, "remove old data")
1✔
139
    encoding_video.remove_old_data()
1✔
140

141
    if USE_REMOTE_ENCODING_TRANSCODING:
1✔
142
        change_encoding_step(video_id, 2, "start remote encoding")
1✔
143
        dressing = None
1✔
144
        dressing_input = ""
1✔
145
        if Dressing.objects.filter(videos=video_to_encode).exists():
1✔
146
            dressing = Dressing.objects.get(videos=video_to_encode)
×
147
            if dressing:
×
148
                dressing_input = get_dressing_input(dressing, FFMPEG_DRESSING_INPUT)
×
149
        start_encoding_task.delay(
1✔
150
            encoding_video.id,
151
            encoding_video.video_file,
152
            encoding_video.cutting_start,
153
            encoding_video.cutting_stop,
154
            json_dressing=dressing.to_json() if dressing else None,
155
            dressing_input=dressing_input,
156
        )
157
    else:
158
        change_encoding_step(video_id, 2, "start standard encoding")
1✔
159
        encoding_video.start_encode()
1✔
160
        final_video = store_encoding_info(video_id, encoding_video)
1✔
161

162
        if encoding_video.error_encoding:
1✔
163
            enc_log, created = EncodingLog.objects.get_or_create(video=final_video)
×
164
            msg = "Error during video `%s` encoding." % video_id
×
165
            if created is False:
×
166
                msg += " See log at:\n%s" % enc_log.logfile.url
×
NEW
167
            change_encoding_step(video_id, -1, msg)
×
168
            send_email(msg, video_id)
×
169
        else:
170
            end_of_encoding(final_video)
1✔
171

172

173
def store_encoding_info(video_id: int, encoding_video: Encoding_video_model) -> Video:
1✔
174
    """Store all encoding file and informations from encoding tasks."""
175
    change_encoding_step(video_id, 3, "store encoding info")
1✔
176
    final_video = encoding_video.store_json_info()
1✔
177
    final_video.is_video = final_video.get_video_m4a() is None
1✔
178
    final_video.encoding_in_progress = False
1✔
179
    final_video.save()
1✔
180
    return final_video
1✔
181

182

183
def get_encoding_video(video_to_encode: Video) -> Encoding_video_model:
1✔
184
    """Get the encoding video object from video."""
185
    dressing = None
1✔
186
    dressing_input = ""
1✔
187
    if Dressing.objects.filter(videos=video_to_encode).exists():
1✔
188
        dressing = Dressing.objects.get(videos=video_to_encode)
×
189
        if dressing:
×
190
            dressing_input = get_dressing_input(dressing, FFMPEG_DRESSING_INPUT)
×
191

192
    if CutVideo.objects.filter(video=video_to_encode).exists():
1✔
193
        cut = CutVideo.objects.get(video=video_to_encode)
1✔
194
        cut_start = time_to_seconds(cut.start)
1✔
195
        cut_end = time_to_seconds(cut.end)
1✔
196
        encoding_video = Encoding_video_model(
1✔
197
            video_to_encode.id,
198
            video_to_encode.video.path,
199
            cut_start,
200
            cut_end,
201
            json_dressing=dressing.to_json() if dressing else None,
202
            dressing_input=dressing_input,
203
        )
204
        return encoding_video
1✔
205

206
    return Encoding_video_model(
1✔
207
        video_to_encode.id,
208
        video_to_encode.video.path,
209
        0,
210
        0,
211
        json_dressing=dressing.to_json() if dressing else None,
212
        dressing_input=dressing_input,
213
    )
214

215

216
def end_of_encoding(video: Video) -> None:
1✔
217
    """Notify user at the end of encoding & call transcription."""
218
    if (
1✔
219
        USE_NOTIFICATIONS
220
        and video.owner.owner.accepts_notifications
221
        and PushInformation.objects.filter(user=video.owner).exists()
222
    ):
223
        send_notification_encoding(video)
×
224
    if EMAIL_ON_ENCODING_COMPLETION:
1✔
225
        send_email_encoding(video)
1✔
226

227
    transcript_video(video.id)
1✔
228
    change_encoding_step(video.id, 0, "end of encoding")
1✔
229

230

231
def transcript_video(video_id: int) -> None:
1✔
232
    """Transcript video audio to text."""
233
    video = Video.objects.get(id=video_id)
1✔
234
    if USE_TRANSCRIPTION and video.transcript not in ["", "0", "1"]:
1✔
235
        change_encoding_step(video_id, 4, "transcript video")
×
236
        start_transcript_video = getattr(transcript, TRANSCRIPT_VIDEO)
×
237
        start_transcript_video(video_id, False)
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc