Files
wp-lfnp/lastfm-now-playing.php
2025-11-14 19:02:49 -08:00

199 lines
6.7 KiB
PHP

<?php
/*
Plugin Name: Last.fm Now Playing Widget
Description: Displays your current or most recent track from Last.fm
Version: 1.0.3
Author: Sophia Atkinson
Author URI: https://sophia.wtf/
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html
Text Domain: wp-lfnp
*/
defined("ABSPATH") || exit();
add_action("admin_menu", function () {
add_options_page(
"Last.fm Now Playing Settings",
"Now Playing (Last.fm)",
"manage_options",
"lastfm-nowplaying",
"lastfm_nowplaying_settings_page"
);
});
function lastfm_nowplaying_settings_page()
{
if (!current_user_can("manage_options")) {
return;
}
if (
isset($_POST["lastfm_username"], $_POST["lastfm_apikey"]) &&
check_admin_referer("lastfm_save_settings", "lastfm_nonce")
) {
update_option("lastfm_username", sanitize_text_field($_POST["lastfm_username"]));
update_option("lastfm_apikey", sanitize_text_field($_POST["lastfm_apikey"]));
echo '<div class="updated"><p>Settings saved.</p></div>';
}
$username = get_option("lastfm_username", "");
$apikey = get_option("lastfm_apikey", "");
?>
<div class="wrap">
<h1>Last.fm Now Playing Settings</h1>
<form method="post">
<?php wp_nonce_field("lastfm_save_settings", "lastfm_nonce"); ?>
<table class="form-table">
<tr>
<th><label for="lastfm_username">Last.fm Username</label></th>
<td><input type="text" name="lastfm_username" value="<?php echo esc_attr($username); ?>" class="regular-text" /></td>
</tr>
<tr>
<th><label for="lastfm_apikey">Last.fm API Key</label></th>
<td><input type="text" name="lastfm_apikey" value="<?php echo esc_attr($apikey); ?>" class="regular-text" /></td>
</tr>
</table>
<?php submit_button("Save Settings"); ?>
</form>
</div>
<?php
}
function lastfm_nowplaying_fetch()
{
$username = get_option("lastfm_username");
$apikey = get_option("lastfm_apikey");
if (!$username || !$apikey) {
return [
"title" => "Not configured",
"artist" => "",
"album" => "",
"image" => "",
"nowplaying" => false,
"played_ago" => ""
];
}
$url = "https://ws.audioscrobbler.com/2.0/?method=user.getrecenttracks&user=" . rawurlencode($username) . "&api_key=" . rawurlencode($apikey) . "&format=json&limit=1";
$response = wp_remote_get($url, ["timeout" => 10]);
if (is_wp_error($response)) {
return ["title" => "Fetch error", "artist" => "", "album" => "", "image" => "", "nowplaying" => false, "played_ago" => ""];
}
$data = json_decode(wp_remote_retrieve_body($response), true);
if (!$data || !isset($data["recenttracks"]["track"][0])) {
return ["title" => "No tracks", "artist" => "", "album" => "", "image" => "", "nowplaying" => false, "played_ago" => ""];
}
$track = $data["recenttracks"]["track"][0];
$image_url = $track["image"][2]["#text"] ?? "";
$image_data_uri = "";
if ($image_url) {
$img_response = wp_remote_get($image_url, ["timeout" => 10]);
if (!is_wp_error($img_response)) {
$img_body = wp_remote_retrieve_body($img_response);
if ($img_body) {
$image_data_uri = "data:image/jpeg;base64," . base64_encode($img_body);
}
}
}
$played_ago = "";
if (empty($track["@attr"]["nowplaying"]) && isset($track["date"]["uts"])) {
$timestamp = (int)$track["date"]["uts"];
$diff = time() - $timestamp;
if ($diff < 60) {
$played_ago = $diff . " seconds ago";
} elseif ($diff < 3600) {
$played_ago = floor($diff / 60) . " minutes ago";
} elseif ($diff < 86400) {
$played_ago = floor($diff / 3600) . " hours ago";
} else {
$played_ago = floor($diff / 86400) . " days ago";
}
}
return [
"title" => $track["name"] ?? "Unknown",
"artist" => $track["artist"]["#text"] ?? "",
"album" => $track["album"]["#text"] ?? "",
"image" => $image_data_uri,
"nowplaying" => isset($track["@attr"]["nowplaying"]),
"played_ago" => $played_ago
];
}
add_shortcode("now-playing-widget", function () {
wp_enqueue_style(
"lastfm-nowplaying-style",
plugin_dir_url(__FILE__) . "css/style.css"
);
$track = lastfm_nowplaying_fetch();
ob_start();
?>
<div class="lfnp" id="widget">
<img title="<?php echo esc_attr($track["album"]); ?>"
id="cover"
src="<?php echo esc_attr($track["image"]); ?>"
alt="Album cover" />
<div title="<?php echo esc_attr($track["title"]); ?>" id="title"><?php echo esc_html($track["title"]); ?></div>
<div title="<?php echo esc_attr($track["artist"]); ?>" id="artist"><?php echo esc_html($track["artist"]); ?></div>
<div id="status"
title="<?php echo !$track["nowplaying"] && $track["played_ago"] ? esc_attr($track["played_ago"]) : ''; ?>">
<?php echo $track["nowplaying"] ? "Now Playing" : "Last Played"; ?>
</div>
</div>
<?php
return ob_get_clean();
});
class LastFM_Now_Playing_Widget extends WP_Widget
{
public function __construct()
{
parent::__construct(
"lastfm_now_playing_widget",
__("Last.fm Now Playing", "lastfm_nowplaying"),
["description" => __("Displays your Last.fm now playing track.", "lastfm_nowplaying")]
);
}
public function widget($args, $instance)
{
$title = apply_filters("widget_title", $instance["title"] ?? "");
echo $args["before_widget"];
if (!empty($title)) {
echo $args["before_title"] . esc_html($title) . $args["after_title"];
}
echo do_shortcode("[now-playing-widget]");
echo $args["after_widget"];
}
public function form($instance)
{
$title = esc_attr($instance["title"] ?? ""); ?>
<p>
<label for="<?php echo esc_attr($this->get_field_id("title")); ?>"><?php _e("Title:"); ?></label>
<input class="widefat" id="<?php echo esc_attr($this->get_field_id("title")); ?>"
name="<?php echo esc_attr($this->get_field_name("title")); ?>" type="text"
value="<?php echo $title; ?>" />
</p>
<?php
}
public function update($new_instance, $old_instance)
{
$instance = [];
$instance["title"] = sanitize_text_field($new_instance["title"] ?? "");
return $instance;
}
}
add_action("widgets_init", function () {
register_widget("LastFM_Now_Playing_Widget");
});