[deploy] Decorator podcast episode metadata (#7303)
* Moves podcast episode metadata to decorator * Updates the podcast episode metadata to use image_url * Syntax tweaks, initializeMedia() fix for initialized audio & brought back use strict
This commit is contained in:
parent
61b6f8ea3e
commit
f2ee0378f9
7 changed files with 137 additions and 91 deletions
|
|
@ -1,4 +1,4 @@
|
|||
'use strict'
|
||||
"use strict"
|
||||
|
||||
/**
|
||||
* This script hunts for podcast's "Record" for both the podcast_episde's
|
||||
|
|
@ -20,7 +20,7 @@
|
|||
* - saveMediaState()
|
||||
*
|
||||
* The following are useful eslint disables for this file in particular. Because
|
||||
* of the way it's wrapped around it's own function (own context) we don't have
|
||||
* of the way it's wrapped around its own function (own context) we don't have
|
||||
* the problem of using a method before it's defined:
|
||||
*/
|
||||
|
||||
|
|
@ -50,18 +50,20 @@ function initializePodcastPlayback() {
|
|||
volume: 1,
|
||||
duration: 1,
|
||||
updated: new Date().getTime(),
|
||||
windowName: window.name
|
||||
windowName: window.name,
|
||||
};
|
||||
}
|
||||
|
||||
function currentAudioState() {
|
||||
try {
|
||||
var currentState = JSON.parse(localStorage.getItem('media_playback_state_v2'));
|
||||
var currentState = JSON.parse(
|
||||
localStorage.getItem('media_playback_state_v2'),
|
||||
);
|
||||
if (!currentState || window.name !== currentState.windowName) {
|
||||
return newAudioState();
|
||||
}
|
||||
return currentState;
|
||||
} catch(e) {
|
||||
} catch (e) {
|
||||
console.log(e); // eslint-disable-line no-console
|
||||
return newAudioState();
|
||||
}
|
||||
|
|
@ -133,26 +135,26 @@ function initializePodcastPlayback() {
|
|||
|
||||
function applyOnclickToPodcastBar(audio) {
|
||||
var currentState = currentAudioState();
|
||||
getById('barPlayPause').onclick = function() {
|
||||
getById('barPlayPause').onclick = function () {
|
||||
playPause(audio);
|
||||
};
|
||||
getById('mutebutt').onclick = function() {
|
||||
getById('mutebutt').onclick = function () {
|
||||
muteUnmute(audio);
|
||||
};
|
||||
getById('volbutt').onclick = function() {
|
||||
getById('volbutt').onclick = function () {
|
||||
muteUnmute(audio);
|
||||
};
|
||||
getById('bufferwrapper').onclick = function(e) {
|
||||
getById('bufferwrapper').onclick = function (e) {
|
||||
goToTime(e, audio);
|
||||
};
|
||||
getById('volumeslider').value = currentState.volume * 100;
|
||||
getById('volumeslider').onchange = function(e) {
|
||||
getById('volumeslider').onchange = function (e) {
|
||||
updateVolume(e, audio);
|
||||
};
|
||||
getById('speed').onclick = function() {
|
||||
getById('speed').onclick = function () {
|
||||
changePlaybackRate(audio);
|
||||
};
|
||||
getById('closebutt').onclick = function() {
|
||||
getById('closebutt').onclick = function () {
|
||||
terminatePodcastBar(audio);
|
||||
};
|
||||
}
|
||||
|
|
@ -162,7 +164,7 @@ function initializePodcastPlayback() {
|
|||
}
|
||||
|
||||
function updateProgressListener(audio) {
|
||||
return function(e) {
|
||||
return function (e) {
|
||||
var bufferValue = 0;
|
||||
if (audio.currentTime > 0) {
|
||||
var bufferEnd = audio.buffered.end(audio.buffered.length - 1);
|
||||
|
|
@ -174,7 +176,10 @@ function initializePodcastPlayback() {
|
|||
|
||||
function loadAudio(audio) {
|
||||
if (isNativeIOS()) {
|
||||
sendPodcastMessage({'action': 'load', 'url': audio.querySelector('source').src});
|
||||
sendPodcastMessage({
|
||||
action: 'load',
|
||||
url: audio.querySelector('source').src,
|
||||
});
|
||||
} else {
|
||||
audio.load();
|
||||
}
|
||||
|
|
@ -193,10 +198,10 @@ function initializePodcastPlayback() {
|
|||
|
||||
function findAndApplyOnclickToRecords() {
|
||||
var records = findRecords();
|
||||
Array.prototype.forEach.call(records, function(record) {
|
||||
Array.prototype.forEach.call(records, function (record) {
|
||||
var episodeSlug = record.getAttribute('data-episode');
|
||||
var podcastSlug = record.getAttribute('data-podcast');
|
||||
record.onclick = function() {
|
||||
record.onclick = function () {
|
||||
if (podcastBarAlreadyExistAndPlayingTargetEpisode(episodeSlug)) {
|
||||
var audio = getById('audio');
|
||||
if (audio) {
|
||||
|
|
@ -214,7 +219,7 @@ function initializePodcastPlayback() {
|
|||
var currentState = currentAudioState();
|
||||
var el = getById('speed');
|
||||
var speed = parseFloat(el.getAttribute('data-speed'));
|
||||
if (speed == 2) {
|
||||
if (speed === 2) {
|
||||
el.setAttribute('data-speed', 0.5);
|
||||
el.innerHTML = '0.5x';
|
||||
currentState.playbackRate = 0.5;
|
||||
|
|
@ -226,7 +231,10 @@ function initializePodcastPlayback() {
|
|||
saveMediaState(currentState);
|
||||
|
||||
if (isNativeIOS()) {
|
||||
sendPodcastMessage({'action':'rate', 'rate': currentState.playbackRate.toString()});
|
||||
sendPodcastMessage({
|
||||
action: 'rate',
|
||||
rate: currentState.playbackRate.toString(),
|
||||
});
|
||||
} else {
|
||||
audio.playbackRate = currentState.playbackRate;
|
||||
}
|
||||
|
|
@ -264,45 +272,61 @@ function initializePodcastPlayback() {
|
|||
return new Promise(function (resolve, reject) {
|
||||
var currentState = currentAudioState();
|
||||
if (isNativeIOS()) {
|
||||
sendPodcastMessage({'action': 'play', 'seconds': currentState.currentTime.toString()});
|
||||
sendPodcastMessage({
|
||||
action: 'play',
|
||||
seconds: currentState.currentTime.toString(),
|
||||
});
|
||||
setPlaying(true);
|
||||
resolve();
|
||||
} else {
|
||||
audio.currrentTime = currentState.currentTime;
|
||||
audio.play().then(function() {
|
||||
setPlaying(true);
|
||||
resolve();
|
||||
}).catch(function(error) {
|
||||
console.log(error); // eslint-disable-line no-console
|
||||
setPlaying(false);
|
||||
reject();
|
||||
});
|
||||
audio
|
||||
.play()
|
||||
.then(function () {
|
||||
setPlaying(true);
|
||||
resolve();
|
||||
})
|
||||
.catch(function (error) {
|
||||
console.log(error); // eslint-disable-line no-console
|
||||
setPlaying(false);
|
||||
reject();
|
||||
});
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
function sendMetadataMessage() {
|
||||
try {
|
||||
var episodeContainer = getByClass('podcast-episode-container')[0];
|
||||
if (episodeContainer === undefined) {
|
||||
episodeContainer = getByClass('podcastliquidtag')[0];
|
||||
}
|
||||
var metadata = JSON.parse(episodeContainer.dataset.meta);
|
||||
var message = {
|
||||
action: 'metadata',
|
||||
episodeName: metadata.episodeName,
|
||||
podcastName: metadata.podcastName,
|
||||
podcastImageUrl: metadata.podcastImageUrl,
|
||||
};
|
||||
sendPodcastMessage(message);
|
||||
} catch (e) {
|
||||
console.log('Unable to load Podcast Episode metadata', e); // eslint-disable-line no-console
|
||||
}
|
||||
}
|
||||
|
||||
function startAudioPlayback(audio) {
|
||||
if (isNativeIOS()) {
|
||||
try {
|
||||
var episodeContainer = document.getElementsByClassName('podcast-episode-container')[0];
|
||||
var metadata = JSON.parse(episodeContainer.dataset.meta);
|
||||
var message = {
|
||||
'action': 'metadata',
|
||||
'episodeName': metadata.episodeName,
|
||||
'podcastName': metadata.podcastName,
|
||||
'podcastImageUrl': metadata.podcastImageUrl
|
||||
}
|
||||
sendPodcastMessage(message);
|
||||
} catch(e) {
|
||||
console.log('Unable to load Podcast Episode metadata', e); // eslint-disable-line no-console
|
||||
}
|
||||
sendMetadataMessage();
|
||||
}
|
||||
playAudio(audio).then(function() {
|
||||
|
||||
playAudio(audio)
|
||||
.then(function () {
|
||||
spinPodcastRecord();
|
||||
startPodcastBar();
|
||||
}).catch(function(error) {
|
||||
})
|
||||
.catch(function (error) {
|
||||
playAudio(audio);
|
||||
setTimeout(function() {
|
||||
setTimeout(function () {
|
||||
spinPodcastRecord('initializing...');
|
||||
startPodcastBar();
|
||||
}, 5);
|
||||
|
|
@ -311,7 +335,7 @@ function initializePodcastPlayback() {
|
|||
|
||||
function pauseAudioPlayback(audio) {
|
||||
if (isNativeIOS()) {
|
||||
sendPodcastMessage({'action': 'pause'});
|
||||
sendPodcastMessage({ action: 'pause' });
|
||||
} else {
|
||||
audio.pause();
|
||||
}
|
||||
|
|
@ -352,14 +376,25 @@ function initializePodcastPlayback() {
|
|||
|
||||
function muteUnmute(audio) {
|
||||
var currentState = currentAudioState();
|
||||
getById('mutebutt').classList.add(currentState.muted ? 'hidden' : 'showing');
|
||||
getById('volumeindicator').classList.add(currentState.muted ? 'showing' : 'hidden');
|
||||
getById('mutebutt').classList.remove(currentState.muted ? 'showing' : 'hidden');
|
||||
getById('volumeindicator').classList.remove(currentState.muted ? 'hidden' : 'showing');
|
||||
getById('mutebutt').classList.add(
|
||||
currentState.muted ? 'hidden' : 'showing',
|
||||
);
|
||||
getById('volumeindicator').classList.add(
|
||||
currentState.muted ? 'showing' : 'hidden',
|
||||
);
|
||||
getById('mutebutt').classList.remove(
|
||||
currentState.muted ? 'showing' : 'hidden',
|
||||
);
|
||||
getById('volumeindicator').classList.remove(
|
||||
currentState.muted ? 'hidden' : 'showing',
|
||||
);
|
||||
|
||||
currentState.muted = !currentState.muted;
|
||||
if (isNativeIOS()) {
|
||||
sendPodcastMessage({'action': 'muted', 'muted': currentState.muted.toString()});
|
||||
sendPodcastMessage({
|
||||
action: 'muted',
|
||||
muted: currentState.muted.toString(),
|
||||
});
|
||||
} else {
|
||||
audio.muted = currentState.muted;
|
||||
}
|
||||
|
|
@ -370,7 +405,7 @@ function initializePodcastPlayback() {
|
|||
var currentState = currentAudioState();
|
||||
currentState.volume = e.target.value / 100;
|
||||
if (isNativeIOS()) {
|
||||
sendPodcastMessage({'action': 'volume', 'volume': currentState.volume});
|
||||
sendPodcastMessage({ action: 'volume', volume: currentState.volume });
|
||||
} else {
|
||||
audio.volume = currentState.volume;
|
||||
}
|
||||
|
|
@ -385,7 +420,7 @@ function initializePodcastPlayback() {
|
|||
var firstDecimal = currentTime - Math.floor(currentTime);
|
||||
if (currentTime > 0) {
|
||||
value = Math.floor((100.0 / duration) * currentTime);
|
||||
if(firstDecimal < 0.4) {
|
||||
if (firstDecimal < 0.4) {
|
||||
// Rewrite to mediaState storage every few beats.
|
||||
var currentState = currentAudioState();
|
||||
currentState.duration = duration;
|
||||
|
|
@ -397,9 +432,7 @@ function initializePodcastPlayback() {
|
|||
progress.style.width = value + '%';
|
||||
buffer.style.width = bufferValue + '%';
|
||||
time.innerHTML =
|
||||
readableDuration(currentTime) +
|
||||
' / ' +
|
||||
readableDuration(duration);
|
||||
readableDuration(currentTime) + ' / ' + readableDuration(duration);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -413,9 +446,12 @@ function initializePodcastPlayback() {
|
|||
currentState.currentTime = duration * percent; // jumps to 29th secs
|
||||
|
||||
if (isNativeIOS()) {
|
||||
sendPodcastMessage({'action': 'seek', 'seconds': currentState.currentTime.toString()});
|
||||
sendPodcastMessage({
|
||||
action: 'seek',
|
||||
seconds: currentState.currentTime.toString(),
|
||||
});
|
||||
} else {
|
||||
audio.currentTime = currentState.currentTime
|
||||
audio.currentTime = currentState.currentTime;
|
||||
}
|
||||
|
||||
time.innerHTML =
|
||||
|
|
@ -436,12 +472,16 @@ function initializePodcastPlayback() {
|
|||
}
|
||||
|
||||
function terminatePodcastBar(audio) {
|
||||
audio.removeEventListener('timeupdate', updateProgressListener(audio), false);
|
||||
audio.removeEventListener(
|
||||
'timeupdate',
|
||||
updateProgressListener(audio),
|
||||
false,
|
||||
);
|
||||
getById('audiocontent').innerHTML = '';
|
||||
stopRotatingActivePodcastIfExist();
|
||||
saveMediaState(newAudioState());
|
||||
if (isNativeIOS()) {
|
||||
sendPodcastMessage({'action': 'terminate'});
|
||||
sendPodcastMessage({ action: 'terminate' });
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -454,7 +494,7 @@ function initializePodcastPlayback() {
|
|||
try {
|
||||
var messageData = getById('audiocontent').dataset.podcast;
|
||||
message = JSON.parse(messageData);
|
||||
} catch(e) {
|
||||
} catch (e) {
|
||||
console.log(e); // eslint-disable-line no-console
|
||||
return;
|
||||
}
|
||||
|
|
@ -466,13 +506,13 @@ function initializePodcastPlayback() {
|
|||
saveMediaState(currentState);
|
||||
updateProgress(currentState.currentTime, currentState.duration, 100);
|
||||
} else {
|
||||
console.log('Unrecognized podcast message: ', message); // eslint-disable-line no-console
|
||||
console.log('Unrecognized podcast message: ', message); // eslint-disable-line no-console
|
||||
}
|
||||
}
|
||||
|
||||
function addMutationObserver() {
|
||||
var mutationObserver = new MutationObserver(function(mutations) {
|
||||
mutations.forEach(function(mutation) {
|
||||
var mutationObserver = new MutationObserver(function (mutations) {
|
||||
mutations.forEach(function (mutation) {
|
||||
handlePodcastMessages(mutation);
|
||||
});
|
||||
});
|
||||
|
|
@ -483,8 +523,8 @@ function initializePodcastPlayback() {
|
|||
var currentState = currentAudioState();
|
||||
document.getElementById('audiocontent').innerHTML = currentState.html;
|
||||
var audio = getById('audio');
|
||||
if (audio == undefined) {
|
||||
audioInitialized = false
|
||||
if (audio === undefined || audio === null) {
|
||||
audioInitialized = false;
|
||||
return;
|
||||
}
|
||||
if (!isNativeIOS()) {
|
||||
|
|
@ -492,15 +532,18 @@ function initializePodcastPlayback() {
|
|||
}
|
||||
loadAudio(audio);
|
||||
if (currentState.playing) {
|
||||
playAudio(audio).catch(function(error) {
|
||||
console.log(error); // eslint-disable-line no-console
|
||||
playAudio(audio).catch(function (error) {
|
||||
pausePodcastBar();
|
||||
});
|
||||
}
|
||||
setTimeout(function(){
|
||||
audio.addEventListener('timeupdate', updateProgressListener(audio), false);
|
||||
setTimeout(function () {
|
||||
audio.addEventListener(
|
||||
'timeupdate',
|
||||
updateProgressListener(audio),
|
||||
false,
|
||||
);
|
||||
addMutationObserver();
|
||||
},500);
|
||||
}, 500);
|
||||
applyOnclickToPodcastBar(audio);
|
||||
}
|
||||
|
||||
|
|
@ -518,7 +561,8 @@ function initializePodcastPlayback() {
|
|||
}
|
||||
var audio = getById('audio');
|
||||
var audioContent = getById('audiocontent');
|
||||
if (audio && audioContent && audioContent.innerHTML.length < 25) { // audio not already loaded
|
||||
if (audio && audioContent && audioContent.innerHTML.length < 25) {
|
||||
// audio not already loaded
|
||||
loadAudio(audio);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,4 +25,13 @@ class PodcastEpisodeDecorator < ApplicationDecorator
|
|||
|
||||
published_at.utc.iso8601
|
||||
end
|
||||
|
||||
def mobile_player_metadata
|
||||
image_url = ApplicationController.helpers.cloudinary(podcast.image_url, 600)
|
||||
{
|
||||
podcastName: podcast.title,
|
||||
episodeName: title,
|
||||
podcastImageUrl: image_url
|
||||
}
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -148,14 +148,6 @@ class PodcastEpisode < ApplicationRecord
|
|||
[]
|
||||
end
|
||||
|
||||
def mobile_player_metadata
|
||||
{
|
||||
podcastName: podcast.title,
|
||||
episodeName: title,
|
||||
podcastImageUrl: ApplicationController.helpers.app_url(podcast.image_url)
|
||||
}
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def index_id
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
type: "fetch", quality: "auto", sign_url: true,
|
||||
flags: "progressive", fetch_format: "jpg") %>
|
||||
|
||||
<div class="podcastliquidtag" style="background: #<%= podcast.main_color_hex %> url(<%= image_url %>)">
|
||||
<div class="podcastliquidtag" style="background: #<%= podcast.main_color_hex %> url(<%= image_url %>)" data-meta="<%= episode.decorate.mobile_player_metadata.to_json %>">
|
||||
<div class="podcastliquidtag__info">
|
||||
<a href="/<%= podcast.slug %>/<%= episode.slug %>">
|
||||
<h1 class="podcastliquidtag__info__episodetitle"><%= episode.title %></h1>
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@
|
|||
|
||||
<% end %>
|
||||
|
||||
<div class="podcast-episode-container" data-meta="<%= @episode.mobile_player_metadata.to_json %>">
|
||||
<div class="podcast-episode-container" data-meta="<%= @episode.decorate.mobile_player_metadata.to_json %>">
|
||||
<div class="hero">
|
||||
<% image_url = cl_image_path(@podcast.pattern_image_url || "https://i.imgur.com/fKYKgo4.png",
|
||||
type: "fetch",
|
||||
|
|
|
|||
|
|
@ -77,4 +77,15 @@ RSpec.describe PodcastEpisodeDecorator, type: :decorator do
|
|||
expect(pe.decorate.published_timestamp).to eq(published_at.utc.iso8601)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#mobile_player_metadata" do
|
||||
it "responds with a hash with metadata used in native mobile players" do
|
||||
pe = build(:podcast_episode)
|
||||
metadata = pe.decorate.mobile_player_metadata
|
||||
expect(metadata).to be_instance_of(Hash)
|
||||
expect(metadata[:podcastName]).to eq(pe.podcast.title)
|
||||
expect(metadata[:episodeName]).to eq(pe.title)
|
||||
expect(metadata[:podcastImageUrl]).to include(pe.podcast.image_url)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -67,16 +67,6 @@ RSpec.describe PodcastEpisode, type: :model do
|
|||
end
|
||||
end
|
||||
|
||||
describe "#mobile_player_metadata" do
|
||||
it "responds with a hash with metadata used in native mobile players" do
|
||||
metadata = podcast_episode.mobile_player_metadata
|
||||
expect(metadata).to be_instance_of(Hash)
|
||||
expect(metadata[:podcastName]).to eq(podcast_episode.podcast.title)
|
||||
expect(metadata[:episodeName]).to eq(podcast_episode.title)
|
||||
expect(metadata[:podcastImageUrl]).to include(podcast_episode.podcast.image_url)
|
||||
end
|
||||
end
|
||||
|
||||
describe ".available" do
|
||||
let_it_be(:podcast) { create(:podcast) }
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue