Example #1
0
        public async Task <MediaBundle <Artist> > GetArtistAsync(Guid userId, string artist, Guid?collectionId, CancellationToken cancellationToken)
        {
            var query = _client.CreateDocumentQuery <Artist>(UriFactory.CreateDocumentCollectionUri(DatabaseConstants.DatabaseId, DatabaseConstants.Artist), _defaultFeedOptions)
                        .AsQueryable()
                        .Where(ar => ar.Name == artist);

            if (collectionId.HasValue)
            {
                query = query.Where(s => s.CollectionId == collectionId.Value);
            }

            var artistModel = query.FirstOrDefault();

            if (artistModel == null)
            {
                return(null);
            }

            var mediaBundle = new MediaBundle <Artist>()
            {
                Media        = artistModel,
                Dispositions = new List <Disposition> {
                    await GetDispositionAsync(userId, artistModel.Id, cancellationToken)
                }
            };

            return(mediaBundle);
        }
Example #2
0
        public async Task <MediaBundle <Track> > GetTrackAsync(Guid userId, string path, Guid?collectionId, bool populate, CancellationToken cancellationToken)
        {
            var query = _client.CreateDocumentQuery <Track>(UriFactory.CreateDocumentCollectionUri(DatabaseConstants.DatabaseId, DatabaseConstants.User), _defaultFeedOptions)
                        .Where(s => s.Path == path);

            var results = await query.AsDocumentQuery().ExecuteNextAsync <Track>(cancellationToken);

            var track = results.FirstOrDefault();

            if (track == null)
            {
                return(null);
            }

            var mediaBundle = new MediaBundle <Track>()
            {
                Media        = track,
                Dispositions = new List <Disposition> {
                    await GetDispositionAsync(userId, track.Id, cancellationToken)
                }
            };

            if (populate)
            {
                await PopulateTrackAsync(userId, mediaBundle, cancellationToken).ConfigureAwait(false);
            }

            return(mediaBundle);
        }
        public static ArtistWithAlbumsID3 ToSubsonicArtistWithAlbumsId3(this MediaBundle <Data.Models.Artist> artistMediaBundle, IEnumerable <MediaBundle <Album> > albumMediaBundles)
        {
            var subsonicArtist = new ArtistWithAlbumsID3();

            var artist = artistMediaBundle.Media;

            subsonicArtist.Name           = artist.Name;
            subsonicArtist.Id             = artist.Id.ToString("n");
            subsonicArtist.CoverArt       = $"ar-{subsonicArtist.Id}";
            subsonicArtist.ArtistImageUrl = artist.ImageUrl;

            var disposition = artistMediaBundle.Dispositions.FirstOrDefault();

            if (disposition?.Favorited.HasValue == true)
            {
                subsonicArtist.Starred = disposition.Favorited.Value;
            }

            var subsonicArtistAlbums = albumMediaBundles.Select(ToSubsonicAlbumId3).AsParallel().ToList();

            subsonicArtist.Albums     = subsonicArtistAlbums;
            subsonicArtist.AlbumCount = subsonicArtistAlbums.Count;

            return(subsonicArtist);
        }
