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.rename;
23
24 import org.opencastproject.job.api.JobContext;
25 import org.opencastproject.mediapackage.MediaPackage;
26 import org.opencastproject.mediapackage.MediaPackageElementFlavor;
27 import org.opencastproject.mediapackage.MediaPackageElements;
28 import org.opencastproject.mediapackage.Track;
29 import org.opencastproject.mediapackage.VideoStream;
30 import org.opencastproject.mediapackage.selector.TrackSelector;
31 import org.opencastproject.metadata.dublincore.DublinCoreCatalog;
32 import org.opencastproject.metadata.dublincore.DublinCoreUtil;
33 import org.opencastproject.util.NotFoundException;
34 import org.opencastproject.workflow.api.AbstractWorkflowOperationHandler;
35 import org.opencastproject.workflow.api.WorkflowInstance;
36 import org.opencastproject.workflow.api.WorkflowOperationException;
37 import org.opencastproject.workflow.api.WorkflowOperationHandler;
38 import org.opencastproject.workflow.api.WorkflowOperationResult;
39 import org.opencastproject.workflow.api.WorkflowOperationResult.Action;
40 import org.opencastproject.workspace.api.Workspace;
41
42 import org.apache.commons.io.FilenameUtils;
43 import org.osgi.service.component.ComponentContext;
44 import org.osgi.service.component.annotations.Activate;
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.IOException;
51 import java.util.Arrays;
52 import java.util.HashMap;
53 import java.util.List;
54 import java.util.Map;
55
56
57
58
59
60 @Component(
61 property = {
62 "service.description=Rename Files Workflow Operation Handler",
63 "workflow.operation=rename-files"
64 },
65 immediate = true,
66 service = WorkflowOperationHandler.class
67 )
68 public class RenameFilesWorkflowOperationHandler extends AbstractWorkflowOperationHandler {
69
70
71 private static final Logger logger = LoggerFactory.getLogger(RenameFilesWorkflowOperationHandler.class);
72
73
74 private Workspace workspace = null;
75
76
77
78
79
80
81
82
83 @Reference
84 public void setWorkspace(Workspace workspace) {
85 this.workspace = workspace;
86 }
87
88
89
90
91
92
93
94 @Override
95 public WorkflowOperationResult start(WorkflowInstance workflowInstance, JobContext context)
96 throws WorkflowOperationException {
97
98 final var operation = workflowInstance.getCurrentOperation();
99 final var mediaPackage = workflowInstance.getMediaPackage();
100 final var mediaPackageId = mediaPackage.getIdentifier().toString();
101
102 logger.info("Running rename files workflow operation on workflow {}", workflowInstance.getId());
103
104
105
106 String pattern = operation.getConfiguration("name-pattern");
107 if (pattern == null) {
108 throw new WorkflowOperationException("name-pattern must be configured");
109 }
110 logger.debug("name-pattern {}", pattern);
111
112
113 var tagsAndFlavors = getTagsAndFlavors(
114 workflowInstance,
115 Configuration.none,
116 Configuration.many,
117 Configuration.none,
118 Configuration.none);
119
120
121 List<MediaPackageElementFlavor> sourceFlavors = tagsAndFlavors.getSrcFlavors();
122
123 TrackSelector trackSelector = new TrackSelector();
124 for (MediaPackageElementFlavor sourceFlavor: sourceFlavors) {
125 trackSelector.addFlavor(sourceFlavor);
126 }
127
128 for (var track: trackSelector.select(mediaPackage, false)) {
129 var uri = track.getURI();
130 var extension = FilenameUtils.getExtension(uri.toString());
131 track.generateIdentifier();
132
133
134 var filename = pattern;
135 for (var entry: placeholders(mediaPackage, track).entrySet()) {
136 filename = filename.replace(entry.getKey(), entry.getValue());
137 }
138 filename = filename.replaceAll("#\\{[a-z.]*}", "_");
139
140
141
142 try (var in = workspace.read(uri)) {
143 var newUri = workspace.put(mediaPackageId, track.getIdentifier(), filename, in);
144 logger.info("Renaming {} to {}", uri, newUri);
145 track.setURI(newUri);
146 } catch (NotFoundException | IOException e) {
147 throw new WorkflowOperationException("Failed moving track file", e);
148 }
149
150
151 logger.debug("Removing old track file {}", uri);
152 try {
153 workspace.delete(uri);
154 } catch (NotFoundException | IOException e) {
155 logger.debug("Could not remove track from workspace. Could be it was never there.");
156 }
157
158 }
159
160 return createResult(mediaPackage, Action.CONTINUE);
161 }
162
163
164
165
166
167
168
169
170
171
172 private Map<String, String> placeholders(MediaPackage mediaPackage, Track element) {
173
174 var placeholders = new HashMap<String, String>();
175
176 var width = Arrays.stream(element.getStreams())
177 .filter(s -> s instanceof VideoStream)
178 .map(s -> (VideoStream) s)
179 .findFirst()
180 .map(VideoStream::getFrameWidth)
181 .map(Object::toString)
182 .orElse("");
183
184 placeholders.put("#{video.width}", width);
185
186 var height = Arrays.stream(element.getStreams())
187 .filter(h -> h instanceof VideoStream)
188 .map(h -> (VideoStream) h)
189 .findFirst()
190 .map(VideoStream::getFrameHeight)
191 .map(Object::toString)
192 .orElse("");
193
194 placeholders.put("#{video.height}", height);
195
196
197 placeholders.put("#{file.extension}", FilenameUtils.getExtension(element.getURI().toString()));
198 placeholders.put("#{file.basename}", FilenameUtils.getBaseName(element.getURI().toString()));
199
200
201 placeholders.put("#{flavor.type}", element.getFlavor().getType());
202 placeholders.put("#{flavor.subtype}", element.getFlavor().getSubtype());
203
204
205 for (var flavor: Arrays.asList(MediaPackageElements.EPISODE, MediaPackageElements.SERIES)) {
206
207 for (var catalog : mediaPackage.getCatalogs(flavor)) {
208 DublinCoreCatalog dc = DublinCoreUtil.loadDublinCore(workspace, catalog);
209 for (var entry : dc.getValues().entrySet()) {
210 var key = String.format("#{%s.%s}", flavor.getSubtype(), entry.getKey().getLocalName());
211 var value = entry.getValue().get(0).getValue();
212 placeholders.put(key, value);
213 }
214 }
215 }
216
217 logger.debug("Placeholders to use for renaming: {}", placeholders);
218 return placeholders;
219 }
220
221 @Activate
222 @Override
223 protected void activate(ComponentContext cc) {
224 super.activate(cc);
225 }
226 }