Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions cds/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -1084,6 +1084,11 @@ def _parse_env_bool(var_name, default=None):
"qs": 'q=keywords.name:"VNR" OR keywords.name:"video news release"',
},
]
###############################################################################
# Record Landing page
###############################################################################

DESCRIPTION_PREVIEW_LINES = 10

###############################################################################
# Security
Expand Down
6 changes: 5 additions & 1 deletion cds/modules/deposit/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@
)
from ..records.minters import cds_doi_generator, is_local_doi, report_number_minter
from ..records.resolver import record_resolver
from ..records.utils import is_record, lowercase_value, parse_video_chapters
from ..records.utils import is_record, lowercase_value, parse_video_chapters, get_existing_chapter_frame_timestamps
from ..records.validators import PartialDraft4Validator
from ..records.permissions import is_public
from .errors import DiscardConflict
Expand Down Expand Up @@ -926,6 +926,10 @@ def _has_chapters_changed(self, old_record=None):
if curr["seconds"] != old["seconds"] or curr["title"] != old["title"]:
return True

if current_chapters and not get_existing_chapter_frame_timestamps(self):
# Chapters did not change, but chapter frames doesn't exist
return True

return False

def _trigger_chapter_frame_extraction(self):
Expand Down
16 changes: 2 additions & 14 deletions cds/modules/flows/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@
from ..opencast.api import OpenCast
from ..opencast.error import RequestError
from ..opencast.utils import get_qualities
from ..records.utils import to_string, parse_video_chapters
from ..records.utils import to_string, parse_video_chapters, get_existing_chapter_frame_timestamps
from ..xrootd.utils import file_opener_xrootd
from .deposit import index_deposit_project
from .files import dispose_object_version, move_file_into_local
Expand Down Expand Up @@ -834,7 +834,7 @@ def run(self, *args, **kwargs):
raise ValueError("Video duration is 0 - cannot extract frames")

# Check which timestamps already have frames
existing_timestamps = self._get_existing_chapter_frame_timestamps(deposit_video)
existing_timestamps = get_existing_chapter_frame_timestamps(deposit_video)

def progress_updater(current_chapter):
"""Progress reporter."""
Expand Down Expand Up @@ -883,18 +883,6 @@ def progress_updater(current_chapter):
self.log("Finished task {0}".format(kwargs["task_id"]))
return "Created {0} chapter frames.".format(total_frames)

def _get_existing_chapter_frame_timestamps(self, deposit):
"""Get timestamps of existing chapter frames."""
master_file = CDSVideosFilesIterator.get_master_video_file(deposit)
frames = CDSVideosFilesIterator.get_video_frames(master_file)

existing = set()
for f in frames:
tags = f.get("tags", {})
if tags.get("is_chapter_frame") == "true":
existing.add(float(tags.get("timestamp")))
return existing

@classmethod
def _create_chapter_frames(
cls,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ <h4>{{translation.title.title}}</h4>
<!-- Date & Views -->
<!-- Description -->
<div ng-init="showFullDescription=false" class="cds-detail-description cds-detail-video-description t-b px-20">
<p class="mb-30" ng-bind-html="(processDescriptionWithClickableTimestamps(record.metadata.description) | trustHtml) || 'No description'"></p>
<p class="mb-30" ng-bind-html="(showFullDescription ? fullDescription : shortDescription | trustHtml) || 'No description'"></p>
<!-- Hidden content -->
<div class="mt-20" ng-show="showFullDescription">
<!-- Contributors -->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@
record-views="{{ record_view_url }}"
media-download-event-url="{{ user_action_media_download_url }}"
related-query-url="{{ related_query_url }}"
preview-lines="{{ config.DESCRIPTION_PREVIEW_LINES }}"
></cds-record-view>
</div>
<!-- Recent videos -->
Expand Down
14 changes: 14 additions & 0 deletions cds/modules/records/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
from urllib import parse

import six
from cds.modules.records.api import CDSVideosFilesIterator
from flask import current_app, g, request
from flask_security import current_user
from invenio_db import db
Expand Down Expand Up @@ -486,6 +487,19 @@ def to_string(value):
return json.dumps(value)


def get_existing_chapter_frame_timestamps(deposit):
"""Get timestamps of existing chapter frames."""
master_file = CDSVideosFilesIterator.get_master_video_file(deposit)
frames = CDSVideosFilesIterator.get_video_frames(master_file)

existing = set()
for f in frames:
tags = f.get("tags", {})
if tags.get("is_chapter_frame") == "true":
existing.add(float(tags.get("timestamp")))
return existing


def parse_video_chapters(description):
"""Parse YouTube-style chapter timestamps from video description.

Expand Down
19 changes: 19 additions & 0 deletions cds/modules/theme/assets/bootstrap3/js/cds_records/cdsRecord.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ function cdsRecordController($scope, $sce, $http, $timeout, $filter) {
$scope.transcriptSearch = "";
$scope.chapters = [];
$scope.activeTab = "chapters"; // Default to chapters tab
$scope.shortDescription = "";
$scope.fullDescription = "";

const REQUEST_HEADERS = {
"Content-Type": "application/json",
Expand Down Expand Up @@ -188,9 +190,24 @@ function cdsRecordController($scope, $sce, $http, $timeout, $filter) {
$scope.$watch("record", function (newVal) {
if (newVal) {
$scope.initVttLoad(newVal);
$scope.prepareDescriptions(newVal.metadata.description);
}
});

$scope.prepareDescriptions = function (description) {
if (!description) {
$scope.shortDescription = "No description";
$scope.fullDescription = "No description";
return;
}

const lines = description.split(/\r?\n/);
const firstTen = lines.slice(0, $scope.DESCRIPTION_PREVIEW_LINES).join("\n");

$scope.shortDescription = $scope.processDescriptionWithClickableTimestamps(firstTen);
$scope.fullDescription = $scope.processDescriptionWithClickableTimestamps(description);
};

$scope.initVttLoad = function (record) {
const files = record.metadata._files || [];

Expand Down Expand Up @@ -644,6 +661,8 @@ function cdsRecordView($http) {

scope.relatedQueryUrl = attrs.relatedQueryUrl;

scope.DESCRIPTION_PREVIEW_LINES = parseInt(attrs.previewLines, 10) || 10;

// Get the record object and make it available to the scope
$http.get(attrs.record).then(
function (response) {
Expand Down
2 changes: 1 addition & 1 deletion tests/unit/test_flows_tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -725,7 +725,7 @@ def test_extract_chapter_frames_task_cleanup(app, db, bucket, video, users):
mock.patch.object(ExtractChapterFramesTask, "_base_payload", {"tags": {"duration": 100}}), \
mock.patch("cds.modules.flows.tasks.ExtractFramesTask._create_object") as mock_create_object, \
mock.patch("cds.modules.flows.tasks.ExtractChapterFramesTask._build_chapter_vtt"), \
mock.patch("cds.modules.flows.tasks.ExtractChapterFramesTask._get_existing_chapter_frame_timestamps") as mock_existing:
mock.patch("cds.modules.flows.tasks.get_existing_chapter_frame_timestamps") as mock_existing:

# Track created & disposed timestamps (floats)
created_timestamps = set()
Expand Down