Example #1
0
        /// <summary>
        /// Creates a TvBroadcastListing
        /// </summary>
        /// <param name="importTag"></param>
        /// <param name="channelSource"></param>
        /// <param name="info"></param>
        /// <returns></returns>
        public TvProgramBroadCastListing AddBroadcastListing(TvProgramBroadCastListingImport importTag, TvChannelListingSource channelSource, IAddTvBroadCastListingInfo info)
        {
            // check if this import's going to violate the PK by trying to import duplicate Listings (on the same ImportId)
            if (CheckForViolatedPK(importTag, channelSource, info) != null)
                throw new TvBroadCastListingAlreadyExistsException(
                    string.Format(
                        "An item with that PK (import, channel, startat) {{{0}, {1}, {2}}} already exists",
                        importTag.TvProgramBroadCastListingImportId, channelSource.TvChannelId, info.StartAt
                    )
                );

            // clean up any whitespace on the text fields and replace as nulls where possible
            info.ProgramTitle = info.ProgramTitle.Trim();
            info.EpisodeTitle = string.IsNullOrWhiteSpace(info.EpisodeTitle) ? null : info.EpisodeTitle.Trim();
            info.EpisodeDescription = string.IsNullOrWhiteSpace(info.EpisodeDescription) ? null : info.EpisodeDescription.Trim();

            // try and find or generate program information from this listing
            TvProgram program = GetOrCreateTvProgramFromListingInfo(info);

            // try and find or generate episode information from this listing
            TvProgramEpisode episode = GetOrCreateTvProgramEpisodeFromListingInfo(program, info);

            // if we don't have an EndDate we can't create a listing
            if (info.EndAt == null || info.StartAt == info.EndAt) return null;

            // see if there's an existing listing for this channel with these exact times
            var existing = FindExistingListing(channelSource, info.StartAt, info.EndAt.Value);
            if (existing != null) {
                // check if it's the same in every way except the importer
                if(
                    // TvChannelId, StartAt, EndAt, Superceded==false are done by the DB
                    existing.ProgramTitle == info.ProgramTitle
                    && existing.EpisodeTitle == info.EpisodeTitle
                    && existing.EpisodeDescription == info.EpisodeDescription
                    && existing.TvProgramId == program.TvProgramId
                    && existing.TvProgramEpisodeId == episode?.TvProgramEpisodeId
                    && existing.Attributes == info.Attributes
                ) {
                    // already an exact match, return that instead
                    return existing;
                }
            }

            // create and add the new listing
            var newItem = new TvProgramBroadCastListing {
                TvProgramBroadCastListingImportId = importTag.TvProgramBroadCastListingImportId,
                TvChannelId = channelSource.TvChannelId,
                StartAt = info.StartAt,
                EndAt = info.EndAt,
                ProgramTitle = info.ProgramTitle,
                EpisodeTitle = info.EpisodeTitle,
                EpisodeDescription = info.EpisodeDescription,
                TvProgramId = program?.TvProgramId,
                TvProgramEpisodeId = episode?.TvProgramEpisodeId,
                Attributes = info.Attributes,
                Superceded = false
            };
            TvListings.Add(newItem);

            // if we had an existing item that wasn't an exact match we mark it as superceded since we've just added a new one
            if (existing != null) {
                existing.Superceded = true;
                TvListings.Update(existing);
            }

            // return the new item we just made
            return newItem;
        }
Example #2
0
        /// <summary>
        /// Checks for an exact PK match on local changes only
        /// </summary>
        /// <param name="importTag"></param>
        /// <param name="channelSource"></param>
        /// <param name="info"></param>
        /// <returns></returns>
        protected TvProgramBroadCastListing CheckForViolatedPK(TvProgramBroadCastListingImport importTag, TvChannelListingSource channelSource, IAddTvBroadCastListingInfo info)
        {
            // in-memory dupe detection to stop duplicate PKs generated by broken feed / import processes
            var local =
                ChangeTracker.Entries<TvProgramBroadCastListing>()
                .SingleOrDefault(x =>
                    x.Property(y => y.TvProgramBroadCastListingImportId).CurrentValue == importTag.TvProgramBroadCastListingImportId
                    && x.Property(y => y.TvChannelId).CurrentValue == channelSource.TvChannelId
                    && x.Property(y => y.StartAt).CurrentValue == info.StartAt
                );
            if (local != null) return local.Entity;

            // we don't need to check the database here because this TvProgramBroadCastListingImportId has been created by this thread
            return null;
        }
Example #3
0
        /// <summary>
        /// Locates an existing listing for this channel at this time that hasn't been superceded
        /// </summary>
        /// <param name="channelSource"></param>
        /// <param name="info"></param>
        /// <returns></returns>
        protected TvProgramBroadCastListing FindExistingListing(TvChannelListingSource channelSource, DateTime startAt, DateTime endAt)
        {
            // check the local changetracker first
            var local =
                ChangeTracker.Entries<TvProgramBroadCastListing>()
                .SingleOrDefault(x =>
                    x.Property(y => y.StartAt).CurrentValue == startAt
                    && x.Property(y => y.EndAt).CurrentValue == endAt
                    && x.Property(y => y.TvChannelId).CurrentValue == channelSource.TvChannelId
                    && x.Property(y => y.Superceded).CurrentValue == false
                );

            // if we already have a matching PK for this listing just return it and don't add anything
            if (local != null) {
                return local.Entity;
            }

            // then the actual database
            var remote =
                TvListings
                .SingleOrDefault(x =>
                    x.StartAt == startAt
                    && x.EndAt == endAt
                    && x.TvChannelId == channelSource.TvChannelId
                    && x.Superceded == false
                );
            if (remote != null) {
                return remote;
            }

            return null;
        }
Example #4
0
        /// <summary>
        /// Locates or creates a TvChannel and its corresponding TvChannelListingSource
        /// </summary>
        /// <param name="import"></param>
        /// <param name="info"></param>
        /// <returns></returns>
        public TvChannelListingSource AddTvChannelListingSource(TvProgramBroadCastListingImport import, IAddTvChannelSourceInfo info)
        {
            // try and find a matching channel by uri
            var local = ChangeTracker.Entries<TvChannelListingSource>().SingleOrDefault(x => x.Property(y => y.SourceChannelUri).CurrentValue == info.Uri);
            if (local != null) return local.Entity;

            // try and find a matching channel by uri
            var remote = TvChannelListingSources.SingleOrDefault(x => x.SourceChannelUri == info.Uri);
            if (remote != null) return remote;

            // add a channel with that displayname
            var newChan = new TvChannel {
                ChannelName = info.DisplayName.Trim()
            };
            TvChannels.Add(newChan);

            // and a link between it and the source with the info it needs for future requests
            var newSource = new TvChannelListingSource {
                SourceChannelUri = info.Uri,
                SourceChannelName = info.SourceName
            };
            TvChannelListingSources.Add(newSource);

            return newSource;
        }