11<?php
22
33namespace Backdrop \gdpr_cookies \Service ;
4+
45use Backdrop \gdpr_cookies \Entity \ThirdPartyServiceEntityInterface ;
56
67/**
@@ -18,6 +19,19 @@ class YoutubeVanisher extends EmbeddedVideoVanisher {
1819 */
1920 const YOUTUBE_VIDEO_ID_REGEX = '~^.*(youtu\.be\/|v\/|u\/\w\/|embed\/|watch\?v=|\&v=)([^#\&\?]*).*~i ' ;
2021
22+ /**
23+ * YouTube parameters to preserve when converting iframes.
24+ */
25+ const PRESERVED_PARAMS = [
26+ 'start ' ,
27+ 'end ' ,
28+ 'autoplay ' ,
29+ 'loop ' ,
30+ 'mute ' ,
31+ 'controls ' ,
32+ 'showinfo ' ,
33+ ];
34+
2135 /**
2236 * {@inheritdoc}
2337 */
@@ -26,35 +40,94 @@ protected function getReplacementMarkup(array $data, ThirdPartyServiceEntityInte
2640 $ data ['height ' ] = "" ;
2741 $ markup = '<div class="youtube_player" videoID=" ' . $ data ['video_id ' ] . '" ' ;
2842 $ markup .= 'width=" ' . $ data ['width ' ] . '" ' ;
29- $ markup .= 'style="aspect-ratio:16/9;"></div> ' ;
43+ $ markup .= 'style="aspect-ratio:16/9;" ' ;
44+
45+ // Add additional parameters.
46+ if (!empty ($ data ['start ' ])) {
47+ $ markup .= ' start=" ' . $ data ['start ' ] . '" ' ;
48+ }
49+ if (!empty ($ data ['end ' ])) {
50+ $ markup .= ' end=" ' . $ data ['end ' ] . '" ' ;
51+ }
52+ if (!empty ($ data ['autoplay ' ])) {
53+ $ markup .= ' autoplay=" ' . $ data ['autoplay ' ] . '" ' ;
54+ }
55+ if (!empty ($ data ['loop ' ])) {
56+ $ markup .= ' loop=" ' . $ data ['loop ' ] . '" ' ;
57+ }
58+ if (!empty ($ data ['mute ' ])) {
59+ $ markup .= ' mute=" ' . $ data ['mute ' ] . '" ' ;
60+ }
61+ if (!empty ($ data ['controls ' ])) {
62+ $ markup .= ' controls=" ' . $ data ['controls ' ] . '" ' ;
63+ }
64+ if (!empty ($ data ['showinfo ' ])) {
65+ $ markup .= ' showinfo=" ' . $ data ['showinfo ' ] . '" ' ;
66+ }
67+
68+ $ markup .= '></div> ' ;
3069 $ markup .= filter_xss_admin ($ entity ->getInfo ());
3170 return $ markup ;
3271 }
3372
73+ $ replacement = '<div class="youtube_player" videoID="@video_id" width="@width" height="@height" ' ;
74+
75+ // Add additional parameters to template.
76+ if (!empty ($ data ['start ' ])) {
77+ $ replacement .= ' start="@start" ' ;
78+ }
79+ if (!empty ($ data ['end ' ])) {
80+ $ replacement .= ' end="@end" ' ;
81+ }
82+ if (!empty ($ data ['autoplay ' ])) {
83+ $ replacement .= ' autoplay="@autoplay" ' ;
84+ }
85+ if (!empty ($ data ['loop ' ])) {
86+ $ replacement .= ' loop="@loop" ' ;
87+ }
88+ if (!empty ($ data ['mute ' ])) {
89+ $ replacement .= ' mute="@mute" ' ;
90+ }
91+ if (!empty ($ data ['controls ' ])) {
92+ $ replacement .= ' controls="@controls" ' ;
93+ }
94+ if (!empty ($ data ['showinfo ' ])) {
95+ $ replacement .= ' showinfo="@showinfo" ' ;
96+ }
97+
98+ $ replacement .= '></div>@info_text ' ;
99+
34100 return str_replace (
35101 [
36102 '@video_id ' ,
37103 '@width ' ,
38104 '@height ' ,
105+ '@start ' ,
106+ '@end ' ,
107+ '@autoplay ' ,
108+ '@loop ' ,
109+ '@mute ' ,
110+ '@controls ' ,
111+ '@showinfo ' ,
39112 '@info_text ' ,
40113 ],
41114 [
42115 $ data ['video_id ' ],
43116 $ data ['width ' ],
44117 $ data ['height ' ],
118+ !empty ($ data ['start ' ]) ? $ data ['start ' ] : '' ,
119+ !empty ($ data ['end ' ]) ? $ data ['end ' ] : '' ,
120+ !empty ($ data ['autoplay ' ]) ? $ data ['autoplay ' ] : '' ,
121+ !empty ($ data ['loop ' ]) ? $ data ['loop ' ] : '' ,
122+ !empty ($ data ['mute ' ]) ? $ data ['mute ' ] : '' ,
123+ !empty ($ data ['controls ' ]) ? $ data ['controls ' ] : '' ,
124+ !empty ($ data ['showinfo ' ]) ? $ data ['showinfo ' ] : '' ,
45125 filter_xss_admin ($ entity ->getInfo ()),
46126 ],
47- $ this -> getReplacementMarkupTemplate ()
127+ $ replacement
48128 );
49129 }
50130
51- /**
52- * {@inheritdoc}
53- */
54- protected function getReplacementMarkupTemplate () {
55- return '<div class="youtube_player" videoID="@video_id" width="@width" height="@height"></div>@info_text ' ;
56- }
57-
58131 /**
59132 * {@inheritdoc}
60133 */
@@ -76,9 +149,68 @@ protected function getVideoData($markup) {
76149 $ data = parent ::getVideoData ($ markup );
77150 $ data ['video_id ' ] = $ this ->extractVideoId ($ data ['src ' ]);
78151
152+ // Extract additional parameters from URL or iframe attributes.
153+ $ data = array_merge ($ data , $ this ->getUrlParams ($ data ['src ' ]));
154+ $ data = array_merge ($ data , $ this ->getIframeAttributes ($ markup ));
155+
79156 return $ data ;
80157 }
81158
159+ /**
160+ * Extracts URL parameters from the YouTube URL.
161+ *
162+ * @param string $url
163+ * The YouTube URL.
164+ *
165+ * @return array
166+ * Array of parameters.
167+ */
168+ protected function getUrlParams ($ url ) {
169+ $ params = [];
170+ $ parsed_url = parse_url ($ url );
171+
172+ if (isset ($ parsed_url ['query ' ])) {
173+ parse_str ($ parsed_url ['query ' ], $ query_params );
174+
175+ // Parameters to preserve
176+ foreach (self ::PRESERVED_PARAMS as $ param ) {
177+ if (isset ($ query_params [$ param ])) {
178+ $ params [$ param ] = $ query_params [$ param ];
179+ }
180+ }
181+
182+ // Convert 't' to 'start' if exists.
183+ if (isset ($ query_params ['t ' ])) {
184+ $ t_value = preg_replace ('/s$/i ' , '' , $ query_params ['t ' ]);
185+ $ params ['start ' ] = $ t_value ;
186+ }
187+ }
188+
189+ return $ params ;
190+ }
191+
192+ /**
193+ * Extracts attributes from the iframe element.
194+ *
195+ * @param string $markup
196+ * The iframe markup.
197+ *
198+ * @return array
199+ * Array of attributes.
200+ */
201+ protected function getIframeAttributes ($ markup ) {
202+ $ attributes = [];
203+
204+ foreach (self ::PRESERVED_PARAMS as $ attribute ) {
205+ $ pattern = '/ ' . $ attribute . '=[" \']([^" \']*)[" \']| ' . $ attribute . '=([^\s>]*)/i ' ;
206+ if (preg_match ($ pattern , $ markup , $ matches )) {
207+ $ attributes [$ attribute ] = !empty ($ matches [1 ]) ? $ matches [1 ] : $ matches [2 ];
208+ }
209+ }
210+
211+ return $ attributes ;
212+ }
213+
82214 /**
83215 * Extracts the video id.
84216 *
0 commit comments