Example #4
0
        public async Task <IEnumerable <MediaBundle <Album> > > GetAlbumsByArtistAsync(Guid userId, Guid artistId, bool populate, CancellationToken cancellationToken)
        {
            var query = _client.CreateDocumentQuery <Album>(UriFactory.CreateDocumentCollectionUri(DatabaseConstants.DatabaseId, DatabaseConstants.Album), _defaultFeedOptions)
                        .Where(al => al.Artists.Select(ar => ar.Media.Id).Contains(artistId) || al.Tracks.Select(t => t.Media).SelectMany(tr => tr.Artists).Select(tar => tar.Media.Id).Contains(artistId));

            var documentQuery = query.AsDocumentQuery();

            var mediaBundles = new List <MediaBundle <Album> >();

            while (documentQuery.HasMoreResults)
            {
                foreach (var album in await documentQuery.ExecuteNextAsync <Album>(cancellationToken).ConfigureAwait(false))
                {
                    var mediaBundle = new MediaBundle <Album>()
                    {
                        Media        = album,
                        Dispositions = new List <Disposition> {
                            await GetDispositionAsync(userId, album.Id, cancellationToken)
                        }
                    };

                    if (populate)
                    {
                        await PopulateAlbumAsync(userId, mediaBundle, cancellationToken).ConfigureAwait(false);
                    }

                    mediaBundles.Add(mediaBundle);
                }
            }

            return(mediaBundles);
        }
        public static Artist ToSubsonicArtist(this MediaBundle <Data.Models.Artist> artistMediaBundle)
        {
            var subsonicArtist = new Artist();

            var artist = artistMediaBundle.Media;

            subsonicArtist.Name           = artist.Name;
            subsonicArtist.Id             = artist.Id.ToString("n");
            subsonicArtist.ArtistImageUrl = artist.ImageUrl;

            var disposition = artistMediaBundle.Dispositions.FirstOrDefault();

            if (disposition != null)
            {
                subsonicArtist.AverageRating = disposition.AverageRating ?? 0.0;

                if (disposition.Favorited.HasValue)
                {
                    subsonicArtist.Starred = disposition.Favorited.Value;
                }

                subsonicArtist.UserRating = disposition.UserRating ?? 0;
            }

            return(subsonicArtist);
        }
Example #6
0
        public Func <CancellationToken, Task <MediaBundle <Track> > > CreateMethod(IMetadataRepository metadataRepository, IMetadataRepositoryCache metadataRepositoryCache, ITagReaderFactory tagReaderFactory)
        {
            return(async cancellationToken =>
            {
                var mediaBundle = await metadataRepository.GetTrackAsync(UserId, Path, CollectionId, Populate, cancellationToken).ConfigureAwait(false);

                Track track = null;

                if (mediaBundle != null)
                {
                    track = mediaBundle.Media;
                }
                else if (!UpdateCollection)
                {
                    return null;
                }

                if (track != null && track.DateFileModified.ToUniversalTime() >= File.GetLastWriteTimeUtc(Path))
                {
                    return mediaBundle;
                }

                var now = DateTime.UtcNow;
                var dateAdded = now;
                Guid?trackId = null;

                if (track != null)
                {
                    trackId = track.Id;
                    dateAdded = track.DateAdded;
                }

                var tagReader = tagReaderFactory.CreateTagReader(Path);

                track = await metadataRepositoryCache.TagReaderToTrackModelAsync(UserId, tagReader, CollectionId, cancellationToken).ConfigureAwait(false);

                if (trackId.HasValue)
                {
                    track.Id = trackId.Value;
                }

                track.CollectionId = CollectionId;
                track.DateAdded = dateAdded;
                track.DateModified = now;
                track.Visible = true;

                await metadataRepository.InsertOrUpdateTrackAsync(track, cancellationToken).ConfigureAwait(false);

                mediaBundle = new MediaBundle <Track>
                {
                    Media = track,
                    Dispositions = new List <Disposition>(),
                    Playback = new List <Playback>()
                };

                return mediaBundle;
            });
        }
        public static Child ToSubsonicChild(this MediaBundle <Album> albumMediaBundle)
        {
            var subsonicChild = new Child();

            var album = albumMediaBundle.Media;

            subsonicChild.Album = album.Name;

            var artist = album.Artists?.FirstOrDefault();

            if (artist != null)
            {
                subsonicChild.ArtistId = artist.Media.Id.ToString("n");
                subsonicChild.Artist   = string.Join(Separator, album.Artists.Select(a => a.Media.Name));
                subsonicChild.Parent   = subsonicChild.ArtistId;
            }

            if (album.Tracks?.Count > 0)
            {
                subsonicChild.CoverArt = album.Tracks.First().Media.Id.ToString("n");
                subsonicChild.Year     = album.Tracks.First().Media.ReleaseDate;
                subsonicChild.Duration = (int)album.Duration.TotalSeconds;
            }

            subsonicChild.Id    = album.Id.ToString("n");
            subsonicChild.Title = album.Name;
            subsonicChild.IsDir = true;

            if (album.Genres?.Any() == true)
            {
                subsonicChild.Genre = string.Join(Separator, album.Genres.Select(g => g.Name));
            }

            var disposition = albumMediaBundle.Dispositions.FirstOrDefault();

            if (disposition != null)
            {
                if (disposition.AverageRating.HasValue)
                {
                    subsonicChild.AverageRating = disposition.AverageRating.Value;
                }

                if (disposition.Favorited.HasValue)
                {
                    subsonicChild.Starred = disposition.Favorited.Value;
                }

                if (disposition.UserRating.HasValue)
                {
                    subsonicChild.UserRating = disposition.UserRating.Value;
                }
            }

            subsonicChild.Created = album.DateAdded;

            return(subsonicChild);
        }
        public Func <CancellationToken, Task <MediaBundle <Album> > > CreateMethod(IMetadataRepository metadataRepository)
        {
            return(async cancelToken =>
            {
                var mediaBundle = await metadataRepository.GetAlbumAsync(UserId, Artists, Name, CollectionId, Populate, cancelToken).ConfigureAwait(false);

                Album album = null;

                if (mediaBundle != null)
                {
                    album = mediaBundle.Media;
                }

                if (album != null)
                {
                    return mediaBundle;
                }

                var now = DateTime.UtcNow;

                var artistMediaBundles = new HashSet <MediaBundle <Artist> >();

                foreach (var artist in Artists)
                {
                    var artistMediaBundle = new MediaBundle <Artist>
                    {
                        Media = artist
                    };

                    artistMediaBundles.Add(artistMediaBundle);
                }

                album = new Album
                {
                    Artists = artistMediaBundles,
                    Name = Name,
                    CollectionId = CollectionId,
                    DateAdded = now,
                    DateModified = now
                };

                await metadataRepository.InsertOrUpdateAlbumAsync(album, cancelToken).ConfigureAwait(false);

                mediaBundle = new MediaBundle <Album>
                {
                    Media = album,
                    Dispositions = new List <Disposition>(),
                    Playback = new List <Playback>()
                };

                return mediaBundle;
            });
        }
