├── LICENSE ├── .gitignore ├── .Rbuildignore ├── NAMESPACE ├── tiktokrmd.Rproj ├── DESCRIPTION ├── LICENSE.md ├── README.Rmd ├── man └── tiktok.Rd ├── R └── tictok.R └── README.md /LICENSE: -------------------------------------------------------------------------------- 1 | YEAR: 2021 2 | COPYRIGHT HOLDER: tiktokrmd authors 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .Rproj.user 2 | .Rhistory 3 | .Rdata 4 | .httr-oauth 5 | .DS_Store 6 | _dev 7 | -------------------------------------------------------------------------------- /.Rbuildignore: -------------------------------------------------------------------------------- 1 | ^tiktokrmd\.Rproj$ 2 | ^\.Rproj\.user$ 3 | ^README\.Rmd$ 4 | ^_dev$ 5 | ^LICENSE\.md$ 6 | -------------------------------------------------------------------------------- /NAMESPACE: -------------------------------------------------------------------------------- 1 | # Generated by roxygen2: do not edit by hand 2 | 3 | S3method(knit_print,tiktok_embed) 4 | S3method(tiktok_html,character) 5 | S3method(tiktok_html,tiktok_embed) 6 | S3method(tiktok_md,character) 7 | S3method(tiktok_md,tiktok_embed) 8 | export(tiktok_embed) 9 | export(tiktok_html) 10 | export(tiktok_md) 11 | importFrom(knitr,knit_print) 12 | -------------------------------------------------------------------------------- /tiktokrmd.Rproj: -------------------------------------------------------------------------------- 1 | Version: 1.0 2 | 3 | RestoreWorkspace: No 4 | SaveWorkspace: No 5 | AlwaysSaveHistory: Default 6 | 7 | EnableCodeIndexing: Yes 8 | UseSpacesForTab: Yes 9 | NumSpacesForTab: 2 10 | Encoding: UTF-8 11 | 12 | RnwWeave: Sweave 13 | LaTeX: pdfLaTeX 14 | 15 | AutoAppendNewline: Yes 16 | StripTrailingWhitespace: Yes 17 | LineEndingConversion: Posix 18 | 19 | BuildType: Package 20 | PackageUseDevtools: Yes 21 | PackageInstallArgs: --no-multiarch --with-keep.source 22 | PackageRoxygenize: rd,collate,namespace 23 | -------------------------------------------------------------------------------- /DESCRIPTION: -------------------------------------------------------------------------------- 1 | Package: tiktokrmd 2 | Title: Embed 'TikTok' Videos in 'R Markdown' 3 | Version: 1.0.0 4 | Authors@R: 5 | person(given = "Garrick", 6 | family = "Aden-Buie", 7 | role = c("aut", "cre"), 8 | email = "garrick@adenbuie.com", 9 | comment = c(ORCID = "0000-0002-7111-0077")) 10 | Description: Get the kids to pay attention to your reports with 11 | embedded 'TikTok' videos! 12 | License: MIT + file LICENSE 13 | Imports: 14 | htmltools, 15 | httr, 16 | knitr 17 | Encoding: UTF-8 18 | LazyData: true 19 | Roxygen: list(markdown = TRUE) 20 | RoxygenNote: 7.1.1 21 | URL: https://github.com/gadenbuie/tiktokrmd 22 | BugReports: https://github.com/gadenbuie/tiktokrmd/issues 23 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | # MIT License 2 | 3 | Copyright (c) 2021 tiktokrmd authors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | output: github_document 3 | --- 4 | 5 | 6 | 7 | ```{r, include = FALSE} 8 | knitr::opts_chunk$set( 9 | echo = FALSE, 10 | collapse = TRUE, 11 | comment = "#>", 12 | fig.path = "man/figures/README-", 13 | out.width = "100%" 14 | ) 15 | ``` 16 | 17 | # tiktokrmd 18 | 19 | 20 | 21 | 22 | Embed TikTok videos in R Markdown things! 23 | 24 | ## Installation 25 | 26 | You can install the released version of tictokrmd from GitHub: 27 | 28 | ``` r 29 | remotes::install_github("gadenbuie/tiktokrmd") 30 | ``` 31 | 32 | ## How to TikTok in R Markdown 33 | 34 | ```{r} 35 | con <- textConnection("h", open = "w", local = TRUE) 36 | tools::Rd2HTML("man/tiktok.Rd", con) 37 | close(con) 38 | first_h2 <- which(grepl("

