#' Get Local Recommendations
#'
#' This is the wrapper function to the Listen Local Demo recommendation system.
#'
#' @rdname recparam
#' @param recommendation_type Defaults to \code{'artists'}, can be \code{'release'}
#' or \code{'both'}.
#' @param limit Number of playlist items used for recommendation seed.
#' @param silent Defaults to \code{TRUE}.
##' @param authorization Defaults to \code{NULL} when
#' \code{\link[spotifyr]{get_spotify_access_token}} is invoked.
#' @param listen_local_artist_data If \code{NULL}, the functions try to load the data from the
#' spotifyrecommendations package.
#' @param local_genre_table_path If \code{NULL}, the functions try to load the data from the
#' spotifyrecommendations package.
#' @param artist_distance_data If \code{NULL}, the functions try to load the data from the
#' spotifyrecommendations package.
#' @param artist_genre_table_path If \code{NULL}, the functions try to load the data from the
#' spotifyrecommendations package.
#' @importFrom dplyr bind_rows ungroup filter select sample_n
#' @importFrom tidyselect all_of any_of
#' @importFrom spotifyr get_spotify_access_token get_artist_audio_features
#' @importFrom assertthat assert_that
#' @return A tibble of recommendations.
#' @export
get_local_recommendations <- function(
playlist_id = "6KHw5aZWWsmRqpT7o290Mo",
target_nationality = "sk",
target_release = "sk",
recommendation_type = "artists",
limit = 20,
n_rec = 4,
silent = TRUE,
authorization = NULL,
listen_local_artist_data = 'not_included/listen_local_artists.rds',
artist_distance_data = 'not_included/artist_distances.rds',
local_genre_table_path = "not_included/local_genre_table.rds",
artist_genre_table_path = "not_included/artist_genre_table.rds") {
if (is.null(authorization)) {
authorization <- spotifyr::get_spotify_access_token()
}
## Load target artist data ---------------------------------------
if ( ! exists ("listen_local_artist_data") ) {
# It should exist in the global environment of the Shiny App
# see Objects visible across all sessions
# https://shiny.rstudio.com/articles/scoping.html
if ( !is.null(listen_local_artist_data) ) {
load_data ( variable_name = "listen_local_artists",
data_path = listen_local_artist_data,
envir = environment() #default, not necessary parameter
)
} else {
data("listen_local_artists", package = 'spotifyrecommendations', envir = environment())
}
}
## Get info about the user's playlist items from Spotify -----------
user_playlist_info <- get_playlist_information(
playlist_id = playlist_id )
if ( recommendation_type == 'artists' ) {
target_nationality <- target_nationality
target_release <- NULL
target_artist_ids <- get_national_artist_ids(target_nationality)
} else if ( recommendation_type == "release") {
target_nationality <- NULL
target_release <- "sk"
target_artist_ids <- NULL
} else {
if ( target_nationality != target_release ) {
target_release <- target_nationality
target_artist_ids <- get_national_artist_ids(target_nationality)
}
}
vars_to_select <- c( "id", "name", "popularity",
"uri", "external_ids.isrc",
"release_country_code",
"target_artists" )
users_artists <- unique(user_playlist_info$user_playlist_artists$id)
message ( "Getting initial user recommendations")
initial_user_recommendations <- initial_recommendations(
playlist_information = user_playlist_info,
target_ids = target_artist_ids,
limit = limit,
silent = silent,
authorization = authorization )
local_recommendations <- initial_user_recommendations
if (
# recommendations are not based on artists
!is.null(target_nationality) ) {
local_recommendations <- local_recommendations %>%
filter ( target_nationality == TRUE)
}
if (
# release country does not play a role
!is.null(target_release)
) {
local_recommendations <- local_recommendations %>%
filter ( target_release == target_release )
}
local_recommendations <- local_recommendations %>%
select ( any_of(vars_to_select) )
if ( nrow(local_recommendations)>=n_rec ) {
#should return n_rec number recommendations
return(local_recommendations)
}
### ----- artist based recommendations ---------------------------------
message ( "... not sufficient, moving on to artits-based recommendations.")
if ( !exists ( "artist_distances" ) ) {
# Should exist in the global session of the Shiny app
if ( !is.null(artist_distance_data) ) {
load_data ( "artist_distances", artist_distance_data )
} else {
data("artist_distance_data", package = 'spotifyrecommendations', envir = environment())
}
}
message ( paste0("There are ", nrow(artist_distances), " artist distances defined.") )
## recommend artists first
recommended_by_artist_similarity <- get_local_artist_recommendations(
user_playlist_artists = users_artists,
target_ids = target_artist_ids,
n_rec = n_rec,
authorization = authorization
)
if ( !is.null(recommended_by_artist_similarity) ) {
message ( paste0(length (recommended_by_artist_similarity), " similar artists found.") )
assertthat::assert_that(all ( recommended_by_artist_similarity %in% target_artist_ids ),
msg = "Wrong nationality is recommended.")
tracks_by_artist_similarity <- lapply ( recommended_by_artist_similarity,
purrr::possibly(spotifyr::get_artist_audio_features, NULL) )
## Exception: artist has no albums
null_values <- vapply ( 1:length(tracks_by_artist_similarity), function(x) is.null(tracks_by_artist_similarity[[x]]), logical(1))
if ( all(null_values) ) {
# recommended_by_artist_similarity did not result in any recommendation candidates
local_recommendations_2 <- local_recommendations
} else {
tracks_by_artist_similarity <- do.call( rbind, tracks_by_artist_similarity )
message ( paste0 (nrow ( tracks_by_artist_similarity ), " track candidates are available from the artists."))
## Find the most suitable tracks from the candidate list.
local_recommendations_by_artist <- get_nearest_tracks(
user_playlist_info = user_playlist_info$user_playlist_tracks,
new_tracks = tracks_by_artist_similarity )
message ( "Nearest candidates are identified")
if ( !is.null(local_recommendations_by_artist) ) {
local_recommendations_2 <- local_recommendations_by_artist %>%
mutate ( release_country_code = get_release_country(.data$external_ids.isrc),
target_artists = TRUE ) %>%
select ( all_of (vars_to_select)) %>%
bind_rows (local_recommendations) %>%
ungroup()
if ( nrow(local_recommendations_2)>=n_rec ) {
return(sample_n(local_recommendations_2,size = n_rec))
}
} else {
# local_recommendations_by_artist is NULL
local_recommendations_2 <- local_recommendations
}
# end when something came up
}
}
### ----- genre based recommendations ----------------------------------
message ( "... not sufficient, moving on to genre-based recommendations.")
if ( !exists("artist_genre_table")) {
if ( !is.null(artist_genre_table_path) ) {
load_data ( "artist_genre_table", artist_genre_table_path )
} else {
data("artist_genre_table_path", package = 'spotifyrecommendations', envir = environment() )
}
}
if ( !exists("local_genre_table")) {
if ( !is.null(local_genre_table_path) ) {
load_data ( "local_genre_table", local_genre_table_path )
} else {
data("local_genre_table_path", package = 'spotifyrecommendations',envir = environment() )
}
}
user_artists_by_genre <- get_artist_genre(
user_playlist_artists = user_playlist_info$user_playlist_artists
)
## recommend artists by genre first
recommended_by_genre <- get_artist_recommendations_genre(
artists_by_genre = user_artists_by_genre,
target_nationality = target_nationality
)
if ( ! all ( recommended_by_genre %in% target_artist_ids ) ) {
stop("Wrong nationality is recommended.")
}
tracks_by_genre_similarity <- lapply (
recommended_by_genre,
purrr::possibly(get_artist_audio_features, NULL))
tracks_by_genre_similarity <- do.call( rbind, tracks_by_genre_similarity )
if ( !is.null(tracks_by_genre_similarity)) {
local_recommendations_by_genre <- get_nearest_tracks(
user_playlist_info = user_playlist_info$user_playlist_tracks,
new_tracks = tracks_by_genre_similarity,
n_rec = n_rec )
}
if ( !is.null(local_recommendations_by_genre ) ) {
## if the genre based recommendations were successful, add them to the the
## existing candidates
local_recommendations_3 <- local_recommendations_by_genre %>%
mutate ( release_country_code = get_release_country(.data$external_ids.isrc),
target_artists = TRUE ) %>%
select ( all_of (vars_to_select)) %>%
bind_rows (local_recommendations_2) %>%
ungroup()
if ( nrow(local_recommendations_3)>=n_rec ) {
## if the candidates are more than required, randomly select n_rec
return( sample_n(local_recommendations_3, size = n_rec) )
}
} else {
## if there were no genre-based recommendations, give whatever we have
local_recommendations_2
}
}
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.