Example #1
0
    static SeriesInfo ParseSeries(Match ma)
    {
      SeriesInfo info = new SeriesInfo();
      Group group = ma.Groups[GROUP_SERIES];
      if (group.Length > 0)
        info.Series = SeriesInfo.CleanupWhiteSpaces(group.Value);

      group = ma.Groups[GROUP_EPISODE];
      if (group.Length > 0)
        info.Episode = SeriesInfo.CleanupWhiteSpaces(group.Value);

      group = ma.Groups[GROUP_SEASONNUM];
      int tmpInt;
      if (group.Length > 0 && int.TryParse(group.Value, out tmpInt))
        info.SeasonNumber = tmpInt;

      // There can be multipe episode numbers in one file
      group = ma.Groups[GROUP_EPISODENUM];
      if (group.Length > 0)
      {
        foreach (Capture capture in group.Captures)
        {
          int episodeNum;
          if (int.TryParse(capture.Value, out episodeNum))
            info.EpisodeNumbers.Add(episodeNum);
        }
      }
      return info;
    }
Example #2
0
 /// <summary>
 /// Tries to match series by checking the <paramref name="folderOrFileName"/> for known patterns. The match is only successful,
 /// if the <see cref="SeriesInfo.IsCompleteMatch"/> is <c>true</c>.
 /// </summary>
 /// <param name="folderOrFileName">Full path to file</param>
 /// <param name="seriesInfo">Returns the parsed SeriesInfo</param>
 /// <returns><c>true</c> if successful.</returns>
 public bool MatchSeries(string folderOrFileName, out SeriesInfo seriesInfo)
 {
   foreach (Regex matcher in _matchers)
   {
     Match ma = matcher.Match(folderOrFileName);
     seriesInfo = ParseSeries(ma);
     if (seriesInfo.IsCompleteMatch)
       return true;
   }
   seriesInfo = null;
   return false;
 }
Example #3
0
 /// <summary>
 /// Tries to match series by checking the <paramref name="folderOrFileName"/> for known patterns. The match is only successful,
 /// if the <see cref="SeriesInfo.IsCompleteMatch"/> is <c>true</c>.
 /// </summary>
 /// <param name="folderOrFileName">Full path to file</param>
 /// <param name="seriesInfo">Returns the parsed SeriesInfo</param>
 /// <returns><c>true</c> if successful.</returns>
 public bool MatchSeries(string folderOrFileName, out SeriesInfo seriesInfo)
 {
   foreach (Regex matcher in _matchers)
   {
     // Calling EnsureLocalFileSystemAccess not necessary; only string operation
     Match ma = matcher.Match(folderOrFileName);
     seriesInfo = ParseSeries(ma);
     if (seriesInfo.IsCompleteMatch)
       return true;
   }
   seriesInfo = null;
   return false;
 }
Example #4
0
    /// <summary>
    /// Tries to match series by reading matroska tags from <paramref name="folderOrFileLfsra"/>.
    /// </summary>
    /// <param name="folderOrFileLfsra"><see cref="ILocalFsResourceAccessor"/> to file or folder</param>
    /// <param name="seriesInfo">Returns the parsed SeriesInfo</param>
    /// <param name="extractedAspectData">Dictionary containing a mapping of media item aspect ids to
    /// already present media item aspects, this metadata extractor should edit. If a media item aspect is not present
    /// in this dictionary but found by this metadata extractor, it will add it to the dictionary.</param>
    /// <returns><c>true</c> if successful.</returns>
    public bool MatchSeries(ILocalFsResourceAccessor folderOrFileLfsra, out SeriesInfo seriesInfo, ref IDictionary<Guid, MediaItemAspect> extractedAspectData)
    {
      // Calling EnsureLocalFileSystemAccess not necessary; only string operation
      string extensionLower = StringUtils.TrimToEmpty(Path.GetExtension(folderOrFileLfsra.LocalFileSystemPath)).ToLower();

      if (!MatroskaConsts.MATROSKA_VIDEO_EXTENSIONS.Contains(extensionLower))
      {
        seriesInfo = null;
        return false;
      }

      MatroskaInfoReader mkvReader = new MatroskaInfoReader(folderOrFileLfsra);
      // Add keys to be extracted to tags dictionary, matching results will returned as value
      Dictionary<string, IList<string>> tagsToExtract = MatroskaConsts.DefaultTags;
      mkvReader.ReadTags(tagsToExtract);

      string title = string.Empty;
      IList<string> tags = tagsToExtract[MatroskaConsts.TAG_SIMPLE_TITLE];
      if (tags != null)
        title = tags.FirstOrDefault();

      if (!string.IsNullOrEmpty(title))
        MediaItemAspect.SetAttribute(extractedAspectData, MediaAspect.ATTR_TITLE, title);

      string yearCandidate = null;
      tags = tagsToExtract[MatroskaConsts.TAG_EPISODE_YEAR] ?? tagsToExtract[MatroskaConsts.TAG_SEASON_YEAR];
      if (tags != null)
        yearCandidate = (tags.FirstOrDefault() ?? string.Empty).Substring(0, 4);

      int year;
      if (int.TryParse(yearCandidate, out year))
        MediaItemAspect.SetAttribute(extractedAspectData, MediaAspect.ATTR_RECORDINGTIME, new DateTime(year, 1, 1));

      tags = tagsToExtract[MatroskaConsts.TAG_EPISODE_SUMMARY];
      string plot = tags != null ? tags.FirstOrDefault() : string.Empty;
      if (!string.IsNullOrEmpty(plot))
        MediaItemAspect.SetAttribute(extractedAspectData, VideoAspect.ATTR_STORYPLOT, plot);

      // Series and episode handling. Prefer information from tags.
      seriesInfo = GetSeriesFromTags(tagsToExtract);

      return true;
    }