Example #9
0
        public async Task <MediaBundle <Artist> > GetArtistAsync(Guid userId, Guid id, CancellationToken cancellationToken)
        {
            var artist = _client.CreateDocumentQuery <Artist>(UriFactory.CreateDocumentCollectionUri(DatabaseConstants.DatabaseId, DatabaseConstants.Artist), _defaultFeedOptions)
                         .FirstOrDefault(s => s.Id == id);

            var mediaBundle = new MediaBundle <Artist>()
            {
                Media        = artist,
                Dispositions = new List <Disposition> {
                    await GetDispositionAsync(userId, id, cancellationToken)
                }
            };

            return(mediaBundle);
        }
Example #10
0
        private async Task PopulateTrackAsync(Guid userId, MediaBundle <Track> track, CancellationToken cancellationToken)
        {
            if (track.Media.Artists == null)
            {
                var trackArtists = await GetArtistsByTrackAsync(userId, track.Media.Id, cancellationToken).ConfigureAwait(false);

                track.Media.Artists = new HashSet <MediaBundle <Artist> >(trackArtists);
            }

            if (track.Media.Genres == null)
            {
                var trackGenres = await GetGenresByTrackAsync(track.Media.Id, cancellationToken).ConfigureAwait(false);

                track.Media.Genres = new HashSet <Genre>(trackGenres);
            }
        }
        public static AlbumWithSongsID3 ToSubsonicAlbumWithSongsId3(this MediaBundle <Album> albumMediaBundle)
        {
            var subsonicAlbum = new AlbumWithSongsID3();

            var album = albumMediaBundle.Media;

            var artist = album.Artists?.FirstOrDefault();

            if (artist != null)
            {
                subsonicAlbum.ArtistId = artist.Media.Id.ToString("n");
                subsonicAlbum.Artist   = string.Join(Separator, album.Artists.Select(a => a.Media.Name));
            }

            if (album.Tracks != null)
            {
                subsonicAlbum.CoverArt  = album.Tracks.First().Media.Id.ToString("n");
                subsonicAlbum.Year      = album.Tracks.First().Media.ReleaseDate;
                subsonicAlbum.Duration  = (int)album.Duration.TotalSeconds;
                subsonicAlbum.SongCount = album.Tracks.Count;
            }

            subsonicAlbum.Id = album.Id.ToString("n");

            if (album.Genres?.Any() == true)
            {
                subsonicAlbum.Genre = string.Join(Separator, album.Genres.Select(g => g.Name));
            }

            var disposition = albumMediaBundle.Dispositions.FirstOrDefault();

            if (disposition?.Favorited.HasValue == true)
            {
                subsonicAlbum.Starred = disposition.Favorited.Value;
            }

            subsonicAlbum.Created = album.DateAdded;
            subsonicAlbum.Name    = album.Name;

            subsonicAlbum.Songs = album.Tracks?.Select(t => t.ToSubsonicSong(albumMediaBundle)).ToList();

            return(subsonicAlbum);
        }
        public static ArtistID3 ToSubsonicArtistId3(this MediaBundle <Data.Models.Artist> artistMediaBundle)
        {
            var subsonicArtist = new ArtistID3();

            var artist = artistMediaBundle.Media;

            subsonicArtist.Name           = artist.Name;
            subsonicArtist.Id             = artist.Id.ToString("n");
            subsonicArtist.CoverArt       = $"ar-{subsonicArtist.Id}";
            subsonicArtist.ArtistImageUrl = artist.ImageUrl;

            var disposition = artistMediaBundle.Dispositions.FirstOrDefault();

            if (disposition?.Favorited.HasValue == true)
            {
                subsonicArtist.Starred = disposition.Favorited.Value;
            }

            return(subsonicArtist);
        }
