Beispiel #1
0
        protected int CompareMediaFiles(SubtitleInfo subtitle, int matchPct)
        {
            int maxPct           = 0;
            var subtitleFileName = ResourcePath.GetFileNameWithoutExtension(subtitle.Name);

            foreach (var mediaFile in subtitle.MediaFiles)
            {
                int pct           = 0;
                var mediaFileName = ResourcePath.GetFileNameWithoutExtension(mediaFile.NativeResourcePath.FileName);

                //Compare file names
                if (subtitleFileName.Equals(mediaFileName, StringComparison.InvariantCultureIgnoreCase))
                {
                    return(100);
                }

                //Compare tags
                pct = Math.Max(CompareTags(subtitleFileName, mediaFileName), pct);

                //Compare letter pairs
                pct = Math.Max(CompareLetterPairs(subtitleFileName, mediaFileName), pct);

                maxPct = Math.Max(maxPct, pct);
            }
            return(maxPct + matchPct);
        }
Beispiel #2
0
            static void Test(string path, string dir, string filename, string filenameNoEx, string extension)
            {
                Assert.True(ResourcePath.GetDirectoryName(path).SequenceEqual(dir));
                Assert.True(ResourcePath.GetDirectoryName(path.AsSpan()).SequenceEqual(dir));

                Assert.True(ResourcePath.GetFileName(path).SequenceEqual(filename));
                Assert.True(ResourcePath.GetFileName(path.AsSpan()).SequenceEqual(filename));

                Assert.True(ResourcePath.GetFileNameWithoutExtension(path).SequenceEqual(filenameNoEx));
                Assert.True(ResourcePath.GetFileNameWithoutExtension(path.AsSpan()).SequenceEqual(filenameNoEx));

                Assert.True(ResourcePath.GetExtension(path).SequenceEqual(extension));
                Assert.True(ResourcePath.GetExtension(path.AsSpan()).SequenceEqual(extension));
            }
Beispiel #3
0
        protected virtual async Task <bool> SaveSubtitleAsync(SubtitleInfo subtitle, IDictionary <BaseSubtitleMatch <TId>, byte[]> downloads, bool overwriteExisting)
        {
            var mediaFile         = subtitle.MediaFiles.First();
            var namingTemplate    = ResourcePath.GetFileNameWithoutExtension(mediaFile.NativeResourcePath.FileName);
            var templatePartMatch = _regexMultiPartVideo.Match(namingTemplate);

            foreach (var subtitleMatch in downloads.Keys)
            {
                var    subPartMatch = _regexMultiPartVideo.Match(subtitleMatch.ItemName);
                string subName      = namingTemplate;
                if (subPartMatch.Success && templatePartMatch.Success)
                {
                    if (!int.TryParse(templatePartMatch.Groups["disc"].Value, out var _) || !int.TryParse(subPartMatch.Groups["disc"].Value, out var partNum))
                    {
                        continue;
                    }

                    subName = _regexMultiPartVideo.Replace(namingTemplate, "${1}${2}${4}" + partNum + "${3}");
                }

                string       lang         = new CultureInfo(subtitleMatch.Language).EnglishName;
                var          dir          = ResourcePathHelper.GetDirectoryName(mediaFile.NativeResourcePath.Serialize());
                var          sub          = $"{subName}.{lang}{Path.GetExtension(subtitleMatch.ItemName)}";
                ResourcePath subtitlePath = ResourcePath.Deserialize(dir);

                //File based access
                var resLoc = new ResourceLocator(mediaFile.NativeSystemId, subtitlePath);
                using (IResourceAccessor mediaItemAccessor = resLoc.CreateAccessor())
                    using (LocalFsResourceAccessorHelper rah = new LocalFsResourceAccessorHelper(mediaItemAccessor))
                        using (rah.LocalFsResourceAccessor.EnsureLocalFileSystemAccess())
                        {
                            using (var stream = rah.LocalFsResourceAccessor.CreateOpenWrite(sub, overwriteExisting))
                            {
                                var bytes = downloads[subtitleMatch];
                                if (stream != null)
                                {
                                    await stream.WriteAsync(bytes, 0, bytes.Length);
                                }
                            }
                        }
            }
            return(true);
        }
        public static bool MergeVideoResourceAspects(IDictionary <Guid, IList <MediaItemAspect> > extractedAspects, IDictionary <Guid, IList <MediaItemAspect> > existingAspects)
        {
            //Extracted aspects
            IList <MultipleMediaItemAspect> providerResourceAspects;

            if (!MediaItemAspect.TryGetAspects(extractedAspects, ProviderResourceAspect.Metadata, out providerResourceAspects))
            {
                return(false);
            }

            string       accessorPath = (string)providerResourceAspects.First().GetAttributeValue(ProviderResourceAspect.ATTR_RESOURCE_ACCESSOR_PATH);
            ResourcePath resourcePath = ResourcePath.Deserialize(accessorPath);

            IList <MultipleMediaItemAspect> videoAspects;

            MediaItemAspect.TryGetAspects(extractedAspects, VideoStreamAspect.Metadata, out videoAspects);

            IList <MultipleMediaItemAspect> videoAudioAspects;

            MediaItemAspect.TryGetAspects(extractedAspects, VideoAudioStreamAspect.Metadata, out videoAudioAspects);

            IList <MultipleMediaItemAspect> subtitleAspects;

            MediaItemAspect.TryGetAspects(extractedAspects, SubtitleAspect.Metadata, out subtitleAspects);

            //Existing aspects
            IList <MultipleMediaItemAspect> existingProviderResourceAspects;

            MediaItemAspect.TryGetAspects(existingAspects, ProviderResourceAspect.Metadata, out existingProviderResourceAspects);

            Dictionary <int, int> resourceIndexMap = new Dictionary <int, int>();
            int newResourceIndex = -1;

            if (existingProviderResourceAspects != null)
            {
                foreach (MultipleMediaItemAspect providerResourceAspect in existingProviderResourceAspects)
                {
                    int resouceIndex = providerResourceAspect.GetAttributeValue <int>(ProviderResourceAspect.ATTR_RESOURCE_INDEX);
                    if (newResourceIndex < resouceIndex)
                    {
                        newResourceIndex = resouceIndex;
                    }
                }
            }
            newResourceIndex++;

            bool resourceExists = false; //Resource might already be added in the initial add

            foreach (MultipleMediaItemAspect providerResourceAspect in providerResourceAspects)
            {
                if (existingProviderResourceAspects != null)
                {
                    accessorPath = (string)providerResourceAspect.GetAttributeValue(ProviderResourceAspect.ATTR_RESOURCE_ACCESSOR_PATH);

                    foreach (MultipleMediaItemAspect exisitingProviderResourceAspect in existingProviderResourceAspects)
                    {
                        string existingAccessorPath = (string)exisitingProviderResourceAspect.GetAttributeValue(ProviderResourceAspect.ATTR_RESOURCE_ACCESSOR_PATH);
                        if (accessorPath.Equals(existingAccessorPath, StringComparison.InvariantCultureIgnoreCase))
                        {
                            resourceExists = true;
                            break;
                        }
                    }
                }

                if (resourceExists)
                {
                    continue;
                }

                int resouceIndex = providerResourceAspect.GetAttributeValue <int>(ProviderResourceAspect.ATTR_RESOURCE_INDEX);
                if (!resourceIndexMap.ContainsKey(resouceIndex))
                {
                    resourceIndexMap.Add(resouceIndex, newResourceIndex);
                }
                newResourceIndex++;

                MultipleMediaItemAspect newPra = MediaItemAspect.CreateAspect(existingAspects, ProviderResourceAspect.Metadata);
                newPra.SetAttribute(ProviderResourceAspect.ATTR_RESOURCE_INDEX, resourceIndexMap[resouceIndex]);
                newPra.SetAttribute(ProviderResourceAspect.ATTR_TYPE, providerResourceAspect.GetAttributeValue(ProviderResourceAspect.ATTR_TYPE));
                newPra.SetAttribute(ProviderResourceAspect.ATTR_MIME_TYPE, providerResourceAspect.GetAttributeValue(ProviderResourceAspect.ATTR_MIME_TYPE));
                newPra.SetAttribute(ProviderResourceAspect.ATTR_SIZE, providerResourceAspect.GetAttributeValue(ProviderResourceAspect.ATTR_SIZE));
                newPra.SetAttribute(ProviderResourceAspect.ATTR_RESOURCE_ACCESSOR_PATH, providerResourceAspect.GetAttributeValue(ProviderResourceAspect.ATTR_RESOURCE_ACCESSOR_PATH));
                newPra.SetAttribute(ProviderResourceAspect.ATTR_PARENT_DIRECTORY_ID, providerResourceAspect.GetAttributeValue(ProviderResourceAspect.ATTR_PARENT_DIRECTORY_ID));
                newPra.SetAttribute(ProviderResourceAspect.ATTR_SYSTEM_ID, providerResourceAspect.GetAttributeValue(ProviderResourceAspect.ATTR_SYSTEM_ID));

                if (videoAspects != null)
                {
                    foreach (MultipleMediaItemAspect videoAspect in videoAspects)
                    {
                        int videoResourceIndex = videoAspect.GetAttributeValue <int>(VideoStreamAspect.ATTR_RESOURCE_INDEX);
                        if (videoResourceIndex == resouceIndex)
                        {
                            MultipleMediaItemAspect newVa = MediaItemAspect.CreateAspect(existingAspects, VideoStreamAspect.Metadata);
                            newVa.SetAttribute(VideoStreamAspect.ATTR_RESOURCE_INDEX, resourceIndexMap[videoResourceIndex]);
                            newVa.SetAttribute(VideoStreamAspect.ATTR_STREAM_INDEX, videoAspect.GetAttributeValue(VideoStreamAspect.ATTR_STREAM_INDEX));
                            newVa.SetAttribute(VideoStreamAspect.ATTR_ASPECTRATIO, videoAspect.GetAttributeValue(VideoStreamAspect.ATTR_ASPECTRATIO));
                            newVa.SetAttribute(VideoStreamAspect.ATTR_AUDIOSTREAMCOUNT, videoAspect.GetAttributeValue(VideoStreamAspect.ATTR_AUDIOSTREAMCOUNT));
                            newVa.SetAttribute(VideoStreamAspect.ATTR_DURATION, videoAspect.GetAttributeValue(VideoStreamAspect.ATTR_DURATION));
                            newVa.SetAttribute(VideoStreamAspect.ATTR_FPS, videoAspect.GetAttributeValue(VideoStreamAspect.ATTR_FPS));
                            newVa.SetAttribute(VideoStreamAspect.ATTR_HEIGHT, videoAspect.GetAttributeValue(VideoStreamAspect.ATTR_HEIGHT));
                            newVa.SetAttribute(VideoStreamAspect.ATTR_VIDEOBITRATE, videoAspect.GetAttributeValue(VideoStreamAspect.ATTR_VIDEOBITRATE));
                            newVa.SetAttribute(VideoStreamAspect.ATTR_VIDEOENCODING, videoAspect.GetAttributeValue(VideoStreamAspect.ATTR_VIDEOENCODING));
                            newVa.SetAttribute(VideoStreamAspect.ATTR_WIDTH, videoAspect.GetAttributeValue(VideoStreamAspect.ATTR_WIDTH));
                            newVa.SetAttribute(VideoStreamAspect.ATTR_VIDEO_TYPE, videoAspect.GetAttributeValue(VideoStreamAspect.ATTR_VIDEO_TYPE));
                            newVa.SetAttribute(VideoStreamAspect.ATTR_VIDEO_PART, videoAspect.GetAttributeValue(VideoStreamAspect.ATTR_VIDEO_PART));
                            newVa.SetAttribute(VideoStreamAspect.ATTR_VIDEO_PART_SET, videoAspect.GetAttributeValue(VideoStreamAspect.ATTR_VIDEO_PART_SET));
                            newVa.SetAttribute(VideoStreamAspect.ATTR_VIDEO_PART_SET_NAME, videoAspect.GetAttributeValue(VideoStreamAspect.ATTR_VIDEO_PART_SET_NAME));
                        }
                    }
                }

                //Correct sets
                Dictionary <string, int> setList = new Dictionary <string, int>();
                MediaItemAspect.TryGetAspects(existingAspects, ProviderResourceAspect.Metadata, out existingProviderResourceAspects);
                IList <MultipleMediaItemAspect> existingVideoAspects;
                if (MediaItemAspect.TryGetAspects(existingAspects, VideoStreamAspect.Metadata, out existingVideoAspects))
                {
                    int newMediaSet = 0;
                    Dictionary <int, int> knownSets = new Dictionary <int, int>();
                    foreach (MultipleMediaItemAspect videoStreamAspect in existingVideoAspects)
                    {
                        string filename = null;
                        foreach (MultipleMediaItemAspect pra in existingProviderResourceAspects)
                        {
                            if (pra.GetAttributeValue <int>(ProviderResourceAspect.ATTR_RESOURCE_INDEX) == videoStreamAspect.GetAttributeValue <int>(VideoStreamAspect.ATTR_RESOURCE_INDEX))
                            {
                                accessorPath = (string)pra.GetAttributeValue(ProviderResourceAspect.ATTR_RESOURCE_ACCESSOR_PATH);
                                resourcePath = resourcePath = ResourcePath.Deserialize(accessorPath);
                                filename     = resourcePath.FileName ?? Path.GetFileName(resourcePath.BasePathSegment.Path);
                                break;
                            }
                        }
                        videoStreamAspect.SetAttribute(VideoStreamAspect.ATTR_VIDEO_PART_SET, GetMultipartSetNumber(ref setList, ref newMediaSet, filename));
                    }
                }

                if (videoAudioAspects != null)
                {
                    foreach (MultipleMediaItemAspect videoAudioAspect in videoAudioAspects)
                    {
                        int audioResourceIndex = videoAudioAspect.GetAttributeValue <int>(VideoAudioStreamAspect.ATTR_RESOURCE_INDEX);
                        if (audioResourceIndex == resouceIndex)
                        {
                            MultipleMediaItemAspect newVaa = MediaItemAspect.CreateAspect(existingAspects, VideoAudioStreamAspect.Metadata);
                            newVaa.SetAttribute(VideoAudioStreamAspect.ATTR_RESOURCE_INDEX, resourceIndexMap[audioResourceIndex]);
                            newVaa.SetAttribute(VideoAudioStreamAspect.ATTR_STREAM_INDEX, videoAudioAspect.GetAttributeValue(VideoAudioStreamAspect.ATTR_STREAM_INDEX));
                            newVaa.SetAttribute(VideoAudioStreamAspect.ATTR_AUDIOBITRATE, videoAudioAspect.GetAttributeValue(VideoAudioStreamAspect.ATTR_AUDIOBITRATE));
                            newVaa.SetAttribute(VideoAudioStreamAspect.ATTR_AUDIOCHANNELS, videoAudioAspect.GetAttributeValue(VideoAudioStreamAspect.ATTR_AUDIOCHANNELS));
                            newVaa.SetAttribute(VideoAudioStreamAspect.ATTR_AUDIOENCODING, videoAudioAspect.GetAttributeValue(VideoAudioStreamAspect.ATTR_AUDIOENCODING));
                            newVaa.SetAttribute(VideoAudioStreamAspect.ATTR_AUDIOLANGUAGE, videoAudioAspect.GetAttributeValue(VideoAudioStreamAspect.ATTR_AUDIOLANGUAGE));
                        }
                    }
                }

                //Internal subtitles
                if (subtitleAspects != null)
                {
                    foreach (MultipleMediaItemAspect subAspect in subtitleAspects)
                    {
                        int videoResourceIndex = subAspect.GetAttributeValue <int>(SubtitleAspect.ATTR_VIDEO_RESOURCE_INDEX);
                        int subResourceIndex   = subAspect.GetAttributeValue <int>(SubtitleAspect.ATTR_RESOURCE_INDEX);
                        if (videoResourceIndex == resouceIndex && subResourceIndex == -1)
                        {
                            MultipleMediaItemAspect newSa = MediaItemAspect.CreateAspect(existingAspects, SubtitleAspect.Metadata);
                            newSa.SetAttribute(SubtitleAspect.ATTR_VIDEO_RESOURCE_INDEX, resourceIndexMap[videoResourceIndex]);
                            newSa.SetAttribute(SubtitleAspect.ATTR_RESOURCE_INDEX, resourceIndexMap[videoResourceIndex]);
                            newSa.SetAttribute(SubtitleAspect.ATTR_STREAM_INDEX, subAspect.GetAttributeValue(SubtitleAspect.ATTR_STREAM_INDEX));
                            newSa.SetAttribute(SubtitleAspect.ATTR_SUBTITLE_ENCODING, subAspect.GetAttributeValue(SubtitleAspect.ATTR_SUBTITLE_ENCODING));
                            newSa.SetAttribute(SubtitleAspect.ATTR_SUBTITLE_FORMAT, subAspect.GetAttributeValue(SubtitleAspect.ATTR_SUBTITLE_FORMAT));
                            newSa.SetAttribute(SubtitleAspect.ATTR_SUBTITLE_LANGUAGE, subAspect.GetAttributeValue(SubtitleAspect.ATTR_SUBTITLE_LANGUAGE));
                            newSa.SetAttribute(SubtitleAspect.ATTR_INTERNAL, subAspect.GetAttributeValue(SubtitleAspect.ATTR_INTERNAL));
                            newSa.SetAttribute(SubtitleAspect.ATTR_DEFAULT, subAspect.GetAttributeValue(SubtitleAspect.ATTR_DEFAULT));
                            newSa.SetAttribute(SubtitleAspect.ATTR_FORCED, subAspect.GetAttributeValue(SubtitleAspect.ATTR_FORCED));
                        }
                    }
                }

                //External subtitles
                ResourcePath existingResourcePath;
                if (subtitleAspects != null)
                {
                    foreach (MultipleMediaItemAspect subAspect in subtitleAspects)
                    {
                        int subResourceIndex = subAspect.GetAttributeValue <int>(SubtitleAspect.ATTR_RESOURCE_INDEX);
                        if (subResourceIndex == resouceIndex)
                        {
                            //Find video resource
                            int videoResourceIndex = -1;
                            if (existingProviderResourceAspects != null)
                            {
                                foreach (MultipleMediaItemAspect existingProviderResourceAspect in existingProviderResourceAspects)
                                {
                                    accessorPath = (string)providerResourceAspect.GetAttributeValue(ProviderResourceAspect.ATTR_RESOURCE_ACCESSOR_PATH);
                                    resourcePath = ResourcePath.Deserialize(accessorPath);

                                    accessorPath         = (string)existingProviderResourceAspect.GetAttributeValue(ProviderResourceAspect.ATTR_RESOURCE_ACCESSOR_PATH);
                                    existingResourcePath = ResourcePath.Deserialize(accessorPath);

                                    if (ResourcePath.GetFileNameWithoutExtension(resourcePath).StartsWith(ResourcePath.GetFileNameWithoutExtension(existingResourcePath), StringComparison.InvariantCultureIgnoreCase))
                                    {
                                        bool resPrimary = existingProviderResourceAspect.GetAttributeValue <int>(ProviderResourceAspect.ATTR_TYPE) == ProviderResourceAspect.TYPE_PRIMARY;
                                        if (resPrimary == true)
                                        {
                                            videoResourceIndex = providerResourceAspect.GetAttributeValue <int>(ProviderResourceAspect.ATTR_RESOURCE_INDEX);
                                            break;
                                        }
                                    }
                                }
                            }

                            if (videoResourceIndex >= 0)
                            {
                                MultipleMediaItemAspect newSa = MediaItemAspect.CreateAspect(existingAspects, SubtitleAspect.Metadata);
                                newSa.SetAttribute(SubtitleAspect.ATTR_VIDEO_RESOURCE_INDEX, videoResourceIndex);
                                newSa.SetAttribute(SubtitleAspect.ATTR_RESOURCE_INDEX, resourceIndexMap[subResourceIndex]);
                                newSa.SetAttribute(SubtitleAspect.ATTR_STREAM_INDEX, subAspect.GetAttributeValue(SubtitleAspect.ATTR_STREAM_INDEX));
                                newSa.SetAttribute(SubtitleAspect.ATTR_SUBTITLE_ENCODING, subAspect.GetAttributeValue(SubtitleAspect.ATTR_SUBTITLE_ENCODING));
                                newSa.SetAttribute(SubtitleAspect.ATTR_SUBTITLE_FORMAT, subAspect.GetAttributeValue(SubtitleAspect.ATTR_SUBTITLE_FORMAT));
                                newSa.SetAttribute(SubtitleAspect.ATTR_SUBTITLE_LANGUAGE, subAspect.GetAttributeValue(SubtitleAspect.ATTR_SUBTITLE_LANGUAGE));
                                newSa.SetAttribute(SubtitleAspect.ATTR_INTERNAL, subAspect.GetAttributeValue(SubtitleAspect.ATTR_INTERNAL));
                                newSa.SetAttribute(SubtitleAspect.ATTR_DEFAULT, subAspect.GetAttributeValue(SubtitleAspect.ATTR_DEFAULT));
                                newSa.SetAttribute(SubtitleAspect.ATTR_FORCED, subAspect.GetAttributeValue(SubtitleAspect.ATTR_FORCED));
                            }
                        }
                    }
                }
            }
            return(true);
        }
