aboutsummaryrefslogtreecommitdiff
path: root/Emby.Naming/ExternalFiles/ExternalPathParser.cs
blob: 3bde3a1cf92aa56b6d5353e268adcf7557a59eba (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
using System;
using System.IO;
using System.Linq;
using Emby.Naming.Common;
using Jellyfin.Extensions;
using MediaBrowser.Model.Dlna;
using MediaBrowser.Model.Globalization;

namespace Emby.Naming.ExternalFiles
{
    /// <summary>
    /// External media file parser class.
    /// </summary>
    public class ExternalPathParser
    {
        private readonly NamingOptions _namingOptions;
        private readonly DlnaProfileType _type;
        private readonly ILocalizationManager _localizationManager;

        /// <summary>
        /// Initializes a new instance of the <see cref="ExternalPathParser"/> class.
        /// </summary>
        /// <param name="localizationManager">The localization manager.</param>
        /// <param name="namingOptions">The <see cref="NamingOptions"/> object containing FileExtensions, MediaDefaultFlags, MediaForcedFlags and MediaFlagDelimiters.</param>
        /// <param name="type">The <see cref="DlnaProfileType"/> of the parsed file.</param>
        public ExternalPathParser(NamingOptions namingOptions, ILocalizationManager localizationManager, DlnaProfileType type)
        {
            _localizationManager = localizationManager;
            _namingOptions = namingOptions;
            _type = type;
        }

        /// <summary>
        /// Parse filename and extract information.
        /// </summary>
        /// <param name="path">Path to file.</param>
        /// <param name="extraString">Part of the filename only containing the extra information.</param>
        /// <returns>Returns null or an <see cref="ExternalPathParserResult"/> object if parsing is successful.</returns>
        public ExternalPathParserResult? ParseFile(string path, string? extraString)
        {
            if (path.Length == 0)
            {
                return null;
            }

            var extension = Path.GetExtension(path);
            if (!(_type == DlnaProfileType.Subtitle && _namingOptions.SubtitleFileExtensions.Contains(extension, StringComparison.OrdinalIgnoreCase))
                && !(_type == DlnaProfileType.Audio && _namingOptions.AudioFileExtensions.Contains(extension, StringComparison.OrdinalIgnoreCase)))
            {
                return null;
            }

            var pathInfo = new ExternalPathParserResult(path);

            if (string.IsNullOrEmpty(extraString))
            {
                return pathInfo;
            }

            foreach (var separator in _namingOptions.MediaFlagDelimiters)
            {
                var languageString = extraString;
                var titleString = string.Empty;
                const int SeparatorLength = 1;

                while (languageString.Length > 0)
                {
                    int lastSeparator = languageString.LastIndexOf(separator);

                    if (lastSeparator == -1)
                    {
                          break;
                    }

                    string currentSlice = languageString[lastSeparator..];
                    string currentSliceWithoutSeparator = currentSlice[SeparatorLength..];

                    if (_namingOptions.MediaDefaultFlags.Any(s => currentSliceWithoutSeparator.Contains(s, StringComparison.OrdinalIgnoreCase)))
                    {
                        pathInfo.IsDefault = true;
                        extraString = extraString.Replace(currentSlice, string.Empty, StringComparison.OrdinalIgnoreCase);
                        languageString = languageString[..lastSeparator];
                        continue;
                    }

                    if (_namingOptions.MediaForcedFlags.Any(s => currentSliceWithoutSeparator.Contains(s, StringComparison.OrdinalIgnoreCase)))
                    {
                        pathInfo.IsForced = true;
                        extraString = extraString.Replace(currentSlice, string.Empty, StringComparison.OrdinalIgnoreCase);
                        languageString = languageString[..lastSeparator];
                        continue;
                    }

                    // Try to translate to three character code
                    var culture = _localizationManager.FindLanguageInfo(currentSliceWithoutSeparator);

                    if (culture != null && pathInfo.Language == null)
                    {
                        pathInfo.Language = culture.ThreeLetterISOLanguageName;
                        extraString = extraString.Replace(currentSlice, string.Empty, StringComparison.OrdinalIgnoreCase);
                    }
                    else
                    {
                        titleString = currentSlice + titleString;
                    }

                    languageString = languageString[..lastSeparator];
                }

                pathInfo.Title = titleString.Length >= SeparatorLength ? titleString[SeparatorLength..] : null;
            }

            return pathInfo;
        }
    }
}