commit
c042f20224
@ -1,13 +0,0 @@
|
|||||||
#pragma warning disable CS1591
|
|
||||||
|
|
||||||
namespace Emby.Server.Implementations.IO
|
|
||||||
{
|
|
||||||
public class ExtendedFileSystemInfo
|
|
||||||
{
|
|
||||||
public bool IsHidden { get; set; }
|
|
||||||
|
|
||||||
public bool IsReadOnly { get; set; }
|
|
||||||
|
|
||||||
public bool Exists { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,28 @@
|
|||||||
|
{
|
||||||
|
"HeaderAlbumArtists": "Vaimbi vemadambarefu",
|
||||||
|
"HeaderContinueWatching": "Simudzira kuona",
|
||||||
|
"HeaderFavoriteSongs": "Nziyo dzaunofarira",
|
||||||
|
"Albums": "Dambarefu",
|
||||||
|
"AppDeviceValues": "Apu: {0}, Dhivhaisi: {1}",
|
||||||
|
"Application": "Purogiramu",
|
||||||
|
"Artists": "Vaimbi",
|
||||||
|
"AuthenticationSucceededWithUserName": "apinda",
|
||||||
|
"Books": "Mabhuku",
|
||||||
|
"CameraImageUploadedFrom": "Mufananidzo mutsva vabva pakamera {0}",
|
||||||
|
"Channels": "Machanewo",
|
||||||
|
"ChapterNameValue": "Chikamu {0}",
|
||||||
|
"Collections": "Akafanana",
|
||||||
|
"Default": "Zvakasarudzwa Kare",
|
||||||
|
"DeviceOfflineWithName": "{0} haasisipo",
|
||||||
|
"DeviceOnlineWithName": "{0} aripo",
|
||||||
|
"External": "Zvekunze",
|
||||||
|
"FailedLoginAttemptWithUserName": "Vatadza kuloga chimboedza kushandisa {0}",
|
||||||
|
"Favorites": "Zvaunofarira",
|
||||||
|
"Folders": "Mafoodha",
|
||||||
|
"Forced": "Zvekumanikidzira",
|
||||||
|
"Genres": "Mhando",
|
||||||
|
"HeaderFavoriteAlbums": "Madambarefu aunofarira",
|
||||||
|
"HeaderFavoriteArtists": "Vaimbi vaunofarira",
|
||||||
|
"HeaderFavoriteEpisodes": "Maepisodhi aunofarira",
|
||||||
|
"HeaderFavoriteShows": "Masirisi aunofarira"
|
||||||
|
}
|
@ -0,0 +1,120 @@
|
|||||||
|
/*
|
||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) .NET Foundation and Contributors
|
||||||
|
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
using System.IO;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Net.Sockets;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Jellyfin.Networking.HappyEyeballs
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the <see cref="HttpClientExtension"/> class.
|
||||||
|
///
|
||||||
|
/// Implementation taken from https://github.com/ppy/osu-framework/pull/4191 .
|
||||||
|
/// </summary>
|
||||||
|
public static class HttpClientExtension
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a value indicating whether the client should use IPv6.
|
||||||
|
/// </summary>
|
||||||
|
public static bool UseIPv6 { get; set; } = true;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Implements the httpclient callback method.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="context">The <see cref="SocketsHttpConnectionContext"/> instance.</param>
|
||||||
|
/// <param name="cancellationToken">The <see cref="CancellationToken"/> instance.</param>
|
||||||
|
/// <returns>The http steam.</returns>
|
||||||
|
public static async ValueTask<Stream> OnConnect(SocketsHttpConnectionContext context, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
if (!UseIPv6)
|
||||||
|
{
|
||||||
|
return await AttemptConnection(AddressFamily.InterNetwork, context, cancellationToken).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
using var cancelIPv6 = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
|
||||||
|
var tryConnectAsyncIPv6 = AttemptConnection(AddressFamily.InterNetworkV6, context, cancelIPv6.Token);
|
||||||
|
|
||||||
|
// GetAwaiter().GetResult() is used instead of .Result as this results in improved exception handling.
|
||||||
|
// The tasks have already been completed.
|
||||||
|
// See https://github.com/dotnet/corefx/pull/29792/files#r189415885 for more details.
|
||||||
|
if (await Task.WhenAny(tryConnectAsyncIPv6, Task.Delay(200, cancelIPv6.Token)).ConfigureAwait(false) == tryConnectAsyncIPv6 && tryConnectAsyncIPv6.IsCompletedSuccessfully)
|
||||||
|
{
|
||||||
|
cancelIPv6.Cancel();
|
||||||
|
return tryConnectAsyncIPv6.GetAwaiter().GetResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
using var cancelIPv4 = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
|
||||||
|
var tryConnectAsyncIPv4 = AttemptConnection(AddressFamily.InterNetwork, context, cancelIPv4.Token);
|
||||||
|
|
||||||
|
if (await Task.WhenAny(tryConnectAsyncIPv6, tryConnectAsyncIPv4).ConfigureAwait(false) == tryConnectAsyncIPv6)
|
||||||
|
{
|
||||||
|
if (tryConnectAsyncIPv6.IsCompletedSuccessfully)
|
||||||
|
{
|
||||||
|
cancelIPv4.Cancel();
|
||||||
|
return tryConnectAsyncIPv6.GetAwaiter().GetResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
return tryConnectAsyncIPv4.GetAwaiter().GetResult();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (tryConnectAsyncIPv4.IsCompletedSuccessfully)
|
||||||
|
{
|
||||||
|
cancelIPv6.Cancel();
|
||||||
|
return tryConnectAsyncIPv4.GetAwaiter().GetResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
return tryConnectAsyncIPv6.GetAwaiter().GetResult();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static async Task<Stream> AttemptConnection(AddressFamily addressFamily, SocketsHttpConnectionContext context, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
// The following socket constructor will create a dual-mode socket on systems where IPV6 is available.
|
||||||
|
var socket = new Socket(addressFamily, SocketType.Stream, ProtocolType.Tcp)
|
||||||
|
{
|
||||||
|
// Turn off Nagle's algorithm since it degrades performance in most HttpClient scenarios.
|
||||||
|
NoDelay = true
|
||||||
|
};
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await socket.ConnectAsync(context.DnsEndPoint, cancellationToken).ConfigureAwait(false);
|
||||||
|
// The stream should take the ownership of the underlying socket,
|
||||||
|
// closing it when it's disposed.
|
||||||
|
return new NetworkStream(socket, ownsSocket: true);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
socket.Dispose();
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,86 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Globalization;
|
|
||||||
using System.IO;
|
|
||||||
|
|
||||||
using Emby.Server.Implementations;
|
|
||||||
using MediaBrowser.Controller;
|
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using SQLitePCL.pretty;
|
|
||||||
|
|
||||||
namespace Jellyfin.Server.Migrations.PreStartupRoutines
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Migrate rating levels to new rating level system.
|
|
||||||
/// </summary>
|
|
||||||
internal class MigrateRatingLevels : IMigrationRoutine
|
|
||||||
{
|
|
||||||
private const string DbFilename = "library.db";
|
|
||||||
private readonly ILogger<MigrateRatingLevels> _logger;
|
|
||||||
private readonly IServerApplicationPaths _applicationPaths;
|
|
||||||
|
|
||||||
public MigrateRatingLevels(ServerApplicationPaths applicationPaths, ILoggerFactory loggerFactory)
|
|
||||||
{
|
|
||||||
_applicationPaths = applicationPaths;
|
|
||||||
_logger = loggerFactory.CreateLogger<MigrateRatingLevels>();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public Guid Id => Guid.Parse("{67445D54-B895-4B24-9F4C-35CE0690EA07}");
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public string Name => "MigrateRatingLevels";
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public bool PerformOnNewInstall => false;
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public void Perform()
|
|
||||||
{
|
|
||||||
var dataPath = _applicationPaths.DataPath;
|
|
||||||
var dbPath = Path.Combine(dataPath, DbFilename);
|
|
||||||
using (var connection = SQLite3.Open(
|
|
||||||
dbPath,
|
|
||||||
ConnectionFlags.ReadWrite,
|
|
||||||
null))
|
|
||||||
{
|
|
||||||
// Back up the database before deleting any entries
|
|
||||||
for (int i = 1; ; i++)
|
|
||||||
{
|
|
||||||
var bakPath = string.Format(CultureInfo.InvariantCulture, "{0}.bak{1}", dbPath, i);
|
|
||||||
if (!File.Exists(bakPath))
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
File.Copy(dbPath, bakPath);
|
|
||||||
_logger.LogInformation("Library database backed up to {BackupPath}", bakPath);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_logger.LogError(ex, "Cannot make a backup of {Library} at path {BackupPath}", DbFilename, bakPath);
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Migrate parental rating levels to new schema
|
|
||||||
_logger.LogInformation("Migrating parental rating levels.");
|
|
||||||
connection.Execute("UPDATE TypedBaseItems SET InheritedParentalRatingValue = NULL WHERE OfficialRating = 'NR'");
|
|
||||||
connection.Execute("UPDATE TypedBaseItems SET InheritedParentalRatingValue = NULL WHERE InheritedParentalRatingValue = ''");
|
|
||||||
connection.Execute("UPDATE TypedBaseItems SET InheritedParentalRatingValue = NULL WHERE InheritedParentalRatingValue = 0");
|
|
||||||
connection.Execute("UPDATE TypedBaseItems SET InheritedParentalRatingValue = 1000 WHERE InheritedParentalRatingValue = 100");
|
|
||||||
connection.Execute("UPDATE TypedBaseItems SET InheritedParentalRatingValue = 1000 WHERE InheritedParentalRatingValue = 15");
|
|
||||||
connection.Execute("UPDATE TypedBaseItems SET InheritedParentalRatingValue = 18 WHERE InheritedParentalRatingValue = 10");
|
|
||||||
connection.Execute("UPDATE TypedBaseItems SET InheritedParentalRatingValue = 18 WHERE InheritedParentalRatingValue = 9");
|
|
||||||
connection.Execute("UPDATE TypedBaseItems SET InheritedParentalRatingValue = 16 WHERE InheritedParentalRatingValue = 8");
|
|
||||||
connection.Execute("UPDATE TypedBaseItems SET InheritedParentalRatingValue = 12 WHERE InheritedParentalRatingValue = 7");
|
|
||||||
connection.Execute("UPDATE TypedBaseItems SET InheritedParentalRatingValue = 12 WHERE InheritedParentalRatingValue = 6");
|
|
||||||
connection.Execute("UPDATE TypedBaseItems SET InheritedParentalRatingValue = 12 WHERE InheritedParentalRatingValue = 5");
|
|
||||||
connection.Execute("UPDATE TypedBaseItems SET InheritedParentalRatingValue = 7 WHERE InheritedParentalRatingValue = 4");
|
|
||||||
connection.Execute("UPDATE TypedBaseItems SET InheritedParentalRatingValue = 6 WHERE InheritedParentalRatingValue = 3");
|
|
||||||
connection.Execute("UPDATE TypedBaseItems SET InheritedParentalRatingValue = 6 WHERE InheritedParentalRatingValue = 2");
|
|
||||||
connection.Execute("UPDATE TypedBaseItems SET InheritedParentalRatingValue = 0 WHERE InheritedParentalRatingValue = 1");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,103 @@
|
|||||||
|
using System;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
using Emby.Server.Implementations.Data;
|
||||||
|
using MediaBrowser.Controller;
|
||||||
|
using MediaBrowser.Controller.Persistence;
|
||||||
|
using MediaBrowser.Model.Globalization;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using SQLitePCL.pretty;
|
||||||
|
|
||||||
|
namespace Jellyfin.Server.Migrations.Routines
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Migrate rating levels to new rating level system.
|
||||||
|
/// </summary>
|
||||||
|
internal class MigrateRatingLevels : IMigrationRoutine
|
||||||
|
{
|
||||||
|
private const string DbFilename = "library.db";
|
||||||
|
private readonly ILogger<MigrateRatingLevels> _logger;
|
||||||
|
private readonly IServerApplicationPaths _applicationPaths;
|
||||||
|
private readonly ILocalizationManager _localizationManager;
|
||||||
|
private readonly IItemRepository _repository;
|
||||||
|
|
||||||
|
public MigrateRatingLevels(
|
||||||
|
IServerApplicationPaths applicationPaths,
|
||||||
|
ILoggerFactory loggerFactory,
|
||||||
|
ILocalizationManager localizationManager,
|
||||||
|
IItemRepository repository)
|
||||||
|
{
|
||||||
|
_applicationPaths = applicationPaths;
|
||||||
|
_localizationManager = localizationManager;
|
||||||
|
_repository = repository;
|
||||||
|
_logger = loggerFactory.CreateLogger<MigrateRatingLevels>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public Guid Id => Guid.Parse("{67445D54-B895-4B24-9F4C-35CE0690EA07}");
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public string Name => "MigrateRatingLevels";
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public bool PerformOnNewInstall => false;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public void Perform()
|
||||||
|
{
|
||||||
|
var dbPath = Path.Combine(_applicationPaths.DataPath, DbFilename);
|
||||||
|
|
||||||
|
// Back up the database before modifying any entries
|
||||||
|
for (int i = 1; ; i++)
|
||||||
|
{
|
||||||
|
var bakPath = string.Format(CultureInfo.InvariantCulture, "{0}.bak{1}", dbPath, i);
|
||||||
|
if (!File.Exists(bakPath))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
File.Copy(dbPath, bakPath);
|
||||||
|
_logger.LogInformation("Library database backed up to {BackupPath}", bakPath);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, "Cannot make a backup of {Library} at path {BackupPath}", DbFilename, bakPath);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Migrate parental rating strings to new levels
|
||||||
|
_logger.LogInformation("Recalculating parental rating levels based on rating string.");
|
||||||
|
using (var connection = SQLite3.Open(
|
||||||
|
dbPath,
|
||||||
|
ConnectionFlags.ReadWrite,
|
||||||
|
null))
|
||||||
|
{
|
||||||
|
var queryResult = connection.Query("SELECT DISTINCT OfficialRating FROM TypedBaseItems");
|
||||||
|
foreach (var entry in queryResult)
|
||||||
|
{
|
||||||
|
var ratingString = entry[0].ToString();
|
||||||
|
if (string.IsNullOrEmpty(ratingString))
|
||||||
|
{
|
||||||
|
connection.Execute("UPDATE TypedBaseItems SET InheritedParentalRatingValue = NULL WHERE OfficialRating IS NULL OR OfficialRating='';");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var ratingValue = _localizationManager.GetRatingLevel(ratingString).ToString();
|
||||||
|
if (string.IsNullOrEmpty(ratingValue))
|
||||||
|
{
|
||||||
|
ratingValue = "NULL";
|
||||||
|
}
|
||||||
|
|
||||||
|
var statement = connection.PrepareStatement("UPDATE TypedBaseItems SET InheritedParentalRatingValue = @Value WHERE OfficialRating = @Rating;");
|
||||||
|
statement.TryBind("@Value", ratingValue);
|
||||||
|
statement.TryBind("@Rating", ratingString);
|
||||||
|
statement.ExecuteQuery();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in new issue