app/model/commands/AddAssetCommand.scala (108 lines of code) (raw):

package model.commands import com.gu.contentatom.thrift.Atom import com.gu.contentatom.thrift.atom.media.{Asset, Metadata, Platform, Category => ThriftCategory, MediaAtom => ThriftMediaAtom} import com.gu.media.logging.Logging import com.gu.media.model.MediaAtom import com.gu.media.util.{MAMLogger, MediaAtomImplicits, ThriftUtil} import com.gu.pandomainauth.model.{User => PandaUser} import data.DataStores import com.gu.media.model.MediaAtom.fromThrift import com.gu.media.youtube.YoutubeUrl import model.commands.CommandExceptions._ import util.{AWSConfig, YouTube} import scala.util.control.NonFatal case class AddAssetCommand(atomId: String, videoUri: String, override val stores: DataStores, youTube: YouTube, user: PandaUser, awsConfig: AWSConfig) extends Command with MediaAtomImplicits with Logging { type T = MediaAtom def process(): MediaAtom = { log.info(s"Request to add new asset $videoUri to $atomId") val atom = getPreviewAtom(atomId) val mediaAtom = atom.tdata val currentAssets: Seq[Asset] = mediaAtom.assets.toSeq videoUri match { case YouTubeId(videoId) if assetAlreadyExists(videoId, currentAssets) => log.info(s"Cannot add asset $videoUri to $atomId as it already exists.") AssetAlreadyAdded case YouTubeId(videoId) => addAsset(atom, mediaAtom, currentAssets, videoId) case _ => NotYoutubeAsset } } private def addAsset(atom: Atom, mediaAtom: ThriftMediaAtom, currentAssets: Seq[Asset], videoId: String) = { val version = getNextAssetVersionNumber(currentAssets) val newAsset = ThriftUtil.parseAsset(uri = videoUri, version = version, mimeType = None) .fold(err => AssetParseFailed, identity) val channel = getYouTubeChannel(newAsset, mediaAtom, atom.id) val metadata = mediaAtom.metadata.getOrElse(Metadata()).copy(channelId = channel) val updatedAtom = atom .withData(mediaAtom.copy( assets = newAsset +: currentAssets, metadata = Some(metadata) )) log.info(s"Adding new asset $videoUri to $atomId") UpdateAtomCommand(atomId, fromThrift(updatedAtom), stores, user, awsConfig).process() } private def getYouTubeChannel(asset: Asset, atom: ThriftMediaAtom, atomId: String): Option[String] = { val existingChannel = atom.metadata.flatMap(_.channelId) def ensureIsGuardianChannel(videoChannel: String) = { if (youTube.channels.exists(_.id == videoChannel)) Some(videoChannel) else IncorrectYouTubeChannel } if (youTube.cannotReachYoutube) { log.info(s"Config says cannot reach Youtube") None } else { try { val maybeVideo = youTube.getVideo(asset.id, List("snippet")) (existingChannel, maybeVideo) match { case (_, None) => Some(YouTubeVideoDoesNotExist(asset.id)) case (None, Some(video)) => { val videoChannel = video.getSnippet.getChannelId atom.category match { // only GLabs atoms can have third party videos case ThriftCategory.Hosted | ThriftCategory.Paid => Some(videoChannel) case _ => { log.info(s"Atom $atomId does not have a channel, so falling back to channel provided by video ${asset.id}") ensureIsGuardianChannel(videoChannel) } } } case (Some(channel), Some(video)) => { val videoChannel = video.getSnippet.getChannelId if (channel != videoChannel) { log.info(s"Atom channel updating. New asset ${asset.id} on channel $videoChannel, atom on channel $channel") } // new asset must be on a Guardian channel ensureIsGuardianChannel(videoChannel) } } } catch { case NonFatal(e) => MAMLogger.error("Unable to lookup YouTube channel", atomId, asset.id, e) existingChannel } } } private def getNextAssetVersionNumber (currentAssets: Seq[Asset]): Long = { currentAssets.foldLeft(1L){ (acc, asset) => { if (asset.version >= acc) asset.version + 1 else acc }} } private def assetAlreadyExists (videoId: String, currentAssets: Seq[Asset]): Boolean = { currentAssets.exists(x => x.platform == Platform.Youtube && x.id == videoId) } private case object YouTubeId { def unapply(videoUri: String): Option[String] = { val platform = ThriftUtil.parsePlatform(videoUri) (platform, videoUri) match { case (Right(Platform.Youtube), YoutubeUrl(videoId)) => Some(videoId) case _ => None } } } }