Пример #1
0
        public async Task <Option <Show> > GetShowByMetadata(int libraryPathId, ShowMetadata metadata)
        {
            await using TvContext dbContext = _dbContextFactory.CreateDbContext();
            Option <int> maybeId = await dbContext.ShowMetadata
                                   .Where(s => s.Title == metadata.Title && s.Year == metadata.Year)
                                   .Where(s => s.Show.LibraryPathId == libraryPathId)
                                   .SingleOrDefaultAsync()
                                   .Map(Optional)
                                   .MapT(sm => sm.ShowId);

            return(await maybeId.Match(
                       id =>
            {
                return dbContext.Shows
                .AsNoTracking()
                .Include(s => s.ShowMetadata)
                .ThenInclude(sm => sm.Artwork)
                .Include(s => s.ShowMetadata)
                .ThenInclude(sm => sm.Genres)
                .Include(s => s.ShowMetadata)
                .ThenInclude(sm => sm.Tags)
                .Include(s => s.LibraryPath)
                .ThenInclude(lp => lp.Library)
                .OrderBy(s => s.Id)
                .SingleOrDefaultAsync(s => s.Id == id)
                .Map(Optional);
            },
                       () => Option <Show> .None.AsTask()));
        }
Пример #2
0
        private void UpdateShow(Show show, IndexWriter writer)
        {
            Option <ShowMetadata> maybeMetadata = show.ShowMetadata.HeadOrNone();

            if (maybeMetadata.IsSome)
            {
                ShowMetadata metadata = maybeMetadata.ValueUnsafe();

                try
                {
                    var doc = new Document
                    {
                        new StringField(IdField, show.Id.ToString(), Field.Store.YES),
                        new StringField(TypeField, ShowType, Field.Store.NO),
                        new TextField(TitleField, metadata.Title, Field.Store.NO),
                        new StringField(SortTitleField, metadata.SortTitle.ToLowerInvariant(), Field.Store.NO),
                        new TextField(LibraryNameField, show.LibraryPath.Library.Name, Field.Store.NO),
                        new StringField(TitleAndYearField, GetTitleAndYear(metadata), Field.Store.NO),
                        new StringField(JumpLetterField, GetJumpLetter(metadata), Field.Store.YES)
                    };

                    if (metadata.ReleaseDate.HasValue)
                    {
                        doc.Add(
                            new StringField(
                                ReleaseDateField,
                                metadata.ReleaseDate.Value.ToString("yyyyMMdd"),
                                Field.Store.NO));
                    }

                    if (!string.IsNullOrWhiteSpace(metadata.Plot))
                    {
                        doc.Add(new TextField(PlotField, metadata.Plot ?? string.Empty, Field.Store.NO));
                    }

                    foreach (Genre genre in metadata.Genres)
                    {
                        doc.Add(new TextField(GenreField, genre.Name, Field.Store.NO));
                    }

                    foreach (Tag tag in metadata.Tags)
                    {
                        doc.Add(new TextField(TagField, tag.Name, Field.Store.NO));
                    }

                    foreach (Studio studio in metadata.Studios)
                    {
                        doc.Add(new TextField(StudioField, studio.Name, Field.Store.NO));
                    }

                    writer.UpdateDocument(new Term(IdField, show.Id.ToString()), doc);
                }
                catch (Exception ex)
                {
                    metadata.Show = null;
                    _logger.LogWarning(ex, "Error indexing show with metadata {@Metadata}", metadata);
                }
            }
        }
Пример #3
0
        public ShowMetadata GetFallbackMetadataForShow(string showFolder)
        {
            string fileName = Path.GetFileName(showFolder);
            var    metadata = new ShowMetadata
            {
                MetadataKind = MetadataKind.Fallback, Title = fileName ?? showFolder
            };

            return(GetTelevisionShowMetadata(fileName, metadata));
        }
        private async Task <Either <BaseError, MediaItemScanResult <Show> > > FindOrCreateShow(
            int libraryPathId,
            string showFolder)
        {
            ShowMetadata metadata = await _localMetadataProvider.GetMetadataForShow(showFolder);

            Option <Show> maybeShow = await _televisionRepository.GetShowByMetadata(libraryPathId, metadata);

            return(await maybeShow.Match(
                       show => Right <BaseError, MediaItemScanResult <Show> >(new MediaItemScanResult <Show>(show)).AsTask(),
                       async() => await _televisionRepository.AddShow(libraryPathId, showFolder, metadata)));
        }
