private static IEnumerable<ICreative> GetSubsequentCreatives(IDocumentCreativeSource creativeSource, Ad creativeConcept, AdDocumentPayload payload) { if (creativeSource == null) throw new ArgumentNullException("creativeSource"); if (payload == null) throw new ArgumentNullException("payload"); if (creativeConcept == null) throw new ArgumentNullException("creativeConcept"); var adPod = payload.AdPods.FirstOrDefault(ap => ap.Ads.Contains(creativeConcept)); if (adPod != null) { return adPod.Ads .SelectMany(a => a.Creatives.OrderBy(c => c.Sequence.GetValueOrDefault(int.MaxValue))) .Where(c => !(c is CreativeCompanions)) .SkipWhile(c => c != creativeSource.Creative) .Skip(1); } return null; }
internal static void MergeWrappedAdBeacons(Ad source, Ad dest) { foreach (var impression in source.Impressions) dest.Impressions.Add(impression); foreach (var error in source.Errors) dest.Errors.Add(error); }
internal static void MergeWrappedAd(Ad source, Ad dest) { // carry over impressions MergeWrappedAdBeacons(source, dest); // carry over tracking events foreach (ICreative destCreative in dest.Creatives) { ICreative sourceCreative = FindMatchingCreative(dest, destCreative, source); if (sourceCreative != null) { MergeWrappedCreative(sourceCreative, destCreative); } } }
internal static async Task<AdDocumentPayload> CreateFromVast(Stream stream, int? maxRedirectDepth, bool allowMultipleAds) #endif { XDocument xDoc = XDocument.Load(stream); XElement vastRoot = xDoc.Element("VAST"); if (vastRoot == null) { vastRoot = xDoc.Element("VideoAdServingTemplate"); if (vastRoot == null) throw new NotImplementedException(); return await CreateFromVast1(vastRoot, maxRedirectDepth, allowMultipleAds); } else { var result = new AdDocumentPayload(); result.Version = (string)vastRoot.Attribute("version"); result.Error = (string)vastRoot.Element("Error"); var eligableAds = vastRoot.Elements("Ad"); if (!allowMultipleAds) { eligableAds = eligableAds.Where(va => string.IsNullOrEmpty((string)va.Attribute("sequence"))); } foreach (var vastAdPod in eligableAds.GroupBy(va => va.Attribute("sequence") != null ? 1 : int.MaxValue).OrderBy(vap => vap.Key)) { var adPod = new AdPod(); foreach (var vastAd in vastAdPod.OrderBy(va => ToNullableInt((string)va.Attribute("sequence")).GetValueOrDefault(0))) { var ad = new Ad(); ad.Id = (string)vastAd.Attribute("id"); if (vastAd.Elements("InLine").Any()) { var vastAdInline = vastAd.Element("InLine"); ad.AdSystem = GetAdSystem(vastAdInline.Element("AdSystem")); ad.Advertiser = (string)vastAdInline.Element("Advertiser"); ad.Description = (string)vastAdInline.Element("Description"); var error = (string)vastAdInline.Element("Error"); if (error != null) ad.Errors.Add(error); ad.Title = (string)vastAdInline.Element("AdTitle"); ad.Survey = GetUriValue(vastAdInline.Element("Survey")); ad.Pricing = new Pricing(); var pricing = vastAdInline.Element("Pricing"); if (pricing != null) { ad.Pricing.Currency = (string)pricing.Attribute("currency"); ad.Pricing.Model = (PricingModel)Enum.Parse(typeof(PricingModel), (string)pricing.Attribute("model"), true); ad.Pricing.Value = Convert.ToDouble((string)pricing); } foreach (var vastImpression in vastAdInline.Elements("Impression")) { ad.Impressions.Add((string)vastImpression); } if (vastAdInline.Elements("Extensions").Any()) { foreach (var vastExtension in vastAdInline.Element("Extensions").Elements("Extension")) { ad.Extensions.Add(new Extension()); // TODO } } LoadCreatives(vastAdInline, ad); adPod.Ads.Add(ad); } else if (vastAd.Elements("Wrapper").Any()) { Ad wrapper = new Ad(); var vastAdWrapper = vastAd.Element("Wrapper"); // parse the wrapper itself wrapper.AdSystem = GetAdSystem(vastAdWrapper.Element("AdSystem")); var error = (string)vastAdWrapper.Element("Error"); if (error != null) wrapper.Errors.Add(error); foreach (var vastImpression in vastAdWrapper.Elements("Impression")) { wrapper.Impressions.Add((string)vastImpression); } LoadCreatives(vastAdWrapper, wrapper); if (vastAdWrapper.Elements("Extensions").Any()) { foreach (var vastExtension in vastAdWrapper.Element("Extensions").Elements("Extension")) { ad.Extensions.Add(new Extension()); // TODO } } AdDocumentPayload wrappedVastDoc = null; var vastAdUri = GetUriValue(vastAdWrapper.Element("VASTAdTagURI")); if (vastAdUri != null && (!maxRedirectDepth.HasValue || maxRedirectDepth.Value > 0)) { try { // load the stream from the web using (var s = await Extensions.LoadStreamAsync(vastAdUri)) { var newAllowMultipleAds = vastAdWrapper.GetBoolAttribute("allowMultipleAds", allowMultipleAds); var followAdditionalWrappers = vastAdWrapper.GetBoolAttribute("followAdditionalWrappers", true); int? nextMaxRedirectDepth = followAdditionalWrappers ? (maxRedirectDepth.HasValue ? maxRedirectDepth.Value - 1 : maxRedirectDepth) : 0; wrappedVastDoc = await CreateFromVast(s, nextMaxRedirectDepth, newAllowMultipleAds); } } catch { /* swallow */ } } AdPod wrappedAdPod = null; if (wrappedVastDoc != null) { wrappedAdPod = wrappedVastDoc.AdPods.FirstOrDefault(); } if (wrappedAdPod == null || !wrappedAdPod.Ads.Any()) { // no ads were returned var fallbackOnNoAd = vastAdWrapper.GetBoolAttribute("fallbackOnNoAd", true); if (fallbackOnNoAd) { wrappedAdPod = FallbackAdPod; } } if (wrappedAdPod != null) { // merge tracking info from this wrapper to every ad in the first adpod in the child foreach (Ad inlineAd in wrappedAdPod.Ads) MergeWrappedAd(wrapper, inlineAd); // add each ad from the first adpod in the child to the current adpod foreach (Ad inlineAd in wrappedAdPod.Ads) adPod.Ads.Add(inlineAd); } } } result.AdPods.Add(adPod); } return result; } }
private static void LoadCreatives(XElement adElement, Ad ad) { var vastCreatives = adElement.Element("Creatives"); if (vastCreatives != null) { foreach (var vastCreative in vastCreatives.Elements("Creative")) { var vastItem = vastCreative.Elements().FirstOrDefault(); if (vastItem != null) { ICreative creative = null; switch (vastItem.Name.LocalName) { case "Linear": var vastLinear = vastItem; var linearCreative = new CreativeLinear(); creative = linearCreative; foreach (var trackingEvent in GetTrackingEvents(vastLinear)) { linearCreative.TrackingEvents.Add(trackingEvent); } if (vastLinear.Elements("AdParameters").Any()) { var xmlEncoded = (bool?)vastLinear.Element("AdParameters").Attribute("xmlEncoded") ?? false; linearCreative.AdParameters = xmlEncoded ? XmlDecode((string)vastLinear.Element("AdParameters")) : (string)vastLinear.Element("AdParameters"); } LoadVideoClicks(vastLinear, linearCreative); if (vastLinear.Elements("CreativeExtensions").Any()) { foreach (var vastExtension in vastLinear.Element("CreativeExtensions").Elements("CreativeExtension")) { linearCreative.Extensions.Add(new Extension()); // TODO } } linearCreative.Duration = ToNullableTimeSpan((string)vastLinear.Element("Duration")); linearCreative.SkipOffset = FlexibleOffset.Parse((string)vastLinear.Attribute("skipoffset")); var vastIcons = vastLinear.Element("Icons"); if (vastIcons != null) { foreach (var vastIcon in vastIcons.Elements("Icon")) { var icon = new Icon(); if (vastIcon.Elements("IconClicks").Any()) { var iconClicks = vastIcon.Element("IconClicks"); icon.ClickThrough = GetUriValue(iconClicks.Element("IconClickThrough")); foreach (var clickTracking in iconClicks.Elements("IconClickTracking")) { icon.ClickTracking.Add((string)clickTracking); } } icon.ApiFramework = (string)vastIcon.Attribute("apiFramework") ?? string.Empty; icon.Duration = ToNullableTimeSpan((string)vastIcon.Attribute("duration")) ?? new TimeSpan?(); icon.Height = (int?)vastIcon.Attribute("height"); icon.Width = (int?)vastIcon.Attribute("width"); icon.Offset = ToNullableTimeSpan((string)vastIcon.Attribute("offset")) ?? new TimeSpan?(); icon.Program = (string)vastIcon.Attribute("program") ?? string.Empty; icon.XPosition = (string)vastIcon.Attribute("xPosition") ?? string.Empty; icon.YPosition = (string)vastIcon.Attribute("yPosition") ?? string.Empty; icon.Item = GetResources(vastIcon).FirstOrDefault(); foreach (var viewTrackingUrl in vastIcon.Elements("IconViewTracking")) { icon.ViewTracking.Add((string)viewTrackingUrl); } linearCreative.Icons.Add(icon); } } if (vastLinear.Elements("MediaFiles").Any()) { foreach (var vastMedia in vastLinear.Element("MediaFiles").Elements("MediaFile")) { var mediaFile = new MediaFile(); mediaFile.ApiFramework = (string)vastMedia.Attribute("apiFramework") ?? string.Empty; mediaFile.Bitrate = ToNullableLong((string)vastMedia.Attribute("bitrate")); mediaFile.Codec = (string)vastMedia.Attribute("codec") ?? string.Empty; mediaFile.Delivery = (MediaFileDelivery)Enum.Parse(typeof(MediaFileDelivery), (string)vastMedia.Attribute("delivery"), true); mediaFile.Height = (int?)vastMedia.Attribute("height") ?? 0; mediaFile.Width = (int?)vastMedia.Attribute("width") ?? 0; mediaFile.Id = (string)vastMedia.Attribute("id"); mediaFile.MaintainAspectRatio = (bool?)vastMedia.Attribute("maintainAspectRatio") ?? false; mediaFile.MaxBitrate = (long?)vastMedia.Attribute("maxBitrate") ?? 0; mediaFile.MinBitrate = (long?)vastMedia.Attribute("minBitrate") ?? 0; mediaFile.Scalable = (bool?)vastMedia.Attribute("scalable") ?? false; mediaFile.Type = (string)vastMedia.Attribute("type"); mediaFile.Value = GetUriValue(vastMedia); linearCreative.MediaFiles.Add(mediaFile); } } break; case "CompanionAds": var vastCompanions = vastItem; creative = LoadCompanions(vastCompanions); break; case "NonLinearAds": var vastNonLinears = vastItem; var nonLinearCreative = new CreativeNonLinears(); creative = nonLinearCreative; foreach (var trackingEvent in GetTrackingEvents(vastNonLinears)) { nonLinearCreative.TrackingEvents.Add(trackingEvent); } foreach (var vastNonLinear in vastNonLinears.Elements("NonLinear")) { var nonLinear = new NonLinear(); if (vastNonLinear.Elements("AdParameters").Any()) { var xmlEncoded = (bool?)vastNonLinear.Element("AdParameters").Attribute("xmlEncoded") ?? false; nonLinear.AdParameters = xmlEncoded ? XmlDecode((string)vastNonLinear.Element("AdParameters")) : (string)vastNonLinear.Element("AdParameters"); } ; nonLinear.ApiFramework = (string)vastNonLinear.Attribute("apiFramework"); nonLinear.ClickThrough = GetUriValue(vastNonLinear.Element("NonLinearClickThrough")); foreach (var vastTracking in vastNonLinear.Elements("NonLinearClickTracking")) { nonLinear.ClickTracking.Add((string)vastTracking); } if (vastNonLinear.Elements("CreativeExtensions").Any()) { foreach (var vastExtension in vastNonLinear.Element("CreativeExtensions").Elements("CreativeExtension")) { nonLinear.Extensions.Add(new Extension()); // TODO } } nonLinear.ExpandedHeight = (int?)vastNonLinear.Attribute("expandedHeight"); nonLinear.ExpandedWidth = (int?)vastNonLinear.Attribute("expandedWidth"); nonLinear.Height = (int?)vastNonLinear.Attribute("height") ?? 0; nonLinear.Width = (int?)vastNonLinear.Attribute("width") ?? 0; nonLinear.MaintainAspectRatio = (bool?)vastNonLinear.Attribute("maintainAspectRatio") ?? false; nonLinear.MinSuggestedDuration = ToNullableTimeSpan((string)vastNonLinear.Attribute("minSuggestedDuration")) ?? new TimeSpan?(); nonLinear.Scalable = (bool?)vastNonLinear.Attribute("scalable") ?? false; nonLinear.Item = GetResources(vastNonLinear).FirstOrDefault(); nonLinearCreative.NonLinears.Add(nonLinear); } break; } if (creative != null) { creative.AdId = (string)vastCreative.Attribute("AdID"); creative.Id = (string)vastCreative.Attribute("id"); creative.Sequence = ToNullableInt((string)vastCreative.Attribute("sequence")); ad.Creatives.Add(creative); } } } } }
internal static ICreative FindMatchingCreative(ICreative creative, Ad searchAd) { var type = creative.GetType(); return(searchAd.Creatives.Where(c => c.GetType() == type).FirstOrDefault()); }
ActiveAdUnit CreateAdUnit(IEnumerable <ICreative> creativeSet, Ad ad, IAdSource adSource) { CreativeCompanions companions = null; var activeAdUnits = new List <ActiveAdUnit>(); foreach (var creative in creativeSet) { if (creative is CreativeLinear) { var linear = (CreativeLinear)creative; var eligableMediaFiles = new Queue <MediaFile>(PrioritizeMedia(linear.MediaFiles)); ActiveAdUnit chosenAd = null; while (eligableMediaFiles.Any()) { var media = eligableMediaFiles.Dequeue(); var creativeSource = new LinearSource(linear, media); var vpaid = OnLoadPlayer(creativeSource); if (vpaid != null) { if (VpaidController.Handshake(vpaid)) { chosenAd = new ActiveAdUnit(creativeSource, vpaid, ad, adSource); break; } else { OnUnloadPlayer(vpaid); } } } if (chosenAd == null) { throw new LoadException(new Exception("Unable to find a player to play the linear ad.")); } activeAdUnits.Add(chosenAd); } else if (creative is CreativeNonLinears) { bool found = false; var nonLinears = (CreativeNonLinears)creative; foreach (var nonLinear in (nonLinears).NonLinears) { var creativeSource = new NonLinearSource(nonLinear, nonLinears); var vpaid = OnLoadPlayer(creativeSource); if (vpaid != null) { if (VpaidController.Handshake(vpaid)) { activeAdUnits.Add(new ActiveAdUnit(creativeSource, vpaid, ad, adSource)); found = true; break; } else { OnUnloadPlayer(vpaid); } } } if (!found) { throw new LoadException(new Exception("Unable to find a player to play any nonlinear ads.")); } } else if (creative is CreativeCompanions) { companions = (CreativeCompanions)creative; } else /* not supported, ignore */ } { } return(activeAdUnits.FirstOrDefault()); // there should only be one linear or nonlinear ad in the sequenced group. Others are ignored. }
private static void LoadCreatives(XElement adElement, Ad ad) { var vastCreatives = adElement.Element("Creatives"); if (vastCreatives != null) { foreach (var vastCreative in vastCreatives.Elements("Creative")) { var vastItem = vastCreative.Elements().FirstOrDefault(); if (vastItem != null) { ICreative creative = null; switch (vastItem.Name.LocalName) { case "Linear": var vastLinear = vastItem; var linearCreative = new CreativeLinear(); creative = linearCreative; foreach (var trackingEvent in GetTrackingEvents(vastLinear)) linearCreative.TrackingEvents.Add(trackingEvent); if (vastLinear.Elements("AdParameters").Any()) { var xmlEncoded = (bool?)vastLinear.Element("AdParameters").Attribute("xmlEncoded") ?? false; linearCreative.AdParameters = xmlEncoded ? XmlDecode((string)vastLinear.Element("AdParameters")) : (string)vastLinear.Element("AdParameters"); } LoadVideoClicks(vastLinear, linearCreative); if (vastLinear.Elements("CreativeExtensions").Any()) { foreach (var vastExtension in vastLinear.Element("CreativeExtensions").Elements("CreativeExtension")) { linearCreative.Extensions.Add(new Extension()); // TODO } } linearCreative.Duration = ToNullableTimeSpan((string)vastLinear.Element("Duration")); linearCreative.SkipOffset = FlexibleOffset.Parse((string)vastLinear.Attribute("skipoffset")); var vastIcons = vastLinear.Element("Icons"); if (vastIcons != null) { foreach (var vastIcon in vastIcons.Elements("Icon")) { var icon = new Icon(); if (vastIcon.Elements("IconClicks").Any()) { var iconClicks = vastIcon.Element("IconClicks"); icon.ClickThrough = GetUriValue(iconClicks.Element("IconClickThrough")); foreach (var clickTracking in iconClicks.Elements("IconClickTracking")) { icon.ClickTracking.Add((string)clickTracking); } } icon.ApiFramework = (string)vastIcon.Attribute("apiFramework") ?? string.Empty; icon.Duration = ToNullableTimeSpan((string)vastIcon.Attribute("duration")) ?? new TimeSpan?(); icon.Height = (int?)vastIcon.Attribute("height"); icon.Width = (int?)vastIcon.Attribute("width"); icon.Offset = ToNullableTimeSpan((string)vastIcon.Attribute("offset")) ?? new TimeSpan?(); icon.Program = (string)vastIcon.Attribute("program") ?? string.Empty; icon.XPosition = (string)vastIcon.Attribute("xPosition") ?? string.Empty; icon.YPosition = (string)vastIcon.Attribute("yPosition") ?? string.Empty; icon.Item = GetResources(vastIcon).FirstOrDefault(); foreach (var viewTrackingUrl in vastIcon.Elements("IconViewTracking")) { icon.ViewTracking.Add((string)viewTrackingUrl); } linearCreative.Icons.Add(icon); } } if (vastLinear.Elements("MediaFiles").Any()) { foreach (var vastMedia in vastLinear.Element("MediaFiles").Elements("MediaFile")) { var mediaFile = new MediaFile(); mediaFile.ApiFramework = (string)vastMedia.Attribute("apiFramework") ?? string.Empty; mediaFile.Bitrate = ToNullableLong((string)vastMedia.Attribute("bitrate")); mediaFile.Codec = (string)vastMedia.Attribute("codec") ?? string.Empty; mediaFile.Delivery = (MediaFileDelivery)Enum.Parse(typeof(MediaFileDelivery), (string)vastMedia.Attribute("delivery"), true); mediaFile.Height = (int?)vastMedia.Attribute("height") ?? 0; mediaFile.Width = (int?)vastMedia.Attribute("width") ?? 0; mediaFile.Id = (string)vastMedia.Attribute("id"); mediaFile.MaintainAspectRatio = (bool?)vastMedia.Attribute("maintainAspectRatio") ?? false; mediaFile.MaxBitrate = (long?)vastMedia.Attribute("maxBitrate") ?? 0; mediaFile.MinBitrate = (long?)vastMedia.Attribute("minBitrate") ?? 0; mediaFile.Scalable = (bool?)vastMedia.Attribute("scalable") ?? false; mediaFile.Type = (string)vastMedia.Attribute("type"); mediaFile.Value = GetUriValue(vastMedia); linearCreative.MediaFiles.Add(mediaFile); } } break; case "CompanionAds": var vastCompanions = vastItem; creative = LoadCompanions(vastCompanions); break; case "NonLinearAds": var vastNonLinears = vastItem; var nonLinearCreative = new CreativeNonLinears(); creative = nonLinearCreative; foreach (var trackingEvent in GetTrackingEvents(vastNonLinears)) nonLinearCreative.TrackingEvents.Add(trackingEvent); foreach (var vastNonLinear in vastNonLinears.Elements("NonLinear")) { var nonLinear = new NonLinear(); if (vastNonLinear.Elements("AdParameters").Any()) { var xmlEncoded = (bool?)vastNonLinear.Element("AdParameters").Attribute("xmlEncoded") ?? false; nonLinear.AdParameters = xmlEncoded ? XmlDecode((string)vastNonLinear.Element("AdParameters")) : (string)vastNonLinear.Element("AdParameters"); }; nonLinear.ApiFramework = (string)vastNonLinear.Attribute("apiFramework"); nonLinear.ClickThrough = GetUriValue(vastNonLinear.Element("NonLinearClickThrough")); foreach (var vastTracking in vastNonLinear.Elements("NonLinearClickTracking")) { nonLinear.ClickTracking.Add((string)vastTracking); } if (vastNonLinear.Elements("CreativeExtensions").Any()) { foreach (var vastExtension in vastNonLinear.Element("CreativeExtensions").Elements("CreativeExtension")) { nonLinear.Extensions.Add(new Extension()); // TODO } } nonLinear.ExpandedHeight = (int?)vastNonLinear.Attribute("expandedHeight"); nonLinear.ExpandedWidth = (int?)vastNonLinear.Attribute("expandedWidth"); nonLinear.Height = (int?)vastNonLinear.Attribute("height") ?? 0; nonLinear.Width = (int?)vastNonLinear.Attribute("width") ?? 0; nonLinear.MaintainAspectRatio = (bool?)vastNonLinear.Attribute("maintainAspectRatio") ?? false; nonLinear.MinSuggestedDuration = ToNullableTimeSpan((string)vastNonLinear.Attribute("minSuggestedDuration")) ?? new TimeSpan?(); nonLinear.Scalable = (bool?)vastNonLinear.Attribute("scalable") ?? false; nonLinear.Item = GetResources(vastNonLinear).FirstOrDefault(); nonLinearCreative.NonLinears.Add(nonLinear); } break; } if (creative != null) { creative.AdId = (string)vastCreative.Attribute("AdID"); creative.Id = (string)vastCreative.Attribute("id"); creative.Sequence = ToNullableInt((string)vastCreative.Attribute("sequence")); ad.Creatives.Add(creative); } } } } }
internal static async Task<AdDocumentPayload> CreateFromVast1(XElement vastRoot, int? maxRedirectDepth, bool allowMultipleAds) { var result = new AdDocumentPayload(); result.Version = (string)vastRoot.Attribute("version"); foreach (var vastAdPod in vastRoot.Elements("Ad").GroupBy(va => va.Attribute("sequence") != null ? 1 : int.MaxValue).OrderBy(vap => vap.Key)) { var adPod = new AdPod(); foreach (var vastAd in vastAdPod.OrderBy(va => ToNullableInt((string)va.Attribute("sequence")).GetValueOrDefault(0))) { var ad = new Ad(); ad.Id = (string)vastAd.Attribute("id"); if (vastAd.Elements("InLine").Any()) { throw new NotImplementedException(); } else if (vastAd.Elements("Wrapper").Any()) { Ad wrapper = new Ad(); var vastAdWrapper = vastAd.Element("Wrapper"); // parse the wrapper itself wrapper.AdSystem = GetAdSystem(vastAdWrapper.Element("AdSystem")); var error = (string)vastAdWrapper.Element("Error"); if (error == null) wrapper.Errors.Add(error); var linearCreative = new CreativeLinear(); foreach (var trackingEvent in GetTrackingEvents(vastAdWrapper)) linearCreative.TrackingEvents.Add(trackingEvent); LoadVideoClicks(vastAdWrapper, linearCreative); wrapper.Creatives.Add(linearCreative); var vastAdUri = GetUriValue(vastAdWrapper.Element("VASTAdTagURL")); if (vastAdUri != null) { // load the stream from the web using (var s = await Extensions.LoadStreamAsync(vastAdUri)) { int? nextMaxRedirectDepth = maxRedirectDepth.HasValue ? maxRedirectDepth.Value - 1 : maxRedirectDepth; var vastDoc = await CreateFromVast(s, nextMaxRedirectDepth, allowMultipleAds); var firstAdPodInChild = vastDoc.AdPods.FirstOrDefault(); if (firstAdPodInChild != null) { // merge tracking info from this wrapper to every ad in the first adpod in the child foreach (Ad inlineAd in firstAdPodInChild.Ads) MergeWrappedAd(wrapper, inlineAd); // add each ad from the first adpod in the child to the current adpod foreach (Ad inlineAd in firstAdPodInChild.Ads) adPod.Ads.Add(inlineAd); } } } } } result.AdPods.Add(adPod); } return result; }
static async Task<Ad> CreateLinearAd(FWAd source, FWAdReference reference) { var ad = new Ad(); var allCallbacks = reference.EventCallbacks; foreach (var url in allCallbacks.Where(ec => ec.Type == FWCallbackType.Impression && ec.Name == FWEventCallback.DefaultImpression).SelectMany(ec => ec.GetUrls())) { ad.Impressions.Add(url); } int index = 0; IEnumerable<FWCreative> creatives = source.Creatives; if (reference.CreativeId != null) { creatives = creatives.Where(c => c.Id == reference.CreativeId); } foreach (var creative in creatives) { index++; var wrappedAds = new List<Ad>(); var linear = new CreativeLinear(); linear.AdParameters = string.Join("&", creative.Parameters.Select(p => Uri.EscapeDataString(p.Name) + "=" + Uri.EscapeDataString(p.Value))); linear.Duration = creative.Duration; linear.Sequence = index; IEnumerable<FWCreativeRendition> creativeRenditions = creative.CreativeRenditions; if (reference.CreativeRenditionId != null) { creativeRenditions = creativeRenditions.Where(cr => cr.Id == reference.CreativeRenditionId).DefaultIfEmpty(creativeRenditions); if (reference.ReplicaId != null) { creativeRenditions = creativeRenditions.Where(cr => cr.AdReplicaId == reference.ReplicaId).DefaultIfEmpty(creativeRenditions); } } foreach (var rendition in creativeRenditions) { if (!string.IsNullOrEmpty(rendition.WrapperType)) { switch (rendition.WrapperType.ToLowerInvariant()) { case "external/vast-2": try { var vastAdUri = new Uri(rendition.WrapperUrl); // load the stream from the web using (var s = await Extensions.LoadStreamAsync(vastAdUri)) { var wrappedVastDoc = await AdModelFactory.CreateFromVast(s, null, true); if (wrappedVastDoc != null) { // use the first ad var wrappedAd = wrappedVastDoc.AdPods.SelectMany(pod => pod.Ads).FirstOrDefault(); if (wrappedAd != null) { wrappedAds.Add(wrappedAd); } } } } catch { /* swallow */ } break; } } else { // TODO: FreeWheel assets can contain Content instead of Url. This could be supported someday; for now it is ignored. if (rendition.Asset != null) { var mediaFile = CreateMediaFile(creative, rendition, rendition.Asset); if (mediaFile != null) { mediaFile.Ranking = (int)rendition.Preference + 1; // add one to indicate this is preferred over "OtherAssets" linear.MediaFiles.Add(mediaFile); } } foreach (var asset in rendition.OtherAssets) { var mediaFile = CreateMediaFile(creative, rendition, asset); if (mediaFile != null) { mediaFile.Ranking = (int)rendition.Preference; linear.MediaFiles.Add(mediaFile); } } } } // generate callback urls from one base url foreach (var eventCallback in allCallbacks.Where(ec => ec.Type == FWCallbackType.Impression)) { foreach (var url in eventCallback.GetUrls()) { switch (eventCallback.Name.ToLower()) { case "start": linear.TrackingEvents.Add(new TrackingEvent() { Type = TrackingType.Start, Value = url }); break; case "firstquartile": linear.TrackingEvents.Add(new TrackingEvent() { Type = TrackingType.FirstQuartile, Value = url }); break; case "midpoint": linear.TrackingEvents.Add(new TrackingEvent() { Type = TrackingType.Midpoint, Value = url }); break; case "thirdquartile": linear.TrackingEvents.Add(new TrackingEvent() { Type = TrackingType.ThirdQuartile, Value = url }); break; case "complete": linear.TrackingEvents.Add(new TrackingEvent() { Type = TrackingType.Complete, Value = url }); break; } } } // generate callback urls from one base url foreach (var eventCallback in allCallbacks.Where(ec => ec.Type == FWCallbackType.Standard)) { foreach (var url in eventCallback.GetUrls()) { switch (eventCallback.Name.Replace("-", "").ToLower()) { case "_creativeview": linear.TrackingEvents.Add(new TrackingEvent() { Type = TrackingType.CreativeView, Value = url }); break; case "_mute": linear.TrackingEvents.Add(new TrackingEvent() { Type = TrackingType.Mute, Value = url }); break; case "_unmute": linear.TrackingEvents.Add(new TrackingEvent() { Type = TrackingType.Unmute, Value = url }); break; case "_pause": linear.TrackingEvents.Add(new TrackingEvent() { Type = TrackingType.Pause, Value = url }); break; case "_rewind": linear.TrackingEvents.Add(new TrackingEvent() { Type = TrackingType.Rewind, Value = url }); break; case "_resume": linear.TrackingEvents.Add(new TrackingEvent() { Type = TrackingType.Resume, Value = url }); break; case "_fullscreen": linear.TrackingEvents.Add(new TrackingEvent() { Type = TrackingType.Fullscreen, Value = url }); break; case "_exitfullscreen": linear.TrackingEvents.Add(new TrackingEvent() { Type = TrackingType.ExitFullscreen, Value = url }); break; case "_expand": linear.TrackingEvents.Add(new TrackingEvent() { Type = TrackingType.Expand, Value = url }); break; case "_collapse": linear.TrackingEvents.Add(new TrackingEvent() { Type = TrackingType.Collapse, Value = url }); break; case "_acceptinvitation": linear.TrackingEvents.Add(new TrackingEvent() { Type = TrackingType.AcceptInvitation, Value = url }); break; case "_close": linear.TrackingEvents.Add(new TrackingEvent() { Type = TrackingType.Close, Value = url }); break; case "_skip": linear.TrackingEvents.Add(new TrackingEvent() { Type = TrackingType.Skip, Value = url }); break; case "_progress": linear.TrackingEvents.Add(new TrackingEvent() { Type = TrackingType.Progress, Value = url }); break; } } } foreach (var url in allCallbacks.Where(ec => ec.Type == FWCallbackType.Click && !ec.ShowBrowser).SelectMany(ec => ec.GetUrls())) { linear.ClickTracking.Add(url); } var clickUrl = allCallbacks.Where(ec => ec.Type == FWCallbackType.Click && ec.ShowBrowser).SelectMany(ec => ec.GetUrls()).FirstOrDefault(); if (clickUrl != null) { linear.ClickThrough = new Uri(clickUrl); } // generate callback urls from one base url ONLY when the callback does not already exist foreach (var eventCallback in allCallbacks.Where(ec => ec.Type == FWCallbackType.Generic)) { foreach (var url in eventCallback.GetUrls()) { var baseUrl = url + string.Format("&metr={0}", FreeWheelFactory.GetSupportedMetrics()); // quartile events var quartileUrl = baseUrl + "&ct=[LASTQUARTILE]&et=i"; // [LASTQUARTILE] will get replaced by the VPAID controller AddSecondaryCallback(linear.TrackingEvents, new TrackingEvent() { Type = TrackingType.FirstQuartile, Value = quartileUrl + "&cn=firstQuartile" }); AddSecondaryCallback(linear.TrackingEvents, new TrackingEvent() { Type = TrackingType.Midpoint, Value = quartileUrl + "&cn=midPoint" }); AddSecondaryCallback(linear.TrackingEvents, new TrackingEvent() { Type = TrackingType.ThirdQuartile, Value = quartileUrl + "&cn=thirdQuartile" }); AddSecondaryCallback(linear.TrackingEvents, new TrackingEvent() { Type = TrackingType.Complete, Value = quartileUrl + "&cn=complete" }); // advanced metrics var advancedUrl = baseUrl + "&et=s"; AddSecondaryCallback(linear.TrackingEvents, new TrackingEvent() { Type = TrackingType.Mute, Value = advancedUrl + "&cn=_mute" }); AddSecondaryCallback(linear.TrackingEvents, new TrackingEvent() { Type = TrackingType.Unmute, Value = advancedUrl + "&cn=_un-mute" }); AddSecondaryCallback(linear.TrackingEvents, new TrackingEvent() { Type = TrackingType.Collapse, Value = advancedUrl + "&cn=_collapse" }); AddSecondaryCallback(linear.TrackingEvents, new TrackingEvent() { Type = TrackingType.Expand, Value = advancedUrl + "&cn=_expand" }); AddSecondaryCallback(linear.TrackingEvents, new TrackingEvent() { Type = TrackingType.Pause, Value = advancedUrl + "&cn=_pause" }); AddSecondaryCallback(linear.TrackingEvents, new TrackingEvent() { Type = TrackingType.Resume, Value = advancedUrl + "&cn=_resume" }); AddSecondaryCallback(linear.TrackingEvents, new TrackingEvent() { Type = TrackingType.Rewind, Value = advancedUrl + "&cn=_rewind" }); AddSecondaryCallback(linear.TrackingEvents, new TrackingEvent() { Type = TrackingType.AcceptInvitation, Value = advancedUrl + "&cn=_accept-invitation" }); AddSecondaryCallback(linear.TrackingEvents, new TrackingEvent() { Type = TrackingType.Close, Value = advancedUrl + "&cn=_close" }); //AddSecondaryCallback(linear.TrackingEvents, new TrackingEvent() { Type = TrackingType.Minimize, Value = advancedUrl + "&cn=_minimize" }); } } ad.Creatives.Add(linear); foreach (var wrappedAd in wrappedAds) { AdModelFactory.MergeWrappedAdBeacons(wrappedAd, ad); var wrappedCreative = AdModelFactory.FindMatchingCreative(linear, wrappedAd); AdModelFactory.MergeWrappedCreative(wrappedCreative, linear); } } return ad; }
ActiveAdUnit CreateAdUnit(IEnumerable<ICreative> creativeSet, Ad ad, IAdSource adSource) { CreativeCompanions companions = null; var activeAdUnits = new List<ActiveAdUnit>(); foreach (var creative in creativeSet) { if (creative is CreativeLinear) { var linear = (CreativeLinear)creative; var eligableMediaFiles = new Queue<MediaFile>(PrioritizeMedia(linear.MediaFiles)); ActiveAdUnit chosenAd = null; while (eligableMediaFiles.Any()) { var media = eligableMediaFiles.Dequeue(); var creativeSource = new LinearSource(linear, media); var vpaid = OnLoadPlayer(creativeSource); if (vpaid != null) { if (VpaidController.Handshake(vpaid)) { chosenAd = new ActiveAdUnit(creativeSource, vpaid, ad, adSource); break; } else { OnUnloadPlayer(vpaid); } } } if (chosenAd == null) throw new LoadException(new Exception("Unable to find a player to play the linear ad.")); activeAdUnits.Add(chosenAd); } else if (creative is CreativeNonLinears) { bool found = false; var nonLinears = (CreativeNonLinears)creative; foreach (var nonLinear in (nonLinears).NonLinears) { var creativeSource = new NonLinearSource(nonLinear, nonLinears); var vpaid = OnLoadPlayer(creativeSource); if (vpaid != null) { if (VpaidController.Handshake(vpaid)) { activeAdUnits.Add(new ActiveAdUnit(creativeSource, vpaid, ad, adSource)); found = true; break; } else { OnUnloadPlayer(vpaid); } } } if (!found) { throw new LoadException(new Exception("Unable to find a player to play any nonlinear ads.")); } } else if (creative is CreativeCompanions) { companions = (CreativeCompanions)creative; } else { /* not supported, ignore */ } } return activeAdUnits.FirstOrDefault(); // there should only be one linear or nonlinear ad in the sequenced group. Others are ignored. }
async Task StartAdUnitAsync(ActiveAdUnit adUnit, Ad ad, CancellationToken cancellationToken) { // start the ad await VpaidController.StartAdAsync(adUnit, cancellationToken); // fire the impression beacon foreach (var url in ad.Impressions) { VpaidController.TrackUrl(url, adUnit.CreativeSource); } }
async Task<ActiveAdUnit> LoadAdUnitAsync(ICollection<ICreative> creativeSet, Ad ad, IAdSource adSource, CancellationToken cancellationToken) { bool preloaded = false; ActiveAdUnit result = null; // check to see if there are any pre-loading ads. if (loadOperation != null) { try { if (loadOperation.AdSource == adSource) { cancellationToken.Register(() => { if (loadOperation != null) { // no need to wait var dummyTask = loadOperation.CancelAsync(); } }); result = await loadOperation.Task; preloaded = true; } else { await loadOperation.CancelAsync(); } } catch { /* ignore, we'll try again regardless of reason, it was just a preload optimization anyway */ } finally { loadOperation = null; } cancellationToken.ThrowIfCancellationRequested(); } if (result == null) { result = CreateAdUnit(creativeSet, ad, adSource); } if (result == null) throw new LoadException(new Exception("No ad unit could be created")); if (!preloaded) { // Start initializing the ad. It is OK if there are other ads playing still. loadOperation = LoadAdUnit(result, cancellationToken); try { await loadOperation.Task; } catch (OperationCanceledException) { throw; } catch (Exception ex) { throw new LoadException(ex); } finally { loadOperation = null; } cancellationToken.ThrowIfCancellationRequested(); } return result; }
internal static async Task <AdDocumentPayload> CreateFromVast1(XElement vastRoot, int?maxRedirectDepth, bool allowMultipleAds) { var result = new AdDocumentPayload(); result.Version = (string)vastRoot.Attribute("version"); foreach (var vastAdPod in vastRoot.Elements("Ad").GroupBy(va => va.Attribute("sequence") != null ? 1 : int.MaxValue).OrderBy(vap => vap.Key)) { var adPod = new AdPod(); foreach (var vastAd in vastAdPod.OrderBy(va => ToNullableInt((string)va.Attribute("sequence")).GetValueOrDefault(0))) { var ad = new Ad(); ad.Id = (string)vastAd.Attribute("id"); if (vastAd.Elements("InLine").Any()) { throw new NotImplementedException(); } else if (vastAd.Elements("Wrapper").Any()) { Ad wrapper = new Ad(); var vastAdWrapper = vastAd.Element("Wrapper"); // parse the wrapper itself wrapper.AdSystem = GetAdSystem(vastAdWrapper.Element("AdSystem")); var error = (string)vastAdWrapper.Element("Error"); if (error == null) { wrapper.Errors.Add(error); } var linearCreative = new CreativeLinear(); foreach (var trackingEvent in GetTrackingEvents(vastAdWrapper)) { linearCreative.TrackingEvents.Add(trackingEvent); } LoadVideoClicks(vastAdWrapper, linearCreative); wrapper.Creatives.Add(linearCreative); var vastAdUri = GetUriValue(vastAdWrapper.Element("VASTAdTagURL")); if (vastAdUri != null) { // load the stream from the web using (var s = await Extensions.LoadStreamAsync(vastAdUri)) { int?nextMaxRedirectDepth = maxRedirectDepth.HasValue ? maxRedirectDepth.Value - 1 : maxRedirectDepth; var vastDoc = await CreateFromVast(s, nextMaxRedirectDepth, allowMultipleAds); var firstAdPodInChild = vastDoc.AdPods.FirstOrDefault(); if (firstAdPodInChild != null) { // merge tracking info from this wrapper to every ad in the first adpod in the child foreach (Ad inlineAd in firstAdPodInChild.Ads) { MergeWrappedAd(wrapper, inlineAd); } // add each ad from the first adpod in the child to the current adpod foreach (Ad inlineAd in firstAdPodInChild.Ads) { adPod.Ads.Add(inlineAd); } } } } } } result.AdPods.Add(adPod); } return(result); }
private static ICreative FindMatchingCreative(Ad ad, ICreative creative, Ad wrapperAd) { Type type = creative.GetType(); var appropriateCreatives = ad.Creatives.Where(c => c.GetType() == type).ToList(); var appropriateWrapperCreatives = wrapperAd.Creatives.Where(c => c.GetType() == type).ToList(); int index = appropriateCreatives.IndexOf(creative); if (appropriateWrapperCreatives.Count > index) return appropriateWrapperCreatives.ElementAt(index); else return null; }
internal static ICreative FindMatchingCreative(ICreative creative, Ad searchAd) { var type = creative.GetType(); return searchAd.Creatives.Where(c => c.GetType() == type).FirstOrDefault(); }
internal static async Task <AdDocumentPayload> CreateFromVast(Stream stream, int?maxRedirectDepth, bool allowMultipleAds) #endif { XDocument xDoc = XDocument.Load(stream); XElement vastRoot = xDoc.Element("VAST"); if (vastRoot == null) { vastRoot = xDoc.Element("VideoAdServingTemplate"); if (vastRoot == null) { throw new NotImplementedException(); } return(await CreateFromVast1(vastRoot, maxRedirectDepth, allowMultipleAds)); } else { var result = new AdDocumentPayload(); result.Version = (string)vastRoot.Attribute("version"); result.Error = (string)vastRoot.Element("Error"); var eligableAds = vastRoot.Elements("Ad"); if (!allowMultipleAds) { eligableAds = eligableAds.Where(va => string.IsNullOrEmpty((string)va.Attribute("sequence"))); } foreach (var vastAdPod in eligableAds.GroupBy(va => va.Attribute("sequence") != null ? 1 : int.MaxValue).OrderBy(vap => vap.Key)) { var adPod = new AdPod(); foreach (var vastAd in vastAdPod.OrderBy(va => ToNullableInt((string)va.Attribute("sequence")).GetValueOrDefault(0))) { var ad = new Ad(); ad.Id = (string)vastAd.Attribute("id"); if (vastAd.Elements("InLine").Any()) { var vastAdInline = vastAd.Element("InLine"); ad.AdSystem = GetAdSystem(vastAdInline.Element("AdSystem")); ad.Advertiser = (string)vastAdInline.Element("Advertiser"); ad.Description = (string)vastAdInline.Element("Description"); var error = (string)vastAdInline.Element("Error"); if (error != null) { ad.Errors.Add(error); } ad.Title = (string)vastAdInline.Element("AdTitle"); ad.Survey = GetUriValue(vastAdInline.Element("Survey")); ad.Pricing = new Pricing(); var pricing = vastAdInline.Element("Pricing"); if (pricing != null) { ad.Pricing.Currency = (string)pricing.Attribute("currency"); ad.Pricing.Model = (PricingModel)Enum.Parse(typeof(PricingModel), (string)pricing.Attribute("model"), true); ad.Pricing.Value = Convert.ToDouble((string)pricing); } foreach (var vastImpression in vastAdInline.Elements("Impression")) { ad.Impressions.Add((string)vastImpression); } if (vastAdInline.Elements("Extensions").Any()) { foreach (var vastExtension in vastAdInline.Element("Extensions").Elements("Extension")) { ad.Extensions.Add(new Extension()); // TODO } } LoadCreatives(vastAdInline, ad); adPod.Ads.Add(ad); } else if (vastAd.Elements("Wrapper").Any()) { Ad wrapper = new Ad(); var vastAdWrapper = vastAd.Element("Wrapper"); // parse the wrapper itself wrapper.AdSystem = GetAdSystem(vastAdWrapper.Element("AdSystem")); var error = (string)vastAdWrapper.Element("Error"); if (error != null) { wrapper.Errors.Add(error); } foreach (var vastImpression in vastAdWrapper.Elements("Impression")) { wrapper.Impressions.Add((string)vastImpression); } LoadCreatives(vastAdWrapper, wrapper); if (vastAdWrapper.Elements("Extensions").Any()) { foreach (var vastExtension in vastAdWrapper.Element("Extensions").Elements("Extension")) { ad.Extensions.Add(new Extension()); // TODO } } AdDocumentPayload wrappedVastDoc = null; var vastAdUri = GetUriValue(vastAdWrapper.Element("VASTAdTagURI")); if (vastAdUri != null && (!maxRedirectDepth.HasValue || maxRedirectDepth.Value > 0)) { try { // load the stream from the web using (var s = await Extensions.LoadStreamAsync(vastAdUri)) { var newAllowMultipleAds = vastAdWrapper.GetBoolAttribute("allowMultipleAds", allowMultipleAds); var followAdditionalWrappers = vastAdWrapper.GetBoolAttribute("followAdditionalWrappers", true); int?nextMaxRedirectDepth = followAdditionalWrappers ? (maxRedirectDepth.HasValue ? maxRedirectDepth.Value - 1 : maxRedirectDepth) : 0; wrappedVastDoc = await CreateFromVast(s, nextMaxRedirectDepth, newAllowMultipleAds); } } catch { /* swallow */ } } AdPod wrappedAdPod = null; if (wrappedVastDoc != null) { wrappedAdPod = wrappedVastDoc.AdPods.FirstOrDefault(); } if (wrappedAdPod == null || !wrappedAdPod.Ads.Any()) { // no ads were returned var fallbackOnNoAd = vastAdWrapper.GetBoolAttribute("fallbackOnNoAd", true); if (fallbackOnNoAd) { wrappedAdPod = FallbackAdPod; } } if (wrappedAdPod != null) { // merge tracking info from this wrapper to every ad in the first adpod in the child foreach (Ad inlineAd in wrappedAdPod.Ads) { MergeWrappedAd(wrapper, inlineAd); } // add each ad from the first adpod in the child to the current adpod foreach (Ad inlineAd in wrappedAdPod.Ads) { adPod.Ads.Add(inlineAd); } } } } result.AdPods.Add(adPod); } return(result); } }
private static AdDocumentPayload CreateDocument(IClipAdPayload mediaSource) { var adDocument = new AdDocumentPayload(); var adPod = new AdPod(); var ad = new Ad(); var linearCreative = new CreativeLinear(); linearCreative.ClickThrough = mediaSource.ClickThrough; linearCreative.MediaFiles.Add(new MediaFile() { Type = mediaSource.MimeType, Value = mediaSource.MediaSource }); ad.Creatives.Add(linearCreative); adPod.Ads.Add(ad); adDocument.AdPods.Add(adPod); return adDocument; }
async Task <ActiveAdUnit> LoadAdUnitAsync(ICollection <ICreative> creativeSet, Ad ad, IAdSource adSource, CancellationToken cancellationToken) { bool preloaded = false; ActiveAdUnit result = null; // check to see if there are any pre-loading ads. if (loadOperation != null) { try { if (loadOperation.AdSource == adSource) { cancellationToken.Register(() => { if (loadOperation != null) { // no need to wait var dummyTask = loadOperation.CancelAsync(); } }); result = await loadOperation.Task; preloaded = true; } else { await loadOperation.CancelAsync(); } } catch { /* ignore, we'll try again regardless of reason, it was just a preload optimization anyway */ } finally { loadOperation = null; } cancellationToken.ThrowIfCancellationRequested(); } if (result == null) { result = CreateAdUnit(creativeSet, ad, adSource); } if (result == null) { throw new LoadException(new Exception("No ad unit could be created")); } if (!preloaded) { // Start initializing the ad. It is OK if there are other ads playing still. loadOperation = LoadAdUnit(result, cancellationToken); try { await loadOperation.Task; } catch (OperationCanceledException) { throw; } catch (Exception ex) { throw new LoadException(ex); } finally { loadOperation = null; } cancellationToken.ThrowIfCancellationRequested(); } return(result); }