PluginProbe
FluentCommunity – Ultra-Fast High-Performance Social Network, Community, LMS & Online Courses / 2.6.01
FluentCommunity – Ultra-Fast High-Performance Social Network, Community, LMS & Online Courses v2.6.01
2.10.0 2.10.01 2.9.1 2.9.0 2.8.1 2.8.0 2.7.7 2.7.5 2.7.0 2.6.01 2.6.0 2.5.0 2.4.01 trunk 1.0.90 1.0.91 1.0.92 1.0.93 1.0.94 1.0.95 1.0.96 1.0.97 1.0.98 1.0.99 1.1.0 All 77 releases
fluent-community / Modules / Integrations / FluentPlayer / Http / Controllers / MediaController.php

MediaController.php in FluentCommunity – Ultra-Fast High-Performance Social Network, Community, LMS & Online Courses 2.6.01, at Modules/Integrations/FluentPlayer/Http/Controllers/MediaController.php

319 lines 12.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace FluentCommunity\Modules\Integrations\FluentPlayer\Http\Controllers;
4
5 use FluentCommunity\App\Http\Controllers\Controller;
6 use FluentCommunity\App\Models\Media;
7 use FluentCommunity\App\Services\Helper;
8 use FluentCommunity\App\Services\Libs\FileSystem;
9 use FluentCommunity\Framework\Http\Request\Request;
10 use FluentCommunity\Framework\Support\Arr;
11 use FluentCommunity\Modules\Integrations\FluentPlayer\Bootstrap;
12
13 class MediaController extends Controller
14 {
15 public function uploadVideo(Request $request)
16 {
17 $getFluentPlayerStatus = Bootstrap::getPluginStatus();
18 if ($getFluentPlayerStatus !== 'active') {
19 return $this->sendError([
20 'message' => __('Uploading videos is not allowed. Activate FluentPlayer to upload videos.', 'fluent-community')
21 ]);
22 }
23
24 $fluentPlayerSettings = Bootstrap::getSettings();
25 if (!Arr::isTrue($fluentPlayerSettings, 'video_upload')) {
26 return $this->sendError([
27 'message' => __('Uploading videos is not allowed', 'fluent-community')
28 ]);
29 }
30 $uploadRole = Arr::get($fluentPlayerSettings, 'video_upload_role');
31 $uploadRole = $uploadRole ?: 'admin';
32 $isAllowed = false;
33 if ('admin' === $uploadRole && Helper::isSiteAdmin()) {
34 $isAllowed = true;
35 } else if ('admin_moderator' === $uploadRole && (Helper::isModerator() || Helper::isSiteAdmin())) {
36 $isAllowed = true;
37 } else if ('everyone' === $uploadRole) {
38 $isAllowed = true;
39 }
40 if (!$isAllowed) {
41 return $this->sendError([
42 'message' => __('You do not have permission to upload videos', 'fluent-community')
43 ]);
44 }
45
46 $allowedVideoTypes = apply_filters('fluent_community/support_video_types', [
47 'video/mp4',
48 'video/m3u8',
49 'video/mpd',
50 'video/webm',
51 'video/mov',
52 'video/quicktime'
53 ]);
54 $maxFileUnit = apply_filters('fluent_community/video_upload_max_file_unit', 'MB');
55 $maxFileSize = apply_filters('fluent_community/video_upload_max_file_size', 300);
56 $allowedFileSize = $maxFileSize;
57 if (strtoupper($maxFileUnit) == 'MB') {
58 $allowedFileSize = $maxFileSize * 1024;
59 } else if (strtoupper($maxFileUnit) == 'GB') {
60 $allowedFileSize = $maxFileSize * 1024 * 1024;
61 }
62
63 $allowedTypesString = implode(',', $allowedVideoTypes);
64
65 $files = $this->validate($request->files(), [
66 'file' => 'mimetypes:' . $allowedTypesString . '|max:' . $allowedFileSize,
67 ], [
68 'file.mimetypes' => __('The file must be a valid video type (MP4, M3U8, MPD, WebM, MOV).', 'fluent-community'),
69 /* translators: %1$s is the maximum file size value, %2$s is the size unit (KB, MB, etc.) */
70 'file.max' => sprintf(__('The file size must be less than %1$s%2$s.', 'fluent-community'), $maxFileSize, $maxFileUnit)
71 ]);
72 // File size check
73 if ($error = Helper::checkUploadSizeError()) {
74 return $this->sendError($error, 413);
75 }
76
77 $uploadedFiles = FileSystem::put($files);
78 $file = $uploadedFiles[0];
79
80 $upload_dir = wp_upload_dir();
81 $file['path'] = $upload_dir['basedir'] . '/fluent-community/' . $file['file'];
82
83 $mediaData = [
84 'media_type' => 'fluent_player',
85 'driver' => 'local',
86 'media_path' => $file['path'],
87 'media_url' => $file['url'],
88 'settings' => [
89 'src' => $file['url'],
90 'title' => $file['original_name']
91 ]
92 ];
93
94 $mediaData = apply_filters('fluent_community/media_upload_data', $mediaData, $file);
95
96 if (is_wp_error($mediaData)) {
97 return $this->sendError([
98 'message' => $mediaData->get_error_message(),
99 'errors' => $mediaData->get_error_data()
100 ]);
101 }
102
103 if (!$mediaData) {
104 return $this->sendError([
105 'message' => __('Error while uploading the video', 'fluent-community')
106 ]);
107 }
108 $mediaData['settings']['src'] = Arr::get($mediaData, 'media_url', $file['url']);
109
110 // Disable crossorigin for cloud storage drivers that may lack CORS headers
111 $driver = Arr::get($mediaData, 'driver', 'local');
112 if ($driver === 's3') {
113 $mediaData['settings']['crossorigin'] = false;
114 }
115
116 $media = Media::create($mediaData);
117 return [
118 'media' => [
119 'media_id' => $media->id,
120 'url' => $media->public_url,
121 'media_key' => $media->media_key,
122 'type' => $media->media_type,
123 'settings' => $media->settings,
124 'html' => ''
125 ]
126 ];
127 }
128
129 public function getFluentPlayerContent(Request $request)
130 {
131 if (!defined('FLUENT_PLAYER_VERSION')) {
132 return [
133 'html' => '',
134 ];
135 }
136 $mediaId = intval($request->get('media_id'));
137 $instanceKey = sanitize_key($request->get('player_instance_key'));
138 $shareUrl = esc_url_raw($request->get('share_url'));
139 $media = Media::find($mediaId);
140 if (!$media) {
141 $media = (object) $request->all();
142 } else if ($shareUrl) {
143 $media->share_url = $shareUrl;
144 }
145 return $this->generateFluentPlayerHtml($mediaId, $media, $instanceKey);
146 }
147
148 private function generateFluentPlayerHtml($mediaId, $media, $instanceKey = '')
149 {
150 $mediaVarName = 'fluentPlayerMedia_' . $mediaId . '_' . wp_rand(1000, 9999);
151 $playerKey = 'fcom_' . $mediaId;
152 $instanceId = $playerKey . ($instanceKey ? '_' . $instanceKey : '');
153 $mediaSettings = [];
154 $formattedMedia = [
155 'ID' => $mediaId
156 ];
157 if (!empty($media->settings)) {
158 $mediaSettings = $media->settings;
159 }
160 if (empty($mediaSettings['src']) && !empty($media->url)) {
161 $mediaSettings['src'] = $media->url;
162 }
163 if (empty($mediaSettings['title']) && !empty($media->title)) {
164 $mediaSettings['title'] = $media->title;
165 }
166 if (empty($mediaSettings['posterSrc']) && !empty($media->image)) {
167 $mediaSettings['posterSrc'] = $media->image;
168 }
169 if (empty($mediaSettings['share_url']) && !empty($media->share_url)) {
170 $mediaSettings['share_url'] = esc_url_raw($media->share_url);
171 }
172 $src = Arr::get($mediaSettings, 'src', '');
173 // Normalize YouTube /live/ URLs to /watch?v= so Vidstack can resolve them
174 if ($src && strpos($src, 'youtube.com/live/') !== false) {
175 $src = preg_replace('/youtube\.com\/live\/([^?&#]+)\??/', 'youtube.com/watch?v=$1&', $src);
176 $src = rtrim($src, '&');
177 $mediaSettings['src'] = $src;
178 }
179 if ($src && preg_match('#youtube\.com/shorts/#i', $src)) {
180 $mediaSettings['is_short'] = true;
181 }
182
183 $mediaSettings = wp_parse_args($mediaSettings, $this->getFluentplayerDefaultsSettings());
184 $formattedMedia['settings'] = $mediaSettings;
185 $formattedMedia['deep_link_ref'] = $playerKey;
186
187 // Generate the HTML using fluent-player's view system
188 ob_start();
189 if (class_exists('\FluentPlayer\App\App')) {
190 try {
191 $fluentPlayerApp = \FluentPlayer\App\App::getInstance();
192 if ($fluentPlayerApp) {
193 $fluentPlayerApp->view->render('player', [
194 'media_id' => $mediaId,
195 'instance_id' => $instanceId,
196 'media_var_name' => $mediaVarName,
197 'player_ref' => $playerKey,
198 'settings' => $mediaSettings
199 ]);
200 }
201 } catch (\Exception $e) {
202 }
203 }
204 $html = ob_get_clean();
205 return [
206 'html' => $html ? $html . $this->generateFluentPlayerCustomStyle($instanceId, $mediaSettings) : '',
207 'media' => $formattedMedia
208 ];
209 }
210
211 private function generateFluentPlayerCustomStyle($instanceId, $settings)
212 {
213 $customCss = '';
214 $playerWidth = Arr::get($settings, 'playerWidth');
215 if ($playerWidth) {
216 $customCss .= "
217 #fluent_player_" . esc_attr($instanceId) . " .fluent-player-container {
218 width: " . esc_attr($playerWidth) . 'px' . ";
219 }
220 ";
221 }
222 $brandingColor = Arr::get($settings, 'brandColor', '');
223 if ($brandingColor) {
224 $customCss .= "
225 #fluent_player_" . esc_attr($instanceId) . " {
226 --media-brand: " . esc_attr($brandingColor) . ";
227 }
228 ";
229 }
230 $brandingColor = Arr::get($settings, 'brandColor', '');
231 $controlBarColor = Arr::get($settings, 'controlBarColor', '');
232 if ($brandingColor || $controlBarColor) {
233 $customCss .= "
234 #fluent_player_" . esc_attr($instanceId) . " {";
235 if ($brandingColor) {
236 $customCss .= "
237 --media-brand: " . esc_attr($brandingColor) . ";";
238 }
239 if ($controlBarColor) {
240 $customCss .= "
241 --fp-control-bar-bg: " . esc_attr($controlBarColor) . ";";
242 }
243 $customCss .= "
244 }
245 ";
246 }
247 if (!empty(Arr::get($settings, 'posterSrc', ''))) {
248 $customCss .= "
249 #fluent_player_" . esc_attr($instanceId) . " .fluent-player-container {
250 background-image: url('" . esc_url(Arr::get($settings, 'posterSrc', '')) . "');
251 background-size: cover;
252 background-position: center;
253 min-height: 100%;
254 }
255 ";
256 }
257
258 $aspectRatio = Arr::get($settings, 'aspectRatio');
259 if ($aspectRatio && $aspectRatio != 'original') {
260 $cssAspectRatio = preg_replace('/^(\d+):(\d+)$/', '$1/$2', $aspectRatio);
261 $customCss .= "
262 #fluent_player_" . esc_attr($instanceId) . " {
263 aspect-ratio: " . esc_attr($cssAspectRatio) . ";
264 }
265 #fluent_player_" . esc_attr($instanceId) . " media-player[data-view-type='video'] {
266 aspect-ratio: " . esc_attr($cssAspectRatio) . ";
267 }
268 ";
269 } else {
270 $customCss .= "
271 #fluent_player_" . esc_attr($instanceId) . " {
272 max-width: 100%;
273 min-height: 300px;
274 }
275
276 @media (max-width: 768px) {
277 #fluent_player_" . esc_attr($instanceId) . " {
278 min-height: 200px;
279 }
280 }
281 ";
282 }
283 if (!empty($customCss)) {
284 return '<style>' . $customCss . '</style>';
285 }
286 return '';
287 }
288
289 private function getFluentplayerDefaultsSettings()
290 {
291 $settings = [
292 'src' => '',
293 'title' => '',
294 'posterSrc' => '',
295 'viewType' => 'video',
296 'brandColor' => '#4a90e2',
297 'aspectRatio' => 'original',
298 'playerWidth' => '',
299 ];
300 $mediaSettings = Bootstrap::getSettings();
301 if (Arr::isTrue($mediaSettings, 'behaviors.muted_autoplay')) {
302 $mediaSettings['autoplay'] = true;
303 $mediaSettings['muted'] = true;
304 }
305 $settings['loadStrategy'] = 'idle'; // for SPA context this needs to be set to 'idle'
306 $settings = array_merge($settings, $mediaSettings);
307
308 // Apply iOS Safari compatibility (playsinline, preload; muted only when autoplay is on)
309 if (class_exists('\FluentPlayer\App\Services\MediaService')) {
310 [$isIosSafari, $iosSafariSettings] = \FluentPlayer\App\Services\MediaService::getIOSSafariSettings($settings);
311 if ($isIosSafari) {
312 $settings = array_merge($settings, $iosSafariSettings);
313 }
314 }
315
316 return apply_filters('fluent_community/fluentplayer_defaults_settings', $settings);
317 }
318 }
319