Example #13
0
        public async Task <MediaBundle <Album> > GetAlbumAsync(Guid userId, Guid id, bool populate, CancellationToken cancellationToken)
        {
            var album = _client.CreateDocumentQuery <Album>(UriFactory.CreateDocumentCollectionUri(DatabaseConstants.DatabaseId, DatabaseConstants.Album), _defaultFeedOptions)
                        .FirstOrDefault(s => s.Id == id);

            var mediaBundle = new MediaBundle <Album>()
            {
                Media        = album,
                Dispositions = new List <Disposition> {
                    await GetDispositionAsync(userId, id, cancellationToken)
                }
            };

            if (populate)
            {
                await PopulateAlbumAsync(userId, mediaBundle, cancellationToken).ConfigureAwait(false);
            }

            return(mediaBundle);
        }
Example #14
0
        private async Task PopulateAlbumAsync(Guid userId, MediaBundle <Album> album, CancellationToken cancellationToken)
        {
            if (album.Media.Artists == null)
            {
                var albumArtists = await GetArtistsByAlbumAsync(userId, album.Media.Id, cancellationToken).ConfigureAwait(false);

                album.Media.Artists = new HashSet <MediaBundle <Artist> >(albumArtists);
            }

            if (album.Media.Tracks == null)
            {
                var albumTracks = await GetTracksByAlbumAsync(userId, album.Media.Id, true, cancellationToken).ConfigureAwait(false);

                foreach (var track in albumTracks.OrderBy(t => t.Media.DiscNumber).ThenBy(t => t.Media.Number))
                {
                    await PopulateTrackAsync(userId, track, cancellationToken).ConfigureAwait(false);

                    album.Media.AddTrack(track);
                }
            }
        }
