Code view:

A painting is a person's account of this edit as text, recorded independently of the node mapping - a rendering often has several equally defensible answers where the mapping has one. Deletions and insertions carry no position on the opposite side in a painting, so that panel draws no caret for them.

Before

1using System;
2using System.IO;
3using MediaBrowser.Controller.Entities;
4using MediaBrowser.Controller.IO;
5using MediaBrowser.Controller.Resolvers;
6using MediaBrowser.Model.IO;
7
8namespace Emby.Server.Implementations.Library;
9
…lines 10–66 unchanged (57 lines)
67 }
68
69 private static bool CheckIgnoreRules(string path, string ignoreFileContent, bool isDirectory)
70 {
71 // If file has content, base ignoring off the content .gitignore-style rules
72 var rules = ignoreFileContent.Split('\n', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
73 var ignore = new Ignore.Ignore();
74 ignore.Add(rules);
75
76 // Mitigate the problem of the Ignore library not handling Windows paths correctly.
77 // See https://github.com/jellyfin/jellyfin/issues/15484
78 var pathToCheck = IsWindows ? path.NormalizePath('/') : path;
79
80 // Add trailing slash for directories to match "folder/"
81 if (isDirectory)
82 {
83 pathToCheck = string.Concat(pathToCheck.AsSpan().TrimEnd('/'), "/");
84 }
85
86 return ignore.IsIgnored(pathToCheck);
87 }
88
89 private static string GetFileContent(FileInfo ignoreFile)
90 {
91 ignoreFile = FileSystemHelper.ResolveLinkTarget(ignoreFile, returnFinalTarget: true) ?? ignoreFile;
92 return ignoreFile.Exists
93 ? File.ReadAllText(ignoreFile.FullName)
94 : string.Empty;
95 }
96}
97

After

