Compare commits

..

11 commits

Author SHA1 Message Date
Mark McDowall
52972e7efc
Add private IPv6 networks 2025-11-03 07:35:36 -08:00
Mark McDowall
8c50919499
Bump version to 4.0.16 2025-10-28 15:53:41 -07:00
Polgonite
fdc07a47b1
Fixed: qBittorrent /login API success check 2025-10-26 08:31:50 -07:00
Collin Heist
36225c3709
Fixed: Prevent modals from overflowing screen width
Closes #8085
2025-10-26 08:31:50 -07:00
康小广
bc037ae356
Follow redirects when fetching Custom Lists 2025-10-26 08:31:50 -07:00
Mark McDowall
77a335de30
Fixed: Default runtime to 45 minutes if unavailable when importing episode files
Closes #7780
2025-10-26 08:31:50 -07:00
Mark McDowall
88d56361c4
Add XML declaration and clean up Kodi metadata generation
Closes #7753
2025-10-26 08:31:50 -07:00
Mark McDowall
d10107739b
Set known networks to RFC 1918 ranges during startup 2025-10-25 19:18:43 -07:00
Mark McDowall
7db7567c8e
Bump version to 4.0.15 2025-06-09 17:19:54 -07:00
Michael Peleshenko
2b2b973b30
Fixed: Prevent series without IMDB ID from being removed erroneously 2025-06-09 17:19:10 -07:00
Mark McDowall
bb954a7424
Fixed: Trakt Import List authentication after 24 hours
Closes #7874
2025-06-09 17:18:54 -07:00
12 changed files with 265 additions and 214 deletions

View file

@ -22,7 +22,7 @@ env:
FRAMEWORK: net6.0
RAW_BRANCH_NAME: ${{ github.head_ref || github.ref_name }}
SONARR_MAJOR_VERSION: 4
VERSION: 4.0.14
VERSION: 4.0.16
jobs:
backend:

View file

@ -19,6 +19,7 @@
.modal {
position: relative;
display: flex;
max-width: 90%;
max-height: 90%;
border-radius: 6px;
opacity: 1;

View file

@ -390,5 +390,12 @@ public virtual HttpRequestBuilder AddFormUpload(string name, string fileName, by
return this;
}
public virtual HttpRequestBuilder AllowRedirect(bool allowAutoRedirect = true)
{
AllowAutoRedirect = allowAutoRedirect;
return this;
}
}
}

View file

@ -0,0 +1,9 @@
using System.IO;
using System.Text;
namespace NzbDrone.Common;
public class Utf8StringWriter : StringWriter
{
public override Encoding Encoding => Encoding.UTF8;
}

View file

@ -213,5 +213,16 @@ public void should_use_runtime_from_episode_over_series()
Subject.IsSample(_localEpisode).Should().Be(DetectSampleResult.Sample);
}
[Test]
public void should_default_to_45_minutes_if_runtime_is_zero()
{
GivenRuntime(120);
_localEpisode.Series.Runtime = 0;
_localEpisode.Episodes.First().Runtime = 0;
Subject.IsSample(_localEpisode).Should().Be(DetectSampleResult.Sample);
}
}
}

View file