Example #5
0
    public SeriesItem(MediaItem mediaItem) : base(mediaItem)
    {
      SeriesInfo seriesInfo = new SeriesInfo();
      MediaItemAspect seriesAspect;
      if (!mediaItem.Aspects.TryGetValue(SeriesAspect.ASPECT_ID, out seriesAspect)) 
        return;

      Series = seriesInfo.Series = (string) seriesAspect[SeriesAspect.ATTR_SERIESNAME] ?? string.Empty;
      EpisodeName = seriesInfo.Episode = (string) seriesAspect[SeriesAspect.ATTR_EPISODENAME] ?? string.Empty;
      seriesInfo.SeasonNumber = (int) (seriesAspect[SeriesAspect.ATTR_SEASON] ?? 0);
      Season = seriesInfo.SeasonNumber.ToString();

      IList<int> episodes = seriesAspect[SeriesAspect.ATTR_EPISODE] as IList<int>;
      if (episodes != null)
      {
        foreach (int episode in episodes)
          seriesInfo.EpisodeNumbers.Add(episode);
        EpisodeNumber = seriesInfo.FormatString(string.Format("{{{0}}}", SeriesInfo.EPISODENUM_INDEX));
      }
      // Use the short string without series name here
      SimpleTitle = seriesInfo.ToShortString();
    }
Example #6
0
    /// <summary>
    /// Tries to match series by checking the <paramref name="folderOrFileName"/> for known patterns. The match is only successful,
    /// if the <see cref="SeriesInfo.IsCompleteMatch"/> is <c>true</c>.
    /// </summary>
    /// <param name="folderOrFileName">Full path to file</param>
    /// <param name="seriesInfo">Returns the parsed SeriesInfo</param>
    /// <returns><c>true</c> if successful.</returns>
    public bool MatchSeries(string folderOrFileName, out SeriesInfo seriesInfo)
    {
      var settings = ServiceRegistration.Get<ISettingsManager>().Load<SeriesMetadataExtractorSettings>();

      // First do replacements before match
      foreach (var replacement in settings.Replacements.Where(r => r.BeforeMatch))
      {
        replacement.Replace(ref folderOrFileName);
      }

      foreach (var pattern in settings.Patterns)
      {
        // Calling EnsureLocalFileSystemAccess not necessary; only string operation
        Regex matcher;
        if (pattern.GetRegex(out matcher))
        {
          Match ma = matcher.Match(folderOrFileName);
          seriesInfo = ParseSeries(ma);
          if (seriesInfo.IsCompleteMatch)
          {
            // Do replacements after successful match
            foreach (var replacement in settings.Replacements.Where(r => !r.BeforeMatch))
            {
              string tmp = seriesInfo.Series;
              replacement.Replace(ref tmp);
              seriesInfo.Series = tmp;

              tmp = seriesInfo.Episode;
              replacement.Replace(ref tmp);
              seriesInfo.Episode = tmp;
            }
            return true;
          }
        }
      }
      seriesInfo = null;
      return false;
    }
    protected SeriesInfo GetSeriesFromTags(IDictionary<string, IList<string>> extractedTags)
    {
      SeriesInfo seriesInfo = new SeriesInfo();
      if (extractedTags[MatroskaConsts.TAG_EPISODE_TITLE] != null)
        seriesInfo.Episode = extractedTags[MatroskaConsts.TAG_EPISODE_TITLE].FirstOrDefault();

      if (extractedTags[MatroskaConsts.TAG_SERIES_TITLE] != null)
        seriesInfo.Series = extractedTags[MatroskaConsts.TAG_SERIES_TITLE].FirstOrDefault();

      if (extractedTags[MatroskaConsts.TAG_SEASON_NUMBER] != null)
        int.TryParse(extractedTags[MatroskaConsts.TAG_SEASON_NUMBER].FirstOrDefault(), out seriesInfo.SeasonNumber);

      if (extractedTags[MatroskaConsts.TAG_EPISODE_NUMBER] != null)
      {
        int episodeNum;
        if (int.TryParse(extractedTags[MatroskaConsts.TAG_EPISODE_NUMBER].FirstOrDefault(), out episodeNum))
          seriesInfo.EpisodeNumbers.Add(episodeNum);
      }
      return seriesInfo;
    }
