Skip to content

Commit

Permalink
Initial cuepoint impl
Browse files Browse the repository at this point in the history
  • Loading branch information
kookster committed Dec 12, 2024
1 parent 37a0574 commit 84e6b56
Show file tree
Hide file tree
Showing 5 changed files with 147 additions and 15 deletions.
2 changes: 1 addition & 1 deletion app/models/integrations/episode_delivery_status.rb
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ def mark_as_not_uploaded!
# Whether the media file has been uploaded to the Integration
# is a subset of whether the episode has been delivered
def mark_as_delivered!
self.class.update_status(integration, episode, delivered: true, uploaded: true)
self.class.update_status(integration, episode, delivered: true, uploaded: true, asset_processing_attempts: 0)
end

def mark_as_not_delivered!
Expand Down
2 changes: 1 addition & 1 deletion app/models/integrations/episode_integrations.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ def sync_log(integration)
end

def episode_delivery_status(integration, with_default = false)
status = episode_delivery_statuses.order(created_at: :desc).send(integration.intern).first
status = episode_delivery_statuses.reset.order(created_at: :desc).send(integration.intern).first
if !status && with_default
Integrations::EpisodeDeliveryStatus.default_status(integration, self)
else
Expand Down
61 changes: 61 additions & 0 deletions app/models/megaphone/cuepoint.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
module Megaphone
class Cuepoint
include Megaphone::Model

CUEPOINT_TYPES = %i[preroll midroll postroll remove]

AD_SOURCES = %i[auto promo span]

CREATE_REQUIRED = %i[cuepoint_type ad_count start_time end_time ad_sources action]

CREATE_ATTRIBUTES = CREATE_REQUIRED + %i[title end_time is_active offset notes]

ALL_ATTRIBUTES = (CREATE_ATTRIBUTES + DEPRECATED + OTHER_ATTRIBUTES)

attr_accessor(*ALL_ATTRIBUTES)

validates_presence_of CREATE_REQUIRED

def self.from_placement(zones)
cuepoints = []
current_cuepoint = nil
original_duration = 0
original_count = 0
zones.each do |zone|
# if this is an ad zone, add it to the cue point
if zone[:type] == "ad"
if current_cuepoint
current_cuepoint.ad_count = current_cuepoint.ad_count + 1
current_cuepoint.ad_sources << source_for_zone(zone)
else
current_cuepoint = new(
cuepoint_type: "#{zone[:section]}roll",
ad_count: 1,
start_time: original_duration,
ad_sources: [source_for_zone(zone)],
action: :insert,
is_active: true
)
cuepoints << current_cuepoint
end
elsif zone[:type] == "original"
current_cuepoint = nil
original_duration += feeder_episode.media[original_count].duration
original_count += 1
end
end
end

def source_for_zone(zone)
if zone[:id].match?(/^house/)
:promo
else
:auto
end
end

def as_json_for_create
as_json(only: CREATE_ATTRIBUTES.map(&:to_s))
end
end
end
85 changes: 72 additions & 13 deletions app/models/megaphone/episode.rb
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,61 @@ def update!(feed = nil)
self
end

# call this when we need to update the audio on mp
# like when dtr wasn't ready at first
# so we can make that update and then mark uploaded
def upload_audio!
set_audio_attributes
update!
end

# call this when audio has been updated on mp
# and we're checking to see if mp is done processing
# so we can update cuepoints and mark delivered
def check_audio!
# Re-request the megaphone api
find_by_megaphone_id

# get the audip attributes
set_audio_attributes

# check to see if the audio on mp matches
if original_filename == source_filename
if !audio_file_processing && audio_file_status == "success"
reset_asset_wait replace_cuepoints!(episode)
delivery_status(true).mark_as_delivered!
else
# still waiting - increment asset state
delivery_status(true).increment_asset_wait
end
else
# this would be a weird timing thing maybe, but ...
# if the files don't match, we need to go back and upload
delivery_status(true).mark_as_not_uploaded!
end
end

def replace_cuepoints!(episode)
# retrieve the placement info from augury
zones = get_placement_zones(feeder_episode.segment_count)

# create cuepoint instances from that
cuepoints = Megaphone::Cuepoint.from_placement(zones)

# put those as a list to the mp api
cuepoints_batch!(cuepoints)
end

def cuepoints_batch!(cuepoints)
# validate all the cuepoints about to be created
cuepoints.all? { |cp| cp.validate!(:create) }
body = cuepoints.map { |cp| cp.as_json_for_create }
self.api_response = api.put("podcasts/#{podcast.id}/episodes/#{id}/cuepoints_batch", body)
update_sync_log
update_delivery_status
self
end

def update_sync_log
SyncLog.log!(
integration: :megaphone,
Expand Down Expand Up @@ -147,6 +202,7 @@ def update_delivery_status
# we're done, mark it as delivered!
delivery_status(true).mark_as_delivered!
end
feeder_episode.episode_delivery_statuses.reset
end

def private_feed
Expand Down Expand Up @@ -174,24 +230,27 @@ def delivery_status(with_default = false)
end

def set_placement_attributes
if (placement = get_placement(feeder_episode.segment_count))
self.expected_adhash = adhash_for_placement(placement)
if (zones = get_placement_zones(feeder_episode.segment_count))
self.expected_adhash = adhash_for_placement(zones)
self.pre_count = expected_adhash.count("0")
self.post_count = expected_adhash.count("2")
end
end

def adhash_for_placement(placement)
placement
.zones
.filter { |z| z["type"] == "ad" }
.map { |z| ADHASH_VALUES[z["section"]] }
def adhash_for_placement(zones)
zones
.filter { |z| z[:type] == "ad" }
.map { |z| ADHASH_VALUES[z[:section]] }
.join("")
end

def get_placement(original_count)
def get_placement_zones(original_count = nil)
if original_count.to_i < 1
original_count = (feeder_episode&.segment_count || 1).to_i
end
placements = Prx::Augury.new.placements(feeder_podcast.id)
placements&.find { |i| i.original_count == original_count }
placement = placements&.find { |i| i.original_count == original_count }
(placement&.zones || []).map(&:with_indifferent_access)
end

# call this before create or update, yah
Expand Down Expand Up @@ -271,13 +330,13 @@ def timings
feeder_episode.media[0..-2].map(&:duration)
end

def pre_after_original?(placement)
sections = placement.zones.split { |z| z[:type] == "original" }
def pre_after_original?(zones)
sections = zones.split { |z| z[:type] == "original" }
sections[1].any? { |z| %w[ad house].include?(z[:type]) && z[:id].match(/pre/) }
end

def post_before_original?(placement)
sections = placement.zones.split { |z| z[:type] == "original" }
def post_before_original?(zones)
sections = zones.split { |z| z[:type] == "original" }
sections[-2].any? { |z| %w[ad house].include?(z[:type]) && z[:id].match(/post/) }
end
end
Expand Down
12 changes: 12 additions & 0 deletions app/models/megaphone/publisher.rb
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,18 @@ def check_status_episodes!
private_feed.episodes.unfinished(:megaphone).each do |ep|
megaphone_episode = Megaphone::Episode.find_by_episode(megaphone_podcast, ep)
next unless megaphone_episode

# check if it is uploaded yet
# if not go looking for the DTR media version
if !megaphone_episode.delivery_status.uploaded?
megaphone_episode.upload_audio!
end

# check if it is uploaded, but not delivered - see if megaphone has processed
status = megaphone_episode.delivery_status
if !status.delivered? && status.uploaded?
megaphone_episode.check_audio!
end
end
end

Expand Down

0 comments on commit 84e6b56

Please sign in to comment.