Skip to content

Commit

Permalink
Overdue pull request with added playlist functions and fixed oauth. (#…
Browse files Browse the repository at this point in the history
…134)

* Additional functions for  playlists.

* squashed some warnings and notes from devtools::check()

* added position to add_video_to_playlist
fixed upload_video.

* Reverting to old file name for consistency.

* yt_oauth fixed to handle second logins. readRDS on line 41 returns a list, not an environment variable. httr::oauth2.0_token functionality made to mirror spotifyr.

* update_video_metadata function added

* az

* Additional functions for  playlists.

* squashed some warnings and notes from devtools::check()

* added position to add_video_to_playlist
fixed upload_video.

* Reverting to old file name for consistency.

* yt_oauth fixed to handle second logins. readRDS on line 41 returns a list, not an environment variable. httr::oauth2.0_token functionality made to mirror spotifyr.

* update_video_metadata function added

* az
  • Loading branch information
TroyHernandez authored Jul 18, 2024
1 parent 774a6f2 commit b5fc8c4
Show file tree
Hide file tree
Showing 24 changed files with 701 additions and 26 deletions.
6 changes: 6 additions & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
# Generated by roxygen2: do not edit by hand

export("%>%")
export(add_video_to_playlist)
export(change_playlist_title)
export(create_playlist)
export(delete_captions)
export(delete_channel_sections)
export(delete_comments)
Expand All @@ -13,6 +16,8 @@ export(get_captions)
export(get_channel_stats)
export(get_comment_threads)
export(get_comments)
export(get_playlist_item_ids)
export(get_playlist_item_videoids)
export(get_playlist_items)
export(get_playlists)
export(get_related_videos)
Expand All @@ -33,6 +38,7 @@ export(list_regions)
export(list_videocats)
export(list_videos)
export(read_sbv)
export(update_video_metadata)
export(upload_caption)
export(upload_video)
export(yt_authorized)
Expand Down
51 changes: 51 additions & 0 deletions R/add_video_to_playlist.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#' Add Video to Playlist
#'
#' @param playlist_id string; Required. The ID of the playlist.
#' @param video_id string; Required. The ID of the video to add.
#' @param ... Additional arguments passed to \code{\link{tuber_POST_json}}.
#'
#' @return Details of the added video in the playlist.
#'
#' @export
#' @references \url{https://developers.google.com/youtube/v3/docs/playlistItems/insert}
#'
#' @examples
#' \dontrun{
#'
#' # Set API token via yt_oauth() first
#'
#' add_video_to_playlist(playlist_id = "YourPlaylistID", video_id = "2_gLD1jarfU")
#' }

add_video_to_playlist <- function(playlist_id, video_id, position = NULL, ...) {

# Prepare the request body
if(is.null(position)){
body <- list(
snippet = list(
playlistId = playlist_id,
resourceId = list(
kind = "youtube#video",
videoId = video_id
)
)
)
} else {
body <- list(
snippet = list(
playlistId = playlist_id,
position = position,
resourceId = list(
kind = "youtube#video",
videoId = video_id
)
)
)
}

# Make the POST request using tuber_POST_json
raw_res <- tuber_POST_json(path = "playlistItems", query = list(part = "snippet"), body = body, ...)

# Return the response
return(raw_res)
}
49 changes: 49 additions & 0 deletions R/change_playlist_title.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#' Change the title of a YouTube playlist.
#'
#' This function updates the title of an existing YouTube playlist using the YouTube Data API.
#'
#' @param playlist_id A character string specifying the ID of the playlist you want to update.
#' @param new_title A character string specifying the new title for the playlist.
#'
#' @return A list containing the server response after the update attempt.
#' @export
#'
#' @examples
#' \dontrun{
#' change_playlist_title(playlist_id = "YourPlaylistID", new_title = "New Playlist Title")
#' }
#'

change_playlist_title <- function(playlist_id, new_title) {
# Check for a valid token
yt_check_token()

# Define the body for the PUT request
body <- list(
id = playlist_id,
snippet = list(title = new_title)
)

body_json <- jsonlite::toJSON(body, auto_unbox = TRUE)

# Use the existing tuber infrastructure to send the PUT request
req <- httr::PUT(
url = "https://www.googleapis.com/youtube/v3/playlists",
query = list(key = getOption("google_key"), part = "snippet"),
config = httr::config(token = getOption("google_token")),
body = body_json,
httr::add_headers(
`Accept` = "application/json",
`Content-Type` = "application/json"
)
)

# Check for errors
tuber_check(req)

# Extract and return the content
return(httr::content(req))
}