Example #8
0
 /// <summary>
 /// Tries to match series by checking the <paramref name="folderOrFileLfsra"/> for known patterns. The match is only successful,
 /// if the <see cref="SeriesInfo.IsCompleteMatch"/> is <c>true</c>.
 /// </summary>
 /// <param name="folderOrFileLfsra"><see cref="ILocalFsResourceAccessor"/> to file</param>
 /// <param name="seriesInfo">Returns the parsed SeriesInfo</param>
 /// <returns><c>true</c> if successful.</returns>
 public bool MatchSeries(ILocalFsResourceAccessor folderOrFileLfsra, out SeriesInfo seriesInfo)
 {
   return MatchSeries(folderOrFileLfsra.LocalFileSystemPath, out seriesInfo);
 }
    public SeriesInfo GetSeriesFromTags(Tags extractedTags)
    {
      SeriesInfo seriesInfo = new SeriesInfo();
      string tmpString;

      if (TryGet(extractedTags, TAG_TITLE, out tmpString))
        seriesInfo.Series = tmpString;

      if (TryGet(extractedTags, TAG_EPISODENAME, out tmpString))
        seriesInfo.Episode = tmpString;

      if (TryGet(extractedTags, TAG_SERIESNUM, out tmpString))
        int.TryParse(tmpString, out seriesInfo.SeasonNumber);

      if (TryGet(extractedTags, TAG_EPISODENUM, out tmpString))
      {
        int episodeNum;
        if (int.TryParse(tmpString, out episodeNum))
          seriesInfo.EpisodeNumbers.Add(episodeNum);
      }
      return seriesInfo;
    }