@ -425,8 +425,8 @@ private void AuthenticateClient(HttpRequestBuilder requestBuilder, QBittorrentSe
}
catch (HttpException ex)
{
_logger.Debug("qbitTorrent authentication failed.");
if (ex.Response.StatusCode == HttpStatusCode.Forbidden)
_logger.Debug(ex, "qbitTorrent authentication failed.");
if (ex.Response.StatusCode is HttpStatusCode.Unauthorized or HttpStatusCode.Forbidden)
{
throw new DownloadClientAuthenticationException("Failed to authenticate with qBittorrent.", ex);
}
@ -438,7 +438,7 @@ private void AuthenticateClient(HttpRequestBuilder requestBuilder, QBittorrentSe
throw new DownloadClientUnavailableException("Failed to connect to qBittorrent, please check your settings.", ex);
}
if (response.Content != "Ok.")
if (response.Content.IsNotNullOrWhiteSpace() && response.Content != "Ok.")
{
// returns "Fails." on bad login
_logger.Debug("qbitTorrent authentication failed.");

View file

@ -8,6 +8,7 @@
using System.Xml;
using System.Xml.Linq;
using NLog;
using NzbDrone.Common;
using NzbDrone.Common.Disk;
using NzbDrone.Common.Extensions;
using NzbDrone.Common.Serializer;
@ -149,13 +150,7 @@ public override MetadataFileResult SeriesMetadata(Series series, SeriesMetadataR
if (Settings.SeriesMetadata)
{
_logger.Debug("Generating Series Metadata for: {0}", series.Title);
var sb = new StringBuilder();
var xws = new XmlWriterSettings();
xws.OmitXmlDeclaration = true;
xws.Indent = false;
using (var xw = XmlWriter.Create(sb, xws))
{
var tvShow = new XElement("tvshow");
tvShow.Add(new XElement("title", series.Title));
@ -248,11 +243,23 @@ public override MetadataFileResult SeriesMetadata(Series series, SeriesMetadataR
tvShow.Add(new XElement("episodeguide", JsonSerializer.Serialize(episodeGuide, serializerSettings)));
}
var doc = new XDocument(tvShow);
doc.Save(xw);
var doc = new XDocument(tvShow)
{
Declaration = new XDeclaration("1.0", "UTF-8", "yes"),
};
xmlResult += doc.ToString();
}
var sb = new StringBuilder();
using var sw = new Utf8StringWriter();
using var xw = XmlWriter.Create(sw, new XmlWriterSettings
{
Encoding = Encoding.UTF8,
Indent = true
});
doc.Save(xw);
xw.Flush();
xmlResult += sw.ToString();
}
if (Settings.SeriesMetadataUrl)
@ -280,16 +287,19 @@ public override MetadataFileResult EpisodeMetadata(Series series, EpisodeFile ep
var watched = GetExistingWatchedStatus(series, episodeFile.RelativePath);
var xmlResult = string.Empty;
var xws = new XmlWriterSettings
{
Encoding = Encoding.UTF8,
Indent = true
};
foreach (var episode in episodeFile.Episodes.Value)
{
var sb = new StringBuilder();
var xws = new XmlWriterSettings();
xws.OmitXmlDeclaration = true;
xws.Indent = false;
using (var xw = XmlWriter.Create(sb, xws))
var doc = new XDocument
{
var doc = new XDocument();
Declaration = new XDeclaration("1.0", "UTF-8", "yes")
};
var image = episode.Images.SingleOrDefault(i => i.CoverType == MediaCoverTypes.Screenshot);
var details = new XElement("episodedetails");
@ -381,13 +391,16 @@ public override MetadataFileResult EpisodeMetadata(Series series, EpisodeFile ep
// details.Add(new XElement("credits", tvdbEpisode.Writer.FirstOrDefault()));
// details.Add(new XElement("director", tvdbEpisode.Directors.FirstOrDefault()));
using var sw = new Utf8StringWriter();
using var xw = XmlWriter.Create(sw, xws);
doc.Add(details);
doc.Save(xw);
xw.Flush();
xmlResult += doc.ToString();
xmlResult += sw.ToString();
xmlResult += Environment.NewLine;
}
}
return new MetadataFileResult(GetEpisodeMetadataFilename(episodeFile.RelativePath), xmlResult.Trim(Environment.NewLine.ToCharArray()));
}

View file

@ -72,7 +72,7 @@ private List<TResource> Execute<TResource>(CustomSettings settings)
}
var baseUrl = settings.BaseUrl.TrimEnd('/');
var request = new HttpRequestBuilder(baseUrl).Accept(HttpAccept.Json).Build();
var request = new HttpRequestBuilder(baseUrl).Accept(HttpAccept.Json).AllowRedirect().Build();
var response = _httpClient.Get(request);
var results = JsonConvert.DeserializeObject<List<TResource>>(response.Content);

View file

@ -305,7 +305,7 @@ private void CleanLibrary()
{
var seriesExists = allListItems.Where(l =>
l.TvdbId == series.TvdbId ||
l.ImdbId == series.ImdbId ||
(l.ImdbId.IsNotNullOrWhiteSpace() && series.ImdbId.IsNotNullOrWhiteSpace() && l.ImdbId == series.ImdbId) ||
l.TmdbId == series.TmdbId ||
series.MalIds.Contains(l.MalId) ||
series.AniListIds.Contains(l.AniListId)).ToList();

View file

@ -1,5 +1,5 @@
using System.Collections.Generic;
using System.Text.Json.Serialization;
using Newtonsoft.Json;
namespace NzbDrone.Core.ImportLists.Trakt
{
@ -17,7 +17,7 @@ public class TraktSeriesResource
public string Title { get; set; }
public int? Year { get; set; }
public TraktSeriesIdsResource Ids { get; set; }
[JsonPropertyName("aired_episodes")]
[JsonProperty("aired_episodes")]
public int AiredEpisodes { get; set; }
}
@ -44,11 +44,11 @@ public class TraktWatchedResponse : TraktResponse
public class RefreshRequestResponse
{
[JsonPropertyName("access_token")]
[JsonProperty("access_token")]
public string AccessToken { get; set; }
[JsonPropertyName("expires_in")]
[JsonProperty("expires_in")]
public int ExpiresIn { get; set; }
[JsonPropertyName("refresh_token")]
[JsonProperty("refresh_token")]
public string RefreshToken { get; set; }
}

View file

@ -66,6 +66,12 @@ public DetectSampleResult IsSample(LocalEpisode localEpisode)
return DetectSampleResult.Indeterminate;
}
if (runtime == 0)
{
_logger.Debug("Series runtime is 0, defaulting runtime to 45 minutes");
runtime = 45;
}
return IsSample(localEpisode.Path, localEpisode.MediaInfo.RunTime, runtime);
}

View file

@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using DryIoc;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Builder;
@ -59,8 +60,11 @@ public void ConfigureServices(IServiceCollection services)
services.Configure<ForwardedHeadersOptions>(options =>
{
options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto | ForwardedHeaders.XForwardedHost;
options.KnownNetworks.Clear();
options.KnownProxies.Clear();
options.KnownNetworks.Add(new IPNetwork(IPAddress.Parse("10.0.0.0"), 8));
options.KnownNetworks.Add(new IPNetwork(IPAddress.Parse("172.16.0.0"), 12));
options.KnownNetworks.Add(new IPNetwork(IPAddress.Parse("192.168.0.0"), 16));
options.KnownNetworks.Add(new IPNetwork(IPAddress.Parse("fc00::"), 7));
options.KnownNetworks.Add(new IPNetwork(IPAddress.Parse("fe80::"), 10));
});
services.AddRouting(options => options.LowercaseUrls = true);