", h))[1] + 1 39 | ex_heading <- which(grepl("

Examples

", h)) 40 | ex_pre <- which(grepl("pre>", h)) 41 | ex_pre_start <- ex_pre[length(ex_pre) - 1] 42 | ex_pre_end <- ex_pre[length(ex_pre)] 43 | 44 | example <- paste(h[(ex_pre_start + 1):(ex_pre_end - 1)], collapse = "\n") 45 | example <- gsub("<", "<", example) 46 | example <- gsub(">", ">", example) 47 | example <- paste0("```{r echo=TRUE, eval=-6:-7}\nlibrary(tiktokrmd)\n\n", example, "\n```") 48 | 49 | tmpfile <- tempfile(fileext = ".Rmd") 50 | writeLines(example, tmpfile) 51 | 52 | documentation <- h[first_h2:(ex_heading - 1)] 53 | ``` 54 | 55 | ### Example 56 | 57 | ```{r child=tmpfile} 58 | ``` 59 | 60 | ### ⚠️ Previewing Locally ⚠️ 61 | 62 | TikTok's embedding script only works when the page with the embedded video is being served. For some reason, it doesn't seem to work when viewing a local file. 63 | 64 | The easiest way around this is to use 65 | the **Infinite Moon Reader** addin (or `inf_mr()`) 66 | from [xaringan](https://github.com/yihui/xaringan) 67 | to render your R Markdown document. 68 | If you're working on a blog post, 69 | `blogdown::serve_site()` probably works fine. 70 | In all cases, 71 | you'll still need to preview the rendered page in an external browser, 72 | like FireFox, Chrome, or Safari. 73 | 74 | ```{r results="asis"} 75 | cat("```{=html}", documentation, "```", sep = "\n") 76 | ``` 77 | 78 | ```{r} 79 | unlink(tmpfile) 80 | ``` 81 | 82 | -------------------------------------------------------------------------------- /man/tiktok.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/tictok.R 3 | \name{tiktok} 4 | \alias{tiktok} 5 | \alias{tiktok_embed} 6 | \alias{tiktok_md} 7 | \alias{tiktok_html} 8 | \title{Embed a TikTok Video} 9 | \usage{ 10 | tiktok_embed(url) 11 | 12 | tiktok_md(tt, ...) 13 | 14 | tiktok_html(tt, include_player = TRUE, ...) 15 | } 16 | \arguments{ 17 | \item{url}{A TikTok video URL} 18 | 19 | \item{tt}{A TikTok video URL or \code{tiktok_embed()} result} 20 | 21 | \item{...}{Ignored} 22 | 23 | \item{include_player}{Include the TikTok embed JavaScript that builds the 24 | rich HTML player (and probably adds a considerable amount of user tracking)} 25 | } 26 | \value{ 27 | \code{tiktok_embed}: Returns the TikTok oEmbed API response. The returned 28 | object has a \code{knit_print()} method for automatic embedding in R Markdown. 29 | 30 | \code{tiktok_md}: A Markdown representation of the TikTok video, in the 31 | format \verb{![ by <author>](<thumbnail_image_url>)} 32 | 33 | \code{tiktok_html}: The TikTok embedding HTML as an \code{htmltools::tagList} 34 | } 35 | \description{ 36 | Embeds a TikTok video in an R Markdown document. In rich HTML formats, the 37 | full TikTok video player is used. Note that the video will likely fail to 38 | appear when previewing locally, unless you serve the document with something 39 | like \code{servr::httd()}. In limited HTML formats or non-HTML formats, the 40 | TikTok content is rendered into an image with a link in markdown. Use the 41 | helper functions listed below if you want to control the output. 42 | } 43 | \section{Functions}{ 44 | \itemize{ 45 | \item \code{tiktok_embed}: Embed a TikTok video in R Markdown, or return the oEmbed 46 | API response. 47 | 48 | \item \code{tiktok_md}: Format the TikTok video url or \code{tiktok_embed()} result as 49 | markdown 50 | 51 | \item \code{tiktok_html}: Format the TikTok video url or \code{tiktok_embed()} result as 52 | HTML 53 | }} 54 | 55 | \examples{ 56 | tt_url <- "https://www.tiktok.com/@aquickspoonful/video/6890681375431691526" 57 | tt <- tiktok_embed(tt_url) 58 | 59 | # in R Markdown, just print the object to embed it 60 | tt 61 | 62 | # Or write a plain markdown version 63 | tiktok_md(tt) 64 | 65 | # Or as HTML without the full TikTok embedded player shenanigans 66 | tiktok_html(tt, include_player = FALSE) 67 | 68 | } 69 | \references{ 70 | \url{https://developers.tiktok.com/doc/Embed} 71 | } 72 | -------------------------------------------------------------------------------- /R/tictok.R: -------------------------------------------------------------------------------- 1 | `%||%` <- function(x, y) if (is.null(x)) y else x 2 | 3 | #' Embed a TikTok Video 4 | #' 5 | #' Embeds a TikTok video in an R Markdown document. In rich HTML formats, the 6 | #' full TikTok video player is used. Note that the video will likely fail to 7 | #' appear when previewing locally, unless you serve the document with something 8 | #' like `servr::httd()`. In limited HTML formats or non-HTML formats, the 9 | #' TikTok content is rendered into an image with a link in markdown. Use the 10 | #' helper functions listed below if you want to control the output. 11 | #' 12 | #' @examples 13 | #' tt_url <- "https://www.tiktok.com/@aquickspoonful/video/6890681375431691526" 14 | #' tt <- tiktok_embed(tt_url) 15 | #' 16 | #' # in R Markdown, just print the object to embed it 17 | #' tt 18 | #' 19 | #' # Or write a plain markdown version 20 | #' tiktok_md(tt) 21 | #' 22 | #' # Or as HTML without the full TikTok embedded player shenanigans 23 | #' tiktok_html(tt, include_player = FALSE) 24 | #' 25 | #' @name tiktok 26 | NULL 27 | 28 | #' @describeIn tiktok Embed a TikTok video in R Markdown, or return the oEmbed 29 | #' API response. 30 | #' @references <https://developers.tiktok.com/doc/Embed> 31 | #' @return `tiktok_embed`: Returns the TikTok oEmbed API response. The returned 32 | #' object has a `knit_print()` method for automatic embedding in R Markdown. 33 | #' @param url A TikTok video URL 34 | #' @export 35 | tiktok_embed <- function(url) { 36 | tt_oembed_url <- sprintf( 37 | "https://www.tiktok.com/oembed?url=%s", 38 | url 39 | ) 40 | res <- httr::GET(tt_oembed_url) 41 | httr::stop_for_status(res, "Get embedding information from tiktok") 42 | tt <- httr::content(res) 43 | 44 | expected_items <- c("title", "author_name", "author_url", "html") 45 | if (!all(expected_items %in% names(tt))) { 46 | warning( 47 | "Received unusual response from TikTok oEmbed API ", 48 | "for this video:", url, 49 | immediate. = TRUE 50 | ) 51 | } 52 | 53 | tt$tiktok_url <- url 54 | structure(tt, class = c("tiktok_embed", "list")) 55 | } 56 | 57 | #' @describeIn tiktok Format the TikTok video url or `tiktok_embed()` result as 58 | #' markdown 59 | #' @param tt A TikTok video URL or `tiktok_embed()` result 60 | #' @param ... Ignored 61 | #' @return `tiktok_md`: A Markdown representation of the TikTok video, in the 62 | #' format `![<title> by <author>](<thumbnail_image_url>)` 63 | #' @export 64 | tiktok_md <- function(tt, ...) UseMethod("tiktok_md", tt) 65 | 66 | #' @export 67 | tiktok_md.character <- function(tt, ...) { 68 | tiktok_md(tiktok_embed(tt), ...) 69 | } 70 | 71 | #' @export 72 | tiktok_md.tiktok_embed <- function(tt, ...) { 73 | author_md <- sprintf("[%s](%s)", tt$author_name, tt$author_url) 74 | title <- if (identical(tt$title, "")) "A TikTok" else tt$title 75 | 76 | caption <- sprintf( 77 | "[%s](%s) by %s", 78 | title, 79 | tt$tiktok_url, 80 | author_md 81 | ) 82 | if (is.null(tt$thumbnail_url) || identical(tt$thumbnail_url, "")) { 83 | return(caption) 84 | } 85 | sprintf("![%s](%s)", caption, tt$thumbnail_url) 86 | } 87 | 88 | #' @describeIn tiktok Format the TikTok video url or `tiktok_embed()` result as 89 | #' HTML 90 | #' @param include_player Include the TikTok embed JavaScript that builds the 91 | #' rich HTML player (and probably adds a considerable amount of user tracking) 92 | #' @return `tiktok_html`: The TikTok embedding HTML as an `htmltools::tagList` 93 | #' @export 94 | tiktok_html <- function(tt, include_player = TRUE, ...) UseMethod("tiktok_html", tt) 95 | 96 | #' @export 97 | tiktok_html.character <- function(tt, include_player = TRUE, ...) { 98 | tiktok_html(tiktok_embed(tt), include_player = include_player, ...) 99 | } 100 | 101 | #' @export 102 | tiktok_html.tiktok_embed <- function(tt, include_player = TRUE, ...) { 103 | if (!"html" %in% names(tt)) return(NULL) 104 | tt <- sub('<script async src="https://www.tiktok.com/embed.js"></script>', "", tt$html) 105 | tt <- htmltools::HTML(tt) 106 | if (!isTRUE(include_player)) { 107 | tt 108 | } else { 109 | htmltools::tagList(tt, tiktok_dependency()) 110 | } 111 | } 112 | 113 | tiktok_dependency <- function() { 114 | htmltools::singleton( 115 | htmltools::tagList( 116 | htmltools::tags$script( 117 | async = NA, 118 | `data-external` = "1", 119 | src = "https://www.tiktok.com/embed.js" 120 | ), 121 | htmltools::tags$style( 122 | "blockquote.tiktok-embed {border:unset;padding:unset;}" 123 | ) 124 | ) 125 | ) 126 | } 127 | 128 | #' @importFrom knitr knit_print 129 | #' @export 130 | knit_print.tiktok_embed <- function(x, ...) { 131 | if (knitr::is_html_output(excludes = "gfm")) { 132 | htmltools::knit_print.shiny.tag.list(tiktok_html(x)) 133 | } else { 134 | knitr::asis_output(tiktok_md(x), cacheable = TRUE) 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | <!-- README.md is generated from README.Rmd. Please edit that file --> 3 | 4 | # tiktokrmd 5 | 6 | <!-- badges: start --> 7 | <!-- badges: end --> 8 | 9 | Embed TikTok videos in R Markdown things! 10 | 11 | ## Installation 12 | 13 | You can install the released version of tictokrmd from GitHub: 14 | 15 | ``` r 16 | remotes::install_github("gadenbuie/tiktokrmd") 17 | ``` 18 | 19 | ## How to TikTok in R Markdown 20 | 21 | ### Example 22 | 23 | ``` r 24 | library(tiktokrmd) 25 | 26 | tt_url <- "https://www.tiktok.com/@aquickspoonful/video/6890681375431691526" 27 | tt <- tiktok_embed(tt_url) 28 | 29 | ## # in R Markdown, just print the object to embed it 30 | ## tt 31 | 32 | # Or write a plain markdown version 33 | tiktok_md(tt) 34 | #> [1] "![[#cake #cakes #dontmixit #cakelover #cakelovers #dumpcake #food #tiktokfood #foodtiktok #easyrecipe #easyrecipes #peach #peaches #cinnamon #fyp](https://www.tiktok.com/@aquickspoonful/video/6890681375431691526) by [Sophia Wasu](https://www.tiktok.com/@aquickspoonful)](https://p16-sign-va.tiktokcdn.com/obj/tos-maliva-p-0068/00189a8b703343bd817a3ccaec240f71?x-expires=1610654400&x-signature=ExJZaEMAgxhyXydfgsqgZqU%2B8y8%3D)" 35 | 36 | # Or as HTML without the full TikTok embedded player shenanigans 37 | tiktok_html(tt, include_player = FALSE) 38 | ``` 39 | 40 | <!--html_preserve--> 41 | <blockquote class="tiktok-embed" cite="https://www.tiktok.com/@aquickspoonful/video/6890681375431691526" data-video-id="6890681375431691526" style="max-width: 605px;min-width: 325px;"> 42 | <section> 43 | <a target="_blank" title="@aquickspoonful" href="https://www.tiktok.com/@aquickspoonful">@aquickspoonful</a> 44 | <p> 45 | <a title="cake" target="_blank" href="https://www.tiktok.com/tag/cake">\#cake</a> 46 | <a title="cakes" target="_blank" href="https://www.tiktok.com/tag/cakes">\#cakes</a> 47 | <a title="dontmixit" target="_blank" href="https://www.tiktok.com/tag/dontmixit">\#dontmixit</a> 48 | <a title="cakelover" target="_blank" href="https://www.tiktok.com/tag/cakelover">\#cakelover</a> 49 | <a title="cakelovers" target="_blank" href="https://www.tiktok.com/tag/cakelovers">\#cakelovers</a> 50 | <a title="dumpcake" target="_blank" href="https://www.tiktok.com/tag/dumpcake">\#dumpcake</a> 51 | <a title="food" target="_blank" href="https://www.tiktok.com/tag/food">\#food</a> 52 | <a title="tiktokfood" target="_blank" href="https://www.tiktok.com/tag/tiktokfood">\#tiktokfood</a> 53 | <a title="foodtiktok" target="_blank" href="https://www.tiktok.com/tag/foodtiktok">\#foodtiktok</a> 54 | <a title="easyrecipe" target="_blank" href="https://www.tiktok.com/tag/easyrecipe">\#easyrecipe</a> 55 | <a title="easyrecipes" target="_blank" href="https://www.tiktok.com/tag/easyrecipes">\#easyrecipes</a> 56 | <a title="peach" target="_blank" href="https://www.tiktok.com/tag/peach">\#peach</a> 57 | <a title="peaches" target="_blank" href="https://www.tiktok.com/tag/peaches">\#peaches</a> 58 | <a title="cinnamon" target="_blank" href="https://www.tiktok.com/tag/cinnamon">\#cinnamon</a> 59 | <a title="fyp" target="_blank" href="https://www.tiktok.com/tag/fyp">\#fyp</a> 60 | </p> 61 | <a target="_blank" title="♬ original sound - Sophia Wasu" href="https://www.tiktok.com/music/original-sound-6890681399725099782">♬ 62 | original sound - Sophia Wasu</a> 63 | </section> 64 | </blockquote> 65 | 66 | <!--/html_preserve--> 67 | 68 | ### ⚠️ Previewing Locally ⚠️ 69 | 70 | TikTok’s embedding script only works when the page with the embedded 71 | video is being served. For some reason, it doesn’t seem to work when 72 | viewing a local file. 73 | 74 | The easiest way around this is to use the **Infinite Moon Reader** addin 75 | (or `inf_mr()`) from [xaringan](https://github.com/yihui/xaringan) to 76 | render your R Markdown document. If you’re working on a blog post, 77 | `blogdown::serve_site()` probably works fine. In all cases, you’ll still 78 | need to preview the rendered page in an external browser, like FireFox, 79 | Chrome, or Safari. 80 | 81 | <h3>Description</h3> 82 | 83 | <p>Embeds a TikTok video in an R Markdown document. In rich HTML formats, the 84 | full TikTok video player is used. Note that the video will likely fail to 85 | appear when previewing locally, unless you serve the document with something 86 | like <code>servr::httd()</code>. In limited HTML formats or non-HTML formats, the 87 | TikTok content is rendered into an image with a link in markdown. Use the 88 | helper functions listed below if you want to control the output. 89 | </p> 90 | 91 | 92 | <h3>Usage</h3> 93 | 94 | <pre> 95 | tiktok_embed(url) 96 | 97 | tiktok_md(tt, ...) 98 | 99 | tiktok_html(tt, include_player = TRUE, ...) 100 | </pre> 101 | 102 | 103 | <h3>Arguments</h3> 104 | 105 | <table summary="R argblock"> 106 | <tr valign="top"><td><code>url</code></td> 107 | <td> 108 | <p>A TikTok video URL</p> 109 | </td></tr> 110 | <tr valign="top"><td><code>tt</code></td> 111 | <td> 112 | <p>A TikTok video URL or <code>tiktok_embed()</code> result</p> 113 | </td></tr> 114 | <tr valign="top"><td><code>...</code></td> 115 | <td> 116 | <p>Ignored</p> 117 | </td></tr> 118 | <tr valign="top"><td><code>include_player</code></td> 119 | <td> 120 | <p>Include the TikTok embed JavaScript that builds the 121 | rich HTML player (and probably adds a considerable amount of user tracking)</p> 122 | </td></tr> 123 | </table> 124 | 125 | 126 | <h3>Value</h3> 127 | 128 | <p><code>tiktok_embed</code>: Returns the TikTok oEmbed API response. The returned 129 | object has a <code>knit_print()</code> method for automatic embedding in R Markdown. 130 | </p> 131 | <p><code>tiktok_md</code>: A Markdown representation of the TikTok video, in the 132 | format <code style="white-space: pre;">![<title> by <author>](<thumbnail_image_url>)</code> 133 | </p> 134 | <p><code>tiktok_html</code>: The TikTok embedding HTML as an <code>htmltools::tagList</code> 135 | </p> 136 | 137 | 138 | <h3>Functions</h3> 139 | 140 | 141 | <ul> 142 | <li> <p><code>tiktok_embed</code>: Embed a TikTok video in R Markdown, or return the oEmbed 143 | API response. 144 | </p> 145 | </li> 146 | <li> <p><code>tiktok_md</code>: Format the TikTok video url or <code>tiktok_embed()</code> result as 147 | markdown 148 | </p> 149 | </li> 150 | <li> <p><code>tiktok_html</code>: Format the TikTok video url or <code>tiktok_embed()</code> result as 151 | HTML 152 | </p> 153 | </li></ul> 154 | 155 | 156 | <h3>References</h3> 157 | 158 | <p><a href="https://developers.tiktok.com/doc/Embed">https://developers.tiktok.com/doc/Embed</a> 159 | </p> 160 | --------------------------------------------------------------------------------