1using System;
2using System.IO;
3using System.Text.RegularExpressions;
4using MediaBrowser.Controller.Entities;
5using MediaBrowser.Controller.IO;
6using MediaBrowser.Controller.Resolvers;
7using MediaBrowser.Model.IO;
8
9namespace Emby.Server.Implementations.Library;
…lines 10–67 unchanged (58 lines)
68 }
69
70 private static bool CheckIgnoreRules(string path, string ignoreFileContent, bool isDirectory)
71 {
72 // If file has content, base ignoring off the content .gitignore-style rules
73 var rules = ignoreFileContent.Split('\n', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
74 return CheckIgnoreRules(path, rules, isDirectory);
75 }
76
77 /// <summary>
78 /// Checks whether a path should be ignored based on an array of ignore rules.
79 /// </summary>
80 /// <param name="path">The path to check.</param>
81 /// <param name="rules">The array of ignore rules.</param>
82 /// <param name="isDirectory">Whether the path is a directory.</param>
83 /// <returns>True if the path should be ignored.</returns>
84 internal static bool CheckIgnoreRules(string path, string[] rules, bool isDirectory)
85 => CheckIgnoreRules(path, rules, isDirectory, IsWindows);
86
87 /// <summary>
88 /// Checks whether a path should be ignored based on an array of ignore rules.
89 /// </summary>
90 /// <param name="path">The path to check.</param>
91 /// <param name="rules">The array of ignore rules.</param>
92 /// <param name="isDirectory">Whether the path is a directory.</param>
93 /// <param name="normalizePath">Whether to normalize backslashes to forward slashes (for Windows paths).</param>
94 /// <returns>True if the path should be ignored.</returns>
95 internal static bool CheckIgnoreRules(string path, string[] rules, bool isDirectory, bool normalizePath)
96 {
97 var ignore = new Ignore.Ignore();
98
99 // Add each rule individually to catch and skip invalid patterns
100 var validRulesAdded = 0;
101 foreach (var rule in rules)
102 {
103 try
104 {
105 ignore.Add(rule);
106 validRulesAdded++;
107 }
108 catch (RegexParseException)
109 {
110 // Ignore invalid patterns
111 }
112 }
113
114 // If no valid rules were added, fall back to ignoring everything (like an empty .ignore file)
115 if (validRulesAdded == 0)
116 {
117 return true;
118 }
119
120 // Mitigate the problem of the Ignore library not handling Windows paths correctly.
121 // See https://github.com/jellyfin/jellyfin/issues/15484
122 var pathToCheck = normalizePath ? path.NormalizePath('/') : path;
123
124 // Add trailing slash for directories to match "folder/"
125 if (isDirectory)
126 {
127 pathToCheck = string.Concat(pathToCheck.AsSpan().TrimEnd('/'), "/");
128 }
129
130 return ignore.IsIgnored(pathToCheck);
131 }
132
133 private static string GetFileContent(FileInfo ignoreFile)
134 {
135 ignoreFile = FileSystemHelper.ResolveLinkTarget(ignoreFile, returnFinalTarget: true) ?? ignoreFile;
136 return ignoreFile.Exists
137 ? File.ReadAllText(ignoreFile.FullName)
…lines 138–141 unchanged (4 lines)

Before

compilation_unit
using_directive
using "using"
identifier "System"
; ";"
using_directive
using "using"
qualified_name
identifier "System"
. "."
identifier "IO"
; ";"
using_directive
using "using"
qualified_name
qualified_name
identifier "MediaBrowser"
. "."
identifier "Controller"
. "."
identifier "Entities"
; ";"
using_directive
using "using"
qualified_name
qualified_name
identifier "MediaBrowser"
. "."
identifier "Controller"
. "."
identifier "IO"
; ";"
using_directive
using "using"
qualified_name
qualified_name
identifier "MediaBrowser"
. "."
identifier "Controller"
. "."
identifier "Resolvers"
; ";"
using_directive
using "using"
qualified_name
qualified_name
identifier "MediaBrowser"
. "."
identifier "Model"
. "."
identifier "IO"
; ";"
file_scoped_namespace_declaration
namespace "namespace"
qualified_name
qualified_name
qualified_name
identifier "Emby"
. "."
identifier "Server"
. "."
identifier "Implementations"
. "."
identifier "Library"
; ";"
comment "/// <summary>"
comment "/// Resolver rule class for ignoring files via .ignore."
comment "/// </summary>"
class_declaration
modifier
public "public"
class "class"
identifier "DotIgnoreIgnoreRule"
base_list
: ":"
identifier "IResolverIgnoreRule"
declaration_list
{ "{"
field_declaration (+21 nodes collapsed)
method_declaration (+107 nodes collapsed)
comment "/// <inheritdoc />"
method_declaration (+30 nodes collapsed)
comment "/// <summary>"
comment "/// Checks whether or not the file is ignored."
comment "/// </summary>"
comment "/// <param name=\"fileInfo\">The file information.</param>"
comment "/// <param name=\"parent\">The parent BaseItem.</param>"
comment "/// <returns>True if the file should be ignored.</returns>"
method_declaration (+211 nodes collapsed)
method_declaration
modifier
private "private"
modifier
static "static"
predefined_type "bool"
identifier "CheckIgnoreRules"
parameter_list
( "("
parameter
predefined_type "string"
identifier "path"
, ","
parameter
predefined_type "string"
identifier "ignoreFileContent"
, ","
parameter
predefined_type "bool"
identifier "isDirectory"
) ")"
block
{ "{"
comment "// If file has content, base ignoring off the content .gitig"...
local_declaration_statement (+33 nodes collapsed)
local_declaration_statement
variable_declaration
implicit_type
var "var"
variable_declarator
identifier "ignore"
= "="
object_creation_expression
new "new"
qualified_name
identifier "Ignore"
. "."
identifier "Ignore"
argument_list
( "("
) ")"
; ";"
expression_statement
invocation_expression
member_access_expression
identifier "ignore"
. "."
identifier "Add"
argument_list
( "("
argument
identifier "rules"
) ")"
; ";"
comment "// Mitigate the problem of the Ignore library not handling W"...
comment "// See https://github.com/jellyfin/jellyfin/issues/15484"
local_declaration_statement
variable_declaration
implicit_type
var "var"
variable_declarator
identifier "pathToCheck"
= "="
conditional_expression
identifier "IsWindows"
? "?"
invocation_expression
member_access_expression
identifier "path"
. "."
identifier "NormalizePath"
argument_list
( "("
argument
character_literal
' "'"
character_literal_content "/"
' "'"
) ")"
: ":"
identifier "path"
; ";"
comment "// Add trailing slash for directories to match \"folder/\""
if_statement (+48 nodes collapsed)
return_statement
return "return"
invocation_expression
member_access_expression
identifier "ignore"
. "."
identifier "IsIgnored"
argument_list
( "("
argument
identifier "pathToCheck"
) ")"
; ";"
} "}"
method_declaration (+67 nodes collapsed)
} "}"

After

compilation_unit
using_directive
using "using"
identifier "System"
; ";"
using_directive
using "using"
qualified_name
identifier "System"
. "."
identifier "IO"
; ";"
using_directive
using "using"
qualified_name
qualified_name
identifier "System"
. "."
identifier "Text"
. "."
identifier "RegularExpressions"
; ";"
using_directive
using "using"
qualified_name
qualified_name
identifier "MediaBrowser"
. "."
identifier "Controller"
. "."
identifier "Entities"
; ";"
using_directive
using "using"
qualified_name
qualified_name
identifier "MediaBrowser"
. "."
identifier "Controller"
. "."
identifier "IO"
; ";"
using_directive
using "using"
qualified_name
qualified_name
identifier "MediaBrowser"
. "."
identifier "Controller"
. "."
identifier "Resolvers"
; ";"
using_directive
using "using"
qualified_name
qualified_name
identifier "MediaBrowser"
. "."
identifier "Model"
. "."
identifier "IO"
; ";"
file_scoped_namespace_declaration
namespace "namespace"
qualified_name
qualified_name
qualified_name
identifier "Emby"
. "."
identifier "Server"
. "."
identifier "Implementations"
. "."
identifier "Library"
; ";"
comment "/// <summary>"
comment "/// Resolver rule class for ignoring files via .ignore."
comment "/// </summary>"
class_declaration
modifier
public "public"
class "class"
identifier "DotIgnoreIgnoreRule"
base_list
: ":"
identifier "IResolverIgnoreRule"
declaration_list
{ "{"
field_declaration (+21 nodes collapsed)
method_declaration (+107 nodes collapsed)
comment "/// <inheritdoc />"
method_declaration (+30 nodes collapsed)
comment "/// <summary>"
comment "/// Checks whether or not the file is ignored."
comment "/// </summary>"
comment "/// <param name=\"fileInfo\">The file information.</param>"
comment "/// <param name=\"parent\">The parent BaseItem.</param>"
comment "/// <returns>True if the file should be ignored.</returns>"
method_declaration (+211 nodes collapsed)
method_declaration
modifier
private "private"
modifier
static "static"
predefined_type "bool"
identifier "CheckIgnoreRules"
parameter_list
( "("
parameter
predefined_type "string"
identifier "path"
, ","
parameter
predefined_type "string"
identifier "ignoreFileContent"
, ","
parameter
predefined_type "bool"
identifier "isDirectory"
) ")"
block
{ "{"
comment "// If file has content, base ignoring off the content .gitig"...
local_declaration_statement (+33 nodes collapsed)
return_statement
return "return"
invocation_expression
identifier "CheckIgnoreRules"
argument_list
( "("
argument
identifier "path"
, ","
argument
identifier "rules"
, ","
argument
identifier "isDirectory"
) ")"
; ";"
} "}"
comment "/// <summary>"
comment "/// Checks whether a path should be ignored based on an arra"...
comment "/// </summary>"
comment "/// <param name=\"path\">The path to check.</param>"
comment "/// <param name=\"rules\">The array of ignore rules.</param>"
comment "/// <param name=\"isDirectory\">Whether the path is a director"...
comment "/// <returns>True if the path should be ignored.</returns>"
method_declaration
modifier
internal "internal"
modifier
static "static"
predefined_type "bool"
identifier "CheckIgnoreRules"
parameter_list
( "("
parameter
predefined_type "string"
identifier "path"
, ","
parameter
array_type
predefined_type "string"
array_rank_specifier
[ "["
] "]"
identifier "rules"
, ","
parameter
predefined_type "bool"
identifier "isDirectory"
) ")"
arrow_expression_clause
=> "=>"
invocation_expression
identifier "CheckIgnoreRules"
argument_list
( "("
argument
identifier "path"
, ","
argument
identifier "rules"
, ","
argument
identifier "isDirectory"
, ","
argument
identifier "IsWindows"
) ")"
; ";"
comment "/// <summary>"
comment "/// Checks whether a path should be ignored based on an arra"...
comment "/// </summary>"
comment "/// <param name=\"path\">The path to check.</param>"
comment "/// <param name=\"rules\">The array of ignore rules.</param>"
comment "/// <param name=\"isDirectory\">Whether the path is a director"...
comment "/// <param name=\"normalizePath\">Whether to normalize backsla"...
comment "/// <returns>True if the path should be ignored.</returns>"
method_declaration
modifier
internal "internal"
modifier
static "static"
predefined_type "bool"
identifier "CheckIgnoreRules"
parameter_list
( "("
parameter
predefined_type "string"
identifier "path"
, ","
parameter
array_type
predefined_type "string"
array_rank_specifier
[ "["
] "]"
identifier "rules"
, ","
parameter
predefined_type "bool"
identifier "isDirectory"
, ","
parameter
predefined_type "bool"
identifier "normalizePath"
) ")"
block
{ "{"
local_declaration_statement
variable_declaration
implicit_type
var "var"
variable_declarator
identifier "ignore"
= "="
object_creation_expression
new "new"
qualified_name
identifier "Ignore"
. "."
identifier "Ignore"
argument_list
( "("
) ")"
; ";"
comment "// Add each rule individually to catch and skip invalid patt"...
local_declaration_statement
variable_declaration
implicit_type
var "var"
variable_declarator
identifier "validRulesAdded"
= "="
integer_literal "0"
; ";"
foreach_statement
foreach "foreach"
( "("
implicit_type
var "var"
identifier "rule"
in "in"
identifier "rules"
) ")"
block
{ "{"
try_statement
try "try"
block
{ "{"
expression_statement
invocation_expression
member_access_expression
identifier "ignore"
. "."
identifier "Add"
argument_list
( "("
argument
identifier "rule"
) ")"
; ";"
expression_statement
postfix_unary_expression
identifier "validRulesAdded"
++ "++"
; ";"
} "}"
catch_clause
catch "catch"
catch_declaration
( "("
identifier "RegexParseException"
) ")"
block
{ "{"
comment "// Ignore invalid patterns"
} "}"
} "}"
comment "// If no valid rules were added, fall back to ignoring every"...
if_statement
if "if"
( "("
binary_expression
identifier "validRulesAdded"
== "=="
integer_literal "0"
) ")"
block
{ "{"
return_statement
return "return"
boolean_literal
true "true"
; ";"
} "}"
comment "// Mitigate the problem of the Ignore library not handling W"...
comment "// See https://github.com/jellyfin/jellyfin/issues/15484"
local_declaration_statement
variable_declaration
implicit_type
var "var"
variable_declarator
identifier "pathToCheck"
= "="
conditional_expression
identifier "normalizePath"
? "?"
invocation_expression
member_access_expression
identifier "path"
. "."
identifier "NormalizePath"
argument_list
( "("
argument
character_literal
' "'"
character_literal_content "/"
' "'"
) ")"
: ":"
identifier "path"
; ";"
comment "// Add trailing slash for directories to match \"folder/\""
if_statement (+48 nodes collapsed)
return_statement
return "return"
invocation_expression
member_access_expression
identifier "ignore"
. "."
identifier "IsIgnored"
argument_list
( "("
argument
identifier "pathToCheck"
) ")"
; ";"
} "}"
method_declaration (+67 nodes collapsed)
} "}"