1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 package org.opencastproject.workflow.handler.composer;
23
24 import org.opencastproject.composer.api.EncoderException;
25 import org.opencastproject.job.api.JobContext;
26 import org.opencastproject.mediapackage.AdaptivePlaylist;
27 import org.opencastproject.mediapackage.AdaptivePlaylist.HLSMediaPackageCheck;
28 import org.opencastproject.mediapackage.MediaPackage;
29 import org.opencastproject.mediapackage.MediaPackageElementFlavor;
30 import org.opencastproject.mediapackage.MediaPackageException;
31 import org.opencastproject.mediapackage.Track;
32 import org.opencastproject.mediapackage.selector.TrackSelector;
33 import org.opencastproject.serviceregistry.api.ServiceRegistry;
34 import org.opencastproject.util.NotFoundException;
35 import org.opencastproject.workflow.api.AbstractWorkflowOperationHandler;
36 import org.opencastproject.workflow.api.ConfiguredTagsAndFlavors;
37 import org.opencastproject.workflow.api.WorkflowInstance;
38 import org.opencastproject.workflow.api.WorkflowOperationException;
39 import org.opencastproject.workflow.api.WorkflowOperationHandler;
40 import org.opencastproject.workflow.api.WorkflowOperationInstance;
41 import org.opencastproject.workflow.api.WorkflowOperationResult;
42 import org.opencastproject.workflow.api.WorkflowOperationResult.Action;
43 import org.opencastproject.workspace.api.Workspace;
44
45 import org.osgi.service.component.annotations.Component;
46 import org.osgi.service.component.annotations.Reference;
47 import org.slf4j.Logger;
48 import org.slf4j.LoggerFactory;
49
50 import java.io.File;
51 import java.io.FileInputStream;
52 import java.io.IOException;
53 import java.io.InputStream;
54 import java.net.URI;
55 import java.net.URISyntaxException;
56 import java.util.ArrayList;
57 import java.util.Collection;
58 import java.util.List;
59 import java.util.function.BiFunction;
60 import java.util.function.Function;
61
62
63
64
65
66 @Component(
67 immediate = true,
68 service = WorkflowOperationHandler.class,
69 property = {
70 "service.description=Sanitize Adaptive Workflow Operation Handler",
71 "workflow.operation=sanitize-adaptive"
72 }
73 )
74 public class SanitizeAdaptiveWorkflowOperationHandler extends AbstractWorkflowOperationHandler {
75
76
77 private static final Logger logger = LoggerFactory.getLogger(SanitizeAdaptiveWorkflowOperationHandler.class);
78 private static final String PLUS = "+";
79 private static final String MINUS = "-";
80
81
82 private Workspace workspace = null;
83
84
85
86
87
88
89
90
91 @Reference
92 public void setWorkspace(Workspace workspace) {
93 this.workspace = workspace;
94 }
95
96 @Reference
97 @Override
98 public void setServiceRegistry(ServiceRegistry serviceRegistry) {
99 super.setServiceRegistry(serviceRegistry);
100 }
101
102
103
104
105
106
107
108 @Override
109 public WorkflowOperationResult start(final WorkflowInstance workflowInstance, JobContext context)
110 throws WorkflowOperationException {
111 logger.debug("Running HLS Check workflow operation on workflow {}", workflowInstance.getId());
112 try {
113 return sanitizeHLS(workflowInstance);
114 } catch (Exception e) {
115 throw new WorkflowOperationException(e);
116 }
117 }
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134 private WorkflowOperationResult sanitizeHLS(WorkflowInstance wi)
135 throws EncoderException,
136 WorkflowOperationException, NotFoundException, MediaPackageException, IOException, URISyntaxException {
137 MediaPackage src = wi.getMediaPackage();
138 MediaPackage mediaPackage = (MediaPackage) src.clone();
139
140 WorkflowOperationInstance operation = wi.getCurrentOperation();
141
142
143 ConfiguredTagsAndFlavors tagsAndFlavors = getTagsAndFlavors(wi,
144 Configuration.none, Configuration.one, Configuration.many, Configuration.one);
145
146
147 MediaPackageElementFlavor sourceFlavor = tagsAndFlavors.getSingleSrcFlavor();
148 ConfiguredTagsAndFlavors.TargetTags targetTrackTags = tagsAndFlavors.getTargetTags();
149 MediaPackageElementFlavor targetFlavor = tagsAndFlavors.getSingleTargetFlavor();
150
151
152 TrackSelector trackSelector = new TrackSelector();
153 trackSelector.addFlavor(sourceFlavor);
154 Collection<Track> tracks = trackSelector.select(mediaPackage, false);
155 List<Track> tracklist = new ArrayList<>(tracks);
156
157
158 if (!tracklist.stream().filter(AdaptivePlaylist.isHLSTrackPred).findAny().isPresent()) {
159 return createResult(mediaPackage, Action.CONTINUE, 0);
160 }
161 HLSMediaPackageCheck hlstree;
162 try {
163 hlstree = new HLSMediaPackageCheck(tracklist, new Function<URI, File>() {
164 @Override
165 public File apply(URI uri) {
166 try {
167 return workspace.get(uri);
168 } catch (NotFoundException | IOException e1) {
169 logger.error("Cannot get {} from workspace", uri, e1);
170 }
171 return null;
172 }
173 });
174 } catch (URISyntaxException e1) {
175 throw new MediaPackageException("Cannot process tracks from workspace");
176 }
177
178
179
180
181 BiFunction<File, Track, Track> replaceHLSPlaylistInWS = (file, track) -> {
182 try (InputStream inputStream = new FileInputStream(file)) {
183
184 URI uri = workspace.put(mediaPackage.getIdentifier().toString(), track.getIdentifier(), file.getName(),
185 inputStream);
186 track.setURI(uri);
187 handleTags(track, targetFlavor, targetTrackTags);
188 return track;
189 } catch (Exception e) {
190 logger.error("Cannot add track file to mediapackage in workspace: {} {} ",
191 mediaPackage.getIdentifier().toString(),
192 file);
193 return null;
194 }
195 };
196
197 Function<Track, Void> removeFromWS = new Function<Track, Void>() {
198 @Override
199 public Void apply(Track track) {
200 try {
201 workspace.delete(track.getURI());
202 } catch (NotFoundException e) {
203 logger.error("Cannot delete from workspace: File not found {} ", track);
204 } catch (IOException e) {
205 logger.error("Cannot delete from workspace: IO Error {} ", track);
206 }
207 return null;
208 }
209 };
210 if (hlstree.needsRewriting()) {
211
212 try {
213 hlstree.rewriteHLS(mediaPackage, replaceHLSPlaylistInWS, removeFromWS);
214 } catch (Exception e) {
215 logger.error("Error: cannot rewrite HLS renditions", e);
216 throw new WorkflowOperationException(e);
217 }
218 for (Track track : tracks) {
219 if (!AdaptivePlaylist.isPlaylist(track.getURI().getPath())) {
220 handleTags(track, targetFlavor, targetTrackTags);
221 logger.info("Set flavor {} and tags to {} ", track, targetFlavor);
222 }
223 }
224 } else {
225 for (Track track : tracks) {
226 handleTags(track, targetFlavor, targetTrackTags);
227 logger.info("Set flavor {} and tags to {} ", track, targetFlavor);
228 }
229 }
230 return createResult(mediaPackage, Action.CONTINUE, 0);
231 }
232
233
234 private void handleTags(Track track, MediaPackageElementFlavor targetFlavor,
235 ConfiguredTagsAndFlavors.TargetTags targetTags) {
236 if (targetFlavor != null) {
237 String flavorType = targetFlavor.getType();
238 String flavorSubtype = targetFlavor.getSubtype();
239 if ("*".equals(flavorType))
240 flavorType = track.getFlavor().getType();
241 if ("*".equals(flavorSubtype))
242 flavorSubtype = track.getFlavor().getSubtype();
243 track.setFlavor(new MediaPackageElementFlavor(flavorType, flavorSubtype));
244 logger.debug("Composed track has flavor '{}'", track.getFlavor());
245 }
246 applyTargetTagsToElement(targetTags, track);
247 }
248 }