# Example usage:
# change_playlist_title(playlist_id = "PLOfOyOpiu5saim7DsJmz61uCf8igQiTpF", new_title = "Lil' Casey's Top 40 Countdown 2023-09-29")
32 changes: 32 additions & 0 deletions R/create_playlist.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#' Create New Playlist
#'
#' @param title string; Required. The title of the playlist.
#' @param description string; Optional. The description of the playlist.
#' @param status string; Optional. Default: 'public'. Can be one of: 'private', 'public', or 'unlisted'.
#' @param ... Additional arguments passed to \code{\link{tuber_POST}}.
#'
#' @return The created playlist's details.
#'
#' @export
#' @references \url{https://developers.google.com/youtube/v3/docs/playlists/insert}
#'
#' @examples
#' \dontrun{
#'
#' # Set API token via yt_oauth() first
#'
#' create_playlist(title = "My New Playlist", description = "This is a test playlist.")
#' }
create_playlist <- function(title, description, status, ...) {
# Prepare the request body
body <- list(
snippet = list(title = title, description = description),
status = list(privacyStatus = status)
)

# Make the POST request using tuber_POST_json
raw_res <- tuber_POST_json(path = "playlists", query = list(part = "snippet,status"), body = body, ...)

# Return the response
return(raw_res)
}
2 changes: 1 addition & 1 deletion R/delete_playlist_items.R
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
#'
#' # Set API token via yt_oauth() first
#'
#' delete_playlist_items(id = "y3ElXcEME3lSISz6izkWVT5GvxjPu8pA")
#' delete_playlist_items(id = "YourPlaylistItemID")
#' }