Пример #5
0
        /// <summary>
        /// Create a details page for an episode.
        /// NOTE: This is public to enable debug markup access.
        /// </summary>
        public DetailsPage CreateEpisodeDetailsPage(int episodeId)
        {
            DetailsPage page = new DetailsPage();

            //
            // Get the full metadata on the episode.
            //

            DataRow         episodeData     = GetEpisodeData(episodeId);
            EpisodeMetadata episodeMetadata = ExtractEpisodeMetadata(episodeData, episodeId);


            //
            // Get the full metadata on the show.
            //

            DataRow      showData     = GetShowData(episodeMetadata.ShowId);
            ShowMetadata showMetadata = ExtractShowMetadata(showData, episodeMetadata.ShowId);


            //
            // Fill in the page's easy properties.
            //

            page.Title      = episodeMetadata.Title;
            page.Summary    = episodeMetadata.Summary;
            page.Background = LoadImage(episodeMetadata.DetailImagePath);


            //
            // Metadata
            //
            // Now that we have all the little pieces, we can put together our
            // final metadata string.
            //

            page.Metadata = String.Format(Z.Resources.TV_Details_Metadata,
                                          showMetadata.Provider,
                                          episodeMetadata.Season,
                                          showMetadata.Genre,
                                          episodeMetadata.Length,
                                          showMetadata.CountryShortName,
                                          episodeMetadata.ReleaseDate.Year);


            //
            // Actions
            //

            CreateEpisodeDetailsCommands(page, episodeData, episodeId);

            return(page);
        }
    private async Task <Either <BaseError, MediaItemScanResult <Show> > > FindOrCreateShow(
        int libraryPathId,
        string showFolder)
    {
        ShowMetadata metadata = await _localMetadataProvider.GetMetadataForShow(showFolder);

        Option <Show> maybeShow = await _televisionRepository.GetShowByMetadata(libraryPathId, metadata);

        foreach (Show show in maybeShow)
        {
            return(new MediaItemScanResult <Show>(show));
        }

        return(await _televisionRepository.AddShow(libraryPathId, showFolder, metadata));
    }
Пример #7
0
        private async Task <Either <BaseError, MediaItemScanResult <PlexShow> > > UpdateArtwork(
            MediaItemScanResult <PlexShow> result,
            PlexShow incoming)
        {
            PlexShow     existing         = result.Item;
            ShowMetadata existingMetadata = existing.ShowMetadata.Head();
            ShowMetadata incomingMetadata = incoming.ShowMetadata.Head();

            if (incomingMetadata.DateUpdated > existingMetadata.DateUpdated)
            {
                await UpdateArtworkIfNeeded(existingMetadata, incomingMetadata, ArtworkKind.Poster);
                await UpdateArtworkIfNeeded(existingMetadata, incomingMetadata, ArtworkKind.FanArt);

                await _metadataRepository.MarkAsUpdated(existingMetadata, incomingMetadata.DateUpdated);
            }

            return(result);
        }
Пример #8
0
        private ShowMetadata GetTelevisionShowMetadata(string fileName, ShowMetadata metadata)
        {
            try
            {
                const string PATTERN = @"^(.*?)[\s.]+?[.\(](\d{4})[.\)].*$";
                Match        match   = Regex.Match(fileName, PATTERN);
                if (match.Success)
                {
                    metadata.Title       = match.Groups[1].Value;
                    metadata.Year        = int.Parse(match.Groups[2].Value);
                    metadata.ReleaseDate = new DateTime(int.Parse(match.Groups[2].Value), 1, 1);
                    metadata.DateUpdated = DateTime.UtcNow;
                }
            }
            catch (Exception)
            {
                // ignored
            }

            return(metadata);
        }
        private async Task <Either <BaseError, MediaItemScanResult <Show> > > UpdateArtworkForShow(
            MediaItemScanResult <Show> result,
            string showFolder,
            ArtworkKind artworkKind)
        {
            try
            {
                Show show = result.Item;
                await LocateArtworkForShow(showFolder, artworkKind).IfSomeAsync(
                    async posterFile =>
                {
                    ShowMetadata metadata = show.ShowMetadata.Head();
                    await RefreshArtwork(posterFile, metadata, artworkKind);
                });

                return(result);
            }
            catch (Exception ex)
            {
                return(BaseError.New(ex.ToString()));
            }
        }
