Skip to content

Commit 64395cf

Browse files
zubeydecivelekzzacharo
authored andcommitted
chapters: improve task and landing page
1 parent 3221879 commit 64395cf

4 files changed

Lines changed: 53 additions & 29 deletions

File tree

cds/modules/deposit/api.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -926,7 +926,7 @@ def _has_chapters_changed(self, old_record=None):
926926
if curr["seconds"] != old["seconds"] or curr["title"] != old["title"]:
927927
return True
928928

929-
if current_chapters and not get_existing_chapter_frame_timestamps(self):
929+
if len(current_chapters) != len(get_existing_chapter_frame_timestamps(self)):
930930
# Chapters did not change, but chapter frames doesn't exist
931931
return True
932932

cds/modules/flows/tasks.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -931,7 +931,10 @@ def _create_chapter_frames(
931931

932932
frame_filename = "chapter-{0}.jpg".format(int(chapter_seconds))
933933
frame_path = os.path.join(output_dir, frame_filename)
934-
934+
935+
# Ensure we don't exceed duration
936+
if chapter_seconds + 0.01 >= duration:
937+
chapter_seconds = max(0, duration - 0.02)
935938
try:
936939
# Extract single frame at chapter timestamp using ff_frames
937940
ff_frames(
@@ -978,6 +981,8 @@ def _build_chapter_vtt(self, chapters, duration):
978981
for i, c in enumerate(sorted(chapters, key=lambda x: x["seconds"])):
979982
start = c["seconds"]
980983
end = chapters[i+1]["seconds"] if i+1 < len(chapters) else duration
984+
if end > duration:
985+
end = duration
981986
start_str = "{:02}:{:02}:{:02}.000".format(
982987
int(start // 3600),
983988
int((start % 3600) // 60),

cds/modules/records/static/templates/cds_records/video/detail.html

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ <h3 class="bt bw-1 pt-10 mb-0">
8888
class="chapter-item"
8989
ng-class="{ 'active': currentChapter === chapter }">
9090
<div class="chapter-content">
91-
<div class="chapter-thumbnail" ng-init="frame = getChapterFrame(chapter)">
91+
<div class="chapter-thumbnail" ng-init="frame = chapterFrames[chapter.seconds]">
9292
<div ng-class="{'is-placeholder': !frame}" class="thumbnail-container">
9393
<img
9494
ng-if="frame"
@@ -326,13 +326,14 @@ <h3><strong>Chapters</strong></h3>
326326
onmouseover="this.style.backgroundColor='#f8f9fa'; this.style.borderColor='#2196F3'; this.style.transform='translateY(-2px)';"
327327
onmouseout="this.style.backgroundColor='white'; this.style.borderColor='#e1e8ed'; this.style.transform='translateY(0)';">
328328
<!-- Chapter Thumbnail -->
329-
<div class="chapter-thumbnail-main-horizontal" style="width: 189px; height: 106px; border-radius: 6px; overflow: hidden; background-color: #f5f5f5; margin-bottom: 8px; position: relative;">
330-
<img ng-if="getChapterFrame(chapter)"
331-
ng-src="/api/iiif/v2/{{ getChapterFrame(chapter).bucket_id }}:{{ getChapterFrame(chapter).version_id }}:{{ getChapterFrame(chapter).key }}/full/320,180/0/default.jpg"
329+
<div class="chapter-thumbnail-main-horizontal" style="width: 189px; height: 106px; border-radius: 6px; overflow: hidden; background-color: #f5f5f5; margin-bottom: 8px; position: relative;"
330+
ng-init="chapterFrame = chapterFrames[chapter.seconds]">
331+
<img ng-if="chapterFrame"
332+
ng-src="/api/iiif/v2/{{ chapterFrame.bucket_id }}:{{ chapterFrame.version_id }}:{{ chapterFrame.key }}/full/320,180/0/default.jpg"
332333
style="width: 100%; height: 100%; object-fit: cover;"
333334
alt="Chapter {{ chapter.timestamp }}"
334335
onerror="this.style.display='none'; this.nextElementSibling.style.display='flex';">
335-
<div ng-if="!getChapterFrame(chapter)"
336+
<div ng-if="!chapterFrame"
336337
style="width: 100%; height: 100%; background-color: #e9ecef; display: flex; align-items: center; justify-content: center;">
337338
<i class="fa fa-film" style="color: #6c757d; font-size: 20px;"></i>
338339
</div>

cds/modules/theme/assets/bootstrap3/js/cds_records/cdsRecord.js

Lines changed: 40 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ function cdsRecordController($scope, $sce, $http, $timeout, $filter) {
6363
$scope.activeTab = "chapters"; // Default to chapters tab
6464
$scope.shortDescription = "";
6565
$scope.fullDescription = "";
66+
$scope.chapterFrames = {};
6667

6768
const REQUEST_HEADERS = {
6869
"Content-Type": "application/json",
@@ -191,6 +192,7 @@ function cdsRecordController($scope, $sce, $http, $timeout, $filter) {
191192
if (newVal) {
192193
$scope.initVttLoad(newVal);
193194
$scope.prepareDescriptions(newVal.metadata.description);
195+
$scope.buildChapterFrames();
194196
}
195197
});
196198

@@ -202,10 +204,14 @@ function cdsRecordController($scope, $sce, $http, $timeout, $filter) {
202204
}
203205

204206
const lines = description.split(/\r?\n/);
205-
const firstTen = lines.slice(0, $scope.DESCRIPTION_PREVIEW_LINES).join("\n");
206-
207-
$scope.shortDescription = $scope.processDescriptionWithClickableTimestamps(firstTen);
208-
$scope.fullDescription = $scope.processDescriptionWithClickableTimestamps(description);
207+
const firstTen = lines
208+
.slice(0, $scope.DESCRIPTION_PREVIEW_LINES)
209+
.join("\n");
210+
211+
$scope.shortDescription =
212+
$scope.processDescriptionWithClickableTimestamps(firstTen);
213+
$scope.fullDescription =
214+
$scope.processDescriptionWithClickableTimestamps(description);
209215
};
210216

211217
$scope.initVttLoad = function (record) {
@@ -405,43 +411,55 @@ function cdsRecordController($scope, $sce, $http, $timeout, $filter) {
405411
});
406412
};
407413

408-
$scope.getChapterFrame = function (chapter) {
409-
if (!$scope.record || !chapter) return null;
414+
$scope.buildChapterFrames = function () {
415+
if (!$scope.record || !$scope.chapters) return;
410416

411-
// Use the findMaster filter to get the master file (this filter is defined in cds/module.js)
412417
const master = $filter("findMaster")($scope.record);
418+
if (!master || !master.frame) return;
413419

414-
if (!master || !master.frame) return null;
415-
416-
// Look for a frame with filename that matches chapter timestamp
417-
// Chapter frames are named like "chapter-{seconds}.jpg"
418-
const expectedFrameName = `chapter-${chapter.seconds}.jpg`;
420+
const frames = master.frame;
421+
let matches = {};
419422

420-
let chapterFrame = master.frame.find(
421-
(frame) => frame.key === expectedFrameName
423+
// --- Exact filename match ---
424+
$scope.chapters.forEach((chapter) => {
425+
const expectedName = `chapter-${chapter.seconds}.jpg`;
426+
const frame = frames.find((f) => f.key === expectedName);
427+
if (frame) {
428+
matches[chapter.seconds] = frame;
429+
}
430+
});
431+
console.log("Exact matches found:", matches);
432+
// Collect chapters still missing
433+
let missing = $scope.chapters.filter(
434+
(c) => !matches.hasOwnProperty(c.seconds)
422435
);
423-
if (!chapterFrame) {
424-
// Find the frame with closest timestamp
436+
437+
// If none missing, return
438+
if (missing.length === 0) {
439+
$scope.chapterFrames = matches;
440+
return;
441+
}
442+
443+
// --- Fallback closest timestamp ---
444+
missing.forEach((chapter) => {
425445
const target = Number(chapter.seconds);
426446
let closest = null;
427447
let minDiff = Infinity;
428448

429-
master.frame.forEach((frame) => {
449+
frames.forEach((frame) => {
430450
if (!frame.tags || frame.tags.timestamp == null) return;
431-
432451
const ts = Number(frame.tags.timestamp);
433-
434452
const diff = Math.abs(ts - target);
435453
if (diff < minDiff) {
436454
minDiff = diff;
437455
closest = frame;
438456
}
439457
});
440458

441-
chapterFrame = closest;
442-
}
459+
matches[chapter.seconds] = closest || null;
460+
});
443461

444-
return chapterFrame || null;
462+
$scope.chapterFrames = matches;
445463
};
446464

447465
$scope.cleanHtmlFromTitle = function (title) {

0 commit comments

Comments
 (0)