delete_playlist_items <- function(id = NULL, ...) {
Expand Down
2 changes: 1 addition & 1 deletion R/get_all_channel_video_stats.R
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ get_all_channel_video_stats <- function(channel_id = NULL, mine = FALSE, ...) {
channel_resources <- list_channel_resources(filter = list(channel_id = channel_id), part = "contentDetails")
playlist_id <- channel_resources$items$contentDetails$relatedPlaylists$uploads

playlist_items <- get_playlist_items(filter = list(playlist_id = playlist_id), max_results = 100)
playlist_items <- get_playlist_items(filter = list(playlist_id = playlist_id), max_results = 50)
vid_ids <- playlist_items$contentDetails$videoId

res <- lapply(vid_ids, get_stats)
Expand Down
74 changes: 74 additions & 0 deletions R/get_playlist_item_ids.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
#' Get Playlist Item IDs
#'
#' @param filter string; Required.
#' named vector of length 1
#' potential names of the entry in the vector:
#' \code{item_id}: comma-separated list of one or more unique playlist item IDs.
#' \code{playlist_id}: YouTube playlist ID.
#'
#' @param part Required. Comma separated string including one or more of the
#' following: \code{contentDetails, id, snippet, status}. Default:
#' \code{contentDetails}.
#' @param max_results Maximum number of items that should be returned.
#' Integer. Optional. Default is 50.
#' If over 50, all the results are returned.
#' @param simplify returns a data.frame rather than a list.
#' @param page_token specific page in the result set that should be
#' returned, optional
#' @param video_id Optional. request should return only the playlist
#' items that contain the specified video.
#' @param \dots Additional arguments passed to \code{\link{tuber_GET}}.
#'
#' @return playlist items
#' @export
#' @references \url{https://developers.google.com/youtube/v3/docs/playlists/list}
#'
#' @examples
#' \dontrun{
#'
#' # Set API token via yt_oauth() first
#'
#' get_playlist_items(filter =
#' c(playlist_id = "PLrEnWoR732-CN09YykVof2lxdI3MLOZda"))
#' get_playlist_items(filter =
#' c(playlist_id = "PL0fOlXVeVW9QMO3GoESky4yDgQfK2SsXN"),
#' max_results = 51)
#' }

get_playlist_item_ids <- function(filter = NULL, part = "contentDetails",
max_results = 50, video_id = NULL,
page_token = NULL, simplify = TRUE, ...) {

if (max_results < 0 || max_results > 50) {
stop("max_results must be a value between 0 and 50.")
}

valid_filters <- c("item_id", "playlist_id")
if (!(names(filter) %in% valid_filters)) {
stop("filter can only take one of the following values: item_id, playlist_id.")
}

if (length(filter) != 1) {
stop("filter must be a vector of length 1.")
}

translate_filter <- c(item_id = "id", playlist_id = "playlistId")
filter_name <- translate_filter[names(filter)]
names(filter) <- filter_name

querylist <- list(part = part,
maxResults = max(min(max_results, 50), 1),
pageToken = page_token, videoId = video_id)
querylist <- c(querylist, filter)

res <- tuber_GET("playlistItems", querylist, ...)
res_items <- res$items

item_ids <- rep("", length(res_items))
for(i in 1:length(res_items)){
item_ids[i] <- res_items[[i]]$id
}
return(item_ids)
}


74 changes: 74 additions & 0 deletions R/get_playlist_item_videoids.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
#' Get Playlist Item Video IDs
#'
#' @param filter string; Required.
#' named vector of length 1
#' potential names of the entry in the vector:
#' \code{item_id}: comma-separated list of one or more unique playlist item IDs.
#' \code{playlist_id}: YouTube playlist ID.
#'
#' @param part Required. Comma separated string including one or more of the
#' following: \code{contentDetails, id, snippet, status}. Default:
#' \code{contentDetails}.
#' @param max_results Maximum number of items that should be returned.
#' Integer. Optional. Default is 50.
#' If over 50, all the results are returned.
#' @param simplify returns a data.frame rather than a list.
#' @param page_token specific page in the result set that should be
#' returned, optional
#' @param video_id Optional. request should return only the playlist
#' items that contain the specified video.
#' @param \dots Additional arguments passed to \code{\link{tuber_GET}}.
#'
#' @return playlist items
#' @export
#' @references \url{https://developers.google.com/youtube/v3/docs/playlists/list}
#'
#' @examples
#' \dontrun{
#'
#' # Set API token via yt_oauth() first
#'
#' get_playlist_items(filter =
#' c(playlist_id = "YourPlaylistID"))
#' get_playlist_items(filter =
#' c(playlist_id = "YourPlaylistID"),
#' max_results = 51)
#' }

get_playlist_item_videoids <- function(filter = NULL, part = "contentDetails",
max_results = 50, video_id = NULL,
page_token = NULL, simplify = TRUE, ...) {

if (max_results < 0 || max_results > 50) {
stop("max_results must be a value between 0 and 50.")
}

valid_filters <- c("item_id", "playlist_id")
if (!(names(filter) %in% valid_filters)) {
stop("filter can only take one of the following values: item_id, playlist_id.")
}

if (length(filter) != 1) {
stop("filter must be a vector of length 1.")
}

translate_filter <- c(item_id = "id", playlist_id = "playlistId")
filter_name <- translate_filter[names(filter)]
names(filter) <- filter_name

querylist <- list(part = part,
maxResults = max(min(max_results, 50), 1),
pageToken = page_token, videoId = video_id)
querylist <- c(querylist, filter)

res <- tuber_GET("playlistItems", querylist, ...)
res_items <- res$items

item_ids <- rep("", length(res_items))
for(i in 1:length(res_items)){
item_ids[i] <- res_items[[i]]$contentDetails$videoId
}
return(item_ids)
}


2 changes: 2 additions & 0 deletions R/get_video_details.R
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ conditional_unnest_wider <- function(data_input, var) {
}
}

# Added to squash notes on devtools check.
utils::globalVariables(c("kind", "etag", "items", "snippet"))

json_to_df <- function(res) {
intermediate <- res %>%
Expand Down
25 changes: 25 additions & 0 deletions R/tuber.R
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,31 @@ tuber_POST <- function(path, query, body = "", ...) {
res
}

#'
#' POST encoded in json
#'
#' @param path path to specific API request URL
#' @param query query list
#' @param body passing image through body
#' @param \dots Additional arguments passed to \code{\link[httr]{GET}}.
#'
#' @return list

tuber_POST_json <- function(path, query, body = "", ...) {

yt_check_token()

req <- httr::POST("https://www.googleapis.com", path = paste0("youtube/v3/", path),
body = body, query = query,
config(token = getOption("google_token")),
encode = "json", ...)

tuber_check(req)
res <- content(req)

res
}

#'
#' DELETE
#'
Expand Down
Loading

0 comments on commit b5fc8c4

Please sign in to comment.