Example #15
0
        public async Task <IEnumerable <MediaBundle <Album> > > GetAlbumsAsync(Guid userId, Guid?collectionId, bool populate, CancellationToken cancellationToken)
        {
            var query = _client.CreateDocumentQuery <Album>(UriFactory.CreateDocumentCollectionUri(DatabaseConstants.DatabaseId, DatabaseConstants.Album), _defaultFeedOptions).AsQueryable();

            if (collectionId.HasValue)
            {
                query = query.Where(s => s.CollectionId == collectionId.Value);
            }

            var documentQuery = query.AsDocumentQuery();

            var mediaBundles = new List <MediaBundle <Album> >();

            while (documentQuery.HasMoreResults)
            {
                foreach (var album in await documentQuery.ExecuteNextAsync <Album>(cancellationToken).ConfigureAwait(false))
                {
                    var mediaBundle = new MediaBundle <Album>()
                    {
                        Media        = album,
                        Dispositions = new List <Disposition> {
                            await GetDispositionAsync(userId, album.Id, cancellationToken)
                        }
                    };

                    if (populate)
                    {
                        await PopulateAlbumAsync(userId, mediaBundle, cancellationToken).ConfigureAwait(false);
                    }

                    mediaBundles.Add(mediaBundle);
                }
            }

            return(mediaBundles);
        }
