public override void ProcessCommand() { logger.Info("Reading Media Info for File: {0}", VideoLocalID); try { VideoLocal vlocal = RepoFactory.VideoLocal.GetByID(VideoLocalID); VideoLocal_Place place = vlocal?.GetBestVideoLocalPlace(); if (place == null) { logger.Error("Cound not find Video: {0}", VideoLocalID); return; } if (place.RefreshMediaInfo()) { RepoFactory.VideoLocal.Save(place.VideoLocal, true); } } catch (Exception ex) { logger.Error("Error processing CommandRequest_ReadMediaInfo: {0} - {1}", VideoLocalID, ex.ToString()); return; } }
public List <Stream> Process(VideoLocal_Place vplace) { string dirname = Path.GetDirectoryName(vplace.FullServerPath); string fname = Path.GetFileNameWithoutExtension(vplace.FilePath); if (string.IsNullOrEmpty(dirname) || string.IsNullOrEmpty(fname)) { return(null); } string basename = Path.Combine(dirname, fname); HashSet <string> extensions = new HashSet <string>(SubtitleHelper.Extensions.Keys); extensions.Remove("idx"); List <Stream> streams = new List <Stream>(); foreach (string n in extensions) { string newname = basename + "." + n; FileSystemResult <IObject> r = vplace.ImportFolder.FileSystem.Resolve(newname); if (r != null && r.IsOk && r.Result is IFile) { List <Stream> ss = GetStreams((IFile)r.Result); if ((ss != null) && (ss.Count > 0)) { streams.AddRange(ss); } } } return(streams); }
public List <Stream> Process(VideoLocal_Place vplace) { string dirname = Path.GetDirectoryName(vplace.FullServerPath); string fname = Path.GetFileNameWithoutExtension(vplace.FilePath); if (string.IsNullOrEmpty(dirname) || string.IsNullOrEmpty(fname)) { return(null); } string basename = Path.Combine(dirname, fname); List <Stream> streams = new List <Stream>(); if (File.Exists(basename + ".idx") && File.Exists(basename + ".sub")) { FileSystemResult <IObject> r = vplace.ImportFolder.FileSystem.Resolve(basename + ".sub"); if (r != null && r.IsOk && r.Result is IFile) { List <Stream> ss = GetStreams((IFile)r.Result); if ((ss != null) && (ss.Count > 0)) { streams.AddRange(ss); } } } return(streams); }
public static List <Stream> GetSubtitleStreams(VideoLocal_Place vplace) { List <Stream> ls = new VobSubSubtitles().Process(vplace); ls.AddRange(new TextSubtitles().Process(vplace)); return(ls); }
private void UpdateMediaContracts(VideoLocal obj) { if (obj.Media == null || obj.MediaVersion < VideoLocal.MEDIA_VERSION || obj.Duration == 0) { VideoLocal_Place place = obj.GetBestVideoLocalPlace(); place?.RefreshMediaInfo(); } }
public static Video VideoFromVideoLocal(IProvider prov, VideoLocal v, int userid) { Video l = new Video(); l.AnimeType = JMMContracts.PlexAndKodi.AnimeTypes.AnimeFile.ToString(); l.Id = v.VideoLocalID.ToString(); l.Type = "episode"; l.Summary = "Episode Overview Not Available"; //TODO Intenationalization l.Title = Path.GetFileNameWithoutExtension(v.FileName); l.AddedAt = v.DateTimeCreated.ToUnixTime(); l.UpdatedAt = v.DateTimeUpdated.ToUnixTime(); l.OriginallyAvailableAt = v.DateTimeCreated.ToPlexDate(); l.Year = v.DateTimeCreated.Year.ToString(); l.Medias = new List <Media>(); VideoLocal_User vlr = v.GetUserRecord(userid); if (vlr != null) { if (vlr.WatchedDate.HasValue) { l.LastViewedAt = vlr.WatchedDate.Value.ToUnixTime(); } if (vlr.ResumePosition > 0) { l.ViewOffset = vlr.ResumePosition.ToString(); } } Media m = v.Media; if (string.IsNullOrEmpty(m?.Duration)) { VideoLocal_Place pl = v.GetBestVideoLocalPlace(); if (pl != null) { if (pl.RefreshMediaInfo()) { RepoFactory.VideoLocal.Save(v, true); } } m = v.Media; } if (m != null) { l.Medias.Add(m); l.Duration = m.Duration; } AddLinksToAnimeEpisodeVideo(prov, l, userid); return(l); }
public static void FixEmptyVideoInfos() { List <VideoLocal> locals = RepoFactory.VideoLocal.GetAll().Where(a => string.IsNullOrEmpty(a.FileName)).ToList(); foreach (VideoLocal v in locals) { VideoLocal_Place p = v.Places.OrderBy(a => a.ImportFolderType).FirstOrDefault(); if (p != null && !string.IsNullOrEmpty(p.FilePath) && v.Media != null) { v.FileName = p.FilePath; int a = p.FilePath.LastIndexOf("\\", StringComparison.InvariantCulture); if (a > 0) { v.FileName = p.FilePath.Substring(a + 1); } VideoLocal_Place.FillVideoInfoFromMedia(v, v.Media); RepoFactory.VideoLocal.Save(v, false); } } }
private VideoLocal_Place ProcessFile_LocalInfo() { // hash and read media info for file int nshareID = -1; string filePath = ""; Tuple <ImportFolder, string> tup = VideoLocal_PlaceRepository.GetFromFullPath(FileName); if (tup == null) { logger.Error($"Unable to locate file {FileName} inside the import folders"); return(null); } ImportFolder folder = tup.Item1; filePath = tup.Item2; IFileSystem f = tup.Item1.FileSystem; if (f == null) { logger.Error("Unable to open filesystem for: {0}", FileName); return(null); } long filesize = 0; if (folder.CloudID == null) // Local Access { if (!File.Exists(FileName)) { logger.Error("File does not exist: {0}", FileName); return(null); } int numAttempts = 0; // Wait 3 minutes seconds before giving up on trying to access the file while ((filesize = CanAccessFile(FileName)) == 0 && (numAttempts < 180)) { numAttempts++; Thread.Sleep(1000); Console.WriteLine("Attempt # " + numAttempts.ToString()); } // if we failed to access the file, get ouuta here if (numAttempts == 180) { logger.Error("Could not access file: " + FileName); return(null); } } FileSystemResult <IObject> source = f.Resolve(FileName); if (source == null || !source.IsOk || (!(source.Result is IFile))) { logger.Error("Could not access file: " + FileName); return(null); } IFile source_file = (IFile)source.Result; if (folder.CloudID.HasValue) { filesize = source_file.Size; } nshareID = folder.ImportFolderID; // check if we have already processed this file VideoLocal_Place vlocalplace = RepoFactory.VideoLocalPlace.GetByFilePathAndShareID(filePath, nshareID); VideoLocal vlocal; if (vlocalplace != null) { vlocal = vlocalplace.VideoLocal; logger.Trace("VideoLocal record found in database: {0}", vlocal.VideoLocalID); if (ForceHash) { vlocal.FileSize = filesize; vlocal.DateTimeUpdated = DateTime.Now; } } else { logger.Trace("VideoLocal, creating temporary record"); vlocal = new VideoLocal(); vlocal.DateTimeUpdated = DateTime.Now; vlocal.DateTimeCreated = vlocal.DateTimeUpdated; vlocal.FileName = Path.GetFileName(filePath); vlocal.FileSize = filesize; vlocal.Hash = string.Empty; vlocal.CRC32 = string.Empty; vlocal.MD5 = source_file.MD5.ToUpperInvariant() ?? string.Empty; vlocal.SHA1 = source_file.SHA1.ToUpperInvariant() ?? string.Empty; vlocal.IsIgnored = 0; vlocal.IsVariation = 0; vlocalplace = new VideoLocal_Place(); vlocalplace.FilePath = filePath; vlocalplace.ImportFolderID = nshareID; vlocalplace.ImportFolderType = folder.ImportFolderType; } // check if we need to get a hash this file Hashes hashes = null; if (string.IsNullOrEmpty(vlocal.Hash) || ForceHash) { // try getting the hash from the CrossRef if (!ForceHash) { List <CrossRef_File_Episode> crossRefs = RepoFactory.CrossRef_File_Episode.GetByFileNameAndSize(vlocal.FileName, vlocal.FileSize); if (crossRefs.Count == 1) { vlocal.Hash = crossRefs[0].Hash; vlocal.HashSource = (int)HashSource.DirectHash; } } // try getting the hash from the LOCAL cache if (!ForceHash && string.IsNullOrEmpty(vlocal.Hash)) { List <FileNameHash> fnhashes = RepoFactory.FileNameHash.GetByFileNameAndSize(vlocal.FileName, vlocal.FileSize); if (fnhashes != null && fnhashes.Count > 1) { // if we have more than one record it probably means there is some sort of corruption // lets delete the local records foreach (FileNameHash fnh in fnhashes) { RepoFactory.FileNameHash.Delete(fnh.FileNameHashID); } } if (fnhashes != null && fnhashes.Count == 1) { logger.Trace("Got hash from LOCAL cache: {0} ({1})", FileName, fnhashes[0].Hash); vlocal.Hash = fnhashes[0].Hash; vlocal.HashSource = (int)HashSource.WebCacheFileName; } } if (string.IsNullOrEmpty(vlocal.Hash)) { FillVideoHashes(vlocal); } if (string.IsNullOrEmpty(vlocal.Hash) && folder.CloudID.HasValue) { //Cloud and no hash, Nothing to do, except maybe Get the mediainfo.... logger.Trace("No Hash found for cloud " + vlocal.FileName + " putting in videolocal table with empty ED2K"); RepoFactory.VideoLocal.Save(vlocal, false); vlocalplace.VideoLocalID = vlocal.VideoLocalID; RepoFactory.VideoLocalPlace.Save(vlocalplace); if (vlocalplace.RefreshMediaInfo()) { RepoFactory.VideoLocal.Save(vlocalplace.VideoLocal, true); } return(vlocalplace); } // hash the file if (string.IsNullOrEmpty(vlocal.Hash) || ForceHash) { JMMService.CmdProcessorHasher.QueueState = PrettyDescriptionHashing; DateTime start = DateTime.Now; logger.Trace("Calculating ED2K hashes for: {0}", FileName); // update the VideoLocal record with the Hash, since cloud support we calculate everything hashes = FileHashHelper.GetHashInfo(FileName.Replace("/", "\\"), true, MainWindow.OnHashProgress, true, true, true); TimeSpan ts = DateTime.Now - start; logger.Trace("Hashed file in {0} seconds --- {1} ({2})", ts.TotalSeconds.ToString("#0.0"), FileName, Utils.FormatByteSize(vlocal.FileSize)); vlocal.Hash = hashes.ed2k?.ToUpperInvariant(); vlocal.CRC32 = hashes.crc32?.ToUpperInvariant(); vlocal.MD5 = hashes.md5?.ToUpperInvariant(); vlocal.SHA1 = hashes.sha1?.ToUpperInvariant(); vlocal.HashSource = (int)HashSource.DirectHash; } FillMissingHashes(vlocal); // We should have a hash by now // before we save it, lets make sure there is not any other record with this hash (possible duplicate file) VideoLocal tlocal = RepoFactory.VideoLocal.GetByHash(vlocal.Hash); bool intercloudfolder = false; VideoLocal_Place prep = tlocal?.Places.FirstOrDefault(a => a.ImportFolder.CloudID == folder.CloudID && a.ImportFolderID == folder.ImportFolderID && vlocalplace.VideoLocal_Place_ID != a.VideoLocal_Place_ID); if (prep != null) { // delete the VideoLocal record logger.Warn("Deleting duplicate video file record"); logger.Warn("---------------------------------------------"); logger.Warn($"Keeping record for: {vlocalplace.FullServerPath}"); logger.Warn($"Deleting record for: {prep.FullServerPath}"); logger.Warn("---------------------------------------------"); // check if we have a record of this in the database, if not create one List <DuplicateFile> dupFiles = RepoFactory.DuplicateFile.GetByFilePathsAndImportFolder(vlocalplace.FilePath, prep.FilePath, vlocalplace.ImportFolderID, prep.ImportFolderID); if (dupFiles.Count == 0) { dupFiles = RepoFactory.DuplicateFile.GetByFilePathsAndImportFolder(prep.FilePath, vlocalplace.FilePath, prep.ImportFolderID, vlocalplace.ImportFolderID); } if (dupFiles.Count == 0) { DuplicateFile dup = new DuplicateFile(); dup.DateTimeUpdated = DateTime.Now; dup.FilePathFile1 = vlocalplace.FilePath; dup.FilePathFile2 = prep.FilePath; dup.ImportFolderIDFile1 = vlocalplace.ImportFolderID; dup.ImportFolderIDFile2 = prep.ImportFolderID; dup.Hash = vlocal.Hash; RepoFactory.DuplicateFile.Save(dup); } //Notify duplicate, don't delete } else if (tlocal != null) { vlocal = tlocal; intercloudfolder = true; } if (!intercloudfolder) { RepoFactory.VideoLocal.Save(vlocal, true); } vlocalplace.VideoLocalID = vlocal.VideoLocalID; RepoFactory.VideoLocalPlace.Save(vlocalplace); if (intercloudfolder) { CommandRequest_ProcessFile cr_procfile3 = new CommandRequest_ProcessFile(vlocal.VideoLocalID, false); cr_procfile3.Save(); return(vlocalplace); } // also save the filename to hash record // replace the existing records just in case it was corrupt FileNameHash fnhash = null; List <FileNameHash> fnhashes2 = RepoFactory.FileNameHash.GetByFileNameAndSize(vlocal.FileName, vlocal.FileSize); if (fnhashes2 != null && fnhashes2.Count > 1) { // if we have more than one record it probably means there is some sort of corruption // lets delete the local records foreach (FileNameHash fnh in fnhashes2) { RepoFactory.FileNameHash.Delete(fnh.FileNameHashID); } } if (fnhashes2 != null && fnhashes2.Count == 1) { fnhash = fnhashes2[0]; } else { fnhash = new FileNameHash(); } fnhash.FileName = vlocal.FileName; fnhash.FileSize = vlocal.FileSize; fnhash.Hash = vlocal.Hash; fnhash.DateTimeUpdated = DateTime.Now; RepoFactory.FileNameHash.Save(fnhash); } else { FillMissingHashes(vlocal); } if ((vlocal.Media == null) || vlocal.MediaVersion < VideoLocal.MEDIA_VERSION || vlocal.Duration == 0) { if (vlocalplace.RefreshMediaInfo()) { RepoFactory.VideoLocal.Save(vlocalplace.VideoLocal, true); } } // now add a command to process the file CommandRequest_ProcessFile cr_procfile = new CommandRequest_ProcessFile(vlocal.VideoLocalID, false); cr_procfile.Save(); return(vlocalplace); }
public RawFile(NancyContext ctx, SVR_VideoLocal vl, int level, int uid) { if (vl != null) { id = vl.VideoLocalID; crc32 = vl.CRC32; ed2khash = vl.ED2KHash; md5 = vl.MD5; sha1 = vl.SHA1; created = vl.DateTimeCreated; updated = vl.DateTimeUpdated; duration = vl.Duration; if (vl.ReleaseGroup != null) { group_full = vl.ReleaseGroup.GroupName; group_short = vl.ReleaseGroup.GroupNameShort; group_id = vl.ReleaseGroup.AniDB_ReleaseGroupID; } size = vl.FileSize; hash = vl.Hash; hash_source = vl.HashSource; is_ignored = vl.IsIgnored; VideoLocal_User vl_user = vl.GetUserRecord(uid); if (vl_user != null) { offset = vl_user.ResumePosition; } else { offset = 0; } VideoLocal_Place place = vl.GetBestVideoLocalPlace(); if (place != null) { filename = place.FilePath; videolocal_place_id = place.VideoLocal_Place_ID; import_folder_id = place.ImportFolderID; } if (vl.EpisodeCrossRefs.Count == 0) { recognized = false; } else { recognized = true; } if (vl.Media != null && (level > 1 || level == 0)) { media = new MediaInfo(); url = APIHelper.ConstructVideoLocalStream(ctx, uid, vl.Media.Id, "file." + vl.Media.Container, false); MediaInfo new_media = new MediaInfo(); new_media.AddGeneral(MediaInfo.General.format, vl.Media.Container); new_media.AddGeneral(MediaInfo.General.duration, vl.Media.Duration); new_media.AddGeneral(MediaInfo.General.id, vl.Media.Id); new_media.AddGeneral(MediaInfo.General.overallbitrate, vl.Media.Bitrate); if (vl.Media.Parts != null) { new_media.AddGeneral(MediaInfo.General.size, vl.Media.Parts[0].Size); foreach (Shoko.Models.PlexAndKodi.Stream p in vl.Media.Parts[0].Streams) { switch (p.StreamType) { //video case "1": new_media.AddVideo(p); break; //audio case "2": new_media.AddAudio(p); break; //subtitle case "3": new_media.AddSubtitle(p); break; //menu case "4": Dictionary <string, string> mdict = new Dictionary <string, string>(); //TODO APIv2: menu object could be usefull for external players new_media.AddMenu(mdict); break; } } } media = new_media; } } }
public static Video GenerateVideoFromAnimeEpisode(AnimeEpisode ep) { Video l = new Video(); List <VideoLocal> vids = ep.GetVideoLocals(); l.Type = "episode"; l.Summary = "Episode Overview Not Available"; //TODO Intenationalization l.Id = ep.AnimeEpisodeID.ToString(); l.AnimeType = JMMContracts.PlexAndKodi.AnimeTypes.AnimeEpisode.ToString(); if (vids.Count > 0) { //List<string> hashes = vids.Select(a => a.Hash).Distinct().ToList(); l.Title = Path.GetFileNameWithoutExtension(vids[0].FileName); l.AddedAt = vids[0].DateTimeCreated.ToUnixTime(); l.UpdatedAt = vids[0].DateTimeUpdated.ToUnixTime(); l.OriginallyAvailableAt = vids[0].DateTimeCreated.ToPlexDate(); l.Year = vids[0].DateTimeCreated.Year.ToString(); l.Medias = new List <Media>(); foreach (VideoLocal v in vids) { if (string.IsNullOrEmpty(v.Media?.Duration)) { VideoLocal_Place pl = v.GetBestVideoLocalPlace(); if (pl != null) { if (pl.RefreshMediaInfo()) { RepoFactory.VideoLocal.Save(v, true); } } } if (v.Media != null) { l.Medias.Add(v.Media); } } } AniDB_Episode aep = ep?.AniDB_Episode; if (aep != null) { l.EpisodeNumber = aep.EpisodeNumber.ToString(); l.Index = aep.EpisodeNumber.ToString(); l.Title = aep.EnglishName; l.OriginalTitle = aep.RomajiName; l.EpisodeType = aep.EpisodeType.ToString(); l.Rating = float.Parse(aep.Rating, CultureInfo.InvariantCulture).ToString(CultureInfo.InvariantCulture); if (aep.AirDateAsDate.HasValue) { l.Year = aep.AirDateAsDate.Value.Year.ToString(); l.OriginallyAvailableAt = aep.AirDateAsDate.Value.ToPlexDate(); } //FIX THIS MetroContract_Anime_Episode contract = new MetroContract_Anime_Episode(); JMMServiceImplementationMetro.SetTvDBInfo(aep.AnimeID, aep, ref contract); l.Thumb = contract.GenPoster(); l.Summary = contract.EpisodeOverview; } l.Id = ep.AnimeEpisodeID.ToString(); return(l); }
public static Video VideoFromAnimeEpisode(IProvider prov, List <Contract_CrossRef_AniDB_TvDBV2> cross, KeyValuePair <AnimeEpisode, Contract_AnimeEpisode> e, int userid) { Video v = (Video)e.Key.PlexContract?.Clone <Video>(); if (v?.Thumb != null) { v.Thumb = ReplaceSchemeHost(v.Thumb); } if (v != null && (v.Medias == null || v.Medias.Count == 0)) { foreach (VideoLocal vl2 in e.Key.GetVideoLocals()) { if (string.IsNullOrEmpty(vl2.Media?.Duration)) { VideoLocal_Place pl = vl2.GetBestVideoLocalPlace(); if (pl != null) { if (pl.RefreshMediaInfo()) { RepoFactory.VideoLocal.Save(vl2, true); } } } } RepoFactory.AnimeEpisode.Save(e.Key); v = (Video)e.Key.PlexContract?.Clone <Video>(); } if (v != null) { if (e.Value != null) { v.ViewCount = e.Value.WatchedCount.ToString(); if (e.Value.WatchedDate.HasValue) { v.LastViewedAt = e.Value.WatchedDate.Value.ToUnixTime(); } } v.ParentIndex = "1"; if (e.Key.EpisodeTypeEnum != enEpisodeType.Episode) { v.ParentIndex = null; } if (cross != null && cross.Count > 0) { Contract_CrossRef_AniDB_TvDBV2 c2 = cross.FirstOrDefault( a => a.AniDBStartEpisodeType == int.Parse(v.EpisodeType) && a.AniDBStartEpisodeNumber <= int.Parse(v.EpisodeNumber)); if (c2?.TvDBSeasonNumber > 0) { v.ParentIndex = c2.TvDBSeasonNumber.ToString(); } } AddLinksToAnimeEpisodeVideo(prov, v, userid); } v.AddResumePosition(prov, userid); return(v); }
public static Video GenerateVideoFromAnimeEpisode(AnimeEpisode ep) { Video l = new Video(); List <VideoLocal> vids = ep.GetVideoLocals(); l.Type = "episode"; l.Summary = "Episode Overview Not Available"; //TODO Intenationalization l.Id = ep.AnimeEpisodeID.ToString(); l.AnimeType = JMMContracts.PlexAndKodi.AnimeTypes.AnimeEpisode.ToString(); if (vids.Count > 0) { //List<string> hashes = vids.Select(a => a.Hash).Distinct().ToList(); l.Title = Path.GetFileNameWithoutExtension(vids[0].FileName); l.AddedAt = vids[0].DateTimeCreated.ToUnixTime(); l.UpdatedAt = vids[0].DateTimeUpdated.ToUnixTime(); l.OriginallyAvailableAt = vids[0].DateTimeCreated.ToPlexDate(); l.Year = vids[0].DateTimeCreated.Year.ToString(); l.Medias = new List <Media>(); foreach (VideoLocal v in vids) { if (string.IsNullOrEmpty(v.Media?.Duration)) { VideoLocal_Place pl = v.GetBestVideoLocalPlace(); if (pl != null) { if (pl.RefreshMediaInfo()) { RepoFactory.VideoLocal.Save(v, true); } } } v.Media?.Parts?.Where(a => a != null)?.ToList()?.ForEach(a => { if (String.IsNullOrEmpty(a.LocalKey)) { a.LocalKey = v?.GetBestVideoLocalPlace()?.FullServerPath ?? null; } }); if (v.Media != null) { l.Medias.Add(v.Media); } } AniDB_Episode aep = ep?.AniDB_Episode; if (aep != null) { l.EpisodeNumber = aep.EpisodeNumber.ToString(); l.Index = aep.EpisodeNumber.ToString(); l.Title = aep.EnglishName; l.OriginalTitle = aep.RomajiName; l.EpisodeType = aep.EpisodeType.ToString(); l.Rating = float.Parse(aep.Rating, CultureInfo.InvariantCulture).ToString(CultureInfo.InvariantCulture); if (aep.AirDateAsDate.HasValue) { l.Year = aep.AirDateAsDate.Value.Year.ToString(); l.OriginallyAvailableAt = aep.AirDateAsDate.Value.ToPlexDate(); } #region TvDB using (var session = DatabaseFactory.SessionFactory.OpenSession()) { List <CrossRef_AniDB_TvDBV2> xref_tvdb2 = RepoFactory.CrossRef_AniDB_TvDBV2.GetByAnimeIDEpTypeEpNumber(session, aep.AnimeID, aep.EpisodeType, aep.EpisodeNumber); if (xref_tvdb2 != null && xref_tvdb2.Count > 0) { TvDB_Episode tvep = GetTvDBEpisodeFromAniDB(session, aep, xref_tvdb2[0]); if (tvep != null) { l.Thumb = tvep.GenPoster(); l.Summary = tvep.Overview; } else { string anime = "[Blank]"; AnimeSeries ser = ep.GetAnimeSeries(); if (ser != null && ser.GetSeriesName() != null) { anime = ser.GetSeriesName(); } LogManager.GetCurrentClassLogger().Error("Episode " + aep.EpisodeNumber + ": " + aep.EnglishName + " from " + anime + " is out of range for its TvDB Link. Please relink it."); } } } #endregion #region TvDB Overrides CrossRef_AniDB_TvDB_Episode xref_tvdb = RepoFactory.CrossRef_AniDB_TvDB_Episode.GetByAniDBEpisodeID(aep.AniDB_EpisodeID); if (xref_tvdb != null) { TvDB_Episode tvdb_ep = RepoFactory.TvDB_Episode.GetByTvDBID(xref_tvdb.TvDBEpisodeID); if (tvdb_ep != null) { l.Thumb = tvdb_ep.GenPoster(); l.Summary = tvdb_ep.Overview; } } #endregion } if (l.Thumb == null || l.Summary == null) { l.Thumb = ConstructSupportImageLink("plex_404.png"); l.Summary = "Episode Overview not Available"; } } l.Id = ep.AnimeEpisodeID.ToString(); return(l); }