Пример #10
0
        public async Task <Either <BaseError, MediaItemScanResult <Show> > > AddShow(
            int libraryPathId,
            string showFolder,
            ShowMetadata metadata)
        {
            await using TvContext dbContext = _dbContextFactory.CreateDbContext();

            try
            {
                metadata.DateAdded = DateTime.UtcNow;
                metadata.Genres ??= new List <Genre>();
                metadata.Tags ??= new List <Tag>();
                var show = new Show
                {
                    LibraryPathId = libraryPathId,
                    ShowMetadata  = new List <ShowMetadata> {
                        metadata
                    },
                    Seasons = new List <Season>()
                };

                await dbContext.Shows.AddAsync(show);

                await dbContext.SaveChangesAsync();

                await dbContext.Entry(show).Reference(s => s.LibraryPath).LoadAsync();

                await dbContext.Entry(show.LibraryPath).Reference(lp => lp.Library).LoadAsync();

                return(new MediaItemScanResult <Show>(show)
                {
                    IsAdded = true
                });
            }
            catch (Exception ex)
            {
                return(BaseError.New(ex.Message));
            }
        }
Пример #11
0
        /// <summary>
        /// Take the raw show data row and create a nicely typed struct.
        /// </summary>
        private ShowMetadata ExtractShowMetadata(DataRow showData, int showId)
        {
            ShowMetadata metadata = new ShowMetadata();

            metadata.Id = showId;

            metadata.Title = (string)showData["TV_Show_Title"];

            //
            // Provider
            //

            DataRow providerData = Z.DataSetHelpers.GetIDMappedDataRow(showData, "TV_Provider_ID",
                                                                       dataSet.Tables["tbl_TV_Provider"], "TV_Provider_ID");

            metadata.Provider = (string)providerData["TV_Provider"];

            //
            // Genre
            //

            DataRow genreData = Z.DataSetHelpers.GetIDMappedDataRow(showData, "TV_Genre_ID",
                                                                    dataSet.Tables["tbl_TV_Genre"], "TV_Genre_ID");

            metadata.Genre = (string)genreData["TV_Genre"];

            //
            // Country
            //

            DataRow countryData = Z.DataSetHelpers.GetIDMappedDataRow(showData, "TV_Country_ID",
                                                                      dataSet.Tables["tbl_TV_Country"], "TV_Country_ID");

            metadata.CountryFullName  = (string)countryData["TV_Country"];
            metadata.CountryShortName = (string)countryData["TV_Country_Abbrev"];

            return(metadata);
        }
Пример #12
0
    private async Task <Either <BaseError, MediaItemScanResult <Show> > > UpdateArtworkForShow(
        MediaItemScanResult <Show> result,
        string showFolder,
        ArtworkKind artworkKind,
        CancellationToken cancellationToken)
    {
        try
        {
            Show            show         = result.Item;
            Option <string> maybeArtwork = LocateArtworkForShow(showFolder, artworkKind);
            foreach (string artworkFile in maybeArtwork)
            {
                ShowMetadata metadata = show.ShowMetadata.Head();
                await RefreshArtwork(artworkFile, metadata, artworkKind, None, None, cancellationToken);
            }

            return(result);
        }
        catch (Exception ex)
        {
            _client.Notify(ex);
            return(BaseError.New(ex.ToString()));
        }
    }
Пример #13
0
 public Task <bool> AddGenre(ShowMetadata metadata, Genre genre) =>
 _dbConnection.ExecuteAsync(
     "INSERT INTO Genre (Name, ShowMetadataId) VALUES (@Name, @MetadataId)",
     new { genre.Name, MetadataId = metadata.Id }).Map(result => result > 0);