Example #10
0
    protected SeriesInfo GetSeriesFromTags(IDictionary<string, IList<string>> extractedTags)
    {
      SeriesInfo seriesInfo = new SeriesInfo();
      if (extractedTags[MatroskaConsts.TAG_EPISODE_TITLE] != null)
        seriesInfo.Episode = extractedTags[MatroskaConsts.TAG_EPISODE_TITLE].FirstOrDefault();

      if (extractedTags[MatroskaConsts.TAG_SERIES_TITLE] != null)
        seriesInfo.Series = extractedTags[MatroskaConsts.TAG_SERIES_TITLE].FirstOrDefault();

      if (extractedTags[MatroskaConsts.TAG_SERIES_IMDB_ID] != null)
      {
        string imdbId;
        foreach (string candidate in extractedTags[MatroskaConsts.TAG_SERIES_IMDB_ID])
          if (ImdbIdMatcher.TryMatchImdbId(candidate, out imdbId))
          { 
            seriesInfo.ImdbId = imdbId; 
            break;
          }
      }

      // On Series, the counting tag is "TVDB"
      if (extractedTags[MatroskaConsts.TAG_SERIES_TVDB_ID] != null)
      {
        int tmp;
        foreach (string candidate in extractedTags[MatroskaConsts.TAG_SERIES_TVDB_ID])
          if(int.TryParse(candidate, out tmp) == true)
          {
            seriesInfo.TvdbId = tmp;
            break;
          }
      }

      int tmpInt;
      if (extractedTags[MatroskaConsts.TAG_SEASON_NUMBER] != null && int.TryParse(extractedTags[MatroskaConsts.TAG_SEASON_NUMBER].FirstOrDefault(), out tmpInt))
        seriesInfo.SeasonNumber = tmpInt; 

      if (extractedTags[MatroskaConsts.TAG_EPISODE_NUMBER] != null)
      {
        int episodeNum;

        foreach (string s in extractedTags[MatroskaConsts.TAG_EPISODE_NUMBER])
          if (int.TryParse(s, out episodeNum))
            if (!seriesInfo.EpisodeNumbers.Contains(episodeNum))
              seriesInfo.EpisodeNumbers.Add(episodeNum);
      }
      return seriesInfo;
    }
    public SeriesInfo GetSeriesFromTags(Argus.Recording recording)
    {
      SeriesInfo seriesInfo = new SeriesInfo { Series = recording.Title };

      if (recording.SeriesNumber.HasValue)
        seriesInfo.SeasonNumber = recording.SeriesNumber.Value;

      if (recording.EpisodeNumber.HasValue)
        seriesInfo.EpisodeNumbers.Add(recording.EpisodeNumber.Value);

      if (!seriesInfo.IsCompleteMatch)
      {
        // Check for formatted display value, i.e.:
        // <EpisodeNumberDisplay>1.4</EpisodeNumberDisplay>
        if (!string.IsNullOrWhiteSpace(recording.EpisodeNumberDisplay))
        {
          var parts = recording.EpisodeNumberDisplay.Split('.');
          if (parts.Length == 2)
          {
            int val;
            if (int.TryParse(parts[0], out val))
              seriesInfo.SeasonNumber = val;
            if (int.TryParse(parts[1], out val))
              seriesInfo.EpisodeNumbers.Add(val);
          }
        }
      }
      return seriesInfo;
    }
    protected bool ExtractSeriesData(ILocalFsResourceAccessor lfsra, IDictionary<Guid, MediaItemAspect> extractedAspectData)
    {
      // VideoAspect must be present to be sure it is actually a video resource.
      if (!extractedAspectData.ContainsKey(VideoAspect.ASPECT_ID))
        return false;

      SeriesInfo seriesInfo = null;

      // First check if we already have a complete match from a previous MDE
      string title;
      int tvDbId;
      int seasonNumber;
      IEnumerable<int> episodeNumbers;
      if (MediaItemAspect.TryGetAttribute(extractedAspectData, MediaAspect.ATTR_TITLE, out title) &&
          MediaItemAspect.TryGetAttribute(extractedAspectData, SeriesAspect.ATTR_TVDB_ID, out tvDbId) &&
          MediaItemAspect.TryGetAttribute(extractedAspectData, SeriesAspect.ATTR_SEASON, out seasonNumber) &&
          (episodeNumbers = extractedAspectData[SeriesAspect.ASPECT_ID].GetCollectionAttribute<int>(SeriesAspect.ATTR_EPISODE)) != null)
      {
        seriesInfo = new SeriesInfo
        {
          Series = title,
          TvdbId = tvDbId,
          SeasonNumber = seasonNumber,
        };
        episodeNumbers.ToList().ForEach(n => seriesInfo.EpisodeNumbers.Add(n));
      }

      // If there was no complete match, yet, try to get extended information out of matroska files)
      if (seriesInfo == null || !seriesInfo.IsCompleteMatch)
      {
        MatroskaMatcher matroskaMatcher = new MatroskaMatcher();
        if (matroskaMatcher.MatchSeries(lfsra, out seriesInfo, ref extractedAspectData))
        {
          ServiceRegistration.Get<ILogger>().Debug("ExtractSeriesData: Found SeriesInformation by MatroskaMatcher for {0}, IMDB {1}, TVDB {2}, IsCompleteMatch {3}",
            seriesInfo.Series, seriesInfo.ImdbId, seriesInfo.TvdbId, seriesInfo.IsCompleteMatch);
        }
      }

      // If no information was found before, try name matching
      if (seriesInfo == null || !seriesInfo.IsCompleteMatch)
      {
        // Try to match series from folder and file namings
        SeriesMatcher seriesMatcher = new SeriesMatcher();
        seriesMatcher.MatchSeries(lfsra, out seriesInfo);
      }

      // Lookup online information (incl. fanart)
      if (seriesInfo != null && seriesInfo.IsCompleteMatch)
      {
        SeriesTvDbMatcher.Instance.FindAndUpdateSeries(seriesInfo);
        if (!_onlyFanArt)
          seriesInfo.SetMetadata(extractedAspectData);
      }
      return (seriesInfo != null && seriesInfo.IsCompleteMatch && !_onlyFanArt);
    }