1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 package org.opencastproject.transcription.workflowoperation;
22
23 import org.opencastproject.job.api.Job;
24 import org.opencastproject.job.api.JobContext;
25 import org.opencastproject.mediapackage.MediaPackage;
26 import org.opencastproject.mediapackage.MediaPackageElement;
27 import org.opencastproject.mediapackage.MediaPackageElementFlavor;
28 import org.opencastproject.mediapackage.Track;
29 import org.opencastproject.mediapackage.selector.AbstractMediaPackageElementSelector;
30 import org.opencastproject.mediapackage.selector.TrackSelector;
31 import org.opencastproject.serviceregistry.api.ServiceRegistry;
32 import org.opencastproject.transcription.api.TranscriptionService;
33 import org.opencastproject.transcription.api.TranscriptionServiceException;
34 import org.opencastproject.workflow.api.AbstractWorkflowOperationHandler;
35 import org.opencastproject.workflow.api.ConfiguredTagsAndFlavors;
36 import org.opencastproject.workflow.api.WorkflowInstance;
37 import org.opencastproject.workflow.api.WorkflowOperationException;
38 import org.opencastproject.workflow.api.WorkflowOperationHandler;
39 import org.opencastproject.workflow.api.WorkflowOperationInstance;
40 import org.opencastproject.workflow.api.WorkflowOperationResult;
41 import org.opencastproject.workflow.api.WorkflowOperationResult.Action;
42
43 import org.apache.commons.lang3.StringUtils;
44 import org.osgi.service.component.ComponentContext;
45 import org.osgi.service.component.annotations.Activate;
46 import org.osgi.service.component.annotations.Component;
47 import org.osgi.service.component.annotations.Reference;
48 import org.slf4j.Logger;
49 import org.slf4j.LoggerFactory;
50
51 import java.util.Collection;
52 import java.util.List;
53
54 @Component(
55 immediate = true,
56 service = WorkflowOperationHandler.class,
57 property = {
58 "service.description=Start Google Speech Transcription Workflow Operation Handler",
59 "workflow.operation=google-speech-start-transcription"
60 }
61 )
62 public class GoogleSpeechStartTranscriptionOperationHandler extends AbstractWorkflowOperationHandler {
63
64
65
66
67 private static final Logger logger = LoggerFactory.getLogger(GoogleSpeechStartTranscriptionOperationHandler.class);
68
69
70
71
72 static final String LANGUAGE_CODE = "language-code";
73 static final String SKIP_IF_FLAVOR_EXISTS = "skip-if-flavor-exists";
74
75
76
77
78 private TranscriptionService service = null;
79
80
81
82
83 private String language = null;
84
85 @Override
86 @Activate
87 protected void activate(ComponentContext cc) {
88 super.activate(cc);
89 }
90
91
92
93
94
95
96
97
98 @Override
99 public WorkflowOperationResult start(final WorkflowInstance workflowInstance, JobContext context)
100 throws WorkflowOperationException {
101 MediaPackage mediaPackage = workflowInstance.getMediaPackage();
102 WorkflowOperationInstance operation = workflowInstance.getCurrentOperation();
103
104 String skipOption = StringUtils.trimToNull(operation.getConfiguration(SKIP_IF_FLAVOR_EXISTS));
105 if (skipOption != null) {
106 MediaPackageElement[] mpes = mediaPackage.getElementsByFlavor(MediaPackageElementFlavor.parseFlavor(skipOption));
107 if (mpes != null && mpes.length > 0) {
108 logger.info(
109 "Start transcription operation will be skipped because flavor {} already exists in the media package",
110 skipOption);
111 return createResult(Action.SKIP);
112 }
113 }
114
115 logger.debug("Start transcription for mediapackage {} started", mediaPackage);
116
117
118 String langCode = operation.getConfiguration(LANGUAGE_CODE);
119
120
121 ConfiguredTagsAndFlavors tagsAndFlavors = getTagsAndFlavors(
122 workflowInstance, Configuration.many, Configuration.many, Configuration.none, Configuration.none);
123 List<String> sourceTagOption = tagsAndFlavors.getSrcTags();
124 List<MediaPackageElementFlavor> sourceFlavorOption = tagsAndFlavors.getSrcFlavors();
125
126 AbstractMediaPackageElementSelector<Track> elementSelector = new TrackSelector();
127
128
129 if (sourceTagOption.isEmpty() && sourceFlavorOption.isEmpty()) {
130 throw new WorkflowOperationException("No source tag or flavor have been specified!");
131 }
132
133 if (!sourceFlavorOption.isEmpty()) {
134 MediaPackageElementFlavor flavor = sourceFlavorOption.get(0);
135 elementSelector.addFlavor(flavor);
136 }
137 if (StringUtils.isNotBlank(langCode)) {
138 language = StringUtils.trim(langCode);
139 }
140 if (!sourceTagOption.isEmpty()) {
141 elementSelector.addTag(sourceTagOption.get(0));
142 }
143
144 Collection<Track> elements = elementSelector.select(mediaPackage, false);
145 Job job = null;
146 for (Track track : elements) {
147 if (track.hasVideo()) {
148 logger.info("Skipping track {} since it contains a video stream", track);
149 continue;
150 }
151 if (!track.hasAudio()) {
152 logger.info("Track {} from media package {} doesn't contain audio stream. Skip subtitle generation.",
153 track.getFlavor(), mediaPackage.getIdentifier());
154 continue;
155 }
156 try {
157 job = service.startTranscription(mediaPackage.getIdentifier().toString(), track, language);
158
159 break;
160 } catch (TranscriptionServiceException e) {
161 throw new WorkflowOperationException(e);
162 }
163 }
164
165 if (job == null) {
166 logger.info("No matching tracks found");
167 return createResult(mediaPackage, Action.CONTINUE);
168 }
169
170
171 if (!waitForStatus(job).isSuccess()) {
172 throw new WorkflowOperationException("Transcription job did not complete successfully");
173 }
174
175
176 logger.debug("External transcription job for mediapackage {} was created", mediaPackage);
177
178
179 return createResult(Action.CONTINUE);
180 }
181
182 @Reference(target = "(provider=google.speech)")
183 public void setTranscriptionService(TranscriptionService service) {
184 this.service = service;
185 }
186
187 @Reference
188 @Override
189 public void setServiceRegistry(ServiceRegistry serviceRegistry) {
190 super.setServiceRegistry(serviceRegistry);
191 }
192
193 }