aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Emby.Dlna/DlnaManager.cs32
-rw-r--r--Emby.Dlna/PlayTo/SsdpHttpClient.cs4
-rw-r--r--Emby.Server.Implementations/ApplicationHost.cs15
-rw-r--r--Emby.Server.Implementations/Localization/Core/zh-TW.json52
-rw-r--r--Emby.Server.Implementations/Udp/UdpServer.cs6
-rw-r--r--Emby.Server.Implementations/Updates/InstallationManager.cs13
-rw-r--r--Jellyfin.Api/Controllers/PackageController.cs10
-rw-r--r--Jellyfin.Api/Helpers/FileStreamResponseHelpers.cs9
-rw-r--r--Jellyfin.Api/Helpers/StreamingHelpers.cs1
-rw-r--r--Jellyfin.Server.Implementations/JellyfinDb.cs42
-rw-r--r--Jellyfin.Server.Implementations/Migrations/20200905220533_FixDisplayPreferencesIndex.Designer.cs461
-rw-r--r--Jellyfin.Server.Implementations/Migrations/20200905220533_FixDisplayPreferencesIndex.cs51
-rw-r--r--Jellyfin.Server.Implementations/Migrations/JellyfinDbModelSnapshot.cs6
-rw-r--r--Jellyfin.Server/Jellyfin.Server.csproj2
-rw-r--r--MediaBrowser.Common/Updates/IInstallationManager.cs4
-rw-r--r--MediaBrowser.Controller/IServerApplicationHost.cs2
-rw-r--r--MediaBrowser.Model/Dlna/DeviceIdentification.cs6
-rw-r--r--MediaBrowser.Model/System/PublicSystemInfo.cs8
-rw-r--r--MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbEpisodeProvider.cs2
-rw-r--r--MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeasonProvider.cs2
-rw-r--r--MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeriesProvider.cs2
-rw-r--r--MediaBrowser.sln1
22 files changed, 604 insertions, 127 deletions
diff --git a/Emby.Dlna/DlnaManager.cs b/Emby.Dlna/DlnaManager.cs
index d5629684c..5612376a5 100644
--- a/Emby.Dlna/DlnaManager.cs
+++ b/Emby.Dlna/DlnaManager.cs
@@ -126,7 +126,6 @@ namespace Emby.Dlna
var builder = new StringBuilder();
builder.AppendLine("No matching device profile found. The default will need to be used.");
- builder.AppendFormat(CultureInfo.InvariantCulture, "DeviceDescription:{0}", profile.DeviceDescription ?? string.Empty).AppendLine();
builder.AppendFormat(CultureInfo.InvariantCulture, "FriendlyName:{0}", profile.FriendlyName ?? string.Empty).AppendLine();
builder.AppendFormat(CultureInfo.InvariantCulture, "Manufacturer:{0}", profile.Manufacturer ?? string.Empty).AppendLine();
builder.AppendFormat(CultureInfo.InvariantCulture, "ManufacturerUrl:{0}", profile.ManufacturerUrl ?? string.Empty).AppendLine();
@@ -141,17 +140,9 @@ namespace Emby.Dlna
private bool IsMatch(DeviceIdentification deviceInfo, DeviceIdentification profileInfo)
{
- if (!string.IsNullOrEmpty(profileInfo.DeviceDescription))
- {
- if (deviceInfo.DeviceDescription == null || !IsRegexMatch(deviceInfo.DeviceDescription, profileInfo.DeviceDescription))
- {
- return false;
- }
- }
-
if (!string.IsNullOrEmpty(profileInfo.FriendlyName))
{
- if (deviceInfo.FriendlyName == null || !IsRegexMatch(deviceInfo.FriendlyName, profileInfo.FriendlyName))
+ if (deviceInfo.FriendlyName == null || !IsRegexOrSubstringMatch(deviceInfo.FriendlyName, profileInfo.FriendlyName))
{
return false;
}
@@ -159,7 +150,7 @@ namespace Emby.Dlna
if (!string.IsNullOrEmpty(profileInfo.Manufacturer))
{
- if (deviceInfo.Manufacturer == null || !IsRegexMatch(deviceInfo.Manufacturer, profileInfo.Manufacturer))
+ if (deviceInfo.Manufacturer == null || !IsRegexOrSubstringMatch(deviceInfo.Manufacturer, profileInfo.Manufacturer))
{
return false;
}
@@ -167,7 +158,7 @@ namespace Emby.Dlna
if (!string.IsNullOrEmpty(profileInfo.ManufacturerUrl))
{
- if (deviceInfo.ManufacturerUrl == null || !IsRegexMatch(deviceInfo.ManufacturerUrl, profileInfo.ManufacturerUrl))
+ if (deviceInfo.ManufacturerUrl == null || !IsRegexOrSubstringMatch(deviceInfo.ManufacturerUrl, profileInfo.ManufacturerUrl))
{
return false;
}
@@ -175,7 +166,7 @@ namespace Emby.Dlna
if (!string.IsNullOrEmpty(profileInfo.ModelDescription))
{
- if (deviceInfo.ModelDescription == null || !IsRegexMatch(deviceInfo.ModelDescription, profileInfo.ModelDescription))
+ if (deviceInfo.ModelDescription == null || !IsRegexOrSubstringMatch(deviceInfo.ModelDescription, profileInfo.ModelDescription))
{
return false;
}
@@ -183,7 +174,7 @@ namespace Emby.Dlna
if (!string.IsNullOrEmpty(profileInfo.ModelName))
{
- if (deviceInfo.ModelName == null || !IsRegexMatch(deviceInfo.ModelName, profileInfo.ModelName))
+ if (deviceInfo.ModelName == null || !IsRegexOrSubstringMatch(deviceInfo.ModelName, profileInfo.ModelName))
{
return false;
}
@@ -191,7 +182,7 @@ namespace Emby.Dlna
if (!string.IsNullOrEmpty(profileInfo.ModelNumber))
{
- if (deviceInfo.ModelNumber == null || !IsRegexMatch(deviceInfo.ModelNumber, profileInfo.ModelNumber))
+ if (deviceInfo.ModelNumber == null || !IsRegexOrSubstringMatch(deviceInfo.ModelNumber, profileInfo.ModelNumber))
{
return false;
}
@@ -199,7 +190,7 @@ namespace Emby.Dlna
if (!string.IsNullOrEmpty(profileInfo.ModelUrl))
{
- if (deviceInfo.ModelUrl == null || !IsRegexMatch(deviceInfo.ModelUrl, profileInfo.ModelUrl))
+ if (deviceInfo.ModelUrl == null || !IsRegexOrSubstringMatch(deviceInfo.ModelUrl, profileInfo.ModelUrl))
{
return false;
}
@@ -207,7 +198,7 @@ namespace Emby.Dlna
if (!string.IsNullOrEmpty(profileInfo.SerialNumber))
{
- if (deviceInfo.SerialNumber == null || !IsRegexMatch(deviceInfo.SerialNumber, profileInfo.SerialNumber))
+ if (deviceInfo.SerialNumber == null || !IsRegexOrSubstringMatch(deviceInfo.SerialNumber, profileInfo.SerialNumber))
{
return false;
}
@@ -216,11 +207,11 @@ namespace Emby.Dlna
return true;
}
- private bool IsRegexMatch(string input, string pattern)
+ private bool IsRegexOrSubstringMatch(string input, string pattern)
{
try
{
- return Regex.IsMatch(input, pattern);
+ return input.Contains(pattern, StringComparison.OrdinalIgnoreCase) || Regex.IsMatch(input, pattern, RegexOptions.IgnoreCase | RegexOptions.CultureInvariant);
}
catch (ArgumentException ex)
{
@@ -511,8 +502,7 @@ namespace Emby.Dlna
public string GetServerDescriptionXml(IHeaderDictionary headers, string serverUuId, string serverAddress)
{
- var profile = GetProfile(headers) ??
- GetDefaultProfile();
+ var profile = GetDefaultProfile();
var serverId = _appHost.SystemId;
diff --git a/Emby.Dlna/PlayTo/SsdpHttpClient.cs b/Emby.Dlna/PlayTo/SsdpHttpClient.cs
index 8683c8997..c8c36fc97 100644
--- a/Emby.Dlna/PlayTo/SsdpHttpClient.cs
+++ b/Emby.Dlna/PlayTo/SsdpHttpClient.cs
@@ -101,7 +101,7 @@ namespace Emby.Dlna.PlayTo
LoadOptions.PreserveWhitespace);
}
- private Task<HttpResponseMessage> PostSoapDataAsync(
+ private async Task<HttpResponseMessage> PostSoapDataAsync(
string url,
string soapAction,
string postData,
@@ -126,7 +126,7 @@ namespace Emby.Dlna.PlayTo
options.Content = new StringContent(postData, Encoding.UTF8, MediaTypeNames.Text.Xml);
- return _httpClientFactory.CreateClient(NamedClient.Default).SendAsync(options, HttpCompletionOption.ResponseHeadersRead, cancellationToken);
+ return await _httpClientFactory.CreateClient(NamedClient.Default).SendAsync(options, HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false);
}
}
}
diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs
index c37e87d96..642e2fdbe 100644
--- a/Emby.Server.Implementations/ApplicationHost.cs
+++ b/Emby.Server.Implementations/ApplicationHost.cs
@@ -238,8 +238,14 @@ namespace Emby.Server.Implementations
public IServerConfigurationManager ServerConfigurationManager => (IServerConfigurationManager)ConfigurationManager;
/// <summary>
- /// Initializes a new instance of the <see cref="ApplicationHost" /> class.
+ /// Initializes a new instance of the <see cref="ApplicationHost"/> class.
/// </summary>
+ /// <param name="applicationPaths">Instance of the <see cref="IServerApplicationPaths"/> interface.</param>
+ /// <param name="loggerFactory">Instance of the <see cref="ILoggerFactory"/> interface.</param>
+ /// <param name="options">Instance of the <see cref="IStartupOptions"/> interface.</param>
+ /// <param name="fileSystem">Instance of the <see cref="IFileSystem"/> interface.</param>
+ /// <param name="networkManager">Instance of the <see cref="INetworkManager"/> interface.</param>
+ /// <param name="serviceCollection">Instance of the <see cref="IServiceCollection"/> interface.</param>
public ApplicationHost(
IServerApplicationPaths applicationPaths,
ILoggerFactory loggerFactory,
@@ -1137,7 +1143,8 @@ namespace Emby.Server.Implementations
Id = SystemId,
OperatingSystem = OperatingSystem.Id.ToString(),
ServerName = FriendlyName,
- LocalAddress = localAddress
+ LocalAddress = localAddress,
+ StartupWizardCompleted = ConfigurationManager.CommonConfiguration.IsStartupWizardCompleted
};
}
@@ -1431,10 +1438,6 @@ namespace Emby.Server.Implementations
}
}
- public virtual void EnableLoopback(string appName)
- {
- }
-
private bool _disposed = false;
/// <summary>
diff --git a/Emby.Server.Implementations/Localization/Core/zh-TW.json b/Emby.Server.Implementations/Localization/Core/zh-TW.json
index a21cdad95..01108fe84 100644
--- a/Emby.Server.Implementations/Localization/Core/zh-TW.json
+++ b/Emby.Server.Implementations/Localization/Core/zh-TW.json
@@ -1,6 +1,6 @@
{
"Albums": "專輯",
- "AppDeviceValues": "軟體: {0}, 裝置: {1}",
+ "AppDeviceValues": "軟體:{0},裝置:{1}",
"Application": "應用程式",
"Artists": "演出者",
"AuthenticationSucceededWithUserName": "{0} 成功授權",
@@ -11,7 +11,7 @@
"Collections": "合輯",
"DeviceOfflineWithName": "{0} 已經斷線",
"DeviceOnlineWithName": "{0} 已經連線",
- "FailedLoginAttemptWithUserName": "來自 {0} 的失敗登入嘗試",
+ "FailedLoginAttemptWithUserName": "來自使用者 {0} 的失敗登入",
"Favorites": "我的最愛",
"Folders": "資料夾",
"Genres": "風格",
@@ -28,8 +28,8 @@
"HomeVideos": "自製影片",
"ItemAddedWithName": "{0} 已新增至媒體庫",
"ItemRemovedWithName": "{0} 已從媒體庫移除",
- "LabelIpAddressValue": "IP 位置: {0}",
- "LabelRunningTimeValue": "運行時間: {0}",
+ "LabelIpAddressValue": "IP 位址:{0}",
+ "LabelRunningTimeValue": "運行時間:{0}",
"Latest": "最新",
"MessageApplicationUpdated": "Jellyfin Server 已經更新",
"MessageApplicationUpdatedTo": "Jellyfin Server 已經更新至 {0}",
@@ -42,18 +42,18 @@
"NameInstallFailed": "{0} 安裝失敗",
"NameSeasonNumber": "第 {0} 季",
"NameSeasonUnknown": "未知季數",
- "NewVersionIsAvailable": "新版本的Jellyfin Server 軟體已經推出可供下載。",
+ "NewVersionIsAvailable": "新版本的 Jellyfin Server 軟體已經可供下載。",
"NotificationOptionApplicationUpdateAvailable": "有可用的應用程式更新",
- "NotificationOptionApplicationUpdateInstalled": "應用程式已更新",
+ "NotificationOptionApplicationUpdateInstalled": "軟體更新已安裝",
"NotificationOptionAudioPlayback": "音樂開始播放",
"NotificationOptionAudioPlaybackStopped": "音樂停止播放",
"NotificationOptionCameraImageUploaded": "相機相片已上傳",
"NotificationOptionInstallationFailed": "安裝失敗",
"NotificationOptionNewLibraryContent": "已新增新內容",
- "NotificationOptionPluginError": "插件安裝錯誤",
- "NotificationOptionPluginInstalled": "插件已安裝",
- "NotificationOptionPluginUninstalled": "插件已移除",
- "NotificationOptionPluginUpdateInstalled": "插件已更新",
+ "NotificationOptionPluginError": "外掛安裝失敗",
+ "NotificationOptionPluginInstalled": "外掛已安裝",
+ "NotificationOptionPluginUninstalled": "外掛已移除",
+ "NotificationOptionPluginUpdateInstalled": "外掛已更新",
"NotificationOptionServerRestartRequired": "伺服器需要重新啟動",
"NotificationOptionTaskFailed": "排程任務失敗",
"NotificationOptionUserLockedOut": "使用者已鎖定",
@@ -61,14 +61,14 @@
"NotificationOptionVideoPlaybackStopped": "影片停止播放",
"Photos": "相片",
"Playlists": "播放清單",
- "Plugin": "插件",
+ "Plugin": "外掛",
"PluginInstalledWithName": "{0} 已安裝",
"PluginUninstalledWithName": "{0} 已移除",
"PluginUpdatedWithName": "{0} 已更新",
"ProviderValue": "提供商: {0}",
- "ScheduledTaskFailedWithName": "{0} 已失敗",
- "ScheduledTaskStartedWithName": "{0} 已開始",
- "ServerNameNeedsToBeRestarted": "{0} 需要重新啟動",
+ "ScheduledTaskFailedWithName": "排程任務 {0} 已失敗",
+ "ScheduledTaskStartedWithName": "排程任務 {0} 已開始",
+ "ServerNameNeedsToBeRestarted": "伺服器 {0} 需要重新啟動",
"Shows": "節目",
"Songs": "歌曲",
"StartupEmbyServerIsLoading": "Jellyfin Server正在啟動,請稍後再試一次。",
@@ -78,10 +78,10 @@
"User": "使用者",
"UserCreatedWithName": "使用者 {0} 已建立",
"UserDeletedWithName": "使用者 {0} 已移除",
- "UserDownloadingItemWithValues": "{0} 正在下載 {1}",
+ "UserDownloadingItemWithValues": "使用者 {0} 正在下載 {1}",
"UserLockedOutWithName": "使用者 {0} 已鎖定",
- "UserOfflineFromDevice": "{0} 已從 {1} 斷線",
- "UserOnlineFromDevice": "{0} 已連線,來自 {1}",
+ "UserOfflineFromDevice": "使用者 {0} 已從 {1} 斷線",
+ "UserOnlineFromDevice": "使用者 {0} 已從 {1} 連線",
"UserPasswordChangedWithName": "使用者 {0} 的密碼已變更",
"UserPolicyUpdatedWithName": "使用者條約已更新為 {0}",
"UserStartedPlayingItemWithValues": "{0}正在使用 {2} 播放 {1}",
@@ -95,23 +95,23 @@
"TaskDownloadMissingSubtitlesDescription": "在網路上透過中繼資料搜尋遺失的字幕。",
"TaskDownloadMissingSubtitles": "下載遺失的字幕",
"TaskRefreshChannels": "重新整理頻道",
- "TaskUpdatePlugins": "更新插件",
+ "TaskUpdatePlugins": "更新外掛",
"TaskRefreshPeople": "重新整理人員",
- "TaskCleanLogsDescription": "刪除超過{0}天的紀錄檔案。",
+ "TaskCleanLogsDescription": "刪除超過 {0} 天的舊紀錄檔。",
"TaskCleanLogs": "清空紀錄資料夾",
- "TaskRefreshLibraryDescription": "掃描媒體庫內新的檔案並重新整理描述資料。",
- "TaskRefreshLibrary": "掃描媒體庫",
+ "TaskRefreshLibraryDescription": "重新掃描媒體庫的新檔案並更新描述資料。",
+ "TaskRefreshLibrary": "重新掃描媒體庫",
"TaskRefreshChapterImages": "擷取章節圖片",
- "TaskCleanCacheDescription": "刪除系統長時間不需要的快取。",
+ "TaskCleanCacheDescription": "刪除系統已不需要的快取。",
"TaskCleanCache": "清除快取資料夾",
"TasksLibraryCategory": "媒體庫",
- "TaskRefreshChannelsDescription": "重新整理網絡頻道資料。",
+ "TaskRefreshChannelsDescription": "重新整理網路頻道資料。",
"TaskCleanTranscodeDescription": "刪除超過一天的轉碼檔案。",
"TaskCleanTranscode": "清除轉碼資料夾",
- "TaskUpdatePluginsDescription": "下載並安裝配置為自動更新的插件的更新。",
+ "TaskUpdatePluginsDescription": "為設置自動更新的外掛下載並安裝更新。",
"TaskRefreshPeopleDescription": "更新媒體庫中演員和導演的中繼資料。",
- "TaskRefreshChapterImagesDescription": "為有章節的視頻創建縮圖。",
- "TasksChannelsCategory": "網絡頻道",
+ "TaskRefreshChapterImagesDescription": "為有章節的影片建立縮圖。",
+ "TasksChannelsCategory": "網路頻道",
"TasksApplicationCategory": "應用程式",
"TasksMaintenanceCategory": "維修"
}
diff --git a/Emby.Server.Implementations/Udp/UdpServer.cs b/Emby.Server.Implementations/Udp/UdpServer.cs
index 73fcbcec3..b7a59cee2 100644
--- a/Emby.Server.Implementations/Udp/UdpServer.cs
+++ b/Emby.Server.Implementations/Udp/UdpServer.cs
@@ -68,12 +68,6 @@ namespace Emby.Server.Implementations.Udp
{
_logger.LogError(ex, "Error sending response message");
}
-
- var parts = messageText.Split('|');
- if (parts.Length > 1)
- {
- _appHost.EnableLoopback(parts[1]);
- }
}
else
{
diff --git a/Emby.Server.Implementations/Updates/InstallationManager.cs b/Emby.Server.Implementations/Updates/InstallationManager.cs
index f121a3493..e19158f8e 100644
--- a/Emby.Server.Implementations/Updates/InstallationManager.cs
+++ b/Emby.Server.Implementations/Updates/InstallationManager.cs
@@ -183,7 +183,8 @@ namespace Emby.Server.Implementations.Updates
IEnumerable<PackageInfo> availablePackages,
string name = null,
Guid guid = default,
- Version minVersion = null)
+ Version minVersion = null,
+ Version specificVersion = null)
{
var package = FilterPackages(availablePackages, name, guid).FirstOrDefault();
@@ -197,7 +198,11 @@ namespace Emby.Server.Implementations.Updates
var availableVersions = package.versions
.Where(x => Version.Parse(x.targetAbi) <= appVer);
- if (minVersion != null)
+ if (specificVersion != null)
+ {
+ availableVersions = availableVersions.Where(x => new Version(x.version) == specificVersion);
+ }
+ else if (minVersion != null)
{
availableVersions = availableVersions.Where(x => new Version(x.version) >= minVersion);
}
@@ -227,8 +232,8 @@ namespace Emby.Server.Implementations.Updates
{
foreach (var plugin in _applicationHost.Plugins)
{
- var compatibleversions = GetCompatibleVersions(pluginCatalog, plugin.Name, plugin.Id, plugin.Version);
- var version = compatibleversions.FirstOrDefault(y => y.Version > plugin.Version);
+ var compatibleVersions = GetCompatibleVersions(pluginCatalog, plugin.Name, plugin.Id, minVersion: plugin.Version);
+ var version = compatibleVersions.FirstOrDefault(y => y.Version > plugin.Version);
if (version != null && CompletedInstallations.All(x => x.Guid != version.Guid))
{
yield return version;
diff --git a/Jellyfin.Api/Controllers/PackageController.cs b/Jellyfin.Api/Controllers/PackageController.cs
index 7e406b418..9509f8708 100644
--- a/Jellyfin.Api/Controllers/PackageController.cs
+++ b/Jellyfin.Api/Controllers/PackageController.cs
@@ -49,9 +49,10 @@ namespace Jellyfin.Api.Controllers
{
var packages = await _installationManager.GetAvailablePackages().ConfigureAwait(false);
var result = _installationManager.FilterPackages(
- packages,
- name,
- string.IsNullOrEmpty(assemblyGuid) ? default : Guid.Parse(assemblyGuid)).FirstOrDefault();
+ packages,
+ name,
+ string.IsNullOrEmpty(assemblyGuid) ? default : Guid.Parse(assemblyGuid))
+ .FirstOrDefault();
return result;
}
@@ -93,7 +94,8 @@ namespace Jellyfin.Api.Controllers
packages,
name,
string.IsNullOrEmpty(assemblyGuid) ? Guid.Empty : Guid.Parse(assemblyGuid),
- string.IsNullOrEmpty(version) ? null : Version.Parse(version)).FirstOrDefault();
+ specificVersion: string.IsNullOrEmpty(version) ? null : Version.Parse(version))
+ .FirstOrDefault();
if (package == null)
{
diff --git a/Jellyfin.Api/Helpers/FileStreamResponseHelpers.cs b/Jellyfin.Api/Helpers/FileStreamResponseHelpers.cs
index 884bfbe44..6b516977e 100644
--- a/Jellyfin.Api/Helpers/FileStreamResponseHelpers.cs
+++ b/Jellyfin.Api/Helpers/FileStreamResponseHelpers.cs
@@ -1,4 +1,4 @@
-using System;
+using System;
using System.IO;
using System.Net.Http;
using System.Threading;
@@ -123,10 +123,9 @@ namespace Jellyfin.Api.Helpers
state.Dispose();
}
- var memoryStream = new MemoryStream();
- await new ProgressiveFileCopier(outputPath, job, transcodingJobHelper, CancellationToken.None).WriteToAsync(memoryStream, CancellationToken.None).ConfigureAwait(false);
- memoryStream.Position = 0;
- return new FileStreamResult(memoryStream, contentType);
+ await new ProgressiveFileCopier(outputPath, job, transcodingJobHelper, CancellationToken.None)
+ .WriteToAsync(httpContext.Response.Body, CancellationToken.None).ConfigureAwait(false);
+ return new FileStreamResult(httpContext.Response.Body, contentType);
}
finally
{
diff --git a/Jellyfin.Api/Helpers/StreamingHelpers.cs b/Jellyfin.Api/Helpers/StreamingHelpers.cs
index c11799bc8..89ab2da62 100644
--- a/Jellyfin.Api/Helpers/StreamingHelpers.cs
+++ b/Jellyfin.Api/Helpers/StreamingHelpers.cs
@@ -92,7 +92,6 @@ namespace Jellyfin.Api.Helpers
}
var enableDlnaHeaders = !string.IsNullOrWhiteSpace(streamingRequest.Params) ||
- streamingRequest.StreamOptions.ContainsKey("dlnaheaders") ||
string.Equals(httpRequest.Headers["GetContentFeatures.DLNA.ORG"], "1", StringComparison.OrdinalIgnoreCase);
var state = new StreamState(mediaSourceManager, transcodingJobType, transcodingJobHelper)
diff --git a/Jellyfin.Server.Implementations/JellyfinDb.cs b/Jellyfin.Server.Implementations/JellyfinDb.cs
index 08e4db388..45e71f16e 100644
--- a/Jellyfin.Server.Implementations/JellyfinDb.cs
+++ b/Jellyfin.Server.Implementations/JellyfinDb.cs
@@ -1,6 +1,5 @@
#pragma warning disable CS1591
-using System;
using System.Linq;
using Jellyfin.Data.Entities;
using Jellyfin.Data.Interfaces;
@@ -9,7 +8,7 @@ using Microsoft.EntityFrameworkCore;
namespace Jellyfin.Server.Implementations
{
/// <inheritdoc/>
- public partial class JellyfinDb : DbContext
+ public class JellyfinDb : DbContext
{
/// <summary>
/// Initializes a new instance of the <see cref="JellyfinDb"/> class.
@@ -138,47 +137,20 @@ namespace Jellyfin.Server.Implementations
return base.SaveChanges();
}
- /// <inheritdoc/>
- public override void Dispose()
- {
- foreach (var entry in ChangeTracker.Entries())
- {
- entry.State = EntityState.Detached;
- }
-
- GC.SuppressFinalize(this);
- base.Dispose();
- }
-
- /// <inheritdoc />
- protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
- {
- CustomInit(optionsBuilder);
- }
-
/// <inheritdoc />
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
- OnModelCreatingImpl(modelBuilder);
modelBuilder.HasDefaultSchema("jellyfin");
- /*modelBuilder.Entity<Artwork>().HasIndex(t => t.Kind);
-
- modelBuilder.Entity<Genre>().HasIndex(t => t.Name)
- .IsUnique();
+ modelBuilder.Entity<DisplayPreferences>()
+ .HasIndex(entity => entity.UserId)
+ .IsUnique(false);
- modelBuilder.Entity<LibraryItem>().HasIndex(t => t.UrlId)
- .IsUnique();*/
-
- OnModelCreatedImpl(modelBuilder);
+ modelBuilder.Entity<DisplayPreferences>()
+ .HasIndex(entity => new { entity.UserId, entity.Client })
+ .IsUnique();
}
-
- partial void CustomInit(DbContextOptionsBuilder optionsBuilder);
-
- partial void OnModelCreatingImpl(ModelBuilder modelBuilder);
-
- partial void OnModelCreatedImpl(ModelBuilder modelBuilder);
}
}
diff --git a/Jellyfin.Server.Implementations/Migrations/20200905220533_FixDisplayPreferencesIndex.Designer.cs b/Jellyfin.Server.Implementations/Migrations/20200905220533_FixDisplayPreferencesIndex.Designer.cs
new file mode 100644
index 000000000..2234f9d5f
--- /dev/null
+++ b/Jellyfin.Server.Implementations/Migrations/20200905220533_FixDisplayPreferencesIndex.Designer.cs
@@ -0,0 +1,461 @@
+#pragma warning disable CS1591
+
+// <auto-generated />
+using System;
+using Jellyfin.Server.Implementations;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+
+namespace Jellyfin.Server.Implementations.Migrations
+{
+ [DbContext(typeof(JellyfinDb))]
+ [Migration("20200905220533_FixDisplayPreferencesIndex")]
+ partial class FixDisplayPreferencesIndex
+ {
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasDefaultSchema("jellyfin")
+ .HasAnnotation("ProductVersion", "3.1.7");
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property<int>("DayOfWeek")
+ .HasColumnType("INTEGER");
+
+ b.Property<double>("EndHour")
+ .HasColumnType("REAL");
+
+ b.Property<double>("StartHour")
+ .HasColumnType("REAL");
+
+ b.Property<Guid>("UserId")
+ .HasColumnType("TEXT");
+
+ b.HasKey("Id");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("AccessSchedules");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.ActivityLog", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property<DateTime>("DateCreated")
+ .HasColumnType("TEXT");
+
+ b.Property<string>("ItemId")
+ .HasColumnType("TEXT")
+ .HasMaxLength(256);
+
+ b.Property<int>("LogSeverity")
+ .HasColumnType("INTEGER");
+
+ b.Property<string>("Name")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasMaxLength(512);
+
+ b.Property<string>("Overview")
+ .HasColumnType("TEXT")
+ .HasMaxLength(512);
+
+ b.Property<uint>("RowVersion")
+ .IsConcurrencyToken()
+ .HasColumnType("INTEGER");
+
+ b.Property<string>("ShortOverview")
+ .HasColumnType("TEXT")
+ .HasMaxLength(512);
+
+ b.Property<string>("Type")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasMaxLength(256);
+
+ b.Property<Guid>("UserId")
+ .HasColumnType("TEXT");
+
+ b.HasKey("Id");
+
+ b.ToTable("ActivityLogs");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property<int>("ChromecastVersion")
+ .HasColumnType("INTEGER");
+
+ b.Property<string>("Client")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasMaxLength(32);
+
+ b.Property<string>("DashboardTheme")
+ .HasColumnType("TEXT")
+ .HasMaxLength(32);
+
+ b.Property<bool>("EnableNextVideoInfoOverlay")
+ .HasColumnType("INTEGER");
+
+ b.Property<int?>("IndexBy")
+ .HasColumnType("INTEGER");
+
+ b.Property<int>("ScrollDirection")
+ .HasColumnType("INTEGER");
+
+ b.Property<bool>("ShowBackdrop")
+ .HasColumnType("INTEGER");
+
+ b.Property<bool>("ShowSidebar")
+ .HasColumnType("INTEGER");
+
+ b.Property<int>("SkipBackwardLength")
+ .HasColumnType("INTEGER");
+
+ b.Property<int>("SkipForwardLength")
+ .HasColumnType("INTEGER");
+
+ b.Property<string>("TvHome")
+ .HasColumnType("TEXT")
+ .HasMaxLength(32);
+
+ b.Property<Guid>("UserId")
+ .HasColumnType("TEXT");
+
+ b.HasKey("Id");
+
+ b.HasIndex("UserId");
+
+ b.HasIndex("UserId", "Client")
+ .IsUnique();
+
+ b.ToTable("DisplayPreferences");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property<int>("DisplayPreferencesId")
+ .HasColumnType("INTEGER");
+
+ b.Property<int>("Order")
+ .HasColumnType("INTEGER");
+
+ b.Property<int>("Type")
+ .HasColumnType("INTEGER");
+
+ b.HasKey("Id");
+
+ b.HasIndex("DisplayPreferencesId");
+
+ b.ToTable("HomeSection");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property<DateTime>("LastModified")
+ .HasColumnType("TEXT");
+
+ b.Property<string>("Path")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasMaxLength(512);
+
+ b.Property<Guid?>("UserId")
+ .HasColumnType("TEXT");
+
+ b.HasKey("Id");
+
+ b.HasIndex("UserId")
+ .IsUnique();
+
+ b.ToTable("ImageInfos");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property<string>("Client")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasMaxLength(32);
+
+ b.Property<int?>("IndexBy")
+ .HasColumnType("INTEGER");
+
+ b.Property<Guid>("ItemId")
+ .HasColumnType("TEXT");
+
+ b.Property<bool>("RememberIndexing")
+ .HasColumnType("INTEGER");
+
+ b.Property<bool>("RememberSorting")
+ .HasColumnType("INTEGER");
+
+ b.Property<string>("SortBy")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasMaxLength(64);
+
+ b.Property<int>("SortOrder")
+ .HasColumnType("INTEGER");
+
+ b.Property<Guid>("UserId")
+ .HasColumnType("TEXT");
+
+ b.Property<int>("ViewType")
+ .HasColumnType("INTEGER");
+
+ b.HasKey("Id");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("ItemDisplayPreferences");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property<int>("Kind")
+ .HasColumnType("INTEGER");
+
+ b.Property<Guid?>("Permission_Permissions_Guid")
+ .HasColumnType("TEXT");
+
+ b.Property<uint>("RowVersion")
+ .IsConcurrencyToken()
+ .HasColumnType("INTEGER");
+
+ b.Property<bool>("Value")
+ .HasColumnType("INTEGER");
+
+ b.HasKey("Id");
+
+ b.HasIndex("Permission_Permissions_Guid");
+
+ b.ToTable("Permissions");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property<int>("Kind")
+ .HasColumnType("INTEGER");
+
+ b.Property<Guid?>("Preference_Preferences_Guid")
+ .HasColumnType("TEXT");
+
+ b.Property<uint>("RowVersion")
+ .IsConcurrencyToken()
+ .HasColumnType("INTEGER");
+
+ b.Property<string>("Value")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasMaxLength(65535);
+
+ b.HasKey("Id");
+
+ b.HasIndex("Preference_Preferences_Guid");
+
+ b.ToTable("Preferences");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.User", b =>
+ {
+ b.Property<Guid>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("TEXT");
+
+ b.Property<string>("AudioLanguagePreference")
+ .HasColumnType("TEXT")
+ .HasMaxLength(255);
+
+ b.Property<string>("AuthenticationProviderId")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasMaxLength(255);
+
+ b.Property<bool>("DisplayCollectionsView")
+ .HasColumnType("INTEGER");
+
+ b.Property<bool>("DisplayMissingEpisodes")
+ .HasColumnType("INTEGER");
+
+ b.Property<string>("EasyPassword")
+ .HasColumnType("TEXT")
+ .HasMaxLength(65535);
+
+ b.Property<bool>("EnableAutoLogin")
+ .HasColumnType("INTEGER");
+
+ b.Property<bool>("EnableLocalPassword")
+ .HasColumnType("INTEGER");
+
+ b.Property<bool>("EnableNextEpisodeAutoPlay")
+ .HasColumnType("INTEGER");
+
+ b.Property<bool>("EnableUserPreferenceAccess")
+ .HasColumnType("INTEGER");
+
+ b.Property<bool>("HidePlayedInLatest")
+ .HasColumnType("INTEGER");
+
+ b.Property<long>("InternalId")
+ .HasColumnType("INTEGER");
+
+ b.Property<int>("InvalidLoginAttemptCount")
+ .HasColumnType("INTEGER");
+
+ b.Property<DateTime?>("LastActivityDate")
+ .HasColumnType("TEXT");
+
+ b.Property<DateTime?>("LastLoginDate")
+ .HasColumnType("TEXT");
+
+ b.Property<int?>("LoginAttemptsBeforeLockout")
+ .HasColumnType("INTEGER");
+
+ b.Property<int?>("MaxParentalAgeRating")
+ .HasColumnType("INTEGER");
+
+ b.Property<bool>("MustUpdatePassword")
+ .HasColumnType("INTEGER");
+
+ b.Property<string>("Password")
+ .HasColumnType("TEXT")
+ .HasMaxLength(65535);
+
+ b.Property<string>("PasswordResetProviderId")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasMaxLength(255);
+
+ b.Property<bool>("PlayDefaultAudioTrack")
+ .HasColumnType("INTEGER");
+
+ b.Property<bool>("RememberAudioSelections")
+ .HasColumnType("INTEGER");
+
+ b.Property<bool>("RememberSubtitleSelections")
+ .HasColumnType("INTEGER");
+
+ b.Property<int?>("RemoteClientBitrateLimit")
+ .HasColumnType("INTEGER");
+
+ b.Property<uint>("RowVersion")
+ .IsConcurrencyToken()
+ .HasColumnType("INTEGER");
+
+ b.Property<string>("SubtitleLanguagePreference")
+ .HasColumnType("TEXT")
+ .HasMaxLength(255);
+
+ b.Property<int>("SubtitleMode")
+ .HasColumnType("INTEGER");
+
+ b.Property<int>("SyncPlayAccess")
+ .HasColumnType("INTEGER");
+
+ b.Property<string>("Username")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasMaxLength(255);
+
+ b.HasKey("Id");
+
+ b.ToTable("Users");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b =>
+ {
+ b.HasOne("Jellyfin.Data.Entities.User", null)
+ .WithMany("AccessSchedules")
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b =>
+ {
+ b.HasOne("Jellyfin.Data.Entities.User", null)
+ .WithOne("DisplayPreferences")
+ .HasForeignKey("Jellyfin.Data.Entities.DisplayPreferences", "UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b =>
+ {
+ b.HasOne("Jellyfin.Data.Entities.DisplayPreferences", null)
+ .WithMany("HomeSections")
+ .HasForeignKey("DisplayPreferencesId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b =>
+ {
+ b.HasOne("Jellyfin.Data.Entities.User", null)
+ .WithOne("ProfileImage")
+ .HasForeignKey("Jellyfin.Data.Entities.ImageInfo", "UserId");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b =>
+ {
+ b.HasOne("Jellyfin.Data.Entities.User", null)
+ .WithMany("ItemDisplayPreferences")
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b =>
+ {
+ b.HasOne("Jellyfin.Data.Entities.User", null)
+ .WithMany("Permissions")
+ .HasForeignKey("Permission_Permissions_Guid");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b =>
+ {
+ b.HasOne("Jellyfin.Data.Entities.User", null)
+ .WithMany("Preferences")
+ .HasForeignKey("Preference_Preferences_Guid");
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/Jellyfin.Server.Implementations/Migrations/20200905220533_FixDisplayPreferencesIndex.cs b/Jellyfin.Server.Implementations/Migrations/20200905220533_FixDisplayPreferencesIndex.cs
new file mode 100644
index 000000000..33c5bb4ca
--- /dev/null
+++ b/Jellyfin.Server.Implementations/Migrations/20200905220533_FixDisplayPreferencesIndex.cs
@@ -0,0 +1,51 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1601
+
+using Microsoft.EntityFrameworkCore.Migrations;
+
+namespace Jellyfin.Server.Implementations.Migrations
+{
+ public partial class FixDisplayPreferencesIndex : Migration
+ {
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.DropIndex(
+ name: "IX_DisplayPreferences_UserId",
+ schema: "jellyfin",
+ table: "DisplayPreferences");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_DisplayPreferences_UserId",
+ schema: "jellyfin",
+ table: "DisplayPreferences",
+ column: "UserId");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_DisplayPreferences_UserId_Client",
+ schema: "jellyfin",
+ table: "DisplayPreferences",
+ columns: new[] { "UserId", "Client" },
+ unique: true);
+ }
+
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.DropIndex(
+ name: "IX_DisplayPreferences_UserId",
+ schema: "jellyfin",
+ table: "DisplayPreferences");
+
+ migrationBuilder.DropIndex(
+ name: "IX_DisplayPreferences_UserId_Client",
+ schema: "jellyfin",
+ table: "DisplayPreferences");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_DisplayPreferences_UserId",
+ schema: "jellyfin",
+ table: "DisplayPreferences",
+ column: "UserId",
+ unique: true);
+ }
+ }
+}
diff --git a/Jellyfin.Server.Implementations/Migrations/JellyfinDbModelSnapshot.cs b/Jellyfin.Server.Implementations/Migrations/JellyfinDbModelSnapshot.cs
index a6e6a2324..ccfcf96b1 100644
--- a/Jellyfin.Server.Implementations/Migrations/JellyfinDbModelSnapshot.cs
+++ b/Jellyfin.Server.Implementations/Migrations/JellyfinDbModelSnapshot.cs
@@ -15,7 +15,7 @@ namespace Jellyfin.Server.Implementations.Migrations
#pragma warning disable 612, 618
modelBuilder
.HasDefaultSchema("jellyfin")
- .HasAnnotation("ProductVersion", "3.1.6");
+ .HasAnnotation("ProductVersion", "3.1.7");
modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b =>
{
@@ -136,7 +136,9 @@ namespace Jellyfin.Server.Implementations.Migrations
b.HasKey("Id");
- b.HasIndex("UserId")
+ b.HasIndex("UserId");
+
+ b.HasIndex("UserId", "Client")
.IsUnique();
b.ToTable("DisplayPreferences");
diff --git a/Jellyfin.Server/Jellyfin.Server.csproj b/Jellyfin.Server/Jellyfin.Server.csproj
index c3bec1c71..0ac309a0b 100644
--- a/Jellyfin.Server/Jellyfin.Server.csproj
+++ b/Jellyfin.Server/Jellyfin.Server.csproj
@@ -54,7 +54,7 @@
<PackageReference Include="Serilog.Sinks.Console" Version="3.1.1" />
<PackageReference Include="Serilog.Sinks.File" Version="4.1.0" />
<PackageReference Include="Serilog.Sinks.Graylog" Version="2.1.3" />
- <PackageReference Include="SQLitePCLRaw.bundle_e_sqlite3" Version="2.0.3" />
+ <PackageReference Include="SQLitePCLRaw.bundle_e_sqlite3" Version="2.0.4" />
<PackageReference Include="SQLitePCLRaw.provider.sqlite3.netstandard11" Version="1.1.14" />
</ItemGroup>
diff --git a/MediaBrowser.Common/Updates/IInstallationManager.cs b/MediaBrowser.Common/Updates/IInstallationManager.cs
index 4b4030bc2..169aca2ca 100644
--- a/MediaBrowser.Common/Updates/IInstallationManager.cs
+++ b/MediaBrowser.Common/Updates/IInstallationManager.cs
@@ -73,12 +73,14 @@ namespace MediaBrowser.Common.Updates
/// <param name="name">The name.</param>
/// <param name="guid">The guid of the plugin.</param>
/// <param name="minVersion">The minimum required version of the plugin.</param>
+ /// <param name="specificVersion">The specific version of the plugin to install.</param>
/// <returns>All compatible versions ordered from newest to oldest.</returns>
IEnumerable<InstallationInfo> GetCompatibleVersions(
IEnumerable<PackageInfo> availablePackages,
string name = null,
Guid guid = default,
- Version minVersion = null);
+ Version minVersion = null,
+ Version specificVersion = null);
/// <summary>
/// Returns the available plugin updates.
diff --git a/MediaBrowser.Controller/IServerApplicationHost.cs b/MediaBrowser.Controller/IServerApplicationHost.cs
index 9f4c00e1c..cfad17fb7 100644
--- a/MediaBrowser.Controller/IServerApplicationHost.cs
+++ b/MediaBrowser.Controller/IServerApplicationHost.cs
@@ -114,8 +114,6 @@ namespace MediaBrowser.Controller
/// <exception cref="NotSupportedException"><see cref="CanLaunchWebBrowser"/> is false.</exception>
void LaunchUrl(string url);
- void EnableLoopback(string appName);
-
IEnumerable<WakeOnLanInfo> GetWakeOnLanInfo();
string ExpandVirtualPath(string path);
diff --git a/MediaBrowser.Model/Dlna/DeviceIdentification.cs b/MediaBrowser.Model/Dlna/DeviceIdentification.cs
index 85cc9e3c1..43407383a 100644
--- a/MediaBrowser.Model/Dlna/DeviceIdentification.cs
+++ b/MediaBrowser.Model/Dlna/DeviceIdentification.cs
@@ -38,12 +38,6 @@ namespace MediaBrowser.Model.Dlna
public string ModelDescription { get; set; }
/// <summary>
- /// Gets or sets the device description.
- /// </summary>
- /// <value>The device description.</value>
- public string DeviceDescription { get; set; }
-
- /// <summary>
/// Gets or sets the model URL.
/// </summary>
/// <value>The model URL.</value>
diff --git a/MediaBrowser.Model/System/PublicSystemInfo.cs b/MediaBrowser.Model/System/PublicSystemInfo.cs
index b6196a43f..d2f7556a5 100644
--- a/MediaBrowser.Model/System/PublicSystemInfo.cs
+++ b/MediaBrowser.Model/System/PublicSystemInfo.cs
@@ -24,7 +24,7 @@ namespace MediaBrowser.Model.System
public string Version { get; set; }
/// <summary>
- /// The product name. This is the AssemblyProduct name.
+ /// Gets or sets the product name. This is the AssemblyProduct name.
/// </summary>
public string ProductName { get; set; }
@@ -39,5 +39,11 @@ namespace MediaBrowser.Model.System
/// </summary>
/// <value>The id.</value>
public string Id { get; set; }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether the startup wizard is completed.
+ /// </summary>
+ /// <value>The startup completion status.</value>
+ public bool StartupWizardCompleted { get; set; }
}
}
diff --git a/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbEpisodeProvider.cs b/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbEpisodeProvider.cs
index 90e3cea93..ed4739acb 100644
--- a/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbEpisodeProvider.cs
+++ b/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbEpisodeProvider.cs
@@ -109,7 +109,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV
item.ParentIndexNumber = info.ParentIndexNumber;
item.IndexNumberEnd = info.IndexNumberEnd;
- if (response.External_Ids.Tvdb_Id > 0)
+ if (response.External_Ids != null && response.External_Ids.Tvdb_Id > 0)
{
item.SetProviderId(MetadataProvider.Tvdb, response.External_Ids.Tvdb_Id.Value.ToString(CultureInfo.InvariantCulture));
}
diff --git a/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeasonProvider.cs b/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeasonProvider.cs
index 11a02c1ed..40f1c4e69 100644
--- a/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeasonProvider.cs
+++ b/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeasonProvider.cs
@@ -75,7 +75,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV
result.Item.Overview = seasonInfo.Overview;
- if (seasonInfo.External_Ids.Tvdb_Id > 0)
+ if (seasonInfo.External_Ids != null && seasonInfo.External_Ids.Tvdb_Id > 0)
{
result.Item.SetProviderId(MetadataProvider.Tvdb, seasonInfo.External_Ids.Tvdb_Id.Value.ToString(CultureInfo.InvariantCulture));
}
diff --git a/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeriesProvider.cs b/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeriesProvider.cs
index 430d2525c..fa0873b9d 100644
--- a/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeriesProvider.cs
+++ b/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeriesProvider.cs
@@ -92,7 +92,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV
remoteResult.SetProviderId(MetadataProvider.Tmdb, obj.Id.ToString(_usCulture));
remoteResult.SetProviderId(MetadataProvider.Imdb, obj.External_Ids.Imdb_Id);
- if (obj.External_Ids.Tvdb_Id > 0)
+ if (obj.External_Ids != null && obj.External_Ids.Tvdb_Id > 0)
{
remoteResult.SetProviderId(MetadataProvider.Tvdb, obj.External_Ids.Tvdb_Id.Value.ToString(_usCulture));
}
diff --git a/MediaBrowser.sln b/MediaBrowser.sln
index fd45dca2a..25402aee1 100644
--- a/MediaBrowser.sln
+++ b/MediaBrowser.sln
@@ -208,6 +208,5 @@ Global
{A2FD0A10-8F62-4F9D-B171-FFDF9F0AFA9D} = {FBBB5129-006E-4AD7-BAD5-8B7CA1D10ED6}
{2E3A1B4B-4225-4AAA-8B29-0181A84E7AEE} = {FBBB5129-006E-4AD7-BAD5-8B7CA1D10ED6}
{462584F7-5023-4019-9EAC-B98CA458C0A0} = {FBBB5129-006E-4AD7-BAD5-8B7CA1D10ED6}
- {7C93C84F-105C-48E5-A878-406FA0A5B296} = {FBBB5129-006E-4AD7-BAD5-8B7CA1D10ED6}
EndGlobalSection
EndGlobal