You've already forked wp-fedistream
795 lines
20 KiB
PHP
795 lines
20 KiB
PHP
|
|
<?php
|
||
|
|
/**
|
||
|
|
* User Library class.
|
||
|
|
*
|
||
|
|
* @package WP_FediStream
|
||
|
|
*/
|
||
|
|
|
||
|
|
namespace WP_FediStream\User;
|
||
|
|
|
||
|
|
// Prevent direct file access.
|
||
|
|
if ( ! defined( 'ABSPATH' ) ) {
|
||
|
|
exit;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Handles user library features (favorites, follows, history).
|
||
|
|
*/
|
||
|
|
class Library {
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Constructor.
|
||
|
|
*/
|
||
|
|
public function __construct() {
|
||
|
|
add_action( 'wp_ajax_fedistream_toggle_favorite', array( $this, 'ajax_toggle_favorite' ) );
|
||
|
|
add_action( 'wp_ajax_fedistream_toggle_follow', array( $this, 'ajax_toggle_follow' ) );
|
||
|
|
add_action( 'wp_ajax_fedistream_get_library', array( $this, 'ajax_get_library' ) );
|
||
|
|
add_action( 'wp_ajax_fedistream_get_followed_artists', array( $this, 'ajax_get_followed_artists' ) );
|
||
|
|
add_action( 'wp_ajax_fedistream_get_history', array( $this, 'ajax_get_history' ) );
|
||
|
|
add_action( 'wp_ajax_fedistream_clear_history', array( $this, 'ajax_clear_history' ) );
|
||
|
|
|
||
|
|
// Add library buttons to content.
|
||
|
|
add_filter( 'fedistream_track_actions', array( $this, 'add_favorite_button' ), 10, 2 );
|
||
|
|
add_filter( 'fedistream_album_actions', array( $this, 'add_favorite_button' ), 10, 2 );
|
||
|
|
add_filter( 'fedistream_artist_actions', array( $this, 'add_follow_button' ), 10, 2 );
|
||
|
|
|
||
|
|
// Record play history.
|
||
|
|
add_action( 'fedistream_track_played', array( $this, 'record_play_history' ), 10, 2 );
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Toggle favorite via AJAX.
|
||
|
|
*
|
||
|
|
* @return void
|
||
|
|
*/
|
||
|
|
public function ajax_toggle_favorite(): void {
|
||
|
|
check_ajax_referer( 'fedistream_library', 'nonce' );
|
||
|
|
|
||
|
|
if ( ! is_user_logged_in() ) {
|
||
|
|
wp_send_json_error( array( 'message' => __( 'You must be logged in.', 'wp-fedistream' ) ) );
|
||
|
|
}
|
||
|
|
|
||
|
|
$content_type = isset( $_POST['content_type'] ) ? sanitize_text_field( wp_unslash( $_POST['content_type'] ) ) : '';
|
||
|
|
$content_id = isset( $_POST['content_id'] ) ? absint( $_POST['content_id'] ) : 0;
|
||
|
|
|
||
|
|
if ( ! in_array( $content_type, array( 'track', 'album', 'playlist' ), true ) || ! $content_id ) {
|
||
|
|
wp_send_json_error( array( 'message' => __( 'Invalid request.', 'wp-fedistream' ) ) );
|
||
|
|
}
|
||
|
|
|
||
|
|
$user_id = get_current_user_id();
|
||
|
|
$is_favorited = self::is_favorited( $user_id, $content_type, $content_id );
|
||
|
|
|
||
|
|
if ( $is_favorited ) {
|
||
|
|
$result = self::remove_favorite( $user_id, $content_type, $content_id );
|
||
|
|
$action = 'removed';
|
||
|
|
} else {
|
||
|
|
$result = self::add_favorite( $user_id, $content_type, $content_id );
|
||
|
|
$action = 'added';
|
||
|
|
}
|
||
|
|
|
||
|
|
if ( $result ) {
|
||
|
|
wp_send_json_success(
|
||
|
|
array(
|
||
|
|
'action' => $action,
|
||
|
|
'is_favorited' => ! $is_favorited,
|
||
|
|
'message' => 'added' === $action
|
||
|
|
? __( 'Added to your library.', 'wp-fedistream' )
|
||
|
|
: __( 'Removed from your library.', 'wp-fedistream' ),
|
||
|
|
)
|
||
|
|
);
|
||
|
|
} else {
|
||
|
|
wp_send_json_error( array( 'message' => __( 'Failed to update library.', 'wp-fedistream' ) ) );
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Toggle follow via AJAX.
|
||
|
|
*
|
||
|
|
* @return void
|
||
|
|
*/
|
||
|
|
public function ajax_toggle_follow(): void {
|
||
|
|
check_ajax_referer( 'fedistream_library', 'nonce' );
|
||
|
|
|
||
|
|
if ( ! is_user_logged_in() ) {
|
||
|
|
wp_send_json_error( array( 'message' => __( 'You must be logged in.', 'wp-fedistream' ) ) );
|
||
|
|
}
|
||
|
|
|
||
|
|
$artist_id = isset( $_POST['artist_id'] ) ? absint( $_POST['artist_id'] ) : 0;
|
||
|
|
|
||
|
|
if ( ! $artist_id ) {
|
||
|
|
wp_send_json_error( array( 'message' => __( 'Invalid artist.', 'wp-fedistream' ) ) );
|
||
|
|
}
|
||
|
|
|
||
|
|
$user_id = get_current_user_id();
|
||
|
|
$is_following = self::is_following( $user_id, $artist_id );
|
||
|
|
|
||
|
|
if ( $is_following ) {
|
||
|
|
$result = self::unfollow_artist( $user_id, $artist_id );
|
||
|
|
$action = 'unfollowed';
|
||
|
|
} else {
|
||
|
|
$result = self::follow_artist( $user_id, $artist_id );
|
||
|
|
$action = 'followed';
|
||
|
|
}
|
||
|
|
|
||
|
|
if ( $result ) {
|
||
|
|
wp_send_json_success(
|
||
|
|
array(
|
||
|
|
'action' => $action,
|
||
|
|
'is_following' => ! $is_following,
|
||
|
|
'message' => 'followed' === $action
|
||
|
|
? __( 'You are now following this artist.', 'wp-fedistream' )
|
||
|
|
: __( 'You unfollowed this artist.', 'wp-fedistream' ),
|
||
|
|
)
|
||
|
|
);
|
||
|
|
} else {
|
||
|
|
wp_send_json_error( array( 'message' => __( 'Failed to update follow status.', 'wp-fedistream' ) ) );
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Get user library via AJAX.
|
||
|
|
*
|
||
|
|
* @return void
|
||
|
|
*/
|
||
|
|
public function ajax_get_library(): void {
|
||
|
|
check_ajax_referer( 'fedistream_library', 'nonce' );
|
||
|
|
|
||
|
|
if ( ! is_user_logged_in() ) {
|
||
|
|
wp_send_json_error( array( 'message' => __( 'You must be logged in.', 'wp-fedistream' ) ) );
|
||
|
|
}
|
||
|
|
|
||
|
|
$user_id = get_current_user_id();
|
||
|
|
$type = isset( $_POST['type'] ) ? sanitize_text_field( wp_unslash( $_POST['type'] ) ) : 'all';
|
||
|
|
$page = isset( $_POST['page'] ) ? absint( $_POST['page'] ) : 1;
|
||
|
|
$per_page = 20;
|
||
|
|
|
||
|
|
$library = self::get_user_library( $user_id, $type, $page, $per_page );
|
||
|
|
|
||
|
|
wp_send_json_success( $library );
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Get followed artists via AJAX.
|
||
|
|
*
|
||
|
|
* @return void
|
||
|
|
*/
|
||
|
|
public function ajax_get_followed_artists(): void {
|
||
|
|
check_ajax_referer( 'fedistream_library', 'nonce' );
|
||
|
|
|
||
|
|
if ( ! is_user_logged_in() ) {
|
||
|
|
wp_send_json_error( array( 'message' => __( 'You must be logged in.', 'wp-fedistream' ) ) );
|
||
|
|
}
|
||
|
|
|
||
|
|
$user_id = get_current_user_id();
|
||
|
|
$page = isset( $_POST['page'] ) ? absint( $_POST['page'] ) : 1;
|
||
|
|
$per_page = 20;
|
||
|
|
|
||
|
|
$artists = self::get_followed_artists( $user_id, $page, $per_page );
|
||
|
|
|
||
|
|
wp_send_json_success( $artists );
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Get listening history via AJAX.
|
||
|
|
*
|
||
|
|
* @return void
|
||
|
|
*/
|
||
|
|
public function ajax_get_history(): void {
|
||
|
|
check_ajax_referer( 'fedistream_library', 'nonce' );
|
||
|
|
|
||
|
|
if ( ! is_user_logged_in() ) {
|
||
|
|
wp_send_json_error( array( 'message' => __( 'You must be logged in.', 'wp-fedistream' ) ) );
|
||
|
|
}
|
||
|
|
|
||
|
|
$user_id = get_current_user_id();
|
||
|
|
$page = isset( $_POST['page'] ) ? absint( $_POST['page'] ) : 1;
|
||
|
|
$per_page = 50;
|
||
|
|
|
||
|
|
$history = self::get_listening_history( $user_id, $page, $per_page );
|
||
|
|
|
||
|
|
wp_send_json_success( $history );
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Clear listening history via AJAX.
|
||
|
|
*
|
||
|
|
* @return void
|
||
|
|
*/
|
||
|
|
public function ajax_clear_history(): void {
|
||
|
|
check_ajax_referer( 'fedistream_library', 'nonce' );
|
||
|
|
|
||
|
|
if ( ! is_user_logged_in() ) {
|
||
|
|
wp_send_json_error( array( 'message' => __( 'You must be logged in.', 'wp-fedistream' ) ) );
|
||
|
|
}
|
||
|
|
|
||
|
|
$user_id = get_current_user_id();
|
||
|
|
$result = self::clear_listening_history( $user_id );
|
||
|
|
|
||
|
|
if ( $result ) {
|
||
|
|
wp_send_json_success( array( 'message' => __( 'History cleared.', 'wp-fedistream' ) ) );
|
||
|
|
} else {
|
||
|
|
wp_send_json_error( array( 'message' => __( 'Failed to clear history.', 'wp-fedistream' ) ) );
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Add a favorite.
|
||
|
|
*
|
||
|
|
* @param int $user_id User ID.
|
||
|
|
* @param string $content_type Content type (track, album, playlist).
|
||
|
|
* @param int $content_id Content ID.
|
||
|
|
* @return bool
|
||
|
|
*/
|
||
|
|
public static function add_favorite( int $user_id, string $content_type, int $content_id ): bool {
|
||
|
|
global $wpdb;
|
||
|
|
|
||
|
|
$table = $wpdb->prefix . 'fedistream_favorites';
|
||
|
|
|
||
|
|
$result = $wpdb->insert(
|
||
|
|
$table,
|
||
|
|
array(
|
||
|
|
'user_id' => $user_id,
|
||
|
|
'content_type' => $content_type,
|
||
|
|
'content_id' => $content_id,
|
||
|
|
'created_at' => current_time( 'mysql' ),
|
||
|
|
),
|
||
|
|
array( '%d', '%s', '%d', '%s' )
|
||
|
|
);
|
||
|
|
|
||
|
|
if ( $result ) {
|
||
|
|
do_action( 'fedistream_favorite_added', $user_id, $content_type, $content_id );
|
||
|
|
}
|
||
|
|
|
||
|
|
return (bool) $result;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Remove a favorite.
|
||
|
|
*
|
||
|
|
* @param int $user_id User ID.
|
||
|
|
* @param string $content_type Content type (track, album, playlist).
|
||
|
|
* @param int $content_id Content ID.
|
||
|
|
* @return bool
|
||
|
|
*/
|
||
|
|
public static function remove_favorite( int $user_id, string $content_type, int $content_id ): bool {
|
||
|
|
global $wpdb;
|
||
|
|
|
||
|
|
$table = $wpdb->prefix . 'fedistream_favorites';
|
||
|
|
|
||
|
|
$result = $wpdb->delete(
|
||
|
|
$table,
|
||
|
|
array(
|
||
|
|
'user_id' => $user_id,
|
||
|
|
'content_type' => $content_type,
|
||
|
|
'content_id' => $content_id,
|
||
|
|
),
|
||
|
|
array( '%d', '%s', '%d' )
|
||
|
|
);
|
||
|
|
|
||
|
|
if ( $result ) {
|
||
|
|
do_action( 'fedistream_favorite_removed', $user_id, $content_type, $content_id );
|
||
|
|
}
|
||
|
|
|
||
|
|
return (bool) $result;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Check if content is favorited.
|
||
|
|
*
|
||
|
|
* @param int $user_id User ID.
|
||
|
|
* @param string $content_type Content type.
|
||
|
|
* @param int $content_id Content ID.
|
||
|
|
* @return bool
|
||
|
|
*/
|
||
|
|
public static function is_favorited( int $user_id, string $content_type, int $content_id ): bool {
|
||
|
|
global $wpdb;
|
||
|
|
|
||
|
|
$table = $wpdb->prefix . 'fedistream_favorites';
|
||
|
|
|
||
|
|
$exists = $wpdb->get_var(
|
||
|
|
$wpdb->prepare(
|
||
|
|
"SELECT id FROM {$table} WHERE user_id = %d AND content_type = %s AND content_id = %d",
|
||
|
|
$user_id,
|
||
|
|
$content_type,
|
||
|
|
$content_id
|
||
|
|
)
|
||
|
|
);
|
||
|
|
|
||
|
|
return (bool) $exists;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Follow an artist.
|
||
|
|
*
|
||
|
|
* @param int $user_id User ID.
|
||
|
|
* @param int $artist_id Artist post ID.
|
||
|
|
* @return bool
|
||
|
|
*/
|
||
|
|
public static function follow_artist( int $user_id, int $artist_id ): bool {
|
||
|
|
global $wpdb;
|
||
|
|
|
||
|
|
$table = $wpdb->prefix . 'fedistream_user_follows';
|
||
|
|
|
||
|
|
$result = $wpdb->insert(
|
||
|
|
$table,
|
||
|
|
array(
|
||
|
|
'user_id' => $user_id,
|
||
|
|
'artist_id' => $artist_id,
|
||
|
|
'created_at' => current_time( 'mysql' ),
|
||
|
|
),
|
||
|
|
array( '%d', '%d', '%s' )
|
||
|
|
);
|
||
|
|
|
||
|
|
if ( $result ) {
|
||
|
|
do_action( 'fedistream_artist_followed', $user_id, $artist_id );
|
||
|
|
}
|
||
|
|
|
||
|
|
return (bool) $result;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Unfollow an artist.
|
||
|
|
*
|
||
|
|
* @param int $user_id User ID.
|
||
|
|
* @param int $artist_id Artist post ID.
|
||
|
|
* @return bool
|
||
|
|
*/
|
||
|
|
public static function unfollow_artist( int $user_id, int $artist_id ): bool {
|
||
|
|
global $wpdb;
|
||
|
|
|
||
|
|
$table = $wpdb->prefix . 'fedistream_user_follows';
|
||
|
|
|
||
|
|
$result = $wpdb->delete(
|
||
|
|
$table,
|
||
|
|
array(
|
||
|
|
'user_id' => $user_id,
|
||
|
|
'artist_id' => $artist_id,
|
||
|
|
),
|
||
|
|
array( '%d', '%d' )
|
||
|
|
);
|
||
|
|
|
||
|
|
if ( $result ) {
|
||
|
|
do_action( 'fedistream_artist_unfollowed', $user_id, $artist_id );
|
||
|
|
}
|
||
|
|
|
||
|
|
return (bool) $result;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Check if user is following an artist.
|
||
|
|
*
|
||
|
|
* @param int $user_id User ID.
|
||
|
|
* @param int $artist_id Artist post ID.
|
||
|
|
* @return bool
|
||
|
|
*/
|
||
|
|
public static function is_following( int $user_id, int $artist_id ): bool {
|
||
|
|
global $wpdb;
|
||
|
|
|
||
|
|
$table = $wpdb->prefix . 'fedistream_user_follows';
|
||
|
|
|
||
|
|
$exists = $wpdb->get_var(
|
||
|
|
$wpdb->prepare(
|
||
|
|
"SELECT id FROM {$table} WHERE user_id = %d AND artist_id = %d",
|
||
|
|
$user_id,
|
||
|
|
$artist_id
|
||
|
|
)
|
||
|
|
);
|
||
|
|
|
||
|
|
return (bool) $exists;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Record play history.
|
||
|
|
*
|
||
|
|
* @param int $track_id Track post ID.
|
||
|
|
* @param int $user_id User ID (0 for anonymous).
|
||
|
|
* @return void
|
||
|
|
*/
|
||
|
|
public function record_play_history( int $track_id, int $user_id ): void {
|
||
|
|
if ( ! $user_id ) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
global $wpdb;
|
||
|
|
|
||
|
|
$table = $wpdb->prefix . 'fedistream_listening_history';
|
||
|
|
|
||
|
|
// Check if recently played (within last 30 seconds) to avoid duplicates.
|
||
|
|
$recent = $wpdb->get_var(
|
||
|
|
$wpdb->prepare(
|
||
|
|
"SELECT id FROM {$table} WHERE user_id = %d AND track_id = %d AND played_at > DATE_SUB(NOW(), INTERVAL 30 SECOND)",
|
||
|
|
$user_id,
|
||
|
|
$track_id
|
||
|
|
)
|
||
|
|
);
|
||
|
|
|
||
|
|
if ( $recent ) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
$wpdb->insert(
|
||
|
|
$table,
|
||
|
|
array(
|
||
|
|
'user_id' => $user_id,
|
||
|
|
'track_id' => $track_id,
|
||
|
|
'played_at' => current_time( 'mysql' ),
|
||
|
|
),
|
||
|
|
array( '%d', '%d', '%s' )
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Get user library.
|
||
|
|
*
|
||
|
|
* @param int $user_id User ID.
|
||
|
|
* @param string $type Content type filter (all, tracks, albums, playlists).
|
||
|
|
* @param int $page Page number.
|
||
|
|
* @param int $per_page Items per page.
|
||
|
|
* @return array
|
||
|
|
*/
|
||
|
|
public static function get_user_library( int $user_id, string $type = 'all', int $page = 1, int $per_page = 20 ): array {
|
||
|
|
global $wpdb;
|
||
|
|
|
||
|
|
$table = $wpdb->prefix . 'fedistream_favorites';
|
||
|
|
$offset = ( $page - 1 ) * $per_page;
|
||
|
|
|
||
|
|
$where = 'WHERE user_id = %d';
|
||
|
|
$params = array( $user_id );
|
||
|
|
|
||
|
|
if ( 'all' !== $type && in_array( $type, array( 'track', 'album', 'playlist' ), true ) ) {
|
||
|
|
$where .= ' AND content_type = %s';
|
||
|
|
$params[] = $type;
|
||
|
|
}
|
||
|
|
|
||
|
|
$total = $wpdb->get_var(
|
||
|
|
$wpdb->prepare(
|
||
|
|
"SELECT COUNT(*) FROM {$table} {$where}",
|
||
|
|
...$params
|
||
|
|
)
|
||
|
|
);
|
||
|
|
|
||
|
|
$params[] = $per_page;
|
||
|
|
$params[] = $offset;
|
||
|
|
|
||
|
|
$favorites = $wpdb->get_results(
|
||
|
|
$wpdb->prepare(
|
||
|
|
"SELECT content_type, content_id, created_at FROM {$table} {$where} ORDER BY created_at DESC LIMIT %d OFFSET %d",
|
||
|
|
...$params
|
||
|
|
)
|
||
|
|
);
|
||
|
|
|
||
|
|
$items = array();
|
||
|
|
|
||
|
|
foreach ( $favorites as $favorite ) {
|
||
|
|
$post = get_post( $favorite->content_id );
|
||
|
|
|
||
|
|
if ( ! $post || 'publish' !== $post->post_status ) {
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
|
||
|
|
$item = array(
|
||
|
|
'id' => $post->ID,
|
||
|
|
'type' => $favorite->content_type,
|
||
|
|
'title' => $post->post_title,
|
||
|
|
'permalink' => get_permalink( $post ),
|
||
|
|
'added_at' => $favorite->created_at,
|
||
|
|
'thumbnail' => get_the_post_thumbnail_url( $post, 'medium' ),
|
||
|
|
);
|
||
|
|
|
||
|
|
if ( 'track' === $favorite->content_type ) {
|
||
|
|
$item['duration'] = get_post_meta( $post->ID, '_fedistream_duration', true );
|
||
|
|
$item['artist'] = self::get_track_artist_name( $post->ID );
|
||
|
|
} elseif ( 'album' === $favorite->content_type ) {
|
||
|
|
$item['artist'] = self::get_album_artist_name( $post->ID );
|
||
|
|
$item['track_count'] = get_post_meta( $post->ID, '_fedistream_total_tracks', true );
|
||
|
|
}
|
||
|
|
|
||
|
|
$items[] = $item;
|
||
|
|
}
|
||
|
|
|
||
|
|
return array(
|
||
|
|
'items' => $items,
|
||
|
|
'total' => (int) $total,
|
||
|
|
'page' => $page,
|
||
|
|
'per_page' => $per_page,
|
||
|
|
'total_pages' => (int) ceil( $total / $per_page ),
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Get followed artists.
|
||
|
|
*
|
||
|
|
* @param int $user_id User ID.
|
||
|
|
* @param int $page Page number.
|
||
|
|
* @param int $per_page Items per page.
|
||
|
|
* @return array
|
||
|
|
*/
|
||
|
|
public static function get_followed_artists( int $user_id, int $page = 1, int $per_page = 20 ): array {
|
||
|
|
global $wpdb;
|
||
|
|
|
||
|
|
$table = $wpdb->prefix . 'fedistream_user_follows';
|
||
|
|
$offset = ( $page - 1 ) * $per_page;
|
||
|
|
|
||
|
|
$total = $wpdb->get_var(
|
||
|
|
$wpdb->prepare(
|
||
|
|
"SELECT COUNT(*) FROM {$table} WHERE user_id = %d",
|
||
|
|
$user_id
|
||
|
|
)
|
||
|
|
);
|
||
|
|
|
||
|
|
$follows = $wpdb->get_results(
|
||
|
|
$wpdb->prepare(
|
||
|
|
"SELECT artist_id, created_at FROM {$table} WHERE user_id = %d ORDER BY created_at DESC LIMIT %d OFFSET %d",
|
||
|
|
$user_id,
|
||
|
|
$per_page,
|
||
|
|
$offset
|
||
|
|
)
|
||
|
|
);
|
||
|
|
|
||
|
|
$artists = array();
|
||
|
|
|
||
|
|
foreach ( $follows as $follow ) {
|
||
|
|
$post = get_post( $follow->artist_id );
|
||
|
|
|
||
|
|
if ( ! $post || 'publish' !== $post->post_status ) {
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
|
||
|
|
$artists[] = array(
|
||
|
|
'id' => $post->ID,
|
||
|
|
'name' => $post->post_title,
|
||
|
|
'permalink' => get_permalink( $post ),
|
||
|
|
'followed_at' => $follow->created_at,
|
||
|
|
'thumbnail' => get_the_post_thumbnail_url( $post, 'thumbnail' ),
|
||
|
|
'type' => get_post_meta( $post->ID, '_fedistream_artist_type', true ) ?: 'solo',
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
return array(
|
||
|
|
'artists' => $artists,
|
||
|
|
'total' => (int) $total,
|
||
|
|
'page' => $page,
|
||
|
|
'per_page' => $per_page,
|
||
|
|
'total_pages' => (int) ceil( $total / $per_page ),
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Get listening history.
|
||
|
|
*
|
||
|
|
* @param int $user_id User ID.
|
||
|
|
* @param int $page Page number.
|
||
|
|
* @param int $per_page Items per page.
|
||
|
|
* @return array
|
||
|
|
*/
|
||
|
|
public static function get_listening_history( int $user_id, int $page = 1, int $per_page = 50 ): array {
|
||
|
|
global $wpdb;
|
||
|
|
|
||
|
|
$table = $wpdb->prefix . 'fedistream_listening_history';
|
||
|
|
$offset = ( $page - 1 ) * $per_page;
|
||
|
|
|
||
|
|
$total = $wpdb->get_var(
|
||
|
|
$wpdb->prepare(
|
||
|
|
"SELECT COUNT(*) FROM {$table} WHERE user_id = %d",
|
||
|
|
$user_id
|
||
|
|
)
|
||
|
|
);
|
||
|
|
|
||
|
|
$history = $wpdb->get_results(
|
||
|
|
$wpdb->prepare(
|
||
|
|
"SELECT track_id, played_at FROM {$table} WHERE user_id = %d ORDER BY played_at DESC LIMIT %d OFFSET %d",
|
||
|
|
$user_id,
|
||
|
|
$per_page,
|
||
|
|
$offset
|
||
|
|
)
|
||
|
|
);
|
||
|
|
|
||
|
|
$tracks = array();
|
||
|
|
|
||
|
|
foreach ( $history as $item ) {
|
||
|
|
$post = get_post( $item->track_id );
|
||
|
|
|
||
|
|
if ( ! $post || 'publish' !== $post->post_status ) {
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
|
||
|
|
$tracks[] = array(
|
||
|
|
'id' => $post->ID,
|
||
|
|
'title' => $post->post_title,
|
||
|
|
'permalink' => get_permalink( $post ),
|
||
|
|
'played_at' => $item->played_at,
|
||
|
|
'thumbnail' => get_the_post_thumbnail_url( $post, 'thumbnail' ),
|
||
|
|
'duration' => get_post_meta( $post->ID, '_fedistream_duration', true ),
|
||
|
|
'artist' => self::get_track_artist_name( $post->ID ),
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
return array(
|
||
|
|
'tracks' => $tracks,
|
||
|
|
'total' => (int) $total,
|
||
|
|
'page' => $page,
|
||
|
|
'per_page' => $per_page,
|
||
|
|
'total_pages' => (int) ceil( $total / $per_page ),
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Clear listening history.
|
||
|
|
*
|
||
|
|
* @param int $user_id User ID.
|
||
|
|
* @return bool
|
||
|
|
*/
|
||
|
|
public static function clear_listening_history( int $user_id ): bool {
|
||
|
|
global $wpdb;
|
||
|
|
|
||
|
|
$table = $wpdb->prefix . 'fedistream_listening_history';
|
||
|
|
$result = $wpdb->delete( $table, array( 'user_id' => $user_id ), array( '%d' ) );
|
||
|
|
|
||
|
|
return false !== $result;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Get track artist name.
|
||
|
|
*
|
||
|
|
* @param int $track_id Track post ID.
|
||
|
|
* @return string
|
||
|
|
*/
|
||
|
|
private static function get_track_artist_name( int $track_id ): string {
|
||
|
|
$artist_ids = get_post_meta( $track_id, '_fedistream_artist_ids', true );
|
||
|
|
|
||
|
|
if ( is_array( $artist_ids ) && ! empty( $artist_ids ) ) {
|
||
|
|
$names = array();
|
||
|
|
foreach ( $artist_ids as $artist_id ) {
|
||
|
|
$artist = get_post( $artist_id );
|
||
|
|
if ( $artist ) {
|
||
|
|
$names[] = $artist->post_title;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return implode( ', ', $names );
|
||
|
|
}
|
||
|
|
|
||
|
|
$album_id = get_post_meta( $track_id, '_fedistream_album_id', true );
|
||
|
|
$artist_id = $album_id ? get_post_meta( $album_id, '_fedistream_album_artist', true ) : 0;
|
||
|
|
|
||
|
|
if ( $artist_id ) {
|
||
|
|
$artist = get_post( $artist_id );
|
||
|
|
return $artist ? $artist->post_title : '';
|
||
|
|
}
|
||
|
|
|
||
|
|
return '';
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Get album artist name.
|
||
|
|
*
|
||
|
|
* @param int $album_id Album post ID.
|
||
|
|
* @return string
|
||
|
|
*/
|
||
|
|
private static function get_album_artist_name( int $album_id ): string {
|
||
|
|
$artist_id = get_post_meta( $album_id, '_fedistream_album_artist', true );
|
||
|
|
|
||
|
|
if ( $artist_id ) {
|
||
|
|
$artist = get_post( $artist_id );
|
||
|
|
return $artist ? $artist->post_title : '';
|
||
|
|
}
|
||
|
|
|
||
|
|
return '';
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Add favorite button to track/album actions.
|
||
|
|
*
|
||
|
|
* @param string $actions HTML actions.
|
||
|
|
* @param int $post_id Post ID.
|
||
|
|
* @return string
|
||
|
|
*/
|
||
|
|
public function add_favorite_button( string $actions, int $post_id ): string {
|
||
|
|
if ( ! is_user_logged_in() ) {
|
||
|
|
return $actions;
|
||
|
|
}
|
||
|
|
|
||
|
|
$post = get_post( $post_id );
|
||
|
|
if ( ! $post ) {
|
||
|
|
return $actions;
|
||
|
|
}
|
||
|
|
|
||
|
|
$content_type = str_replace( 'fedistream_', '', $post->post_type );
|
||
|
|
$user_id = get_current_user_id();
|
||
|
|
$is_favorited = self::is_favorited( $user_id, $content_type, $post_id );
|
||
|
|
|
||
|
|
$button = sprintf(
|
||
|
|
'<button class="fedistream-favorite-btn%s" data-content-type="%s" data-content-id="%d" title="%s">
|
||
|
|
<span class="dashicons dashicons-heart"></span>
|
||
|
|
</button>',
|
||
|
|
$is_favorited ? ' is-favorited' : '',
|
||
|
|
esc_attr( $content_type ),
|
||
|
|
$post_id,
|
||
|
|
$is_favorited ? esc_attr__( 'Remove from library', 'wp-fedistream' ) : esc_attr__( 'Add to library', 'wp-fedistream' )
|
||
|
|
);
|
||
|
|
|
||
|
|
return $actions . $button;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Add follow button to artist actions.
|
||
|
|
*
|
||
|
|
* @param string $actions HTML actions.
|
||
|
|
* @param int $artist_id Artist post ID.
|
||
|
|
* @return string
|
||
|
|
*/
|
||
|
|
public function add_follow_button( string $actions, int $artist_id ): string {
|
||
|
|
if ( ! is_user_logged_in() ) {
|
||
|
|
return $actions;
|
||
|
|
}
|
||
|
|
|
||
|
|
$user_id = get_current_user_id();
|
||
|
|
$is_following = self::is_following( $user_id, $artist_id );
|
||
|
|
|
||
|
|
$button = sprintf(
|
||
|
|
'<button class="fedistream-follow-btn%s" data-artist-id="%d">
|
||
|
|
<span class="dashicons dashicons-%s"></span>
|
||
|
|
<span class="button-text">%s</span>
|
||
|
|
</button>',
|
||
|
|
$is_following ? ' is-following' : '',
|
||
|
|
$artist_id,
|
||
|
|
$is_following ? 'yes' : 'plus',
|
||
|
|
$is_following ? esc_html__( 'Following', 'wp-fedistream' ) : esc_html__( 'Follow', 'wp-fedistream' )
|
||
|
|
);
|
||
|
|
|
||
|
|
return $actions . $button;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Get user's favorite count.
|
||
|
|
*
|
||
|
|
* @param int $user_id User ID.
|
||
|
|
* @param string $content_type Optional content type filter.
|
||
|
|
* @return int
|
||
|
|
*/
|
||
|
|
public static function get_favorite_count( int $user_id, string $content_type = '' ): int {
|
||
|
|
global $wpdb;
|
||
|
|
|
||
|
|
$table = $wpdb->prefix . 'fedistream_favorites';
|
||
|
|
|
||
|
|
if ( $content_type ) {
|
||
|
|
$count = $wpdb->get_var(
|
||
|
|
$wpdb->prepare(
|
||
|
|
"SELECT COUNT(*) FROM {$table} WHERE user_id = %d AND content_type = %s",
|
||
|
|
$user_id,
|
||
|
|
$content_type
|
||
|
|
)
|
||
|
|
);
|
||
|
|
} else {
|
||
|
|
$count = $wpdb->get_var(
|
||
|
|
$wpdb->prepare(
|
||
|
|
"SELECT COUNT(*) FROM {$table} WHERE user_id = %d",
|
||
|
|
$user_id
|
||
|
|
)
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
return (int) $count;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Get user's followed artist count.
|
||
|
|
*
|
||
|
|
* @param int $user_id User ID.
|
||
|
|
* @return int
|
||
|
|
*/
|
||
|
|
public static function get_following_count( int $user_id ): int {
|
||
|
|
global $wpdb;
|
||
|
|
|
||
|
|
$table = $wpdb->prefix . 'fedistream_user_follows';
|
||
|
|
|
||
|
|
$count = $wpdb->get_var(
|
||
|
|
$wpdb->prepare(
|
||
|
|
"SELECT COUNT(*) FROM {$table} WHERE user_id = %d",
|
||
|
|
$user_id
|
||
|
|
)
|
||
|
|
);
|
||
|
|
|
||
|
|
return (int) $count;
|
||
|
|
}
|
||
|
|
}
|