Beispiel #5
0
        public bool TryMerge(IDictionary <Guid, IList <MediaItemAspect> > extractedAspects, IDictionary <Guid, IList <MediaItemAspect> > existingAspects)
        {
            try
            {
                //Extracted aspects
                IList <MultipleMediaItemAspect> providerResourceAspects;
                if (!MediaItemAspect.TryGetAspects(extractedAspects, ProviderResourceAspect.Metadata, out providerResourceAspects))
                {
                    return(false);
                }

                //Don't merge virtual resource
                string       accessorPath = (string)providerResourceAspects[0].GetAttributeValue(ProviderResourceAspect.ATTR_RESOURCE_ACCESSOR_PATH);
                ResourcePath resourcePath = resourcePath = ResourcePath.Deserialize(accessorPath);
                if (resourcePath.BasePathSegment.ProviderId == VirtualResourceProvider.VIRTUAL_RESOURCE_PROVIDER_ID)
                {
                    return(false);
                }

                IList <MultipleMediaItemAspect> videoAspects;
                MediaItemAspect.TryGetAspects(extractedAspects, VideoStreamAspect.Metadata, out videoAspects);

                IList <MultipleMediaItemAspect> videoAudioAspects;
                MediaItemAspect.TryGetAspects(extractedAspects, VideoAudioStreamAspect.Metadata, out videoAudioAspects);

                IList <MultipleMediaItemAspect> subtitleAspects;
                MediaItemAspect.TryGetAspects(extractedAspects, SubtitleAspect.Metadata, out subtitleAspects);

                //Existing aspects
                IList <MultipleMediaItemAspect> existingProviderResourceAspects;
                MediaItemAspect.TryGetAspects(existingAspects, ProviderResourceAspect.Metadata, out existingProviderResourceAspects);

                //Replace if existing is a virtual resource
                accessorPath = (string)existingProviderResourceAspects[0].GetAttributeValue(ProviderResourceAspect.ATTR_RESOURCE_ACCESSOR_PATH);
                resourcePath = resourcePath = ResourcePath.Deserialize(accessorPath);
                if (resourcePath.BasePathSegment.ProviderId == VirtualResourceProvider.VIRTUAL_RESOURCE_PROVIDER_ID)
                {
                    //Don't allow merge of subtitles into virtual item
                    if (extractedAspects.ContainsKey(SubtitleAspect.ASPECT_ID) && !extractedAspects.ContainsKey(VideoStreamAspect.ASPECT_ID))
                    {
                        return(false);
                    }

                    existingAspects[MediaAspect.ASPECT_ID][0].SetAttribute(MediaAspect.ATTR_ISVIRTUAL, false);
                    existingAspects.Remove(ProviderResourceAspect.ASPECT_ID);
                    foreach (Guid aspect in extractedAspects.Keys)
                    {
                        if (!existingAspects.ContainsKey(aspect))
                        {
                            existingAspects.Add(aspect, extractedAspects[aspect]);
                        }
                    }
                    return(true);
                }

                //Merge
                Dictionary <int, int> resourceIndexMap = new Dictionary <int, int>();
                int newResourceIndex = -1;
                if (existingProviderResourceAspects != null)
                {
                    foreach (MultipleMediaItemAspect providerResourceAspect in existingProviderResourceAspects)
                    {
                        int resouceIndex = providerResourceAspect.GetAttributeValue <int>(ProviderResourceAspect.ATTR_RESOURCE_INDEX);
                        if (newResourceIndex < resouceIndex)
                        {
                            newResourceIndex = resouceIndex;
                        }
                    }
                }
                newResourceIndex++;

                bool resourceExists = false; //Resource might already be added in the initial add
                foreach (MultipleMediaItemAspect providerResourceAspect in providerResourceAspects)
                {
                    if (existingProviderResourceAspects != null)
                    {
                        accessorPath = (string)providerResourceAspect.GetAttributeValue(ProviderResourceAspect.ATTR_RESOURCE_ACCESSOR_PATH);

                        foreach (MultipleMediaItemAspect exisitingProviderResourceAspect in existingProviderResourceAspects)
                        {
                            string existingAccessorPath = (string)exisitingProviderResourceAspect.GetAttributeValue(ProviderResourceAspect.ATTR_RESOURCE_ACCESSOR_PATH);
                            if (accessorPath.Equals(existingAccessorPath, StringComparison.InvariantCultureIgnoreCase))
                            {
                                resourceExists = true;
                                break;
                            }
                        }
                    }

                    if (resourceExists)
                    {
                        continue;
                    }

                    int resouceIndex = providerResourceAspect.GetAttributeValue <int>(ProviderResourceAspect.ATTR_RESOURCE_INDEX);
                    if (!resourceIndexMap.ContainsKey(resouceIndex))
                    {
                        resourceIndexMap.Add(resouceIndex, newResourceIndex);
                    }
                    newResourceIndex++;

                    MultipleMediaItemAspect newPra = MediaItemAspect.CreateAspect(existingAspects, ProviderResourceAspect.Metadata);
                    newPra.SetAttribute(ProviderResourceAspect.ATTR_RESOURCE_INDEX, resourceIndexMap[resouceIndex]);
                    newPra.SetAttribute(ProviderResourceAspect.ATTR_PRIMARY, providerResourceAspect.GetAttributeValue(ProviderResourceAspect.ATTR_PRIMARY));
                    newPra.SetAttribute(ProviderResourceAspect.ATTR_MIME_TYPE, providerResourceAspect.GetAttributeValue(ProviderResourceAspect.ATTR_MIME_TYPE));
                    newPra.SetAttribute(ProviderResourceAspect.ATTR_SIZE, providerResourceAspect.GetAttributeValue(ProviderResourceAspect.ATTR_SIZE));
                    newPra.SetAttribute(ProviderResourceAspect.ATTR_RESOURCE_ACCESSOR_PATH, providerResourceAspect.GetAttributeValue(ProviderResourceAspect.ATTR_RESOURCE_ACCESSOR_PATH));
                    newPra.SetAttribute(ProviderResourceAspect.ATTR_PARENT_DIRECTORY_ID, providerResourceAspect.GetAttributeValue(ProviderResourceAspect.ATTR_PARENT_DIRECTORY_ID));
                    newPra.SetAttribute(ProviderResourceAspect.ATTR_SYSTEM_ID, providerResourceAspect.GetAttributeValue(ProviderResourceAspect.ATTR_SYSTEM_ID));

                    if (videoAspects != null)
                    {
                        foreach (MultipleMediaItemAspect videoAspect in videoAspects)
                        {
                            int videoResourceIndex = videoAspect.GetAttributeValue <int>(VideoStreamAspect.ATTR_RESOURCE_INDEX);
                            if (videoResourceIndex == resouceIndex)
                            {
                                MultipleMediaItemAspect newVa = MediaItemAspect.CreateAspect(existingAspects, VideoStreamAspect.Metadata);
                                newVa.SetAttribute(VideoStreamAspect.ATTR_RESOURCE_INDEX, resourceIndexMap[videoResourceIndex]);
                                newVa.SetAttribute(VideoStreamAspect.ATTR_STREAM_INDEX, videoAspect.GetAttributeValue(VideoStreamAspect.ATTR_STREAM_INDEX));
                                newVa.SetAttribute(VideoStreamAspect.ATTR_ASPECTRATIO, videoAspect.GetAttributeValue(VideoStreamAspect.ATTR_ASPECTRATIO));
                                newVa.SetAttribute(VideoStreamAspect.ATTR_AUDIOSTREAMCOUNT, videoAspect.GetAttributeValue(VideoStreamAspect.ATTR_AUDIOSTREAMCOUNT));
                                newVa.SetAttribute(VideoStreamAspect.ATTR_DURATION, videoAspect.GetAttributeValue(VideoStreamAspect.ATTR_DURATION));
                                newVa.SetAttribute(VideoStreamAspect.ATTR_FPS, videoAspect.GetAttributeValue(VideoStreamAspect.ATTR_FPS));
                                newVa.SetAttribute(VideoStreamAspect.ATTR_HEIGHT, videoAspect.GetAttributeValue(VideoStreamAspect.ATTR_HEIGHT));
                                newVa.SetAttribute(VideoStreamAspect.ATTR_VIDEOBITRATE, videoAspect.GetAttributeValue(VideoStreamAspect.ATTR_VIDEOBITRATE));
                                newVa.SetAttribute(VideoStreamAspect.ATTR_VIDEOENCODING, videoAspect.GetAttributeValue(VideoStreamAspect.ATTR_VIDEOENCODING));
                                newVa.SetAttribute(VideoStreamAspect.ATTR_WIDTH, videoAspect.GetAttributeValue(VideoStreamAspect.ATTR_WIDTH));
                                newVa.SetAttribute(VideoStreamAspect.ATTR_VIDEO_TYPE, videoAspect.GetAttributeValue(VideoStreamAspect.ATTR_VIDEO_TYPE));
                                newVa.SetAttribute(VideoStreamAspect.ATTR_VIDEO_PART, videoAspect.GetAttributeValue(VideoStreamAspect.ATTR_VIDEO_PART));
                                newVa.SetAttribute(VideoStreamAspect.ATTR_VIDEO_PART_SET, videoAspect.GetAttributeValue(VideoStreamAspect.ATTR_VIDEO_PART_SET));
                                newVa.SetAttribute(VideoStreamAspect.ATTR_VIDEO_PART_SET_NAME, videoAspect.GetAttributeValue(VideoStreamAspect.ATTR_VIDEO_PART_SET_NAME));
                            }
                        }
                    }

                    //Correct sets
                    Dictionary <string, int> setList = new Dictionary <string, int>();
                    MediaItemAspect.TryGetAspects(existingAspects, ProviderResourceAspect.Metadata, out existingProviderResourceAspects);
                    IList <MultipleMediaItemAspect> existingVideoAspects;
                    if (MediaItemAspect.TryGetAspects(existingAspects, VideoStreamAspect.Metadata, out existingVideoAspects))
                    {
                        foreach (MultipleMediaItemAspect videoStreamAspect in existingVideoAspects)
                        {
                            int newMediaSet = 0;
                            int mediaSet    = videoStreamAspect.GetAttributeValue <int>(VideoStreamAspect.ATTR_VIDEO_PART_SET);
                            if (mediaSet == 0)
                            {
                                videoStreamAspect.SetAttribute(VideoStreamAspect.ATTR_VIDEO_PART_SET, newMediaSet);
                                newMediaSet++;
                            }
                            else if (mediaSet == -1)
                            {
                                string filename = null;
                                foreach (MultipleMediaItemAspect pra in existingProviderResourceAspects)
                                {
                                    if (pra.GetAttributeValue <int>(ProviderResourceAspect.ATTR_RESOURCE_INDEX) == videoStreamAspect.GetAttributeValue <int>(VideoStreamAspect.ATTR_RESOURCE_INDEX))
                                    {
                                        accessorPath = (string)pra.GetAttributeValue(ProviderResourceAspect.ATTR_RESOURCE_ACCESSOR_PATH);
                                        resourcePath = resourcePath = ResourcePath.Deserialize(accessorPath);
                                        filename     = resourcePath.FileName;
                                        break;
                                    }
                                }

                                videoStreamAspect.SetAttribute(VideoStreamAspect.ATTR_VIDEO_PART_SET, GetMultipartSetNumber(ref setList, ref newMediaSet, filename));
                            }
                        }
                    }

                    if (videoAudioAspects != null)
                    {
                        foreach (MultipleMediaItemAspect videoAudioAspect in videoAudioAspects)
                        {
                            int audioResourceIndex = videoAudioAspect.GetAttributeValue <int>(VideoAudioStreamAspect.ATTR_RESOURCE_INDEX);
                            if (audioResourceIndex == resouceIndex)
                            {
                                MultipleMediaItemAspect newVaa = MediaItemAspect.CreateAspect(existingAspects, VideoAudioStreamAspect.Metadata);
                                newVaa.SetAttribute(VideoAudioStreamAspect.ATTR_RESOURCE_INDEX, resourceIndexMap[audioResourceIndex]);
                                newVaa.SetAttribute(VideoAudioStreamAspect.ATTR_STREAM_INDEX, videoAudioAspect.GetAttributeValue(VideoAudioStreamAspect.ATTR_STREAM_INDEX));
                                newVaa.SetAttribute(VideoAudioStreamAspect.ATTR_AUDIOBITRATE, videoAudioAspect.GetAttributeValue(VideoAudioStreamAspect.ATTR_AUDIOBITRATE));
                                newVaa.SetAttribute(VideoAudioStreamAspect.ATTR_AUDIOCHANNELS, videoAudioAspect.GetAttributeValue(VideoAudioStreamAspect.ATTR_AUDIOCHANNELS));
                                newVaa.SetAttribute(VideoAudioStreamAspect.ATTR_AUDIOENCODING, videoAudioAspect.GetAttributeValue(VideoAudioStreamAspect.ATTR_AUDIOENCODING));
                                newVaa.SetAttribute(VideoAudioStreamAspect.ATTR_AUDIOLANGUAGE, videoAudioAspect.GetAttributeValue(VideoAudioStreamAspect.ATTR_AUDIOLANGUAGE));
                            }
                        }
                    }

                    //Internal subtitles
                    if (subtitleAspects != null)
                    {
                        foreach (MultipleMediaItemAspect subAspect in subtitleAspects)
                        {
                            int videoResourceIndex = subAspect.GetAttributeValue <int>(SubtitleAspect.ATTR_VIDEO_RESOURCE_INDEX);
                            int subResourceIndex   = subAspect.GetAttributeValue <int>(SubtitleAspect.ATTR_RESOURCE_INDEX);
                            if (videoResourceIndex == resouceIndex && subResourceIndex == -1)
                            {
                                MultipleMediaItemAspect newSa = MediaItemAspect.CreateAspect(existingAspects, SubtitleAspect.Metadata);
                                newSa.SetAttribute(SubtitleAspect.ATTR_VIDEO_RESOURCE_INDEX, resourceIndexMap[videoResourceIndex]);
                                newSa.SetAttribute(SubtitleAspect.ATTR_RESOURCE_INDEX, resourceIndexMap[videoResourceIndex]);
                                newSa.SetAttribute(SubtitleAspect.ATTR_STREAM_INDEX, subAspect.GetAttributeValue(SubtitleAspect.ATTR_STREAM_INDEX));
                                newSa.SetAttribute(SubtitleAspect.ATTR_SUBTITLE_ENCODING, subAspect.GetAttributeValue(SubtitleAspect.ATTR_SUBTITLE_ENCODING));
                                newSa.SetAttribute(SubtitleAspect.ATTR_SUBTITLE_FORMAT, subAspect.GetAttributeValue(SubtitleAspect.ATTR_SUBTITLE_FORMAT));
                                newSa.SetAttribute(SubtitleAspect.ATTR_SUBTITLE_LANGUAGE, subAspect.GetAttributeValue(SubtitleAspect.ATTR_SUBTITLE_LANGUAGE));
                                newSa.SetAttribute(SubtitleAspect.ATTR_INTERNAL, subAspect.GetAttributeValue(SubtitleAspect.ATTR_INTERNAL));
                                newSa.SetAttribute(SubtitleAspect.ATTR_DEFAULT, subAspect.GetAttributeValue(SubtitleAspect.ATTR_DEFAULT));
                                newSa.SetAttribute(SubtitleAspect.ATTR_FORCED, subAspect.GetAttributeValue(SubtitleAspect.ATTR_FORCED));
                            }
                        }
                    }

                    //External subtitles
                    ResourcePath existingResourcePath;
                    if (subtitleAspects != null)
                    {
                        foreach (MultipleMediaItemAspect subAspect in subtitleAspects)
                        {
                            int subResourceIndex = subAspect.GetAttributeValue <int>(SubtitleAspect.ATTR_RESOURCE_INDEX);
                            if (subResourceIndex == resouceIndex)
                            {
                                //Find video resource
                                int videoResourceIndex = -1;
                                if (existingProviderResourceAspects != null)
                                {
                                    foreach (MultipleMediaItemAspect existingProviderResourceAspect in existingProviderResourceAspects)
                                    {
                                        accessorPath = (string)providerResourceAspect.GetAttributeValue(ProviderResourceAspect.ATTR_RESOURCE_ACCESSOR_PATH);
                                        resourcePath = ResourcePath.Deserialize(accessorPath);

                                        accessorPath         = (string)existingProviderResourceAspect.GetAttributeValue(ProviderResourceAspect.ATTR_RESOURCE_ACCESSOR_PATH);
                                        existingResourcePath = ResourcePath.Deserialize(accessorPath);

                                        if (ResourcePath.GetFileNameWithoutExtension(resourcePath).StartsWith(ResourcePath.GetFileNameWithoutExtension(existingResourcePath), StringComparison.InvariantCultureIgnoreCase))
                                        {
                                            bool resPrimary = existingProviderResourceAspect.GetAttributeValue <bool>(ProviderResourceAspect.ATTR_PRIMARY);
                                            if (resPrimary == true)
                                            {
                                                videoResourceIndex = providerResourceAspect.GetAttributeValue <int>(ProviderResourceAspect.ATTR_RESOURCE_INDEX);
                                                break;
                                            }
                                        }
                                    }
                                }

                                if (videoResourceIndex >= 0)
                                {
                                    MultipleMediaItemAspect newSa = MediaItemAspect.CreateAspect(existingAspects, SubtitleAspect.Metadata);
                                    newSa.SetAttribute(SubtitleAspect.ATTR_VIDEO_RESOURCE_INDEX, videoResourceIndex);
                                    newSa.SetAttribute(SubtitleAspect.ATTR_RESOURCE_INDEX, resourceIndexMap[subResourceIndex]);
                                    newSa.SetAttribute(SubtitleAspect.ATTR_STREAM_INDEX, subAspect.GetAttributeValue(SubtitleAspect.ATTR_STREAM_INDEX));
                                    newSa.SetAttribute(SubtitleAspect.ATTR_SUBTITLE_ENCODING, subAspect.GetAttributeValue(SubtitleAspect.ATTR_SUBTITLE_ENCODING));
                                    newSa.SetAttribute(SubtitleAspect.ATTR_SUBTITLE_FORMAT, subAspect.GetAttributeValue(SubtitleAspect.ATTR_SUBTITLE_FORMAT));
                                    newSa.SetAttribute(SubtitleAspect.ATTR_SUBTITLE_LANGUAGE, subAspect.GetAttributeValue(SubtitleAspect.ATTR_SUBTITLE_LANGUAGE));
                                    newSa.SetAttribute(SubtitleAspect.ATTR_INTERNAL, subAspect.GetAttributeValue(SubtitleAspect.ATTR_INTERNAL));
                                    newSa.SetAttribute(SubtitleAspect.ATTR_DEFAULT, subAspect.GetAttributeValue(SubtitleAspect.ATTR_DEFAULT));
                                    newSa.SetAttribute(SubtitleAspect.ATTR_FORCED, subAspect.GetAttributeValue(SubtitleAspect.ATTR_FORCED));
                                }
                            }
                        }
                    }
                }

                return(true);
            }
            catch (Exception e)
            {
                // Only log at the info level here - And simply return false. This lets the caller know that we
                // couldn't perform our task here.
                ServiceRegistration.Get <ILogger>().Info("EpisodeMergeHandler: Exception merging resources (Text: '{0}')", e.Message);
                return(false);
            }
        }