Example #16
0
        /// <summary>
        /// Runs the code example.
        /// </summary>
        /// <param name="user">The AdWords user.</param>
        /// <param name="adGroupId">Id of the first adgroup to which ad is added.</param>
        public void Run(AdWordsUser user, long adGroupId)
        {
            // Get the AdGroupAdService.
              AdGroupAdService adGroupAdService = (AdGroupAdService) user.GetService(
              AdWordsService.v201601.AdGroupAdService);

              // Create the HTML5 template ad. See
              // https://developers.google.com/adwords/api/docs/guides/template-ads#html5_ads
              // for more details.
              TemplateAd html5Ad = new TemplateAd() {
            name = "Ad for HTML5",
            templateId = 419,
            finalUrls = new string[] { "http://example.com/html5" },
            displayUrl = "www.example.com/html5",
            dimensions = new Dimensions() {
              width = 300,
              height = 250
            }
              };

              // The HTML5 zip file contains all the HTML, CSS, and images needed for the
              // HTML5 ad. For help on creating an HTML5 zip file, check out Google Web
              // Designer (https://www.google.com/webdesigner/).
              byte[] html5Zip = MediaUtilities.GetAssetDataFromUrl("https://goo.gl/9Y7qI2");

              // Create a media bundle containing the zip file with all the HTML5 components.
              MediaBundle mediaBundle = new MediaBundle() {
            // You may also upload an HTML5 zip using MediaService.upload() method
            // set the mediaId field. See UploadMediaBundle.cs for an example on
            // how to upload HTML5 zip files.
            data = html5Zip,
            entryPoint = "carousel/index.html",
            type = MediaMediaType.MEDIA_BUNDLE
              };

              // Create the template elements for the ad. You can refer to
              // https://developers.google.com/adwords/api/docs/appendix/templateads
              // for the list of available template fields.
              html5Ad.templateElements = new TemplateElement[] {
            new TemplateElement() {
              uniqueName = "adData",
              fields = new TemplateElementField[] {
            new TemplateElementField() {
              name = "Custom_layout",
              fieldMedia = mediaBundle,
              type = TemplateElementFieldType.MEDIA_BUNDLE
            },
            new TemplateElementField() {
              name = "layout",
              fieldText = "Custom",
              type = TemplateElementFieldType.ENUM
            },
              },
            }
              };

              // Create the AdGroupAd.
              AdGroupAd html5AdGroupAd = new AdGroupAd() {
            adGroupId = adGroupId,
            ad = html5Ad,
            // Additional properties (non-required).
            status = AdGroupAdStatus.PAUSED
              };
              AdGroupAdOperation adGroupAdOperation = new AdGroupAdOperation() {
            @operator = Operator.ADD,
            operand = html5AdGroupAd
              };

              try {
            // Add HTML5 ad.
            AdGroupAdReturnValue result =
              adGroupAdService.mutate(new AdGroupAdOperation[] { adGroupAdOperation });

            // Display results.
            if (result != null && result.value != null && result.value.Length > 0) {
              foreach (AdGroupAd adGroupAd in result.value) {
            Console.WriteLine("New HTML5 ad with id \"{0}\" and display url \"{1}\" was added.",
              adGroupAd.ad.id, adGroupAd.ad.displayUrl);
              }
            } else {
              Console.WriteLine("No HTML5 ads were added.");
            }
              } catch (Exception e) {
            throw new System.ApplicationException("Failed to create HTML5 ad.", e);
              }
        }
        public static NowPlayingEntry ToSubsonicNowPlayingEntry(this MediaBundle <Track> trackMediaBundle, MediaBundle <Album> albumMediaBundle, Disposition disposition, Playback playback, User user)
        {
            var nowPlayingEntry = new NowPlayingEntry();

            var track = trackMediaBundle.Media;

            if (albumMediaBundle != null)
            {
                nowPlayingEntry.Album = albumMediaBundle.Media.Name;
            }

            nowPlayingEntry.AlbumId = track.AlbumId.ToString("n");

            var artist = track.Artists.FirstOrDefault();

            if (artist != null)
            {
                nowPlayingEntry.ArtistId = artist.Media.Id.ToString("n");
                nowPlayingEntry.Artist   = string.Join(Separator, track.Artists.Select(a => a.Media.Name));
            }

            nowPlayingEntry.BitRate     = track.Bitrate;
            nowPlayingEntry.ContentType = track.ContentType;
            nowPlayingEntry.CoverArt    = track.Id.ToString("n");
            nowPlayingEntry.Created     = track.DateFileCreated;
            nowPlayingEntry.DiscNumber  = track.DiscNumber;
            nowPlayingEntry.Duration    = (int)track.Duration.TotalSeconds;

            if (track.Genres.Count > 0)
            {
                nowPlayingEntry.Genre = string.Join(Separator, track.Genres.Select(g => g.Name));
            }

            var parentDirectory      = Directory.GetParent(track.Path);
            var grandParentDirectory = Directory.GetParent(parentDirectory.FullName);

            nowPlayingEntry.Id      = track.Id.ToString("n");
            nowPlayingEntry.IsDir   = false;
            nowPlayingEntry.IsVideo = false;
            nowPlayingEntry.Parent  = track.AlbumId.ToString("n");
            nowPlayingEntry.Path    = Path.Combine(grandParentDirectory.Name, parentDirectory.Name, Path.GetFileName(track.Path)).Replace(Path.DirectorySeparatorChar, '/');
            nowPlayingEntry.Size    = track.Size;

            if (disposition != null)
            {
                nowPlayingEntry.AverageRating = disposition.AverageRating ?? 0.0;

                if (disposition.Favorited.HasValue)
                {
                    nowPlayingEntry.Starred = disposition.Favorited.Value;
                }

                nowPlayingEntry.UserRating = disposition.UserRating ?? 0;
            }

            nowPlayingEntry.Suffix = Path.GetExtension(track.Path);
            nowPlayingEntry.Title  = track.Name;
            nowPlayingEntry.Track  = track.Number;
            nowPlayingEntry.Type   = MediaType.Music;
            nowPlayingEntry.Year   = track.ReleaseDate;

            nowPlayingEntry.MinutesAgo = (DateTime.UtcNow - playback.PlaybackDateTime).Minutes;
            nowPlayingEntry.PlayerName = playback.ClientId;
            nowPlayingEntry.Username   = user.Name;

            return(nowPlayingEntry);
        }
 public static Child ToSubsonicSong(this MediaBundle <Track> track, MediaBundle <Album> album)
 {
     return(track.Media.ToSubsonicSong(album?.Media, track.Dispositions.FirstOrDefault()));
 }
        /// <summary>
        /// Runs the code example.
        /// </summary>
        /// <param name="user">The AdWords user.</param>
        /// <param name="adGroupId">Id of the first adgroup to which ad is added.</param>
        public void Run(AdWordsUser user, long adGroupId)
        {
            using (AdGroupAdService adGroupAdService =
                       (AdGroupAdService)user.GetService(AdWordsService.v201809.AdGroupAdService))
            {
                // Create the HTML5 template ad. See
                // https://developers.google.com/adwords/api/docs/guides/template-ads#html5_ads
                // for more details.
                TemplateAd html5Ad = new TemplateAd()
                {
                    name       = "Ad for HTML5",
                    templateId = 419,
                    finalUrls  = new string[]
                    {
                        "http://example.com/html5"
                    },
                    displayUrl = "www.example.com/html5",
                    dimensions = new Dimensions()
                    {
                        width  = 300,
                        height = 250
                    }
                };

                // The HTML5 zip file contains all the HTML, CSS, and images needed for the
                // HTML5 ad. For help on creating an HTML5 zip file, check out Google Web
                // Designer (https://www.google.com/webdesigner/).
                byte[] html5Zip =
                    MediaUtilities.GetAssetDataFromUrl("https://goo.gl/9Y7qI2", user.Config);

                // Create a media bundle containing the zip file with all the HTML5 components.
                MediaBundle mediaBundle = new MediaBundle()
                {
                    // You may also upload an HTML5 zip using MediaService.upload() method
                    // set the mediaId field. See UploadMediaBundle.cs for an example on
                    // how to upload HTML5 zip files.
                    data       = html5Zip,
                    entryPoint = "carousel/index.html",
                    type       = MediaMediaType.MEDIA_BUNDLE
                };

                // Create the template elements for the ad. You can refer to
                // https://developers.google.com/adwords/api/docs/appendix/templateads
                // for the list of available template fields.
                html5Ad.templateElements = new TemplateElement[]
                {
                    new TemplateElement()
                    {
                        uniqueName = "adData",
                        fields     = new TemplateElementField[]
                        {
                            new TemplateElementField()
                            {
                                name       = "Custom_layout",
                                fieldMedia = mediaBundle,
                                type       = TemplateElementFieldType.MEDIA_BUNDLE
                            },
                            new TemplateElementField()
                            {
                                name      = "layout",
                                fieldText = "Custom",
                                type      = TemplateElementFieldType.ENUM
                            },
                        },
                    }
                };

                // Create the AdGroupAd.
                AdGroupAd html5AdGroupAd = new AdGroupAd()
                {
                    adGroupId = adGroupId,
                    ad        = html5Ad,
                    // Additional properties (non-required).
                    status = AdGroupAdStatus.PAUSED
                };
                AdGroupAdOperation adGroupAdOperation = new AdGroupAdOperation()
                {
                    @operator = Operator.ADD,
                    operand   = html5AdGroupAd
                };

                try
                {
                    // Add HTML5 ad.
                    AdGroupAdReturnValue result = adGroupAdService.mutate(new AdGroupAdOperation[]
                    {
                        adGroupAdOperation
                    });

                    // Display results.
                    if (result != null && result.value != null && result.value.Length > 0)
                    {
                        foreach (AdGroupAd adGroupAd in result.value)
                        {
                            Console.WriteLine(
                                "New HTML5 ad with id \"{0}\" and display url \"{1}\" was added.",
                                adGroupAd.ad.id, adGroupAd.ad.displayUrl);
                        }
                    }
                    else
                    {
                        Console.WriteLine("No HTML5 ads were added.");
                    }
                }
                catch (Exception e)
                {
                    throw new System.ApplicationException("Failed to create HTML5 ad.", e);
                }
            }
        }