diff --git a/NAMESPACE b/NAMESPACE index 1c6638a..54dbc17 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -23,6 +23,8 @@ export(tt_request_hidden) export(tt_search) export(tt_search_api) export(tt_search_hidden) +export(tt_user_follower_api) +export(tt_user_following_api) export(tt_user_info) export(tt_user_info_api) export(tt_user_info_hidden) diff --git a/R/api_research.r b/R/api_research.r index 2fa6cc2..4143b26 100644 --- a/R/api_research.r +++ b/R/api_research.r @@ -256,7 +256,7 @@ tt_user_liked_videos_api <- function(username, verbose = TRUE, token = NULL) { - out <- purrr::map(username, function(u) { + purrr::map(username, function(u) { # if username is given as URL if (grepl("/", u)) { u <- extract_regex( @@ -294,6 +294,7 @@ tt_user_liked_videos_api <- function(username, videos <- list() # iterate over pages while (purrr::pluck(res, "data", "has_more", .default = FALSE) && the$page < max_pages) { + the$page <- the$page + 1 the$cursor <- purrr::pluck(res, "data", "cursor") res <- tt_user_request(endpoint = "liked_videos/", @@ -309,7 +310,7 @@ tt_user_liked_videos_api <- function(username, } videos <- dplyr::bind_rows(videos) - videos$liked_by_user <- u + videos <- tibble::add_column(videos, liked_by_user = u) if (verbose) cli::cli_progress_done( result = ifelse(length(videos) > 1, "done", "failed") ) @@ -317,10 +318,117 @@ tt_user_liked_videos_api <- function(username, return(videos) }) |> dplyr::bind_rows() - return(out) } +#' @title Get followers and following of users from the research API +#' +#' @description \ifelse{html}{\figure{api-research.svg}{options: alt='[Works on: +#' Research API]'}}{\strong{[Works on: Research API]}} +#' +#' @param username name(s) of the user(s) to be queried +#' @param fields The fields to be returned (defaults to all) +#' @inheritParams tt_search_api +#' +#' @return A data.frame +#' @export +#' +#' @examples +#' \dontrun{ +#' tt_user_follower_api("jbgruber") +#' # OR +#' tt_user_following_api("https://www.tiktok.com/@tiktok") +#' # OR +#' tt_get_follower("https://www.tiktok.com/@tiktok") +#' } +tt_user_follower_api <- function(username, + max_pages = 1, + cache = TRUE, + verbose = TRUE, + token = NULL) { + + tt_user_follow(endpoint = "followers/", + username = username, + max_pages = max_pages, + cache = cache, + verbose = verbose, + token = token) +} + + +#' @rdname tt_user_follower_api +#' @export +tt_user_following_api <- function(username, + max_pages = 1, + cache = TRUE, + verbose = TRUE, + token = NULL) { + + tt_user_follow(endpoint = "following/", + username = username, + max_pages = max_pages, + cache = cache, + verbose = verbose, + token = token) +} + + +tt_user_follow <- function(endpoint, + username, + max_pages = 1, + cache = TRUE, + verbose = TRUE, + token = NULL) { + + purrr::map(username, function(u) { + # if username is given as URL + if (grepl("/", u)) { + u <- extract_regex( + u, + "(?<=.com/@)(.+?)(?=\\?|$|/)" + ) + } + if (verbose) cli::cli_progress_step(msg = "Getting user {u}", + msg_done = "Got user {u}") + the$result <- TRUE + if (is.null(token)) token <- get_token() + + res <- list(data = list(has_more = TRUE, cursor = NULL)) + the$page <- 0L + followers <- list() + # iterate over pages + while (purrr::pluck(res, "data", "has_more", .default = FALSE) && the$page < max_pages) { + the$page <- the$page + 1 + the$cursor <- purrr::pluck(res, "data", "cursor") + + res <- tt_user_request(endpoint = endpoint, + username = u, + fields = fields, + cursor = the$cursor, + token = token) + + followers <- c(followers, purrr::pluck( + res, + "data", ifelse(endpoint == "followers/", + "user_followers", + "user_following")) + ) + if (cache) { + the$videos <- followers + } + } + + followers <- dplyr::bind_rows(followers) + followers <- tibble::add_column(followers, following_user = u) + if (verbose) cli::cli_progress_done( + result = ifelse(length(followers) > 1, "done", "failed") + ) + + return(followers) + }) |> + dplyr::bind_rows() +} + # used to iterate over search requests tt_user_request <- function(endpoint, username, diff --git a/man/tt_user_follower_api.Rd b/man/tt_user_follower_api.Rd new file mode 100644 index 0000000..5db0bb3 --- /dev/null +++ b/man/tt_user_follower_api.Rd @@ -0,0 +1,56 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/api_research.r +\name{tt_user_follower_api} +\alias{tt_user_follower_api} +\alias{tt_user_following_api} +\title{Get followers and following of users from the research API} +\usage{ +tt_user_follower_api( + username, + max_pages = 1, + cache = TRUE, + verbose = TRUE, + token = NULL +) + +tt_user_following_api( + username, + max_pages = 1, + cache = TRUE, + verbose = TRUE, + token = NULL +) +} +\arguments{ +\item{username}{name(s) of the user(s) to be queried} + +\item{max_pages}{results are returned in batches/pages with 100 videos. How +many should be requested before the function stops?} + +\item{cache}{should progress be saved in the current session? It can then be +retrieved with \code{last_query()} if an error occurs. But the function +will use extra memory.} + +\item{verbose}{should the function print status updates to the screen?} + +\item{token}{The authentication token (usually supplied automatically after +running auth_research once)} + +\item{fields}{The fields to be returned (defaults to all)} +} +\value{ +A data.frame +} +\description{ +\ifelse{html}{\figure{api-research.svg}{options: alt='[Works on: + Research API]'}}{\strong{[Works on: Research API]}} +} +\examples{ +\dontrun{ +tt_user_follower_api("jbgruber") +# OR +tt_user_following_api("https://www.tiktok.com/@tiktok") +# OR +tt_get_follower("https://www.tiktok.com/@tiktok") +} +}