#| '!! shinylive warning !!': |
#| shinylive does not work in self-contained HTML documents.
#| Please set `embed-resources: false` in your metadata.
#| standalone: true
#| viewerHeight: 700
## file: app.R
# Big Thief Lyric Bot
library(shiny)
library(shinythemes)
library(dplyr)
# UI
ui <- fluidPage(
theme = shinytheme("flatly"),
tags$head(
tags$style(HTML("
.main-container {
max-width: 600px;
margin: 20px auto;
text-align: center;
}
.lyrics-display {
background: #f8f9fa;
border-left: 4px solid #007bff;
padding: 30px;
margin: 30px 0;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.lyrics-text {
font-size: 18px;
line-height: 1.6;
color: #2c3e50;
font-style: italic;
white-space: pre-line;
margin-bottom: 20px;
}
.attribution {
font-size: 14px;
color: #6c757d;
font-weight: 500;
}
.btn-generate {
font-size: 16px;
padding: 12px 30px;
margin: 20px 0;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border: none;
border-radius: 25px;
color: white;
transition: all 0.3s ease;
}
.btn-generate:hover {
transform: translateY(-2px);
box-shadow: 0 5px 15px rgba(0,0,0,0.2);
background: linear-gradient(135deg, #764ba2 0%, #667eea 100%);
}
.stats {
font-size: 12px;
color: #868e96;
margin-top: 20px;
}
.loading {
color: #6c757d;
font-style: italic;
}
"))
),
div(class = "main-container",
h1("Big Thief Lyric Generator"),
p("This is a webapp I coded that randomly displays snippets from Big Thief's discography."),
actionButton("generate", "✨ View Random Lyrics", class = "btn btn-generate"),
uiOutput("lyrics_display"),
div(class = "stats",
textOutput("stats_text")
)
)
)
# Server
server <- function(input, output, session) {
# Reactive value to store the loaded data
lyric_chunks <- reactiveVal(NULL)
data_loaded <- reactiveVal(FALSE)
# Load data when app starts
observe({
tryCatch({
data_url <- "https://zacharylhertz.github.io/files/chunks.csv"
temp_file <- tempfile(fileext = ".csv")
download.file(data_url, temp_file, mode = "wb")
chunks_data <- read.csv(temp_file, stringsAsFactors = FALSE)
lyric_chunks(chunks_data)
data_loaded(TRUE)
unlink(temp_file)
}, error = function(e) {
showNotification("Failed to load lyric data. Please check your internet connection.",
type = "error", duration = 5)
})
})
# Random lyric function - now uses reactive data
get_random_lyric <- function() {
chunks_data <- lyric_chunks()
if (is.null(chunks_data) || nrow(chunks_data) == 0) {
return(list(
lyrics = "Unable to load lyrics data",
attribution = "Please refresh the page"
))
}
sample_chunk <- chunks_data %>% slice_sample(n = 1)
lyrics_text <- sample_chunk$lyrics_chunk
# Create title with hyperlink if URL exists and is non-empty
if (!is.null(sample_chunk$url) && !is.na(sample_chunk$url) && sample_chunk$url != "") {
title_html <- paste0('<a href="', sample_chunk$url, '" target="_blank" style="color: inherit; text-decoration: underline;">',
sample_chunk$title, '</a>')
} else {
title_html <- sample_chunk$title
}
attribution <- paste0("— ", title_html, " by ", sample_chunk$artist, " (", sample_chunk$year, ")")
return(list(lyrics = lyrics_text, attribution = attribution))
}
# Reactive values to store current lyrics
current_lyrics <- reactiveVal("🎵 Click the button above to start generating lyrics.")
current_attribution <- reactiveVal("— Ready to explore Adrianne Lenker's penmanship?")
# Update when button is clicked
observeEvent(input$generate, {
if (data_loaded()) {
result <- get_random_lyric()
current_lyrics(paste("🎵", result$lyrics, "🎵"))
current_attribution(result$attribution)
} else {
showNotification("Data is still loading, please wait...", type = "warning")
}
})
# Render the lyrics display
output$lyrics_display <- renderUI({
div(class = "lyrics-display",
div(id = "lyrics-output",
div(class = "lyrics-text", current_lyrics()),
div(class = "attribution", HTML(current_attribution()))
)
)
})
# Stats text
output$stats_text <- renderText({
if (data_loaded() && !is.null(lyric_chunks())) {
paste("Built from", nrow(lyric_chunks()), "lyrical chunks across Big Thief's discography.")
} else {
"Loading lyric data..."
}
})
}
# Create the app
shinyApp(ui = ui, server = server)