Skip to content

Commit 7e2575f

Browse files
feature: add chapters and task for chapter frames
1 parent 262c8c9 commit 7e2575f

10 files changed

Lines changed: 1271 additions & 190 deletions

File tree

cds/modules/deposit/api.py

Lines changed: 84 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@
6565
get_tasks_status_grouped_by_task_name,
6666
merge_tasks_status,
6767
)
68+
from ..flows.tasks import ExtractChapterFramesTask
6869
from ..flows.models import FlowMetadata
6970
from ..invenio_deposit.api import Deposit, has_status, preserve
7071
from ..invenio_deposit.utils import mark_as_action
@@ -76,7 +77,7 @@
7677
)
7778
from ..records.minters import cds_doi_generator, is_local_doi, report_number_minter
7879
from ..records.resolver import record_resolver
79-
from ..records.utils import is_record, lowercase_value
80+
from ..records.utils import is_record, lowercase_value, parse_video_chapters
8081
from ..records.validators import PartialDraft4Validator
8182
from ..records.permissions import is_public
8283
from .errors import DiscardConflict
@@ -504,7 +505,7 @@ def create(cls, data, id_=None, **kwargs):
504505
data.setdefault("_access", {})
505506
access_update = data["_access"].setdefault("update", [])
506507
try:
507-
if current_user.email not in access_update:
508+
if current_user.email not in access_update:
508509
# Add the current user to the ``_access.update`` list
509510
access_update.append(current_user.email)
510511
except AttributeError:
@@ -905,11 +906,84 @@ def _publish_edited(self):
905906

906907
return super(Video, self)._publish_edited()
907908

909+
def _has_chapters_changed(self, old_record=None):
910+
"""Check if chapters in description have changed."""
911+
current_description = self.get("description", "")
912+
current_chapters = parse_video_chapters(current_description)
913+
914+
if old_record is None:
915+
# First publish - trigger if chapters exist
916+
return len(current_chapters) > 0
917+
918+
old_description = old_record.get("description", "")
919+
old_chapters = parse_video_chapters(old_description)
920+
921+
# Compare chapter timestamps and titles
922+
if len(current_chapters) != len(old_chapters):
923+
return True
924+
925+
for curr, old in zip(current_chapters, old_chapters):
926+
if curr["seconds"] != old["seconds"] or curr["title"] != old["title"]:
927+
return True
928+
929+
return False
930+
931+
def _trigger_chapter_frame_extraction(self):
932+
"""Trigger chapter frame extraction asynchronously for existing video files."""
933+
try:
934+
# Find the master video file
935+
master_file = CDSVideosFilesIterator.get_master_video_file(self)
936+
937+
if master_file is None:
938+
current_app.logger.warning(
939+
f"No master video file found for video {self.id}"
940+
)
941+
return
942+
943+
# Get the current flow for this deposit
944+
current_flow = FlowMetadata.get_by_deposit(self["_deposit"]["id"])
945+
946+
if current_flow is None:
947+
current_app.logger.warning(
948+
f"No current flow found for video {self.id}. Cannot trigger chapter frame extraction."
949+
)
950+
return
951+
952+
current_app.logger.info(
953+
f"Triggering asynchronous ExtractChapterFramesTask for video {self.id} with flow {current_flow.id}"
954+
)
955+
956+
payload = current_flow.payload.copy()
957+
958+
current_app.logger.info(f"Submitting ExtractChapterFramesTask with payload: {payload}")
959+
960+
ExtractChapterFramesTask().s(**payload).apply_async()
961+
962+
current_app.logger.info(
963+
f"ExtractChapterFramesTask submitted asynchronously for video {self.id}, flow_id: {current_flow.id}"
964+
)
965+
except Exception as e:
966+
current_app.logger.error(
967+
f"Failed to trigger async chapter frame extraction for video {self.id}: {e}"
968+
)
969+
import traceback
970+
971+
current_app.logger.error(f"Traceback: {traceback.format_exc()}")
972+
908973
@mark_as_action
909974
def publish(self, pid=None, id_=None, **kwargs):
910975
"""Publish a video and update the related project."""
911976
# save a copy of the old PID
912977
video_old_id = self["_deposit"]["id"]
978+
979+
# Check if this is a republish and get the old record
980+
old_record = None
981+
try:
982+
_, old_record = self.fetch_published()
983+
except:
984+
# First publish
985+
pass
986+
913987
try:
914988
self["category"] = self.project["category"]
915989
self["type"] = self.project["type"]
@@ -930,6 +1004,13 @@ def publish(self, pid=None, id_=None, **kwargs):
9301004
video_published = super(Video, self).publish(pid=pid, id_=id_, **kwargs)
9311005
_, record_new = self.fetch_published()
9321006

1007+
# Check if chapters have changed and trigger frame extraction
1008+
if self._has_chapters_changed(old_record):
1009+
current_app.logger.info(
1010+
f"Chapters changed for video {self.id}, triggering frame extraction"
1011+
)
1012+
self._trigger_chapter_frame_extraction()
1013+
9331014
# update associated project
9341015
video_published.project._update_videos(
9351016
[video_build_url(video_old_id)],
@@ -1088,7 +1169,6 @@ def _create_tags(self):
10881169
except IndexError:
10891170
return
10901171

1091-
10921172
def mint_doi(self):
10931173
"""Mint DOI."""
10941174
assert self.has_record()
@@ -1109,7 +1189,7 @@ def mint_doi(self):
11091189
status=PIDStatus.RESERVED,
11101190
)
11111191
return self
1112-
1192+
11131193

11141194
project_resolver = Resolver(
11151195
pid_type="depid",

cds/modules/deposit/receivers.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
from cds.modules.flows.tasks import (
3434
DownloadTask,
3535
ExtractFramesTask,
36+
ExtractChapterFramesTask,
3637
ExtractMetadataTask,
3738
TranscodeVideoTask,
3839
)
@@ -87,4 +88,5 @@ def register_celery_class_based_tasks(sender, app=None):
8788
celery.register_task(ExtractMetadataTask())
8889
celery.register_task(DownloadTask())
8990
celery.register_task(ExtractFramesTask())
91+
celery.register_task(ExtractChapterFramesTask())
9092
celery.register_task(TranscodeVideoTask())

cds/modules/flows/api.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
from .tasks import (
4040
CeleryTask,
4141
DownloadTask,
42+
ExtractChapterFramesTask,
4243
ExtractFramesTask,
4344
ExtractMetadataTask,
4445
TranscodeVideoTask,
@@ -245,6 +246,7 @@ def _find_celery_task_by_name(name):
245246
ExtractMetadataTask,
246247
ExtractFramesTask,
247248
TranscodeVideoTask,
249+
ExtractChapterFramesTask,
248250
]:
249251
if celery_task.name == name:
250252
return celery_task

0 commit comments

Comments
 (0)