PluginProbe ʕ •ᴥ•ʔ
Music Player for WooCommerce / 1.8.3
Music Player for WooCommerce v1.8.3
1.8.3 1.8.2 1.8.1 1.1.10 1.1.11 1.1.2 1.1.3 1.1.4 1.1.5 1.1.6 1.1.7 1.1.8 1.1.9 1.2.0 1.2.1 1.2.2 1.2.3 1.2.4 1.2.5 1.2.6 1.2.7 1.2.8 1.2.9 1.3.0 1.3.1 1.3.10 1.3.11 1.3.2 1.3.3 1.3.4 1.3.5 1.3.6 1.3.7 1.3.8 1.3.9 1.4.0 1.4.1 1.4.2 1.4.3 1.4.4 1.4.5 1.5.0 1.5.1 1.6.0 1.6.1 1.6.2 1.6.3 1.7.0 1.7.1 1.7.2 1.7.3 1.7.4 1.7.5 1.7.6 1.7.7 1.7.8 1.7.9 1.8.0 trunk 1.0.173 1.0.174 1.0.175 1.0.176 1.0.177 1.0.178 1.0.179 1.0.180 1.0.181 1.0.182 1.0.183 1.0.184 1.0.185 1.0.186 1.0.187 1.0.188 1.0.189 1.0.190 1.0.191 1.0.192 1.0.193 1.0.194 1.0.195 1.0.196 1.0.197 1.1.0 1.1.1
music-player-for-woocommerce / inc / skingenerator.inc.php
music-player-for-woocommerce / inc Last commit date
cache.inc.php 1 month ago landing.inc.php 1 month ago skingenerator.inc.php 1 month ago tools.inc.php 1 month ago
skingenerator.inc.php
178 lines
1 <?php
2 if ( !is_admin() ) {
3 print 'Direct access not allowed.';
4 exit;
5 }
6
7 if ( ! class_exists( 'WCMP_SKIN_GENERATOR' ) ) {
8 class WCMP_SKIN_GENERATOR {
9
10 static private $gemini_model = "models/gemini-3.5-flash";
11 static private $gemini_url = "https://generativelanguage.googleapis.com/v1beta/";
12
13 static private function gemini_inference( $prompt, $api_key ) {
14 $inference_url = self::$gemini_url . self::$gemini_model . ":generateContent?key=" . $api_key;
15 $data = [ 'contents' => [[ 'parts' => [[ 'text' => $prompt ]] ]], "generationConfig" => [ "temperature" => 0.0, "topP" => 0.9 ] ];
16
17 // Inferring the model to generate the form.
18 $body = json_encode( $data );
19
20 $response = wp_remote_post( $inference_url, [
21 'headers' => [ 'Content-Type' => 'application/json' ],
22 'body' => $body,
23 'timeout' => 120,
24 ]);
25
26 if ( is_wp_error( $response ) ) {
27 throw new Exception( $response->get_error_message() );
28 }
29
30 $exception = new Exception( __( 'Empty AI model answer', 'music-player-for-woocommerce' ) );
31
32 $data = json_decode(wp_remote_retrieve_body($response), true);
33 if( empty( $data ) ) throw $exception;
34 if ( ! empty( $data[ 'error' ] ) ) throw new Exception( $data['error']['message'] );
35
36 try {
37 $output = $data['candidates'][0]['content']['parts'][0]['text'];
38 // Remove markdown characters from the beginning and end:
39 $output = preg_replace('/^```css\s*(.*?)\s*```$/s', '$1', $output);
40 $output = str_replace( '.wcmp-custom-skin .mejs-container', '.wcmp-custom-skin.mejs-container', $output );
41 } catch ( Exception $err ) {
42 throw $exception;
43 }
44 return $output;
45 } // End gemini_inference.
46
47 static private function wp_connector_inference( $prompt ) {
48 $_set_timeout = function($timeout){ return 120; };
49 add_filter('wp_ai_client_default_request_timeout', $_set_timeout, 999);
50
51 try {
52 $output = wp_ai_client_prompt($prompt)->generate_text();
53 } finally {
54 remove_filter('wp_ai_client_default_request_timeout', $_set_timeout, 999);
55 }
56
57 if (is_wp_error($output)) throw new Exception( $output->get_error_message() );
58 return $output;
59 } // End wp_connector_inference.
60
61 static public function is_wp_connector_available() {
62 // Check if there are models registered using the WordPress Connector API.
63 if ( function_exists('wp_ai_client_prompt') ) {
64 $builder = wp_ai_client_prompt('test');
65 if ($builder->is_supported_for_text_generation()) {
66 return true;
67 }
68 }
69
70 return false;
71 } // End is_wp_connector_available
72
73 static public function model_inference( $inference_data ) {
74
75 // Base CSS.
76 $base_url = includes_url() . 'js/mediaelement/';
77 $base_css_url = $base_url . 'wp-mediaelement.css';
78 $base_css_path = ABSPATH . WPINC . '/js/mediaelement/mediaelementplayer-legacy.css';
79 $schema = file_exists( $base_css_path ) ? file_get_contents( $base_css_path ) : $base_css_url;
80 $schema = str_ireplace( 'url(', 'url(' . $base_url, $schema );
81
82 // Update the URLs of
83 // Generate the prompt.
84 $prompt = "Generate CSS styles for a MediaElementPlayer skin based on the CSS styles:\n\n$schema\n\n"
85 . "The following rules ALWAYS apply regardless of the skin description:\n"
86 . "- Only modify color, background, border-radius, box-shadow, and font properties.\n"
87 . "- Do NOT alter position, z-index, height, width, display, transform, or animation values.\n"
88 . "- Preserve all SVG background-image URLs exactly as they appear in the source CSS.\n"
89 . "- Do not add selectors or properties that are not present in the source CSS.\n"
90 . "- Infer a coherent color palette from the description and apply it consistently across all components (control bar, progress bar, buttons, volume slider, captions).\n\n"
91 . "Output instructions:\n"
92 . "Return only valid CSS code scoped under .wcmp-custom-skin. No comments, no explanations, no description, no extra information, no Markdown, no enclose the response in triple backticks.\n\n"
93 . "Skin description:\n{$inference_data['skin_description']}";
94
95 if ( self::is_wp_connector_available() ) {
96 $output = self::wp_connector_inference( $prompt );
97 } else if ( ! empty( $inference_data['api_key'] ) ) {
98 $output = self::gemini_inference( $prompt, $inference_data['api_key'] );
99 } else {
100 throw new Exception( __( 'There is no enought information to generate the custom skin', 'music-player-for-woocommerce' ) );
101 }
102
103 return $output;
104
105 } // End model_inference.
106
107 } // End class WCMP_SKIN_GENERATOR.
108 }
109
110 // Main code
111
112 /** CALL THE AI SKIN GENERATOR **/
113 if ( ! empty( $_POST['wcmp_skin_generator_description'] ) ) {
114
115 remove_all_actions( 'shutdown' );
116 check_admin_referer( 'wcmp-ai-skin-generator', '_wcmp_nonce' );
117
118 function prepare_inference_data() {
119 $output = [];
120
121 if ( current_user_can( 'manage_options' ) ) new Exception(__( 'You don\'t have enought privileges to generate custom skins.', 'music-player-for-woocommerce' ));
122
123 if ( ! WCMP_SKIN_GENERATOR::is_wp_connector_available() ) {
124 if ( ! isset( $_POST['wcmp_skin_generator_api_key'] ) ) new Exception( __( 'The AI Provider API Key is required.', 'music-player-for-woocommerce' ));
125
126 $api_key = sanitize_text_field( wp_unslash( $_POST['wcmp_skin_generator_api_key'] ) );
127 if ( empty( $api_key ) ) new Exception( __( 'The AI Provider API Key is required.', 'music-player-for-woocommerce' ));
128 $output['api_key'] = $api_key;
129 }
130
131 $skin_description = sanitize_textarea_field( wp_unslash( $_POST['wcmp_skin_generator_description'] ) );
132 if ( empty( $skin_description ) ) new Exception( __( 'The Skin description is required.', 'music-player-for-woocommerce' ));
133 $output['skin_description'] = $skin_description;
134
135 return $output;
136 }
137
138 try {
139 $inference_data = prepare_inference_data();
140 $output['success'] = WCMP_SKIN_GENERATOR::model_inference( $inference_data );
141 } catch( Exception $err ) {
142 $output['error'] = $err->getMessage();
143 }
144
145 print json_encode( $output );
146 exit;
147 } elseif (
148 ! empty( $_POST['wcmp_custom_skin'] )
149 ) {
150 remove_all_actions( 'shutdown' );
151 check_admin_referer( 'wcmp-custom-skin-preview', '_wcmp_nonce' );
152
153 $custom_skin = sanitize_textarea_field( wp_unslash( $_POST['wcmp_custom_skin'] ) );
154 // Re-check if custom_skin is not empty.
155 if ( ! empty( $custom_skin ) ) {
156 print '<link rel="stylesheet" href="'. esc_attr( includes_url( 'js/mediaelement/mediaelementplayer-legacy.min.css' ) ) .'">
157 <link rel="stylesheet" href="' . esc_attr( includes_url( 'js/mediaelement/wp-mediaelement.min.css' ) ) .'">
158 <link rel="stylesheet" href="' . esc_attr( plugin_dir_url( __FILE__ ) . '../vendors/mejs-skins/mejs-skins.min.css' ) . '">
159 <style>
160 body {margin: 0;padding: 20px;font-family: Arial, sans-serif;background: #ffffff;}
161 .player-container {max-width: 600px;margin: 0 auto;}
162 .mejs__container {margin: 0 auto;}' .
163 $custom_skin .
164 '</style>
165 <script type="text/javascript" src="' . esc_attr( includes_url( 'js/jquery/jquery.js' ) ) . '"></script>
166 <script src="' . esc_attr( includes_url( 'js/jquery/jquery-migrate.min.js' ) ) . '"></script>
167 <script src="' . esc_attr( includes_url( 'js/mediaelement/mediaelement-and-player.min.js' ) ) . '"></script>
168 <script src="' . esc_attr( includes_url( 'js/mediaelement/mediaelement-migrate.js' ) ) . '"></script>
169 <script src="' . esc_attr( includes_url( 'js/mediaelement/wp-mediaelement.js' ) ) . '"></script>
170 <script src="' . esc_attr( plugin_dir_url( __FILE__ ) . '../js/public.js' ) . '"></script>
171 <div class="wcmp-player-container">
172 <audio controlslist="nodownload" volume="1" preload="none" data-lazyloading="none" class="wcmp-player mejs-classic wcmp-custom-skin" src="'. esc_attr( plugin_dir_url( __FILE__ ) . '../vendors/demo/demo.mp3' ) . '">
173 <source src="' . esc_attr( plugin_dir_url( __FILE__ ) . '../vendors/demo/demo.mp3' ) . '" type="audio/mp3">
174 </audio>
175 </div>';
176 exit;
177 }
178 }