Пример #14
0
        private async Task <Either <BaseError, MediaItemScanResult <PlexShow> > > UpdateMetadata(
            MediaItemScanResult <PlexShow> result,
            PlexShow incoming)
        {
            PlexShow     existing         = result.Item;
            ShowMetadata existingMetadata = existing.ShowMetadata.Head();
            ShowMetadata incomingMetadata = incoming.ShowMetadata.Head();

            // TODO: this probably doesn't work
            // plex doesn't seem to update genres returned by the main library call
            if (incomingMetadata.DateUpdated > existingMetadata.DateUpdated)
            {
                foreach (Genre genre in existingMetadata.Genres
                         .Filter(g => incomingMetadata.Genres.All(g2 => g2.Name != g.Name))
                         .ToList())
                {
                    existingMetadata.Genres.Remove(genre);
                    if (await _metadataRepository.RemoveGenre(genre))
                    {
                        result.IsUpdated = true;
                    }
                }

                foreach (Genre genre in incomingMetadata.Genres
                         .Filter(g => existingMetadata.Genres.All(g2 => g2.Name != g.Name))
                         .ToList())
                {
                    existingMetadata.Genres.Add(genre);
                    if (await _televisionRepository.AddGenre(existingMetadata, genre))
                    {
                        result.IsUpdated = true;
                    }
                }

                foreach (Studio studio in existingMetadata.Studios
                         .Filter(s => incomingMetadata.Studios.All(s2 => s2.Name != s.Name))
                         .ToList())
                {
                    existingMetadata.Studios.Remove(studio);
                    if (await _metadataRepository.RemoveStudio(studio))
                    {
                        result.IsUpdated = true;
                    }
                }

                foreach (Studio studio in incomingMetadata.Studios
                         .Filter(s => existingMetadata.Studios.All(s2 => s2.Name != s.Name))
                         .ToList())
                {
                    existingMetadata.Studios.Add(studio);
                    if (await _televisionRepository.AddStudio(existingMetadata, studio))
                    {
                        result.IsUpdated = true;
                    }
                }

                await _metadataRepository.MarkAsUpdated(existingMetadata, incomingMetadata.DateUpdated);
            }

            return(result);
        }
Пример #15
0
 public Task <bool> AddActor(ShowMetadata metadata, Actor actor) => throw new NotSupportedException();
Пример #16
0
 public Task <bool> AddStudio(ShowMetadata metadata, Studio studio) => throw new NotSupportedException();
Пример #17
0
 public Task <bool> AddGenre(ShowMetadata metadata, Genre genre) => throw new NotSupportedException();
Пример #18
0
 AddShow(int libraryPathId, string showFolder, ShowMetadata metadata) =>
 throw new NotSupportedException();
Пример #19
0
 public Task <Option <Show> > GetShowByMetadata(int libraryPathId, ShowMetadata metadata) =>
 throw new NotSupportedException();
