PluginProbe
FluentCommunity – Ultra-Fast High-Performance Social Network, Community, LMS & Online Courses / 2.5.0
FluentCommunity – Ultra-Fast High-Performance Social Network, Community, LMS & Online Courses v2.5.0
2.11.0 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 All 78 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.5.0, at Modules/Integrations/FluentPlayer/Http/Controllers/MediaController.php

317 lines 12.0 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 }
254 ";
255 }
256
257 $aspectRatio = Arr::get($settings, 'aspectRatio');
258 if ($aspectRatio && $aspectRatio != 'original') {
259 $cssAspectRatio = preg_replace('/^(\d+):(\d+)$/', '$1/$2', $aspectRatio);
260 $customCss .= "
261 #fluent_player_" . esc_attr($instanceId) . " {
262 aspect-ratio: " . esc_attr($cssAspectRatio) . ";
263 }
264 #fluent_player_" . esc_attr($instanceId) . " media-player[data-view-type='video'] {
265 aspect-ratio: " . esc_attr($cssAspectRatio) . ";
266 }
267 ";
268 } else {
269 $customCss .= "
270 #fluent_player_" . esc_attr($instanceId) . " {
271 min-height: 300px;
272 }
273
274 @media (max-width: 768px) {
275 #fluent_player_" . esc_attr($instanceId) . " {
276 min-height: 200px;
277 }
278 }
279 ";
280 }
281 if (!empty($customCss)) {
282 return '<style>' . $customCss . '</style>';
283 }
284 return '';
285 }
286
287 private function getFluentplayerDefaultsSettings()
288 {
289 $settings = [
290 'src' => '',
291 'title' => '',
292 'posterSrc' => '',
293 'viewType' => 'video',
294 'brandColor' => '#4a90e2',
295 'aspectRatio' => 'original',
296 'playerWidth' => '',
297 ];
298 $mediaSettings = Bootstrap::getSettings();
299 if (Arr::isTrue($mediaSettings, 'behaviors.muted_autoplay')) {
300 $mediaSettings['autoplay'] = true;
301 $mediaSettings['muted'] = true;
302 }
303 $settings['loadStrategy'] = 'idle'; // for SPA context this needs to be set to 'idle'
304 $settings = array_merge($settings, $mediaSettings);
305
306 // Apply iOS Safari compatibility (playsinline, preload; muted only when autoplay is on)
307 if (class_exists('\FluentPlayer\App\Services\MediaService')) {
308 [$isIosSafari, $iosSafariSettings] = \FluentPlayer\App\Services\MediaService::getIOSSafariSettings($settings);
309 if ($isIosSafari) {
310 $settings = array_merge($settings, $iosSafariSettings);
311 }
312 }
313
314 return apply_filters('fluent_community/fluentplayer_defaults_settings', $settings);
315 }
316 }
317