Scrutinizer GitHub App not installed

We could not synchronize checks via GitHub's checks API since Scrutinizer's GitHub App is not installed for this repository.

Install GitHub App

GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Passed
Pull Request — master (#818)
by Sebastian
03:23
created

MediaPlayerController::mainAction()   B

Complexity

Conditions 8
Paths 9

Size

Total Lines 37
Code Lines 22

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 8
eloc 22
c 1
b 0
f 0
nc 9
nop 0
dl 0
loc 37
rs 8.4444
1
<?php
2
3
/**
4
 * (c) Kitodo. Key to digital objects e.V. <[email protected]>
5
 *
6
 * This file is part of the Kitodo and TYPO3 projects.
7
 *
8
 * @license GNU General Public License version 3 or later.
9
 * For the full copyright and license information, please read the
10
 * LICENSE.txt file that was distributed with this source code.
11
 */
12
13
namespace Kitodo\Dlf\Controller;
14
15
use Kitodo\Dlf\Common\Doc;
16
use TYPO3\CMS\Core\Page\PageRenderer;
17
use TYPO3\CMS\Core\Utility\GeneralUtility;
18
use TYPO3\CMS\Core\Utility\MathUtility;
19
20
/**
21
 * Plugin MediaPlayer for the 'dlf' extension
22
 *
23
 * @author Kajetan Dvoracek <[email protected]>
24
 * @package TYPO3
25
 * @subpackage dlf
26
 * @access public
27
 */
28
class MediaPlayerController extends AbstractController
29
{
30
    /**
31
     * The main method of the PlugIn
32
     *
33
     * @access public
34
     *
35
     * @param string $content: The PlugIn content
36
     * @param array $conf: The PlugIn configuration
37
     *
38
     * @return string The content that is displayed on the website
39
     */
40
    public function mainAction()
41
    {
42
        // Load current document.
43
        $this->loadDocument($this->requestData);
44
        if (
45
            $this->document === null
46
            || $this->document->getDoc() === null
47
            || $this->document->getDoc()->numPages < 1
48
        ) {
49
            // Quit without doing anything if required variables are not set.
50
            return;
51
        } else {
52
            if (!empty($this->requestData['logicalPage'])) {
53
                $this->requestData['page'] = $this->document->getDoc()->getPhysicalPage($this->requestData['logicalPage']);
54
                // The logical page parameter should not appear again
55
                unset($this->requestData['logicalPage']);
56
            }
57
            // Set default values if not set.
58
            // $this->requestData['page'] may be integer or string (physical structure @ID)
59
            if ((int) $this->requestData['page'] > 0 || empty($this->requestData['page'])) {
60
                $this->requestData['page'] = MathUtility::forceIntegerInRange((int) $this->requestData['page'], 1, $this->document->getDoc()->numPages, 1);
61
            } else {
62
                $this->requestData['page'] = array_search($this->requestData['page'], $this->document->getDoc()->physicalStructure);
63
            }
64
            $this->requestData['double'] = MathUtility::forceIntegerInRange($this->requestData['double'], 0, 1, 0);
65
        }
66
67
        $doc = $this->document->getDoc();
68
        $pageNo = $this->requestData['page'];
69
        $video = $this->getVideoInfo($doc, $pageNo);
70
        if ($video === null) {
71
            return;
72
        }
73
74
        $this->addPlayerJS();
75
76
        $this->view->assign('video', $video);
77
    }
78
79
    /**
80
     * Build video info to be passed to the player template.
81
     *
82
     * @return ?array The video data, or `null` if no video source is found
83
     */
84
    protected function getVideoInfo(Doc $doc, int $pageNo): ?array
85
    {
86
        $videoFileGrps = GeneralUtility::trimExplode(',', $this->extConf['fileGrpVideo']);
87
        $mainVideoFileGrp = $videoFileGrps[0] ?? '';
88
89
        $thumbFileGroups = GeneralUtility::trimExplode(',', $this->extConf['fileGrpThumbs']);
90
        $waveformFileGroups = GeneralUtility::trimExplode(',', $this->extConf['fileGrpWaveform']);
91
92
        $initialMode = 'audio';
93
94
        // Collect video file source URLs
95
        // TODO: This is for multiple sources (MPD, HLS, MP3, ...) - revisit, make sure it's ordered by preference!
96
        $videoSources = [];
97
        $videoFiles = $this->findFiles($doc, $pageNo, $videoFileGrps);
98
        foreach ($videoFiles as $videoFile) {
99
            if ($this->isMediaMime($videoFile['mimeType'])) {
100
                $fileMetadata = $doc->getMetadata($videoFile['fileId'], $this->settings['storagePid']);
101
102
                $videoSources[] = [
103
                    'mimeType' => $videoFile['mimeType'],
104
                    'url' => $videoFile['url'],
105
                    'fileId' => $videoFile['fileId'],
106
                    'frameRate' => $fileMetadata['video_frame_rate'][0] ?? '',
107
                ];
108
109
                // TODO: Better guess of initial mode?
110
                //       Perhaps we could look for VIDEOMD/AUDIOMD in METS
111
                if ($videoFile['fileGrp'] === $mainVideoFileGrp || strpos($videoFile['mimeType'], 'video/') === 0) {
112
                    $initialMode = 'video';
113
                }
114
            }
115
        }
116
        if (empty($videoSources)) {
117
            return null;
118
        }
119
120
        // List all chapters for chapter markers
121
        $videoChapters = [];
122
        foreach ($doc->tableOfContents as $entry) {
123
            $this->recurseChapters($entry, $videoChapters);
124
        }
125
126
        // Get additional video URLs
127
        $videoUrl = [];
128
        if (!empty($thumbFiles = $this->findFiles($doc, 0, $thumbFileGroups))) { // 0 = for whole video (not just chapter)
129
            $videoUrl['poster'] = $thumbFiles[0];
130
        }
131
        if (!empty($waveformFiles = $this->findFiles($doc, $pageNo, $waveformFileGroups))) {
132
            $videoUrl['waveform'] = $waveformFiles[0];
133
        }
134
135
        return [
136
            'start' => $videoChapters[$pageNo - 1]['timecode'] ?: '',
137
            'mode' => $initialMode,
138
            'chapters' => $videoChapters,
139
            'metadata' => $doc->getTitledata($this->settings['storagePid']),
140
            'sources' => $videoSources,
141
            'url' => $videoUrl,
142
        ];
143
    }
144
145
    /**
146
     * Find files of the given file groups that are referenced on a page.
147
     *
148
     * @param Doc $doc
149
     * @param int $pageNo
150
     * @param string[] $fileGrps
151
     * @return string[]
152
     */
153
    protected function findFiles(Doc $doc, int $pageNo, array $fileGrps): array
154
    {
155
        $pagePhysKey = $doc->physicalStructure[$pageNo];
156
        $pageFiles = $doc->physicalStructureInfo[$pagePhysKey]['all_files'] ?? [];
157
        $filesInGrp = array_intersect_key($pageFiles, array_flip($fileGrps));
158
159
        $result = [];
160
        foreach ($filesInGrp as $fileGrp => $fileIds) {
161
            foreach ($fileIds as $fileId) {
162
                $result[] = [
163
                    'fileGrp' => $fileGrp,
164
                    'fileId' => $fileId,
165
                    'url' => $doc->getFileLocation($fileId),
166
                    'mimeType' => $doc->getFileMimeType($fileId),
167
                ];
168
            }
169
        }
170
        return $result;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $result returns an array which contains values of type array<string,mixed|string> which are incompatible with the documented value type string.
Loading history...
171
    }
172
173
    /**
174
     * Recursively push chapters in given logical structure to $outChapters.
175
     */
176
    protected function recurseChapters(array $logInfo, array &$outChapters)
177
    {
178
        if (empty($logInfo['children']) && isset($logInfo['videoChapter'])) {
179
            $outChapters[] = [
180
                'fileIds' => $logInfo['videoChapter']['fileIds'],
181
                'fileIdsJoin' => $logInfo['videoChapter']['fileIdsJoin'],
182
                'pageNo' => $logInfo['points'],
183
                'title' => $logInfo['label'] ?? '',
184
                'timecode' => $logInfo['videoChapter']['timecode'],
185
            ];
186
        }
187
188
        foreach ($logInfo['children'] ?? [] as $child) {
189
            $this->recurseChapters($child, $outChapters);
190
        }
191
    }
192
193
    protected function isMediaMime(string $mimeType)
194
    {
195
        return (
196
            strpos($mimeType, 'audio/') === 0
197
            || strpos($mimeType, 'video/') === 0
198
            || $mimeType == 'application/dash+xml'
199
            || $mimeType == 'application/x-mpegurl'
200
            || $mimeType == 'application/vnd.apple.mpegurl'
201
        );
202
    }
203
204
    /**
205
     * Adds Player javascript
206
     *
207
     * @access protected
208
     *
209
     * @return void
210
     */
211
    protected function addPlayerJS()
212
    {
213
        // TODO: TYPO3 v10
214
        // $assetCollector = GeneralUtility::makeInstance(AssetCollector::class);
215
        // $assetCollector->addJavaScript('DlfMediaPlayer.js', 'EXT:dlf/Resources/Public/Javascript/DlfMediaPlayer.js');
216
        // $assetCollector->addStyleSheet('DlfMediaPlayer.css', 'EXT:dlf/Resources/Public/Css/DlfMediaPlayerStyles.css');
217
218
        // TODO: Move to TypoScript
219
        $pageRenderer = GeneralUtility::makeInstance(PageRenderer::class);
220
        $pageRenderer->addCssFile('EXT:dlf/Resources/Public/Css/DlfMediaPlayer.css');
221
        $pageRenderer->addCssFile('EXT:dlf/Resources/Public/Css/DlfMediaVendor.css', 'stylesheet', 'all', '', true, false, '', /* excludeFromConcatenation= */true);
222
        $pageRenderer->addCssFile('EXT:dlf/Resources/Public/Css/DlfMediaPlayerStyles.css');
223
        $pageRenderer->addJsFooterFile('EXT:dlf/Resources/Public/Javascript/DlfMediaPlayer.js');
224
        $pageRenderer->addJsFooterFile('EXT:dlf/Resources/Public/Javascript/DlfMediaVendor.js', 'text/javascript', true, false, '', /* excludeFromConcatenation= */true);
225
    }
226
}
227