Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/main' into feeder-episode-deleti…
Browse files Browse the repository at this point in the history
…on-archives-delegated-delivery
  • Loading branch information
svevang committed Oct 4, 2023
2 parents aea73a7 + 5f6b7b6 commit 6802753
Show file tree
Hide file tree
Showing 29 changed files with 654 additions and 218 deletions.
1 change: 1 addition & 0 deletions app/assets/stylesheets/shared/bootstrap-variables.scss
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ $utilities: (
property: line-height,
class: lh,
values: (
0: 0,
1: 1,
xs: $line-height-xs,
sm: $line-height-sm,
Expand Down
6 changes: 5 additions & 1 deletion app/controllers/episode_player_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ def show

authorize @episode, :show?

@embed_player_type = params[:embed_player_type]
@player_options = {}
@player_options[:embed_player_type] = params[:embed_player_type] || "standard"
@player_options[:embed_player_theme] = params[:embed_player_theme] || "dark"
@player_options[:accent_color] = params[:accent_color] || ["#ff9600"]
@player_options[:episode_guid] = Episode.find_by_guid!(params[:episode_id])
end
end
5 changes: 3 additions & 2 deletions app/controllers/podcast_player_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@ class PodcastPlayerController < ApplicationController
# GET /podcasts/1/player
def show
@player_options = {}
@player_options[:embed_player_type] = params[:embed_player_type] || "card"
@player_options[:embed_player_type] = params[:embed_player_type] || "standard"
@player_options[:embed_player_theme] = params[:embed_player_theme] || "dark"
@player_options[:accent_color] = params[:accent_color] || ["#ff9600"]
@player_options[:all_episodes] = params[:all_episodes] || "all"

@player_options[:episode_number] = params[:episode_number]
@player_options[:season] = params[:season]
@player_options[:category] = params[:category]
Expand Down
8 changes: 4 additions & 4 deletions app/helpers/application_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -53,14 +53,14 @@ def help_text(text)
end
end

def field_link(href)
link_to href, class: "input-group-text prx-input-group-text", target: :_blank do
def field_link(href, data = {})
link_to href, class: "input-group-text prx-input-group-text", target: :_blank, data: data do
tag.span "open_in_new", class: "material-icons text-primary"
end
end

def field_copy(content)
data = {controller: "clipboard", clipboard_copy_value: content, clipboard_tooltip_value: t("helpers.application.field_copy_tooltip")}
def field_copy(content, data = {})
data = {controller: "clipboard", clipboard_copy_value: content, clipboard_tooltip_value: t("helpers.application.field_copy_tooltip")}.merge(data)

tag.button class: "input-group-text prx-input-group-text", data: data do
tag.span "link", class: "material-icons text-primary"
Expand Down
79 changes: 44 additions & 35 deletions app/helpers/embed_player_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ module EmbedPlayerHelper

EMBED_PLAYER_LANDING_PATH = "/listen"
EMBED_PLAYER_PATH = "/e"
EMBED_PLAYER_PREVIEW_PATH = "/preview"
EMBED_PLAYER_FEED = "uf"
EMBED_PLAYER_GUID = "ge"
EMBED_PLAYER_CARD = "ca"
Expand All @@ -11,6 +12,7 @@ module EmbedPlayerHelper
EMBED_PLAYER_IMAGE = "ui"
EMBED_PLAYER_RSS_URL = "us"
EMBED_PLAYER_AUDIO_URL = "ua"
EMBED_PLAYER_AUDIO_URL_PREVIEW = "uap"
DOVETAIL_TOKEN = "_t"
EMBED_PLAYER_PLAYLIST = "sp"
EMBED_PLAYER_SEASON = "se"
Expand All @@ -23,73 +25,80 @@ def embed_player_landing_url(podcast, ep = nil)
"#{play_root}#{EMBED_PLAYER_LANDING_PATH}?#{params.to_query}"
end

def embed_player_episode_url(ep, type = nil, preview = false)
def embed_player_episode_url(ep, options = nil, preview = false)
params = {}

if preview && !ep.published?
if !ep.published?
params[EMBED_PLAYER_TITLE] = ep.title
params[EMBED_PLAYER_SUBTITLE] = ep.podcast.title
params[EMBED_PLAYER_IMAGE] = ep.ready_image&.url || ep.podcast.ready_image&.url
params[EMBED_PLAYER_RSS_URL] = ep.podcast_feed_url
params[EMBED_PLAYER_AUDIO_URL] = enclosure_with_token(ep)
params[EMBED_PLAYER_AUDIO_URL] = ep.enclosure_url
params[EMBED_PLAYER_AUDIO_URL_PREVIEW] = enclosure_with_token(ep)
else
params[EMBED_PLAYER_FEED] = ep.podcast_feed_url
params[EMBED_PLAYER_GUID] = ep.item_guid
end

if type == "card" || type == "fixed_card"
if options.present? && options[:embed_player_type] == "card"
params[EMBED_PLAYER_CARD] = "1"
end

embed_params(params)
embed_params(params, preview)
end

def embed_player_podcast_url(podcast, options, preview = false)
params = {}
params[EMBED_PLAYER_FEED] = podcast.published_url

params[EMBED_PLAYER_PLAYLIST] = (options[:all_episodes] == "all") ? options[:all_episodes] : options[:episode_number]
params[EMBED_PLAYER_SEASON] = options[:season]
params[EMBED_PLAYER_CATEGORY] = options[:category]
if options[:all_episodes] === "all"
params[EMBED_PLAYER_PLAYLIST] = "all"
end

# TODO: the height styling doesn't really work here in the way Play specifies how it needs to be for a playlist, so leaving this as a TODO for now.
# if options[:embed_player_type] == "card" || options[:embed_player_type] == "fixed_card"
# params[EMBED_PLAYER_CARD] = "1"
# end
if options[:all_episodes] == "number" && options[:episode_number].to_i > 1
params[EMBED_PLAYER_PLAYLIST] = options[:episode_number]
end

embed_params(params)
end
if !options[:season].to_s.strip.empty? && options[:season].to_i > 0
params[EMBED_PLAYER_SEASON] = options[:season]
end

def embed_player_episode_iframe(ep, type = nil, preview = false)
src = embed_player_episode_url(ep, type, preview)
allow = "monetization"
if !options[:category].to_s.strip.empty?
params[EMBED_PLAYER_CATEGORY] = options[:category]
end

if type == "card"
# TODO: this is NOW working, but I'm not sure how helpful this is to a producer that wishes to embed it.
tag.iframe src: src, allow: allow, width: "100%", height: "700", style: "--aspect-ratio: 2/3; width: 100%;"
elsif type == "fixed_card"
tag.iframe src: src, allow: allow, width: "500", height: "700"
else
tag.iframe src: src, allow: allow, width: "100%", height: "200"
if options[:embed_player_type] == "card"
params[EMBED_PLAYER_CARD] = "1"
end

embed_params(params, preview)
end

def embed_player_podcast_iframe(podcast, options, preview = false)
src = embed_player_podcast_url(podcast, options, preview)
def embed_player_iframe(options)
src = ""
allow = "monetization"
iframe_height = "200"
iframe_styles = ""
wrapper_styles = "line-height: 0;"

if options[:embed_player_type] == "card"
# TODO: this is NOW working, but I'm not sure how helpful this is to a producer that wishes to embed it.
tag.iframe src: src, allow: allow, width: "100%", height: "700", style: "--aspect-ratio: 2/3; width: 100%;"
elsif options[:embed_player_type] == "fixed_card"
tag.iframe src: src, allow: allow, width: "500", height: "700"
else
tag.iframe src: src, allow: allow, width: "100%", height: "200"
wrapper_styles = "position: relative; height: 0; width: 100%; padding-top: calc(100% + #{iframe_height}px); line-height: 0;"
iframe_height = "100%"
iframe_styles = "position: absolute; inset: 0;"
end

tag.div style: wrapper_styles, data: {embed_preview_target: "embedIframeWrapper"} do
tag.iframe class: "bg-light", src: src, allow: allow, width: "100%", height: iframe_height, style: iframe_styles, data: {embed_preview_target: "embedIframe"}
end
end

def embed_player_type_options(selected)
opts = %w[standard card fixed_card].map { |v| [t("helpers.label.episode.embed_player_types.#{v}"), v] }
opts = %w[standard card].map { |v| [t("helpers.label.episode.embed_player_types.#{v}"), v] }
options_for_select(opts, selected)
end

def embed_player_theme_options(selected)
opts = %w[dark light auto].map { |v| [t("helpers.label.episode.embed_player_themes.#{v}"), v] }
options_for_select(opts, selected)
end

Expand All @@ -105,8 +114,8 @@ def embed_player_all_episodes_options(selected)

private

def embed_params(params)
"#{play_root}#{EMBED_PLAYER_PATH}?#{params.to_query}"
def embed_params(params, preview = false)
"https://#{ENV["PLAY_HOST"]}#{preview ? EMBED_PLAYER_PREVIEW_PATH : EMBED_PLAYER_PATH}?#{params.to_query}"
end

def enclosure_with_token(ep)
Expand Down
27 changes: 25 additions & 2 deletions app/javascript/controllers/clipboard_controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,18 @@ import { Controller } from "@hotwired/stimulus"
export default class extends Controller {
static values = { copy: String, tooltip: String }

originalStyleDisplay

connect() {
this.originalStyleDisplay = this.element.style.display

navigator.permissions.query({ name: "clipboard-write" }).then((result) => {
this.updatePermissionState(result.state)
result.addEventListener("change", () => {
this.updatePermissionState(result.state)
})
})

this.element.dataset.action = "clipboard#copy"
this.tip = new bootstrap.Tooltip(this.element, { title: this.tooltipValue })
this.tip.disable()
Expand All @@ -13,9 +24,21 @@ export default class extends Controller {
this.tip.dispose()
}

copy(event) {
updatePermissionState(state) {
switch (state) {
case "denied":
this.element.style.display = "none"
break
case "prompt":
this.element.style.display = this.originalStyleDisplay
break
}
}

async copy(event) {
event.preventDefault()
navigator.clipboard.writeText(this.copyValue)

await navigator.clipboard.writeText(this.copyValue)

// briefly show "copied" tooltip
this.tip.enable()
Expand Down
141 changes: 141 additions & 0 deletions app/javascript/controllers/embed_preview_controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
import { Controller } from "@hotwired/stimulus"

export default class extends Controller {
static targets = ["accentColor", "embedIframe", "embedIframeWrapper", "embedUrl", "embedHtml"]

static values = {
embedUrl: String,
embedType: String,
}

connect() {
const that = this
window.addEventListener(
"message",
(e) => {
that.handlePostMessage(e)
},
false
)

if (this.hasEmbedIframeTarget && this.hasEmbedUrlValue) {
this.embedIframeTarget.setAttribute("src", this.embedUrlValue)
}
}

disconnect() {
const that = this
window.removeEventListener(
"message",
(e) => {
that.handlePostMessage(e)
},
false
)
}

handlePostMessage(e) {
// Bail if post message didn't originate from a Play domain.
if (!/^https?:\/\/play(?:\.staging)?\.prx\.(?:org|tech|test)$/.test(e.origin)) return

this.previewSource = e.source
this.previewOrigin = e.origin

this.updateEmbedUrlTarget(e.data.embedUrl)
this.updateEmbedUHtmlTarget(e.data.embedHtml)
this.updateEmbedStyles(e.data.embedStyles, e.data.embedHeight)
}

postConfigChange(config) {
this.previewSource.postMessage(config, this.previewOrigin)
}

updateEmbedUrlTarget(embedUrl) {
if (!embedUrl) return

for (const elm of this.embedUrlTargets) {
switch (elm.tagName) {
case "INPUT":
elm.value = embedUrl
break

case "A":
elm.href = embedUrl
break

case "BUTTON":
elm.setAttribute("data-clipboard-copy-value", embedUrl)
break
}
}
}

updateEmbedUHtmlTarget(embedHtml) {
if (!embedHtml) return

for (const elm of this.embedHtmlTargets) {
switch (elm.tagName) {
case "INPUT":
elm.value = embedHtml
break

case "BUTTON":
elm.setAttribute("data-clipboard-copy-value", embedHtml)
break
}
}
}

updateEmbedStyles(styles, height) {
this.embedIframeTarget.removeAttribute("class")

if (this.embedType === "card") {
this.embedIframeTarget.setAttribute("height", "100%")
this.embedIframeTarget.setAttribute("style", styles.iframe)
this.embedIframeWrapperTarget.setAttribute("style", styles.wrapper)
} else {
this.embedIframeTarget.setAttribute("height", height)
this.embedIframeTarget.setAttribute("style", styles.iframe)
this.embedIframeWrapperTarget.setAttribute("style", styles.wrapper)
}
}

changeType(e) {
this.embedType = e.target.value
this.postConfigChange({ showCoverArt: e.target.value === "card" })
}

changeMaxWidth(e) {
let maxWidth = e.target.value ? parseInt(e.target.value, 10) : null

if (maxWidth && maxWidth < e.target.min) {
maxWidth = null
}

this.postConfigChange({ maxWidth })
}

changePlaylist(e) {
const showPlaylist = !e.target.value ? "all" : (e.target.value > 1 && e.target.value) || null

this.postConfigChange({ showPlaylist })
}

changeSeason(e) {
this.postConfigChange({ playlistSeason: e.target.value })
}

changeCategory(e) {
this.postConfigChange({ playlistCategory: e.target.value })
}

changeTheme(e) {
this.postConfigChange({ theme: e.target.value !== "dark" ? e.target.value : null })
}

changeAccentColor(e) {
const accentColor = e.target.value !== "#ff9600" ? [e.target.value] : null

this.postConfigChange({ accentColor })
}
}
15 changes: 15 additions & 0 deletions app/javascript/controllers/form_select_controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { Controller } from "@hotwired/stimulus"

export default class extends Controller {
static targets = ["link", "help"]

static values = {
help: Object,
}

updateHelp(event) {
if (this.hasHelpValue && this.hasHelpTarget) {
this.helpTarget.innerText = this.helpValue[event.target.value]
}
}
}
Loading

0 comments on commit 6802753

Please sign in to comment.