auth_key = get_option($this->option_name); add_action('rest_api_init', array($this, 'register_routes')); add_action('admin_menu', array($this, 'add_admin_menu')); add_action('admin_init', array($this, 'register_settings')); register_activation_hook(__FILE__, array($this, 'activate_plugin')); } public function activate_plugin() { // Set default AUTH_KEY if not exists if (!get_option($this->option_name)) { update_option($this->option_name, wp_generate_password(32, false)); } } public function register_routes() { register_rest_route('image-scrobble/v1', '/create', array( 'methods' => 'POST', 'callback' => array($this, 'create_image'), 'permission_callback' => array($this, 'check_auth') )); register_rest_route('image-scrobble/v1', '/scrobble', array( 'methods' => 'POST', 'callback' => array($this, 'scrobble'), 'permission_callback' => array($this, 'check_auth') )); } public function check_auth($request) { $auth_header = $request->get_header('Authorization'); return $auth_header && $auth_header === "Bearer {$this->auth_key}"; } public function create_image($request) { // Retrieve the raw image data from the request body $image_data = $request->get_body(); // Sanitize and retrieve parameters from the request $author = sanitize_text_field($request->get_param('author')); $album_title = sanitize_text_field($request->get_param('album_title')); $song_title = sanitize_text_field($request->get_param('song_title')); // New parameter // Validate required parameters if (empty($author)) { return new WP_Error( 'missing_author', 'Author is required.', array('status' => 400) ); } // Ensure that either album_title or song_title is provided if (empty($album_title) && empty($song_title)) { return new WP_Error( 'missing_titles', 'Either album title or song title is required.', array('status' => 400) ); } // Determine which title to use: album_title takes precedence over song_title $title = !empty($album_title) ? $album_title : $song_title; // Generate a hash of the image data to check for duplicates $image_hash = md5($image_data); // Check if an image with this hash already exists to prevent duplicates $existing_attachment = $this->get_attachment_by_hash($image_hash); if ($existing_attachment) { return new WP_REST_Response( array('url' => wp_get_attachment_url($existing_attachment->ID)), 200 ); } // Get the upload directory information $upload_dir = wp_upload_dir(); // Create a sanitized filename using the author and the determined title $filename = sanitize_file_name("{$author} - {$title}.jpg"); // Ensure the filename is unique within the upload directory $unique_filename = wp_unique_filename($upload_dir['path'], $filename); // Construct the full file path $file_path = trailingslashit($upload_dir['path']) . $unique_filename; // Attempt to save the image data to the specified file path if (file_put_contents($file_path, $image_data) === false) { return new WP_Error( 'file_save_failed', 'Failed to save the image file.', array('status' => 500) ); } // Prepare the attachment data $attachment = array( 'post_mime_type' => 'image/jpeg', 'post_title' => "{$author} - {$title}", 'post_content' => '', 'post_status' => 'inherit' ); // Insert the attachment into the WordPress media library $attach_id = wp_insert_attachment($attachment, $file_path); // Check for errors during attachment insertion if (is_wp_error($attach_id)) { @unlink($file_path); // Clean up the file if attachment creation failed return $attach_id; // Return the WP_Error } // Generate and update attachment metadata require_once(ABSPATH . 'wp-admin/includes/image.php'); $attach_data = wp_generate_attachment_metadata($attach_id, $file_path); wp_update_attachment_metadata($attach_id, $attach_data); // Save the image hash in the attachment's metadata for future duplicate checks update_post_meta($attach_id, 'image_hash', $image_hash); // Retrieve the URL of the newly created attachment $image_url = wp_get_attachment_url($attach_id); // Return a successful response with the image URL return new WP_REST_Response( array('url' => $image_url), 200 ); } private function get_attachment_by_hash($hash) { $args = array( 'post_type' => 'attachment', 'post_status' => 'inherit', 'posts_per_page' => 1, 'meta_query' => array( array( 'key' => 'image_hash', 'value' => $hash, 'compare' => '=' ) ) ); $query = new WP_Query($args); if ($query->have_posts()) { return $query->posts[0]; } return null; } public function scrobble($request) { global $wpdb; $data = $request->get_json_params(); // Updated required fields: 'album_name' is no longer required $required_fields = ['song_name', 'author']; // Check for missing required fields foreach ($required_fields as $field) { if (!isset($data[$field])) { return new WP_Error('missing_field', 'Missing required field: ' . $field, array('status' => 400)); } } $table_name = 'song_scrobbles'; $cover_url = isset($data['cover_url']) ? $data['cover_url'] : null; $album_name = isset($data['album_name']) ? $data['album_name'] : null; // If 'album_name' is not provided, 'cover_url' must be present if (empty($album_name)) { if (empty($cover_url)) { return new WP_Error( 'missing_cover_url', 'Cover URL must be provided if album name is not present', array('status' => 400) ); } } else { // If 'album_name' is provided but 'cover_url' is not, attempt to retrieve it from existing entries if (empty($cover_url)) { // Prepare case-insensitive search $song_name_lower = strtolower($data['song_name']); $album_name_lower = strtolower($album_name); $author_lower = strtolower($data['author']); // Query to find the most recent matching entry $query = $wpdb->prepare( "SELECT cover_url FROM $table_name WHERE LOWER(album_name) = %s AND LOWER(author) = %s ORDER BY id DESC LIMIT 1", $album_name_lower, $author_lower ); $cover_url = $wpdb->get_var($query); // If no matching entry is found, return an error if (!$cover_url) { return new WP_Error( 'missing_cover_url', 'Cover URL not provided and no existing entry found for the given album and author', array('status' => 400) ); } } } // Insert the scrobble data into the database $result = $wpdb->insert( $table_name, array( 'song_name' => $data['song_name'], 'album_name' => $album_name, // This can be null 'cover_url' => $cover_url, 'author' => $data['author'], 'length_seconds' => isset($data['length_seconds']) ? intval($data['length_seconds']) : null ), array('%s', '%s', '%s', '%s', '%d') ); // Handle potential database insertion errors if ($result === false) { return new WP_Error('db_error', 'Error saving scrobble', array('status' => 500)); } // Return a successful response return new WP_REST_Response(array('message' => 'Scrobble saved successfully'), 201); } public function add_admin_menu() { add_options_page( 'Image Scrobble Settings', 'Image Scrobble', 'manage_options', 'image-scrobble-settings', array($this, 'settings_page') ); } public function register_settings() { register_setting('image_scrobble_settings', $this->option_name); } public function settings_page() { ?>