Wiki source code of VideoUpload
Last modified by Ryan C on 2025/03/07 23:43
Show last authors
author | version | line-number | content |
---|---|---|---|
1 | {{include reference="XWikiTubeCode.Macros"/}} | ||
2 | |||
3 | {{velocity}} | ||
4 | #* Upload and transcode files *# | ||
5 | #set($videoUploader = $xwiki.parseGroovyFromPage("XWikiTubeCode.VideoUploadGroovy")) | ||
6 | #set($discard = $videoUploader.init($xwiki, $xcontext, $services)) | ||
7 | #set($discard = $xcontext.put("videoUploader", $videoUploader)) | ||
8 | #set($action = $request.action) | ||
9 | |||
10 | #if ("$!action" != '') | ||
11 | #if ($action == "uploadVideo") | ||
12 | ## Check the video target document | ||
13 | #set($targetDocRef = "") | ||
14 | #if ("$!request.targetDocRef" != '' && $xwiki.exists($request.targetDocRef)) | ||
15 | #set($targetDocRef = $request.targetDocRef) | ||
16 | #end | ||
17 | #set($rep = $videoUploader.uploadVideo("videoInput", $targetDocRef)) | ||
18 | #if ($rep.ret == true) | ||
19 | ## Display video information | ||
20 | #displayVideoInfo($rep.video) | ||
21 | ## Encode the video | ||
22 | #set($ffmpeg = $videoUploader.mediaTranscoder.checkFFmpeg()) | ||
23 | #if ($ffmpeg) | ||
24 | #set($video = $rep.video) | ||
25 | #set($videoDocRef = $video.videoDocRef) | ||
26 | #if("$!videoDocRef" != '' && $xwiki.exists($videoDocRef)) | ||
27 | #set($discard = $videoUploader.encodeVideo($videoDocRef, "libvpx-vp9")) | ||
28 | #set($videoDoc = $xwiki.getDocument($videoDocRef)) | ||
29 | #set($videoObj = $videoDoc.getObject("XWikiTubeCode.MediaClass", "original", "1")) | ||
30 | #if("$!videoObj" != '') | ||
31 | #set($discard = $videoObj.set("encoded", 1)) | ||
32 | #set($discard = $videoDoc.save()) | ||
33 | #end | ||
34 | #end | ||
35 | #end | ||
36 | #else | ||
37 | #if($rep.error == "file_exists") | ||
38 | {{warning}}The video name alreay exists.{{/warning}} | ||
39 | #end | ||
40 | #end | ||
41 | #elseif($action == 'getXWikiTubeVideos') | ||
42 | ## List all XWiki videos filtred by user | ||
43 | #set($offset = $mathtool.toInteger($request.get('offset'))) | ||
44 | #set($offset = $offset - 1) | ||
45 | #if($offset < 0) | ||
46 | #set($offset = 0) | ||
47 | #end | ||
48 | #set($limit = $mathtool.toInteger($request.get('limit'))) | ||
49 | #if(!$hasAdmin) | ||
50 | #set($userFilter = " and doc.author=${xcontext.user}") | ||
51 | #end | ||
52 | #set($filterName = "$!{request.get('name')}") | ||
53 | #if("$!filterName" != '') | ||
54 | #set($filterNameCond = " and media.name like :filterName") | ||
55 | #end | ||
56 | #set($xwql = "from doc.object(XWikiTubeCode.MediaClass) as media where doc.fullName<>'XWikiTubeCode.MediaTemplate' and media.original=1 $!userFilter $!filterNameCond order by doc.creationDate") | ||
57 | #set($query = $services.query.xwql($xwql)) | ||
58 | #if("$!filterName" != '') | ||
59 | #set($query = $query.bindValue("filterName","%$filterName%")) | ||
60 | #end | ||
61 | #set($totalRows = $query.count()) | ||
62 | ##set($results = $query.setLimit($limit).setOffset($offset).execute()) | ||
63 | #set($results = $query.execute()) | ||
64 | #set($returnedRows = $results.size()) | ||
65 | ## === | ||
66 | ## JSON | ||
67 | ## === | ||
68 | #set($rows = []) | ||
69 | #foreach($mediaDocRef in $results) | ||
70 | #set($mediaDoc = $xwiki.getDocument($mediaDocRef)) | ||
71 | #set($mediaObj = $mediaDoc.getObject("XWikiTubeCode.MediaClass")) | ||
72 | #set($name = $mediaObj.getValue("name")) | ||
73 | #set($extension = $mediaObj.getValue("extension")) | ||
74 | #set($mimeType = $mediaObj.getValue("mimeType")) | ||
75 | #set($size = $mathtool.div($mediaObj.getValue("size"), 1000000)) | ||
76 | #set($duration = $mediaObj.getValue("duration")) | ||
77 | #set($resolution = $mediaObj.getValue("resolution")) | ||
78 | #set($creator = $xwiki.getUserName($mediaDoc.author, false)) | ||
79 | #set($creationDate = $xwiki.formatDate($mediaDoc.creationDate)) | ||
80 | #set($encoded = "False") | ||
81 | #if($mediaObj.getValue("encoded") == "1") | ||
82 | #set($encoded = "True") | ||
83 | #end | ||
84 | #set($mediaURL = $xwiki.getURL($mediaDocRef)) | ||
85 | #set($actionLinks = "<div class='actionsrow'>") | ||
86 | #set($actionLinks = "${actionLinks}<div class='actionsrow'><a href='$mediaURL' rel='${mediaDocRef}' class='glyphicon glyphicon-play' title='Play'></a>") | ||
87 | #if($hasAdmin || ($xcontext.user == $mediaDoc.author)) | ||
88 | #set($actionLinks = "${actionLinks}<a href='javascript:;' rel='${mediaDocRef}' class='glyphicon glyphicon-cog' title='Encode'></a>") | ||
89 | #set($actionLinks = "${actionLinks}<a href='javascript:;' rel='${mediaDocRef}' class='glyphicon glyphicon-trash delete-media' title='Delete'></a>") | ||
90 | #end | ||
91 | #set($actionLinks = "${actionLinks}</div>") | ||
92 | #set($row = {"doc_viewable": true, "name": $name, "extension": $extension, "mimeType": $mimeType, "size": "${size} MB", "duration": "${duration} s", "resolution": $resolution, "creator": "$creator", "creationDate": $creationDate, "encoded": $encoded, "actions": $actionLinks}) | ||
93 | #set($discard = $rows.add($row)) | ||
94 | #end | ||
95 | { | ||
96 | "totalrows": $totalRows, | ||
97 | "matchingtags": {}, | ||
98 | "tags" : [], | ||
99 | "returnedrows": $returnedRows, | ||
100 | "offset": ($offset + 1), | ||
101 | "reqNo": $mathtool.toInteger($request.reqNo), | ||
102 | "rows": $jsontool.serialize($rows) | ||
103 | } | ||
104 | #elseif($action == 'deleteMedia') | ||
105 | #if("$!request.mediaDocRef" != "" && $xwiki.exists($request.mediaDocRef)) | ||
106 | #set($mediaDocRef = $request.mediaDocRef) | ||
107 | #set($rep = $videoUploader.deleteMedia($mediaDocRef)) | ||
108 | $rep | ||
109 | #end | ||
110 | #elseif($action == 'selectVideo') | ||
111 | #if("$!request.videoDocRef" != "" && $xwiki.exists($request.videoDocRef)) | ||
112 | #set($videoDocRef = $request.videoDocRef) | ||
113 | #set($videoDoc = $xwiki.getDocument($videoDocRef)) | ||
114 | #set($attachments = $videoDoc.getAttachmentList()) | ||
115 | #set($videoAttachments = []) | ||
116 | #foreach($att in $attachments) | ||
117 | #if($att.getMimeType().contains("video")) | ||
118 | #set($discard = $videoAttachments.add($att)) | ||
119 | #end | ||
120 | #end | ||
121 | {{html}}#displayVideoEncodeForm($videoAttachments){{/html}} | ||
122 | #end | ||
123 | #elseif($action == 'initVideoEncoding') | ||
124 | #if("$!request.videoDocRef" != '' && $xwiki.exists($request.videoDocRef) && "$!request.videoName" != '') | ||
125 | #set($videoDocRef = $request.videoDocRef) | ||
126 | #set($videoName = $request.videoName) | ||
127 | #set($newLine = $escapetool.getNewline()) | ||
128 | #set($rep = $videoUploader.encodeAttachmentVideo($videoDocRef, $videoName)) | ||
129 | #if($rep) | ||
130 | $videoUploader.logger.info("${newLine}Video encoding initialization phase succeed, document=${videoDocRef}, video=${videoName}${newLine}") | ||
131 | #else | ||
132 | $videoUploader.logger.severe("${newLine}Video encoding initialization phase has failed, document=${videoDocRef}, video=${videoName}${newLine}") | ||
133 | #end | ||
134 | {"initStatus": $rep.ret, "error": "$!rep.error"} | ||
135 | #end | ||
136 | #elseif($action == 'videoEncode') | ||
137 | #if("$!request.videoDocRef" != '' && $xwiki.exists($request.videoDocRef) && "$!request.videoName" != '') | ||
138 | #set($videoDocRef = $request.videoDocRef) | ||
139 | #set($videoName = $request.videoName) | ||
140 | #set($videoDoc = $xwiki.getDocument($videoDocRef)) | ||
141 | #set($waitingCommands = $videoDoc.getObjects("XWikiTubeCode.CommandClass", "status", "waiting")) | ||
142 | #set($completeCommands = $videoDoc.getObjects("XWikiTubeCode.CommandClass", "status", "complete")) | ||
143 | #set($noAudioStreamCommands = $videoDoc.getObjects("XWikiTubeCode.CommandClass", "status", "noaudiostream")) | ||
144 | #set($noVideoStreamCommands = $videoDoc.getObjects("XWikiTubeCode.CommandClass", "status", "novideostream")) | ||
145 | #set($discard = $completeCommands.addAll($noAudioStreamCommands)) | ||
146 | #set($discard = $completeCommands.addAll($noVideoStreamCommands)) | ||
147 | #set($runingCommands = $videoDoc.getObjects("XWikiTubeCode.CommandClass", "status", "transcoding")) | ||
148 | #set($transcodingErrorCommands = $videoDoc.getObjects("XWikiTubeCode.CommandClass", "status", "transcoding_error")) | ||
149 | #set($discard = $runingCommands.addAll($transcodingErrorCommands)) | ||
150 | #set($newLine = $escapetool.getNewline()) | ||
151 | |||
152 | ## Check waiting commands | ||
153 | #set($waitingCmdsJSON = []) | ||
154 | #if($waitingCommands.size() > 0) | ||
155 | ## Check if there is no runing command and check also if FFmpeg is not runing | ||
156 | #set($ffmpegRunning = $videoUploader.mediaTranscoder.checkFFmpegRunning()) | ||
157 | #if(!$ffmpegRunning && $runingCommands.size() == 0) | ||
158 | ## Start a new command | ||
159 | #set($nextCmd = $waitingCommands[0]) | ||
160 | #if($nextCmd.outputFile != "" && !$nextCmd.outputFile.contains("manifest")) | ||
161 | ## video and audio streams commands | ||
162 | #set($sourceVideoPath = $videoUploader.fileNameUtils.concat($nextCmd.getValue("workDir"), $videoName)) | ||
163 | #set($commandStatus = "transcoding") | ||
164 | #if($nextCmd.outputFile.contains("audio")) ## audio | ||
165 | ## Check if the original video has audio stream | ||
166 | #if($videoUploader.mediaTranscoder.hasAudioStream($sourceVideoPath)) | ||
167 | ## Start the command | ||
168 | #set($rep = $videoUploader.commandRunner.run(["bash", "-c", $nextCmd.getValue("cmd")], '', 2147483647)) | ||
169 | $videoUploader.logger.info("${newLine}Start FFmpeg command «${nextCmd.getValue('cmd')}» , document=${videoDocRef}, video=${videoName}${newLine}") | ||
170 | #else | ||
171 | ## Update the command status to complete | ||
172 | #set($commandStatus = "noaudiostream") | ||
173 | #end | ||
174 | #else | ||
175 | ## Check if the original video has video stream | ||
176 | #if($videoUploader.mediaTranscoder.hasVideoStream($sourceVideoPath)) | ||
177 | ## Start the command | ||
178 | #set($rep = $videoUploader.commandRunner.run(["bash", "-c", $nextCmd.getValue("cmd")], '', 2147483647)) | ||
179 | $videoUploader.logger.info("${newLine}Start FFmpeg command «${nextCmd.getValue('cmd')}» , document=${videoDocRef}, video=${videoName}${newLine}") | ||
180 | #else | ||
181 | ## Update the command status to complete | ||
182 | #set($commandStatus = "novideostream") | ||
183 | #end | ||
184 | #end | ||
185 | ## Update the status of the command object | ||
186 | #set($cmdObj = $videoDoc.getObject("XWikiTubeCode.CommandClass", "outputFile", $nextCmd.outputFile)) | ||
187 | #if($cmdObj) | ||
188 | #set($discard = $cmdObj.set("status", $commandStatus)) | ||
189 | #set($discard = $videoDoc.save()) | ||
190 | #end | ||
191 | #elseif($nextCmd.outputFile.contains("manifest")) | ||
192 | ## Manifest file command | ||
193 | ## Generate the manifest command and update the command object | ||
194 | #set($manifestCmd = $videoUploader.mediaTranscoder.generateDASHManifestCommand($nextCmd.getValue("workDir"))) | ||
195 | #set($rep = $videoUploader.commandRunner.run(["bash", "-c", $manifestCmd], '', 2147483647)) | ||
196 | $videoUploader.logger.info("${newLine}Start FFmpeg command «${manifestCmd}» , document=${videoDocRef}, video=${videoName}${newLine}") | ||
197 | ## Update the status/cmd properties of the command object | ||
198 | #set($cmdObj = $videoDoc.getObject("XWikiTubeCode.CommandClass", "outputFile", $nextCmd.outputFile)) | ||
199 | #if($cmdObj) | ||
200 | #set($discard = $cmdObj.set("status", "transcoding")) | ||
201 | #set($discard = $cmdObj.set("cmd", $manifestCmd)) | ||
202 | #set($discard = $videoDoc.save()) | ||
203 | #end | ||
204 | #end | ||
205 | #end | ||
206 | #foreach($cmd in $waitingCommands) | ||
207 | #set($discard = $waitingCmdsJSON.add({"progress": 0, "stream": $cmd.outputFile.replace("_output.txt", "")})) | ||
208 | #end | ||
209 | #end | ||
210 | |||
211 | ## Check runing commands | ||
212 | #set($encodeError = false) | ||
213 | #set($runingCmdsJSON = []) | ||
214 | #foreach($cmd in $runingCommands) | ||
215 | #set($outputFilePath = "${cmd.workDir}/${cmd.outputFile}") | ||
216 | #set($errorFilePath = "${cmd.workDir}/${cmd.outputFile.replace('output', 'error')}") | ||
217 | #set($progressRep = $videoUploader.checkEncodingProgress($outputFilePath, $errorFilePath, $cmd.getValue("duration"))) | ||
218 | #if($progressRep.status == "end") ## Command complete | ||
219 | ## Update the command object | ||
220 | #set($cmdObj = $videoDoc.getObject("XWikiTubeCode.CommandClass", "outputFile", $cmd.outputFile)) | ||
221 | #if($cmdObj) | ||
222 | #set($discard = $cmdObj.set("status", "complete")) | ||
223 | #set($discard = $videoDoc.save()) | ||
224 | $videoUploader.logger.info("${newLine}FFmpeg command successfully completed «${cmd.getValue('cmd')}» , document=${videoDocRef}, video=${videoName}${newLine}") | ||
225 | #end | ||
226 | #set($discard = $runingCmdsJSON.add({"progress": 100, "stream": $cmd.outputFile.replace("_output.txt", "")})) | ||
227 | #elseif($progressRep.status == "empty_file") ## FFmpeg Error | ||
228 | #set($discard = $runingCmdsJSON.add({"progress": 0, "stream": $cmd.outputFile.replace("_output.txt", ""), "error": $!progressRep.error})) | ||
229 | #set($encodeError = true) | ||
230 | ## Update the command object | ||
231 | #set($cmdObj = $videoDoc.getObject("XWikiTubeCode.CommandClass", "outputFile", $cmd.outputFile)) | ||
232 | #if($cmdObj) | ||
233 | #set($discard = $cmdObj.set("status", "transcoding_error")) | ||
234 | #set($discard = $videoDoc.save()) | ||
235 | $videoUploader.logger.severe("${newLine}FFmpeg command error «${cmd.getValue('cmd')}» , document=${videoDocRef}, video=${videoName}, error=$!{progressRep.error}${newLine}") | ||
236 | #end | ||
237 | #else | ||
238 | #set($discard = $runingCmdsJSON.add({"progress": $progressRep.progress, "stream": $cmd.outputFile.replace("_output.txt", "")})) | ||
239 | #end | ||
240 | #end | ||
241 | ## | ||
242 | |||
243 | ## Check complete commands | ||
244 | #set($completeCmdsJSON = []) | ||
245 | #foreach($cmd in $completeCommands) | ||
246 | #set($discard = $completeCmdsJSON.add({"progress": 100, "stream": $cmd.outputFile.replace("_output.txt", "")})) | ||
247 | #end | ||
248 | ## | ||
249 | $jsontool.serialize({"encodeError": $encodeError, "waitingCmds": $waitingCmdsJSON, "completeCmds": $completeCmdsJSON, "runingCmds": $runingCmdsJSON}) | ||
250 | #end | ||
251 | #elseif($action == 'attachEncodedFiles') | ||
252 | #if("$!request.videoDocRef" != '' && $xwiki.exists($request.videoDocRef) && "$!request.videoName" != '') | ||
253 | #set($videoDocRef = $request.videoDocRef) | ||
254 | #set($videoName = $request.videoName) | ||
255 | #set($videoDoc = $xwiki.getDocument($videoDocRef)) | ||
256 | #set($originalVideoObj = $videoDoc.getObject("XWikiTubeCode.MediaClass", "original", 1)) | ||
257 | #set($newLine = $escapetool.getNewline()) | ||
258 | #if($originalVideoObj && $originalVideoObj.getValue("name") == $videoName && $originalVideoObj.getValue("encoded") != 1) | ||
259 | ## Start files attachments | ||
260 | #set($videoDir = $originalVideoObj.getValue("dirPath")) | ||
261 | #set($rep = $videoUploader.attachEncodingFilesToDoc($videoDir, $videoDocRef, $videoName)) | ||
262 | #if($rep) | ||
263 | $videoUploader.logger.info("${newLine}Attaching encoded files to document success: document=$videoDocRef, video=${videoName}${newLine}") | ||
264 | #else | ||
265 | $videoUploader.logger.severe("${newLine}Attaching encoded files to document fails: document=$videoDocRef, video=${videoName}${newLine}") | ||
266 | #end | ||
267 | $rep | ||
268 | #end | ||
269 | #end | ||
270 | #end | ||
271 | #end | ||
272 | {{/velocity}} |