Пример #20
0
    private async Task <Either <BaseError, MediaItemScanResult <PlexShow> > > UpdateMetadata(
        MediaItemScanResult <PlexShow> result,
        PlexShow incoming,
        PlexLibrary library,
        PlexConnection connection,
        PlexServerAuthToken token,
        bool deepScan)
    {
        PlexShow     existing         = result.Item;
        ShowMetadata existingMetadata = existing.ShowMetadata.Head();

        if (result.IsAdded || existing.Etag != incoming.Etag || deepScan)
        {
            Either <BaseError, ShowMetadata> maybeMetadata =
                await _plexServerApiClient.GetShowMetadata(
                    library,
                    incoming.Key.Replace("/children", string.Empty).Split("/").Last(),
                    connection,
                    token);

            await maybeMetadata.Match(
                async fullMetadata =>
            {
                if (existingMetadata.MetadataKind != MetadataKind.External)
                {
                    existingMetadata.MetadataKind = MetadataKind.External;
                    await _metadataRepository.MarkAsExternal(existingMetadata);
                }

                if (existingMetadata.ContentRating != fullMetadata.ContentRating)
                {
                    existingMetadata.ContentRating = fullMetadata.ContentRating;
                    await _metadataRepository.SetContentRating(existingMetadata, fullMetadata.ContentRating);
                    result.IsUpdated = true;
                }

                foreach (Genre genre in existingMetadata.Genres
                         .Filter(g => fullMetadata.Genres.All(g2 => g2.Name != g.Name))
                         .ToList())
                {
                    existingMetadata.Genres.Remove(genre);
                    if (await _metadataRepository.RemoveGenre(genre))
                    {
                        result.IsUpdated = true;
                    }
                }

                foreach (Genre genre in fullMetadata.Genres
                         .Filter(g => existingMetadata.Genres.All(g2 => g2.Name != g.Name))
                         .ToList())
                {
                    existingMetadata.Genres.Add(genre);
                    if (await _televisionRepository.AddGenre(existingMetadata, genre))
                    {
                        result.IsUpdated = true;
                    }
                }

                foreach (Studio studio in existingMetadata.Studios
                         .Filter(s => fullMetadata.Studios.All(s2 => s2.Name != s.Name))
                         .ToList())
                {
                    existingMetadata.Studios.Remove(studio);
                    if (await _metadataRepository.RemoveStudio(studio))
                    {
                        result.IsUpdated = true;
                    }
                }

                foreach (Studio studio in fullMetadata.Studios
                         .Filter(s => existingMetadata.Studios.All(s2 => s2.Name != s.Name))
                         .ToList())
                {
                    existingMetadata.Studios.Add(studio);
                    if (await _televisionRepository.AddStudio(existingMetadata, studio))
                    {
                        result.IsUpdated = true;
                    }
                }

                foreach (Actor actor in existingMetadata.Actors
                         .Filter(
                             a => fullMetadata.Actors.All(
                                 a2 => a2.Name != a.Name || a.Artwork == null && a2.Artwork != null))
                         .ToList())
                {
                    existingMetadata.Actors.Remove(actor);
                    if (await _metadataRepository.RemoveActor(actor))
                    {
                        result.IsUpdated = true;
                    }
                }

                foreach (Actor actor in fullMetadata.Actors
                         .Filter(a => existingMetadata.Actors.All(a2 => a2.Name != a.Name))
                         .ToList())
                {
                    existingMetadata.Actors.Add(actor);
                    if (await _televisionRepository.AddActor(existingMetadata, actor))
                    {
                        result.IsUpdated = true;
                    }
                }

                foreach (MetadataGuid guid in existingMetadata.Guids
                         .Filter(g => fullMetadata.Guids.All(g2 => g2.Guid != g.Guid))
                         .ToList())
                {
                    existingMetadata.Guids.Remove(guid);
                    if (await _metadataRepository.RemoveGuid(guid))
                    {
                        result.IsUpdated = true;
                    }
                }

                foreach (MetadataGuid guid in fullMetadata.Guids
                         .Filter(g => existingMetadata.Guids.All(g2 => g2.Guid != g.Guid))
                         .ToList())
                {
                    existingMetadata.Guids.Add(guid);
                    if (await _metadataRepository.AddGuid(existingMetadata, guid))
                    {
                        result.IsUpdated = true;
                    }
                }

                foreach (Tag tag in existingMetadata.Tags
                         .Filter(g => fullMetadata.Tags.All(g2 => g2.Name != g.Name))
                         .ToList())
                {
                    existingMetadata.Tags.Remove(tag);
                    if (await _metadataRepository.RemoveTag(tag))
                    {
                        result.IsUpdated = true;
                    }
                }

                foreach (Tag tag in fullMetadata.Tags
                         .Filter(g => existingMetadata.Tags.All(g2 => g2.Name != g.Name))
                         .ToList())
                {
                    existingMetadata.Tags.Add(tag);
                    if (await _televisionRepository.AddTag(existingMetadata, tag))
                    {
                        result.IsUpdated = true;
                    }
                }

                if (result.IsUpdated)
                {
                    await _metadataRepository.MarkAsUpdated(existingMetadata, fullMetadata.DateUpdated);
                }
            },
                _ => Task.CompletedTask);
        }

        return(result);
    }
Пример #21
0
 public Task <bool> AddStudio(ShowMetadata metadata, Studio studio) =>
 _dbConnection.ExecuteAsync(
     "INSERT INTO Studio (Name, ShowMetadataId) VALUES (@Name, @MetadataId)",
     new { studio.Name, MetadataId = metadata.Id }).Map(result => result > 0);
Пример #22
0
 public Task <bool> AddTag(ShowMetadata metadata, Tag tag) =>
 _dbConnection.ExecuteAsync(
     "INSERT INTO Tag (Name, ShowMetadataId) VALUES (@Name, @MetadataId)",
     new { tag.Name, MetadataId = metadata.Id }).Map(result => result > 0);
Пример #23
0
 public Task <bool> AddTag(ShowMetadata metadata, Tag tag) => throw new NotSupportedException();
