Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 104 |
|
0.00% |
0 / 9 |
CRAP | |
0.00% |
0 / 1 |
TranscodeStatusTable | |
0.00% |
0 / 104 |
|
0.00% |
0 / 9 |
702 | |
0.00% |
0 / 1 |
__construct | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
2 | |||
getHTML | |
0.00% |
0 / 10 |
|
0.00% |
0 / 1 |
2 | |||
codecFromTranscodeKey | |
0.00% |
0 / 7 |
|
0.00% |
0 / 1 |
20 | |||
getTranscodesTable | |
0.00% |
0 / 23 |
|
0.00% |
0 / 1 |
56 | |||
transcodeRowsToTemplateParams | |
0.00% |
0 / 25 |
|
0.00% |
0 / 1 |
6 | |||
getSourceUrl | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getTranscodeDuration | |
0.00% |
0 / 6 |
|
0.00% |
0 / 1 |
6 | |||
getTranscodeBitrate | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
6 | |||
getStatusMsg | |
0.00% |
0 / 26 |
|
0.00% |
0 / 1 |
42 |
1 | <?php |
2 | |
3 | namespace MediaWiki\TimedMediaHandler; |
4 | |
5 | use File; |
6 | use IContextSource; |
7 | use MediaWiki\Html\Html; |
8 | use MediaWiki\Html\TemplateParser; |
9 | use MediaWiki\Linker\LinkRenderer; |
10 | use MediaWiki\TimedMediaHandler\WebVideoTranscode\WebVideoTranscode; |
11 | use MediaWiki\Utils\MWTimestamp; |
12 | |
13 | /** |
14 | * TranscodeStatusTable outputs a "transcode" status table to the ImagePage |
15 | * |
16 | * If logged in as autoconfirmed users can reset transcode states |
17 | * via the transcode api entry point |
18 | * |
19 | */ |
20 | class TranscodeStatusTable { |
21 | /** @var IContextSource */ |
22 | private $context; |
23 | |
24 | /** @var LinkRenderer */ |
25 | private $linkRenderer; |
26 | |
27 | /** @var TemplateParser */ |
28 | private $templateParser; |
29 | |
30 | /** |
31 | * @param IContextSource $context |
32 | * @param LinkRenderer $linkRenderer |
33 | */ |
34 | public function __construct( |
35 | IContextSource $context, |
36 | LinkRenderer $linkRenderer |
37 | ) { |
38 | $this->context = $context; |
39 | $this->linkRenderer = $linkRenderer; |
40 | $this->templateParser = new TemplateParser( __DIR__ . '/../templates' ); |
41 | } |
42 | |
43 | /** |
44 | * @param File $file |
45 | * @return string |
46 | */ |
47 | public function getHTML( $file ) { |
48 | // Add transcode table css and javascript: |
49 | $this->context->getOutput()->addModules( [ 'ext.tmh.transcodetable' ] ); |
50 | |
51 | $o = '<h2 id="transcodestatus">' . wfMessage( 'timedmedia-status-header' )->escaped() . '</h2>'; |
52 | // Give the user a purge page link |
53 | $o .= $this->linkRenderer->makeLink( |
54 | $file->getTitle(), |
55 | $this->context->msg( 'timedmedia-update-status' )->text(), |
56 | [], |
57 | [ 'action' => 'purge' ] |
58 | ); |
59 | |
60 | $o .= $this->getTranscodesTable( $file ); |
61 | |
62 | return $o; |
63 | } |
64 | |
65 | /** |
66 | * Get the video or audio codec for the defined transcode, |
67 | * for grouping/sorting purposes. |
68 | * @param string $key |
69 | * @return string |
70 | */ |
71 | public static function codecFromTranscodeKey( $key ) { |
72 | if ( isset( WebVideoTranscode::$derivativeSettings[$key] ) ) { |
73 | $settings = WebVideoTranscode::$derivativeSettings[$key]; |
74 | if ( isset( $settings['videoCodec'] ) ) { |
75 | return $settings['videoCodec']; |
76 | } |
77 | |
78 | if ( isset( $settings['audioCodec'] ) ) { |
79 | return $settings['audioCodec']; |
80 | } |
81 | // else |
82 | // this this shouldn't happen... |
83 | // fall through |
84 | } |
85 | // else |
86 | // derivative type no longer defined or invalid def? |
87 | // fall through |
88 | return $key; |
89 | } |
90 | |
91 | /** |
92 | * @param File $file |
93 | * @return string |
94 | */ |
95 | public function getTranscodesTable( $file ) { |
96 | $transcodeRows = WebVideoTranscode::getTranscodeState( $file ); |
97 | |
98 | if ( !$transcodeRows ) { |
99 | return '<p>' . wfMessage( 'timedmedia-no-derivatives' )->escaped() . '</p>'; |
100 | } |
101 | |
102 | uksort( $transcodeRows, static function ( $a, $b ) { |
103 | $formatOrder = [ 'vp9', 'vp8', 'h264', 'theora', 'mpeg4', 'mjpeg', 'opus', 'mp3', 'vorbis', 'aac' ]; |
104 | |
105 | $aFormat = self::codecFromTranscodeKey( $a ); |
106 | $bFormat = self::codecFromTranscodeKey( $b ); |
107 | $aIndex = array_search( $aFormat, $formatOrder ); |
108 | $bIndex = array_search( $bFormat, $formatOrder ); |
109 | |
110 | if ( $aIndex === false && $bIndex === false ) { |
111 | return -strnatcmp( $a, $b ); |
112 | } |
113 | if ( $aIndex === false ) { |
114 | return 1; |
115 | } |
116 | if ( $bIndex === false ) { |
117 | return -1; |
118 | } |
119 | if ( $aIndex === $bIndex ) { |
120 | return -strnatcmp( $a, $b ); |
121 | } |
122 | return ( $aIndex - $bIndex ); |
123 | } ); |
124 | |
125 | return $this->templateParser->processTemplate( |
126 | 'TranscodeStatusTable', |
127 | $this->transcodeRowsToTemplateParams( $transcodeRows, $file ) |
128 | ); |
129 | } |
130 | |
131 | /** |
132 | * @param array $transcodeRows |
133 | * @param File $file |
134 | * @return array |
135 | */ |
136 | private function transcodeRowsToTemplateParams( $transcodeRows, $file ) { |
137 | $transcodeRowsForTemplate = []; |
138 | foreach ( $transcodeRows as $transcodeKey => $state ) { |
139 | $transcodeRowsForTemplate[] = [ |
140 | 'transcodeKey' => $transcodeKey, |
141 | 'msg-derivative-key' => wfMessage( 'timedmedia-derivative-' . $transcodeKey ), |
142 | 'bitrate' => $this->getTranscodeBitrate( $file, $state ), |
143 | 'transcode-success' => $state['time_success'] !== null, |
144 | 'msg-timedmedia-download' => wfMessage( 'timedmedia-download' ), |
145 | // Download file |
146 | // |
147 | // Note the <a download> attribute only is applied on same-origin URLs. |
148 | // The "?download" query string append will work on servers configured |
149 | // the way the Wikimedia production servers are, but other sites that |
150 | // store files offsite may not have the same setup. |
151 | // |
152 | // On failure, these should devolve to either downloading or loading a |
153 | // media file inline, depending on the format and browser and server |
154 | // config. |
155 | 'downloadUrl' => wfAppendQuery( self::getSourceUrl( $file, $transcodeKey ), 'download' ), |
156 | 'msg-timedmedia-reset' => wfMessage( 'timedmedia-reset' ), |
157 | 'html-transcode-status' => self::getStatusMsg( $file, $state ), |
158 | 'transcode-duration' => $this->getTranscodeDuration( $file, $state ), |
159 | ]; |
160 | } |
161 | |
162 | $templateParams = [ |
163 | 'msg-timedmedia-transcodeinfo' => wfMessage( 'timedmedia-transcodeinfo' ), |
164 | 'msg-timedmedia-transcodebitrate' => wfMessage( 'timedmedia-transcodebitrate' ), |
165 | 'msg-timedmedia-not-ready' => wfMessage( 'timedmedia-not-ready' ), |
166 | 'msg-timedmedia-direct-link' => wfMessage( 'timedmedia-direct-link' ), |
167 | 'msg-timedmedia-actions' => wfMessage( 'timedmedia-actions' ), |
168 | 'msg-timedmedia-status' => wfMessage( 'timedmedia-status' ), |
169 | 'msg-timedmedia-transcodeduration' => wfMessage( 'timedmedia-transcodeduration' ), |
170 | 'has-reset' => $this->context->getUser()->isAllowed( 'transcode-reset' ), |
171 | 'transcodeRows' => $transcodeRowsForTemplate, |
172 | ]; |
173 | return $templateParams; |
174 | } |
175 | |
176 | /** |
177 | * @param File $file |
178 | * @param string $transcodeKey |
179 | * @return string |
180 | */ |
181 | public static function getSourceUrl( $file, $transcodeKey ) { |
182 | return WebVideoTranscode::getTranscodedUrlForFile( $file, $transcodeKey ); |
183 | } |
184 | |
185 | /** |
186 | * @param File $file |
187 | * @param array $state |
188 | * @return string |
189 | */ |
190 | public function getTranscodeDuration( File $file, array $state ) { |
191 | if ( $state['time_success'] !== null ) { |
192 | $startTime = (int)wfTimestamp( TS_UNIX, $state['time_startwork'] ); |
193 | $endTime = (int)wfTimestamp( TS_UNIX, $state['time_success'] ); |
194 | $delta = $endTime - $startTime; |
195 | return $this->context->getLanguage()->formatTimePeriod( $delta ); |
196 | } |
197 | return ''; |
198 | } |
199 | |
200 | /** |
201 | * @param File $file |
202 | * @param array $state |
203 | * @return string |
204 | */ |
205 | public function getTranscodeBitrate( File $file, array $state ) { |
206 | if ( $state['time_success'] !== null ) { |
207 | return $this->context->getLanguage()->formatBitrate( $state['final_bitrate'] ); |
208 | } |
209 | return ''; |
210 | } |
211 | |
212 | /** |
213 | * @param File $file |
214 | * @param array $state |
215 | * @return string |
216 | */ |
217 | public static function getStatusMsg( $file, $state ) { |
218 | // Check for success: |
219 | if ( $state['time_success'] !== null ) { |
220 | return wfMessage( 'timedmedia-completed-on' ) |
221 | ->dateTimeParams( $state[ 'time_success' ] )->escaped(); |
222 | } |
223 | // Check for error: |
224 | if ( $state['time_error'] !== null ) { |
225 | $attribs = []; |
226 | if ( $state['error'] !== null ) { |
227 | $attribs = [ |
228 | 'class' => 'mw-tmh-pseudo-error-link', |
229 | 'data-error' => $state['error'], |
230 | ]; |
231 | } |
232 | |
233 | return Html::rawElement( 'span', $attribs, |
234 | wfMessage( 'timedmedia-error-on' ) |
235 | ->dateTimeParams( $state['time_error'] )->escaped() |
236 | ); |
237 | } |
238 | |
239 | // Check for started encoding |
240 | if ( $state['time_startwork'] !== null ) { |
241 | // Get the rough estimate of time done: ( this is not very costly considering everything else |
242 | // that happens in an action=purge video page request ) |
243 | /*$filePath = WebVideoTranscode::getTargetEncodePath( $file, $state['key'] ); |
244 | if ( is_file( $filePath ) ) { |
245 | $targetSize = WebVideoTranscode::getProjectedFileSize( $file, $state['key'] ); |
246 | if ( $targetSize === false ) { |
247 | $doneMsg = wfMessage( 'timedmedia-unknown-target-size', |
248 | $wgLang->formatSize( filesize( $filePath ) ) )->escaped(); |
249 | } else { |
250 | $doneMsg = wfMessage('timedmedia-percent-done', |
251 | round( filesize( $filePath ) / $targetSize, 2 ) )->escaped(); |
252 | } |
253 | } */ |
254 | // Predicting percent done is not working well right now ( disabled for now ) |
255 | $doneMsg = ''; |
256 | return wfMessage( |
257 | 'timedmedia-started-transcode', |
258 | ( new MWTimestamp( $state['time_startwork'] ) )->getRelativeTimestamp(), $doneMsg |
259 | )->escaped(); |
260 | } |
261 | // Check for job added ( but not started encoding ) |
262 | if ( $state['time_addjob'] !== null ) { |
263 | return wfMessage( |
264 | 'timedmedia-in-job-queue', |
265 | ( new MWTimestamp( $state['time_addjob'] ) )->getRelativeTimestamp() |
266 | )->escaped(); |
267 | } |
268 | // Return unknown status error: |
269 | return wfMessage( 'timedmedia-status-unknown' )->escaped(); |
270 | } |
271 | } |