public static CreativeCompanions CreateCompanionAds(FWAd source, FWAdReference reference) { var result = new CreativeCompanions(); foreach (var creative in source.Creatives) { var companion = new Companion(); result.Companions.Add(companion); companion.AdSlotId = reference.SlotId ?? string.Empty; var rendition = creative.CreativeRenditions.OrderByDescending(cr => cr.Preference).FirstOrDefault(c => c.Asset.MimeType.ToLowerInvariant().StartsWith("image/")); if (rendition != null) { var asset = rendition.Asset; if (asset != null) { companion.Item = new StaticResource() { Value = new Uri(asset.Url), CreativeType = asset.MimeType }; companion.Width = rendition.Width; companion.Height = rendition.Height; companion.Id = asset.Id ?? string.Empty; } } var allCallbacks = reference.EventCallbacks; foreach (var url in allCallbacks.Where(ec => ec.Type == FWCallbackType.Click && !ec.ShowBrowser).SelectMany(ec => ec.GetUrls())) { companion.ClickTracking.Add(url); } var clickUrl = allCallbacks.Where(ec => ec.Type == FWCallbackType.Click && ec.ShowBrowser).SelectMany(ec => ec.GetUrls()).FirstOrDefault(); if (clickUrl != null) { companion.ClickThrough = new Uri(clickUrl); } } 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; }
internal static FWAd LoadAd(XElement element) { var result = new FWAd(); result.Id = (string)element.Attribute("adId"); result.AdUnit = (string)element.Attribute("adUnit"); result.BundleId = element.GetIntAttribute("bundleId"); result.NoLoad = element.GetBoolAttribute("noLoad", false); result.NoPreload = element.GetBoolAttribute("noPreload", false); var creativesXml = element.Element("creatives"); if (creativesXml != null) { foreach (var creativeXml in creativesXml.Elements("creative")) { result.Creatives.Add(LoadCreative(creativeXml)); } } return result; }