Пример #24
0
    private async Task UpdateShow(ISearchRepository searchRepository, Show show)
    {
        Option <ShowMetadata> maybeMetadata = show.ShowMetadata.HeadOrNone();

        if (maybeMetadata.IsSome)
        {
            ShowMetadata metadata = maybeMetadata.ValueUnsafe();

            try
            {
                var doc = new Document
                {
                    new StringField(IdField, show.Id.ToString(), Field.Store.YES),
                    new StringField(TypeField, ShowType, Field.Store.YES),
                    new TextField(TitleField, metadata.Title, Field.Store.NO),
                    new StringField(SortTitleField, metadata.SortTitle.ToLowerInvariant(), Field.Store.NO),
                    new TextField(LibraryNameField, show.LibraryPath.Library.Name, Field.Store.NO),
                    new StringField(LibraryIdField, show.LibraryPath.Library.Id.ToString(), Field.Store.NO),
                    new StringField(TitleAndYearField, GetTitleAndYear(metadata), Field.Store.NO),
                    new StringField(JumpLetterField, GetJumpLetter(metadata), Field.Store.YES)
                };

                List <string> languages = await searchRepository.GetLanguagesForShow(show);
                await AddLanguages(searchRepository, doc, languages);

                if (!string.IsNullOrWhiteSpace(metadata.ContentRating))
                {
                    foreach (string contentRating in (metadata.ContentRating ?? string.Empty).Split("/")
                             .Map(x => x.Trim()).Where(x => !string.IsNullOrWhiteSpace(x)))
                    {
                        doc.Add(new StringField(ContentRatingField, contentRating, Field.Store.NO));
                    }
                }

                if (metadata.ReleaseDate.HasValue)
                {
                    doc.Add(
                        new StringField(
                            ReleaseDateField,
                            metadata.ReleaseDate.Value.ToString("yyyyMMdd"),
                            Field.Store.NO));
                }

                doc.Add(new StringField(AddedDateField, metadata.DateAdded.ToString("yyyyMMdd"), Field.Store.NO));

                if (!string.IsNullOrWhiteSpace(metadata.Plot))
                {
                    doc.Add(new TextField(PlotField, metadata.Plot ?? string.Empty, Field.Store.NO));
                }

                foreach (Genre genre in metadata.Genres)
                {
                    doc.Add(new TextField(GenreField, genre.Name, Field.Store.NO));
                }

                foreach (Tag tag in metadata.Tags)
                {
                    doc.Add(new TextField(TagField, tag.Name, Field.Store.NO));
                }

                foreach (Studio studio in metadata.Studios)
                {
                    doc.Add(new TextField(StudioField, studio.Name, Field.Store.NO));
                }

                foreach (Actor actor in metadata.Actors)
                {
                    doc.Add(new TextField(ActorField, actor.Name, Field.Store.NO));
                }

                foreach (TraktListItem item in show.TraktListItems)
                {
                    doc.Add(new StringField(TraktListField, item.TraktList.TraktId.ToString(), Field.Store.NO));
                }

                _writer.UpdateDocument(new Term(IdField, show.Id.ToString()), doc);
            }
            catch (Exception ex)
            {
                metadata.Show = null;
                _logger.LogWarning(ex, "Error indexing show with metadata {@Metadata}", metadata);
            }
        }
    }
Пример #25
0
 internal static TelevisionShowCardViewModel ProjectToViewModel(
     ShowMetadata showMetadata,
     Option <JellyfinMediaSource> maybeJellyfin,
     Option <EmbyMediaSource> maybeEmby) =>
Пример #26
0
    private async Task UpdateSeason(ISearchRepository searchRepository, Season season)
    {
        Option <SeasonMetadata> maybeMetadata     = season.SeasonMetadata.HeadOrNone();
        Option <ShowMetadata>   maybeShowMetadata = season.Show.ShowMetadata.HeadOrNone();

        if (maybeMetadata.IsSome && maybeShowMetadata.IsSome)
        {
            SeasonMetadata metadata     = maybeMetadata.ValueUnsafe();
            ShowMetadata   showMetadata = maybeShowMetadata.ValueUnsafe();

            try
            {
                string seasonTitle = $"{showMetadata.Title} - S{season.SeasonNumber}";
                string sortTitle   = $"{showMetadata.SortTitle}_{season.SeasonNumber:0000}"
                                     .ToLowerInvariant();
                string titleAndYear = $"{showMetadata.Title}_{showMetadata.Year}_{season.SeasonNumber}"
                                      .ToLowerInvariant();

                var doc = new Document
                {
                    new StringField(IdField, season.Id.ToString(), Field.Store.YES),
                    new StringField(TypeField, SeasonType, Field.Store.YES),
                    new TextField(TitleField, seasonTitle, Field.Store.NO),
                    new StringField(SortTitleField, sortTitle, Field.Store.NO),
                    new TextField(LibraryNameField, season.LibraryPath.Library.Name, Field.Store.NO),
                    new StringField(LibraryIdField, season.LibraryPath.Library.Id.ToString(), Field.Store.NO),
                    new StringField(TitleAndYearField, titleAndYear, Field.Store.NO),
                    new StringField(JumpLetterField, GetJumpLetter(showMetadata), Field.Store.YES)
                };

                List <string> languages = await searchRepository.GetLanguagesForSeason(season);
                await AddLanguages(searchRepository, doc, languages);

                if (!string.IsNullOrWhiteSpace(showMetadata.ContentRating))
                {
                    foreach (string contentRating in (showMetadata.ContentRating ?? string.Empty).Split("/")
                             .Map(x => x.Trim()).Where(x => !string.IsNullOrWhiteSpace(x)))
                    {
                        doc.Add(new StringField(ContentRatingField, contentRating, Field.Store.NO));
                    }
                }

                if (metadata.ReleaseDate.HasValue)
                {
                    doc.Add(
                        new StringField(
                            ReleaseDateField,
                            metadata.ReleaseDate.Value.ToString("yyyyMMdd"),
                            Field.Store.NO));
                }

                doc.Add(new StringField(AddedDateField, metadata.DateAdded.ToString("yyyyMMdd"), Field.Store.NO));

                foreach (TraktListItem item in season.TraktListItems)
                {
                    doc.Add(new StringField(TraktListField, item.TraktList.TraktId.ToString(), Field.Store.NO));
                }

                foreach (Tag tag in metadata.Tags)
                {
                    doc.Add(new TextField(TagField, tag.Name, Field.Store.NO));
                }

                _writer.UpdateDocument(new Term(IdField, season.Id.ToString()), doc);
            }
            catch (Exception ex)
            {
                metadata.Season = null;
                _logger.LogWarning(ex, "Error indexing show with metadata {@Metadata}", metadata);
            }
        }
    }
