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
68 changes: 64 additions & 4 deletions cds/modules/deposit/ext.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,18 @@

import re
import mimetypes
import tempfile
import os
import shutil

from invenio_base.signals import app_loaded
from invenio_db import db
from invenio_files_rest.models import ObjectVersionTag
from invenio_files_rest.models import ObjectVersion, ObjectVersionTag
from invenio_files_rest.signals import file_uploaded
from invenio_files_rest.errors import InvalidKeyError
from invenio_indexer.signals import before_record_index
from invenio_records_files.utils import sorted_files_from_bucket
from srt_to_vtt import srt_to_vtt

from ..invenio_deposit.signals import post_action
from .indexer import cdsdeposit_indexer_receiver
Expand All @@ -45,16 +49,66 @@
)


def _create_vtt_from_srt(srt_obj):
"""Create a VTT file from an SRT file.

:param srt_obj: ObjectVersion of the SRT file
:returns: ObjectVersion of the created VTT file or None
"""
# Generate VTT filename from SRT filename
vtt_key = srt_obj.key.rsplit(".", 1)[0] + ".vtt"

# Check if VTT file already exists
existing_vtt = ObjectVersion.get(srt_obj.bucket_id, vtt_key)
if existing_vtt:
# If it exists, skip
return existing_vtt

# Ensure the SRT file has a file instance
if not srt_obj.file or not srt_obj.file.uri:
return None

srt_path = srt_obj.file.uri
tmp_dir = None
try:
# Create temporary directory for VTT file
tmp_dir = tempfile.mkdtemp()
vtt_path = os.path.join(tmp_dir, vtt_key)

# Convert using srt-to-vtt library
srt_to_vtt(srt_path, vtt_path)

# Create VTT ObjectVersion
vtt_obj = ObjectVersion.create(
bucket=srt_obj.bucket,
key=vtt_key,
stream=open(vtt_path, "rb"),
size=os.path.getsize(vtt_path),
)
_create_tags(vtt_obj)
return vtt_obj
except (OSError, IOError, AttributeError, Exception):
return None
finally:
# Clean up temporary directory
if tmp_dir and os.path.exists(tmp_dir):
try:
shutil.rmtree(tmp_dir)
except OSError:
pass


def _create_tags(obj):
"""Create additional tags for file."""
pattern_subtitle = re.compile(r".*_([a-zA-Z]{2})\.vtt$")
pattern_poster = re.compile(r"^poster\.(jpg|png)$")

# Get the media_type and content_type(file ext)
file_name = obj.key
mimetypes.add_type("subtitle/vtt", ".vtt")
mimetypes.add_type("text/srt", ".srt")
guessed_type = mimetypes.guess_type(file_name)[0]
if guessed_type is None:
if guessed_type is None:
raise InvalidKeyError(description=f"Unsupported File: {file_name}")

media_type = guessed_type.split("/")[0]
Expand All @@ -73,7 +127,13 @@ def _create_tags(obj):
# other tags
ObjectVersionTag.create_or_update(obj, "content_type", "vtt")
ObjectVersionTag.create_or_update(obj, "context_type", "subtitle")
# poster tag
elif file_ext == "srt":
# Create VTT version from SRT
try:
_create_vtt_from_srt(obj)
except Exception:
pass
# poster tag
elif pattern_poster.match(file_name):
ObjectVersionTag.create_or_update(obj, "context_type", "poster")

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,8 +148,8 @@ <h5 class="text-muted"><strong>Tips and suggestions</strong></h5>
ngf-model-options="{allowInvalid: false}"
ngf-change="$ctrl.addFiles($newFiles, $invalidFiles)"
ngf-select=""
ngf-pattern="'.vtt'"
ngf-accept="'.vtt'"
ngf-pattern="'.vtt,.srt'"
ngf-accept="'.vtt,.srt'"
ngf-validate-fn="$ctrl.validateSubtitles($file)"
ngf-max-size="500GB"
><i class="fa fa-plus-square"></i></a>
Expand All @@ -167,8 +167,8 @@ <h5 class="text-muted"><strong>Tips and suggestions</strong></h5>
ng-if="!$ctrl.cdsDepositCtrl.isPublished()"
ngf-select=""
ngf-change="$ctrl.addFiles($newFiles, $invalidFiles)"
ngf-pattern="'.vtt'"
ngf-accept="'text/vtt'"
ngf-pattern="'.vtt,.srt'"
ngf-accept="'text/vtt,.vtt,.srt'"
ngf-validate-fn="$ctrl.validateSubtitles($file)"
ngf-max-size="500GB"
ngf-multiple="true"
Expand All @@ -183,15 +183,15 @@ <h5 class="text-muted"><strong>Tips and suggestions</strong></h5>
ngf-model-options="{allowInvalid: false}"
ngf-change="$ctrl.addFiles($newFiles, $invalidFiles)"
ngf-select=""
ngf-pattern="'.vtt'"
ngf-accept="'.vtt'"
ngf-pattern="'.vtt,.srt'"
ngf-accept="'.vtt,.srt'"
ngf-validate-fn="$ctrl.validateSubtitles($file)"
ngf-max-size="500GB">select</a> <mark>.vtt</mark> files.
ngf-max-size="500GB">select</a> <mark>.vtt</mark> or <mark>.srt</mark> files.
<hr class="my-10" />
<div class="text-muted text-left">
<h5 class="text-muted"><strong>Tips and suggestions</strong></h5>
<ul>
<li>Subtitle filename should have a valid ISO language code. Example: <mark>subtitles_fr.vtt</mark> </li>
<li>Subtitle filename should have a valid ISO language code. Example: <mark>subtitles_fr.vtt</mark> or <mark>subtitles_fr.srt</mark> </li>
</ul>
</div>
</p>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,12 @@ function cdsUploaderCtrl(

// Filter out files without a valid MIME type or with zero size
_files = _files.filter((file) => {
if (!file.type || file.type.trim() === "") {
// Allow SRT and VTT files even if they don't have a MIME type
var fileName = file.name.toLowerCase();
var isSubtitleFile =
fileName.endsWith(".vtt") || fileName.endsWith(".srt");

if ((!file.type || file.type.trim() === "") && !isSubtitleFile) {
toaster.pop(
"warning",
"Invalid File Type",
Expand Down Expand Up @@ -544,13 +549,14 @@ function cdsUploaderCtrl(
this.validateSubtitles = function (_file) {
// Check if the filename matches the pattern and is a valid ISO language
// i.e. jessica_jones-en.vtt
var match = _file.name.match(/(?:.+)[_|-]([a-zA-Z]{2}).vtt/) || [];
var match = _file.name.match(/(?:.+)[_|-]([a-zA-Z]{2})\.(vtt|srt)/) || [];
return match.length > 1 && match[1] in isoLanguages;
};

this.validateAdditionalFiles = function (_file) {
// If it's a .vtt file, validate as subtitle
if (_file.name.toLowerCase().endsWith(".vtt")) {
// If it's a .vtt or .srt file, validate as subtitle
var fileName = _file.name.toLowerCase();
if (fileName.endsWith(".vtt") || fileName.endsWith(".srt")) {
return this.validateSubtitles(_file);
}
// Accept other types
Expand Down
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,7 @@ simplekv==0.14.1
six==1.17.0
soupsieve==2.6
speaklater==1.3
srt-to-vtt==1.0.0
SQLAlchemy==1.4.54
SQLAlchemy-Continuum==1.4.1
SQLAlchemy-Utils==0.38.3
Expand Down