Пример #27
0
        public string ToXml()
        {
            using var ms  = new MemoryStream();
            using var xml = XmlWriter.Create(ms);
            xml.WriteStartDocument();

            xml.WriteStartElement("tv");
            xml.WriteAttributeString("generator-info-name", "ersatztv");

            foreach (Channel channel in _channels.OrderBy(c => c.Number))
            {
                xml.WriteStartElement("channel");
                xml.WriteAttributeString("id", channel.Number);

                xml.WriteStartElement("display-name");
                xml.WriteAttributeString("lang", "en");
                xml.WriteString(channel.Name);
                xml.WriteEndElement(); // display-name

                xml.WriteStartElement("icon");
                string logo = Optional(channel.Artwork).Flatten()
                              .Filter(a => a.ArtworkKind == ArtworkKind.Logo)
                              .HeadOrNone()
                              .Match(
                    artwork => $"{_scheme}://{_host}/iptv/logos/{artwork.Path}",
                    () => $"{_scheme}://{_host}/images/ersatztv-500.png");
                xml.WriteAttributeString("src", logo);
                xml.WriteEndElement(); // icon

                xml.WriteEndElement(); // channel
            }

            foreach (Channel channel in _channels.OrderBy(c => c.Number))
            {
                foreach (PlayoutItem playoutItem in channel.Playouts.Collect(p => p.Items).OrderBy(i => i.Start))
                {
                    string start = playoutItem.StartOffset.ToString("yyyyMMddHHmmss zzz").Replace(":", string.Empty);
                    string stop  = playoutItem.FinishOffset.ToString("yyyyMMddHHmmss zzz").Replace(":", string.Empty);

                    string title = playoutItem.MediaItem switch
                    {
                        Movie m => m.MovieMetadata.HeadOrNone().Map(mm => mm.Title ?? string.Empty)
                        .IfNone("[unknown movie]"),
                        Episode e => e.Season.Show.ShowMetadata.HeadOrNone().Map(em => em.Title ?? string.Empty)
                        .IfNone("[unknown show]"),
                        _ => "[unknown]"
                    };

                    string subtitle = playoutItem.MediaItem switch
                    {
                        Episode e => e.EpisodeMetadata.HeadOrNone().Match(
                            em => em.Title ?? string.Empty,
                            () => string.Empty),
                        _ => string.Empty
                    };

                    string description = playoutItem.MediaItem switch
                    {
                        Movie m => m.MovieMetadata.HeadOrNone().Map(mm => mm.Plot ?? string.Empty).IfNone(string.Empty),
                        Episode e => e.EpisodeMetadata.HeadOrNone().Map(em => em.Plot ?? string.Empty)
                        .IfNone(string.Empty),
                        _ => string.Empty
                    };

                    string contentRating = playoutItem.MediaItem switch
                    {
                        // TODO: re-implement content rating
                        // Movie m => m.MovieMetadata.HeadOrNone().Map(mm => mm.ContentRating).IfNone(string.Empty),
                        _ => string.Empty
                    };

                    xml.WriteStartElement("programme");
                    xml.WriteAttributeString("start", start);
                    xml.WriteAttributeString("stop", stop);
                    xml.WriteAttributeString("channel", channel.Number);

                    if (playoutItem.MediaItem is Movie movie)
                    {
                        xml.WriteStartElement("category");
                        xml.WriteAttributeString("lang", "en");
                        xml.WriteString("Movie");
                        xml.WriteEndElement(); // category

                        Option <MovieMetadata> maybeMetadata = movie.MovieMetadata.HeadOrNone();
                        if (maybeMetadata.IsSome)
                        {
                            MovieMetadata metadata = maybeMetadata.ValueUnsafe();

                            if (metadata.Year.HasValue)
                            {
                                xml.WriteStartElement("date");
                                xml.WriteString(metadata.Year.Value.ToString());
                                xml.WriteEndElement(); // date
                            }

                            string poster = Optional(metadata.Artwork).Flatten()
                                            .Filter(a => a.ArtworkKind == ArtworkKind.Poster)
                                            .HeadOrNone()
                                            .Match(
                                artwork => $"{_scheme}://{_host}/artwork/posters/{artwork.Path}",
                                () => string.Empty);

                            if (!string.IsNullOrWhiteSpace(poster))
                            {
                                xml.WriteStartElement("icon");
                                xml.WriteAttributeString("src", poster);
                                xml.WriteEndElement(); // icon
                            }
                        }
                    }

                    xml.WriteStartElement("title");
                    xml.WriteAttributeString("lang", "en");
                    xml.WriteString(title);
                    xml.WriteEndElement(); // title

                    if (!string.IsNullOrWhiteSpace(subtitle))
                    {
                        xml.WriteStartElement("sub-title");
                        xml.WriteAttributeString("lang", "en");
                        xml.WriteString(subtitle);
                        xml.WriteEndElement(); // subtitle
                    }

                    xml.WriteStartElement("previously-shown");
                    xml.WriteEndElement(); // previously-shown

                    if (playoutItem.MediaItem is Episode episode)
                    {
                        Option <ShowMetadata> maybeMetadata =
                            Optional(episode.Season?.Show?.ShowMetadata.HeadOrNone()).Flatten();
                        if (maybeMetadata.IsSome)
                        {
                            ShowMetadata metadata = maybeMetadata.ValueUnsafe();
                            string       poster   = Optional(metadata.Artwork).Flatten()
                                                    .Filter(a => a.ArtworkKind == ArtworkKind.Poster)
                                                    .HeadOrNone()
                                                    .Match(
                                artwork => $"{_scheme}://{_host}/artwork/posters/{artwork.Path}",
                                () => string.Empty);

                            if (!string.IsNullOrWhiteSpace(poster))
                            {
                                xml.WriteStartElement("icon");
                                xml.WriteAttributeString("src", poster);
                                xml.WriteEndElement(); // icon
                            }
                        }

                        int s = Optional(episode.Season?.SeasonNumber).IfNone(0);
                        int e = episode.EpisodeNumber;
                        if (s > 0 && e > 0)
                        {
                            xml.WriteStartElement("episode-num");
                            xml.WriteAttributeString("system", "onscreen");
                            xml.WriteString($"S{s:00}E{e:00}");
                            xml.WriteEndElement(); // episode-num

                            xml.WriteStartElement("episode-num");
                            xml.WriteAttributeString("system", "xmltv_ns");
                            xml.WriteString($"{s - 1}.{e - 1}.0/1");
                            xml.WriteEndElement(); // episode-num
                        }
                    }

                    // sb.AppendLine("<icon src=\"\"/>");

                    if (!string.IsNullOrWhiteSpace(description))
                    {
                        xml.WriteStartElement("desc");
                        xml.WriteAttributeString("lang", "en");
                        xml.WriteString(description);
                        xml.WriteEndElement(); // desc
                    }

                    if (!string.IsNullOrWhiteSpace(contentRating))
                    {
                        xml.WriteStartElement("rating");
                        xml.WriteAttributeString("system", "MPAA");
                        xml.WriteStartElement("value");
                        xml.WriteString(contentRating);
                        xml.WriteEndElement(); // value
                        xml.WriteEndElement(); // rating
                    }

                    xml.WriteEndElement(); // programme
                }
            }

            xml.WriteEndElement(); // tv
            xml.WriteEndDocument();

            xml.Flush();
            return(Encoding.UTF8.GetString(ms.ToArray()));
        }
    }
}
Пример #28
0
 internal static TelevisionShowCardViewModel ProjectToViewModel(ShowMetadata showMetadata) =>