mirror of
https://github.com/jellyfin/jellyfin.git
synced 2026-03-27 20:41:54 +00:00
Merge remote-tracking branch 'upstream/dev' into dev
This commit is contained in:
@@ -60,7 +60,6 @@ namespace MediaBrowser.Server.Implementations.Connect
|
||||
{
|
||||
return new ConnectUserPreferences
|
||||
{
|
||||
GroupMoviesIntoBoxSets = config.GroupMoviesIntoBoxSets,
|
||||
PlayDefaultAudioTrack = config.PlayDefaultAudioTrack,
|
||||
SubtitleMode = config.SubtitleMode,
|
||||
PreferredAudioLanguages = string.IsNullOrWhiteSpace(config.AudioLanguagePreference) ? new string[] { } : new[] { config.AudioLanguagePreference },
|
||||
|
||||
@@ -969,16 +969,7 @@ namespace MediaBrowser.Server.Implementations.Dto
|
||||
|
||||
if (fields.Contains(ItemFields.Tags))
|
||||
{
|
||||
var hasTags = item as IHasTags;
|
||||
if (hasTags != null)
|
||||
{
|
||||
dto.Tags = hasTags.Tags;
|
||||
}
|
||||
|
||||
if (dto.Tags == null)
|
||||
{
|
||||
dto.Tags = new List<string>();
|
||||
}
|
||||
dto.Tags = item.Tags;
|
||||
}
|
||||
|
||||
if (fields.Contains(ItemFields.Keywords))
|
||||
|
||||
@@ -562,9 +562,10 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
|
||||
series = _libraryManager.GetItemList(new Controller.Entities.InternalItemsQuery
|
||||
{
|
||||
IncludeItemTypes = new[] { typeof(Series).Name },
|
||||
Recursive = true
|
||||
}).Cast<Series>()
|
||||
.FirstOrDefault(i => string.Equals(i.Name, info.ItemName, StringComparison.OrdinalIgnoreCase));
|
||||
Recursive = true,
|
||||
Name = info.ItemName
|
||||
|
||||
}).Cast<Series>().FirstOrDefault();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -23,7 +23,8 @@ namespace MediaBrowser.Server.Implementations.Library
|
||||
{
|
||||
public event EventHandler<UserDataSaveEventArgs> UserDataSaved;
|
||||
|
||||
private readonly Dictionary<string, UserItemData> _userData = new Dictionary<string, UserItemData>(StringComparer.OrdinalIgnoreCase);
|
||||
private readonly ConcurrentDictionary<string, UserItemData> _userData =
|
||||
new ConcurrentDictionary<string, UserItemData>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
private readonly ILogger _logger;
|
||||
private readonly IServerConfigurationManager _config;
|
||||
@@ -64,13 +65,6 @@ namespace MediaBrowser.Server.Implementations.Library
|
||||
try
|
||||
{
|
||||
await Repository.SaveUserData(userId, key, userData, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
var newValue = userData;
|
||||
|
||||
lock (_userData)
|
||||
{
|
||||
_userData[GetCacheKey(userId, key)] = newValue;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -80,6 +74,9 @@ namespace MediaBrowser.Server.Implementations.Library
|
||||
}
|
||||
}
|
||||
|
||||
var cacheKey = GetCacheKey(userId, item.Id);
|
||||
_userData.AddOrUpdate(cacheKey, userData, (k, v) => userData);
|
||||
|
||||
EventHelper.FireEventIfNotNull(UserDataSaved, this, new UserDataSaveEventArgs
|
||||
{
|
||||
Keys = keys,
|
||||
@@ -122,7 +119,7 @@ namespace MediaBrowser.Server.Implementations.Library
|
||||
|
||||
throw;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -140,7 +137,7 @@ namespace MediaBrowser.Server.Implementations.Library
|
||||
return Repository.GetAllUserData(userId);
|
||||
}
|
||||
|
||||
public UserItemData GetUserData(Guid userId, List<string> keys)
|
||||
public UserItemData GetUserData(Guid userId, Guid itemId, List<string> keys)
|
||||
{
|
||||
if (userId == Guid.Empty)
|
||||
{
|
||||
@@ -150,26 +147,23 @@ namespace MediaBrowser.Server.Implementations.Library
|
||||
{
|
||||
throw new ArgumentNullException("keys");
|
||||
}
|
||||
|
||||
lock (_userData)
|
||||
if (keys.Count == 0)
|
||||
{
|
||||
foreach (var key in keys)
|
||||
{
|
||||
var cacheKey = GetCacheKey(userId, key);
|
||||
UserItemData value;
|
||||
if (_userData.TryGetValue(cacheKey, out value))
|
||||
{
|
||||
return value;
|
||||
}
|
||||
throw new ArgumentException("UserData keys cannot be empty.");
|
||||
}
|
||||
|
||||
value = Repository.GetUserData(userId, key);
|
||||
var cacheKey = GetCacheKey(userId, itemId);
|
||||
|
||||
if (value != null)
|
||||
{
|
||||
_userData[cacheKey] = value;
|
||||
return value;
|
||||
}
|
||||
}
|
||||
return _userData.GetOrAdd(cacheKey, k => GetUserDataInternal(userId, keys));
|
||||
}
|
||||
|
||||
private UserItemData GetUserDataInternal(Guid userId, List<string> keys)
|
||||
{
|
||||
var userData = Repository.GetUserData(userId, keys);
|
||||
|
||||
if (userData != null)
|
||||
{
|
||||
return userData;
|
||||
}
|
||||
|
||||
if (keys.Count > 0)
|
||||
@@ -184,57 +178,13 @@ namespace MediaBrowser.Server.Implementations.Library
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the user data.
|
||||
/// </summary>
|
||||
/// <param name="userId">The user id.</param>
|
||||
/// <param name="key">The key.</param>
|
||||
/// <returns>Task{UserItemData}.</returns>
|
||||
public UserItemData GetUserData(Guid userId, string key)
|
||||
{
|
||||
if (userId == Guid.Empty)
|
||||
{
|
||||
throw new ArgumentNullException("userId");
|
||||
}
|
||||
if (string.IsNullOrEmpty(key))
|
||||
{
|
||||
throw new ArgumentNullException("key");
|
||||
}
|
||||
|
||||
lock (_userData)
|
||||
{
|
||||
var cacheKey = GetCacheKey(userId, key);
|
||||
UserItemData value;
|
||||
if (_userData.TryGetValue(cacheKey, out value))
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
value = Repository.GetUserData(userId, key);
|
||||
|
||||
if (value == null)
|
||||
{
|
||||
value = new UserItemData
|
||||
{
|
||||
UserId = userId,
|
||||
Key = key
|
||||
};
|
||||
}
|
||||
|
||||
_userData[cacheKey] = value;
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the internal key.
|
||||
/// </summary>
|
||||
/// <param name="userId">The user id.</param>
|
||||
/// <param name="key">The key.</param>
|
||||
/// <returns>System.String.</returns>
|
||||
private string GetCacheKey(Guid userId, string key)
|
||||
private string GetCacheKey(Guid userId, Guid itemId)
|
||||
{
|
||||
return userId + key;
|
||||
return userId.ToString("N") + itemId.ToString("N");
|
||||
}
|
||||
|
||||
public UserItemData GetUserData(IHasUserData user, IHasUserData item)
|
||||
@@ -249,7 +199,7 @@ namespace MediaBrowser.Server.Implementations.Library
|
||||
|
||||
public UserItemData GetUserData(Guid userId, IHasUserData item)
|
||||
{
|
||||
return GetUserData(userId, item.GetUserDataKeys());
|
||||
return GetUserData(userId, item.Id, item.GetUserDataKeys());
|
||||
}
|
||||
|
||||
public UserItemDataDto GetUserDataDto(IHasUserData item, User user)
|
||||
|
||||
@@ -105,6 +105,12 @@ namespace MediaBrowser.Server.Implementations.Library
|
||||
}
|
||||
}
|
||||
|
||||
if (_config.Configuration.EnableFolderView)
|
||||
{
|
||||
var name = _localizationManager.GetLocalizedString("ViewType" + CollectionType.Folders);
|
||||
list.Add(await _libraryManager.GetNamedView(name, CollectionType.Folders, string.Empty, cancellationToken).ConfigureAwait(false));
|
||||
}
|
||||
|
||||
if (query.IncludeExternalContent)
|
||||
{
|
||||
var channelResult = await _channelManager.GetChannelsInternal(new ChannelQuery
|
||||
|
||||
@@ -6,6 +6,5 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
||||
public interface IDbConnector
|
||||
{
|
||||
Task<IDbConnection> Connect(string dbPath);
|
||||
void BindSimilarityScoreFunction(IDbConnection connection);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,8 @@ using System.Data.SQLite;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Logging;
|
||||
|
||||
namespace MediaBrowser.Server.Implementations.Persistence
|
||||
@@ -46,13 +48,6 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
||||
return connection;
|
||||
}
|
||||
|
||||
public static void BindGetSimilarityScore(IDbConnection connection, ILogger logger)
|
||||
{
|
||||
var sqlConnection = (SQLiteConnection) connection;
|
||||
SimiliarToFunction.Logger = logger;
|
||||
sqlConnection.BindFunction(new SimiliarToFunction());
|
||||
}
|
||||
|
||||
public static void BindFunction(this SQLiteConnection connection, SQLiteFunction function)
|
||||
{
|
||||
var attributes = function.GetType().GetCustomAttributes(typeof(SQLiteFunctionAttribute), true).Cast<SQLiteFunctionAttribute>().ToArray();
|
||||
@@ -63,113 +58,4 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
||||
connection.BindFunction(attributes[0], function);
|
||||
}
|
||||
}
|
||||
|
||||
[SQLiteFunction(Name = "GetSimilarityScore", Arguments = 12, FuncType = FunctionType.Scalar)]
|
||||
public class SimiliarToFunction : SQLiteFunction
|
||||
{
|
||||
internal static ILogger Logger;
|
||||
|
||||
public override object Invoke(object[] args)
|
||||
{
|
||||
var score = 0;
|
||||
|
||||
var inputOfficialRating = args[0] as string;
|
||||
var rowOfficialRating = args[1] as string;
|
||||
if (!string.IsNullOrWhiteSpace(inputOfficialRating) && string.Equals(inputOfficialRating, rowOfficialRating))
|
||||
{
|
||||
score += 10;
|
||||
}
|
||||
|
||||
long? inputYear = args[2] == null ? (long?)null : (long)args[2];
|
||||
long? rowYear = args[3] == null ? (long?)null : (long)args[3];
|
||||
|
||||
if (inputYear.HasValue && rowYear.HasValue)
|
||||
{
|
||||
var diff = Math.Abs(inputYear.Value - rowYear.Value);
|
||||
|
||||
// Add if they came out within the same decade
|
||||
if (diff < 10)
|
||||
{
|
||||
score += 2;
|
||||
}
|
||||
|
||||
// And more if within five years
|
||||
if (diff < 5)
|
||||
{
|
||||
score += 2;
|
||||
}
|
||||
}
|
||||
|
||||
// genres
|
||||
score += GetListScore(args, 4, 5);
|
||||
|
||||
// tags
|
||||
score += GetListScore(args, 6, 7);
|
||||
|
||||
// keywords
|
||||
score += GetListScore(args, 8, 9);
|
||||
|
||||
// studios
|
||||
score += GetListScore(args, 10, 11, 3);
|
||||
|
||||
|
||||
// TODO: People
|
||||
// var item2PeopleNames = allPeople.Where(i => i.ItemId == item2.Id)
|
||||
//.Select(i => i.Name)
|
||||
//.Where(i => !string.IsNullOrWhiteSpace(i))
|
||||
//.DistinctNames()
|
||||
//.ToDictionary(i => i, StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
// points += item1People.Where(i => item2PeopleNames.ContainsKey(i.Name)).Sum(i =>
|
||||
// {
|
||||
// if (string.Equals(i.Type, PersonType.Director, StringComparison.OrdinalIgnoreCase) || string.Equals(i.Role, PersonType.Director, StringComparison.OrdinalIgnoreCase))
|
||||
// {
|
||||
// return 5;
|
||||
// }
|
||||
// if (string.Equals(i.Type, PersonType.Actor, StringComparison.OrdinalIgnoreCase) || string.Equals(i.Role, PersonType.Actor, StringComparison.OrdinalIgnoreCase))
|
||||
// {
|
||||
// return 3;
|
||||
// }
|
||||
// if (string.Equals(i.Type, PersonType.Composer, StringComparison.OrdinalIgnoreCase) || string.Equals(i.Role, PersonType.Composer, StringComparison.OrdinalIgnoreCase))
|
||||
// {
|
||||
// return 3;
|
||||
// }
|
||||
// if (string.Equals(i.Type, PersonType.GuestStar, StringComparison.OrdinalIgnoreCase) || string.Equals(i.Role, PersonType.GuestStar, StringComparison.OrdinalIgnoreCase))
|
||||
// {
|
||||
// return 3;
|
||||
// }
|
||||
// if (string.Equals(i.Type, PersonType.Writer, StringComparison.OrdinalIgnoreCase) || string.Equals(i.Role, PersonType.Writer, StringComparison.OrdinalIgnoreCase))
|
||||
// {
|
||||
// return 2;
|
||||
// }
|
||||
|
||||
// return 1;
|
||||
// });
|
||||
|
||||
// return points;
|
||||
|
||||
//Logger.Debug("Returning score {0}", score);
|
||||
return score;
|
||||
}
|
||||
|
||||
private int GetListScore(object[] args, int index1, int index2, int value = 10)
|
||||
{
|
||||
var score = 0;
|
||||
|
||||
var inputGenres = args[index1] as string;
|
||||
var rowGenres = args[index2] as string;
|
||||
var inputGenreList = string.IsNullOrWhiteSpace(inputGenres) ? new string[] { } : inputGenres.Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
var rowGenresList = string.IsNullOrWhiteSpace(rowGenres) ? new string[] { } : rowGenres.Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
|
||||
foreach (var genre in inputGenreList)
|
||||
{
|
||||
if (rowGenresList.Contains(genre, StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
score += value;
|
||||
}
|
||||
}
|
||||
|
||||
return score;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,10 +88,13 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
||||
private IDbCommand _deleteProviderIdsCommand;
|
||||
private IDbCommand _saveProviderIdsCommand;
|
||||
|
||||
private IDbCommand _deleteImagesCommand;
|
||||
private IDbCommand _saveImagesCommand;
|
||||
|
||||
private IDbCommand _updateInheritedRatingCommand;
|
||||
private IDbCommand _updateInheritedTagsCommand;
|
||||
|
||||
public const int LatestSchemaVersion = 83;
|
||||
public const int LatestSchemaVersion = 89;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SqliteItemRepository"/> class.
|
||||
@@ -132,9 +135,9 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
||||
string[] queries = {
|
||||
|
||||
"create table if not exists TypedBaseItems (guid GUID primary key, type TEXT, data BLOB, ParentId GUID, Path TEXT)",
|
||||
"create index if not exists idx_TypedBaseItems on TypedBaseItems(guid)",
|
||||
"create index if not exists idx_PathTypedBaseItems on TypedBaseItems(Path)",
|
||||
"create index if not exists idx_ParentIdTypedBaseItems on TypedBaseItems(ParentId)",
|
||||
"create index if not exists idx_TypedBaseItems2 on TypedBaseItems(Type,Guid)",
|
||||
|
||||
"create table if not exists AncestorIds (ItemId GUID, AncestorId GUID, AncestorIdText TEXT, PRIMARY KEY (ItemId, AncestorId))",
|
||||
"create index if not exists idx_AncestorIds1 on AncestorIds(AncestorId)",
|
||||
@@ -145,10 +148,14 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
||||
|
||||
"create table if not exists ItemValues (ItemId GUID, Type INT, Value TEXT)",
|
||||
"create index if not exists idx_ItemValues on ItemValues(ItemId)",
|
||||
"create index if not exists idx_ItemValues2 on ItemValues(ItemId,Type)",
|
||||
|
||||
"create table if not exists ProviderIds (ItemId GUID, Name TEXT, Value TEXT)",
|
||||
"create table if not exists ProviderIds (ItemId GUID, Name TEXT, Value TEXT, PRIMARY KEY (ItemId, Name))",
|
||||
"create index if not exists Idx_ProviderIds on ProviderIds(ItemId)",
|
||||
|
||||
"create table if not exists Images (ItemId GUID NOT NULL, Path TEXT NOT NULL, ImageType INT NOT NULL, DateModified DATETIME, IsPlaceHolder BIT NOT NULL, SortOrder INT)",
|
||||
"create index if not exists idx_Images on Images(ItemId)",
|
||||
|
||||
"create table if not exists People (ItemId GUID, Name TEXT NOT NULL, Role TEXT, PersonType TEXT, SortOrder int, ListOrder int)",
|
||||
"create index if not exists idxPeopleItemId on People(ItemId)",
|
||||
"create index if not exists idxPeopleName on People(Name)",
|
||||
@@ -265,8 +272,6 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
||||
new MediaStreamColumns(_connection, Logger).AddColumns();
|
||||
|
||||
DataExtensions.Attach(_connection, Path.Combine(_config.ApplicationPaths.DataPath, "userdata_v2.db"), "UserDataDb");
|
||||
|
||||
dbConnector.BindSimilarityScoreFunction(_connection);
|
||||
}
|
||||
|
||||
private readonly string[] _retriveItemColumns =
|
||||
@@ -565,6 +570,19 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
||||
_saveProviderIdsCommand.Parameters.Add(_saveProviderIdsCommand, "@Name");
|
||||
_saveProviderIdsCommand.Parameters.Add(_saveProviderIdsCommand, "@Value");
|
||||
|
||||
// images
|
||||
_deleteImagesCommand = _connection.CreateCommand();
|
||||
_deleteImagesCommand.CommandText = "delete from Images where ItemId=@Id";
|
||||
_deleteImagesCommand.Parameters.Add(_deleteImagesCommand, "@Id");
|
||||
|
||||
_saveImagesCommand = _connection.CreateCommand();
|
||||
_saveImagesCommand.CommandText = "insert into Images (ItemId, ImageType, Path, DateModified, IsPlaceHolder, SortOrder) values (@ItemId, @ImageType, @Path, @DateModified, @IsPlaceHolder, @SortOrder)";
|
||||
_saveImagesCommand.Parameters.Add(_saveImagesCommand, "@ItemId");
|
||||
_saveImagesCommand.Parameters.Add(_saveImagesCommand, "@ImageType");
|
||||
_saveImagesCommand.Parameters.Add(_saveImagesCommand, "@Path");
|
||||
_saveImagesCommand.Parameters.Add(_saveImagesCommand, "@DateModified");
|
||||
_saveImagesCommand.Parameters.Add(_saveImagesCommand, "@IsPlaceHolder");
|
||||
_saveImagesCommand.Parameters.Add(_saveImagesCommand, "@SortOrder");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -879,6 +897,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
||||
}
|
||||
|
||||
UpdateUserDataKeys(item.Id, item.GetUserDataKeys().Distinct(StringComparer.OrdinalIgnoreCase).ToList(), transaction);
|
||||
UpdateImages(item.Id, item.ImageInfos, transaction);
|
||||
UpdateProviderIds(item.Id, item.ProviderIds, transaction);
|
||||
UpdateItemValues(item.Id, GetItemValues(item), transaction);
|
||||
}
|
||||
@@ -956,7 +975,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
||||
|
||||
if (type == null)
|
||||
{
|
||||
Logger.Debug("Unknown type {0}", typeString);
|
||||
//Logger.Debug("Unknown type {0}", typeString);
|
||||
|
||||
return null;
|
||||
}
|
||||
@@ -1621,34 +1640,34 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
||||
var item = query.SimilarTo;
|
||||
|
||||
var builder = new StringBuilder();
|
||||
builder.Append("GetSimilarityScore(");
|
||||
builder.Append("(");
|
||||
|
||||
builder.Append("@ItemOfficialRating,");
|
||||
builder.Append("OfficialRating,");
|
||||
builder.Append("((OfficialRating=@ItemOfficialRating) * 10)");
|
||||
//builder.Append("+ ((ProductionYear=@ItemProductionYear) * 10)");
|
||||
|
||||
builder.Append("@ItemProductionYear,");
|
||||
builder.Append("ProductionYear,");
|
||||
builder.Append("+(Select Case When Abs(COALESCE(ProductionYear, 0) - @ItemProductionYear) < 10 Then 2 Else 0 End )");
|
||||
builder.Append("+(Select Case When Abs(COALESCE(ProductionYear, 0) - @ItemProductionYear) < 5 Then 2 Else 0 End )");
|
||||
|
||||
builder.Append("@ItemGenres,");
|
||||
builder.Append("Genres,");
|
||||
//// genres
|
||||
builder.Append("+ ((Select count(value) from ItemValues where ItemId=Guid and Type=2 and value in (select value from itemvalues where ItemId=@SimilarItemId and type=2)) * 10)");
|
||||
|
||||
builder.Append("@ItemTags,");
|
||||
builder.Append("Tags,");
|
||||
//// tags
|
||||
builder.Append("+ ((Select count(value) from ItemValues where ItemId=Guid and Type=4 and value in (select value from itemvalues where ItemId=@SimilarItemId and type=4)) * 10)");
|
||||
|
||||
builder.Append("@ItemKeywords,");
|
||||
builder.Append("(select group_concat((Select Value from ItemValues where ItemId=Guid and Type=5), '|')),");
|
||||
builder.Append("+ ((Select count(value) from ItemValues where ItemId=Guid and Type=5 and value in (select value from itemvalues where ItemId=@SimilarItemId and type=5)) * 10)");
|
||||
|
||||
builder.Append("+ ((Select count(value) from ItemValues where ItemId=Guid and Type=3 and value in (select value from itemvalues where ItemId=@SimilarItemId and type=3)) * 3)");
|
||||
|
||||
//builder.Append("+ ((Select count(Name) from People where ItemId=Guid and Name in (select Name from People where ItemId=@SimilarItemId)) * 3)");
|
||||
|
||||
////builder.Append("(select group_concat((Select Name from People where ItemId=Guid and Name in (Select Name from People where ItemId=@SimilarItemId)), '|'))");
|
||||
|
||||
builder.Append("@ItemStudios,");
|
||||
builder.Append("Studios");
|
||||
builder.Append(") as SimilarityScore");
|
||||
|
||||
list.Add(builder.ToString());
|
||||
cmd.Parameters.Add(cmd, "@ItemOfficialRating", DbType.String).Value = item.OfficialRating;
|
||||
cmd.Parameters.Add(cmd, "@ItemProductionYear", DbType.Int32).Value = item.ProductionYear ?? -1;
|
||||
cmd.Parameters.Add(cmd, "@ItemGenres", DbType.String).Value = string.Join("|", item.Genres.ToArray());
|
||||
cmd.Parameters.Add(cmd, "@ItemTags", DbType.String).Value = string.Join("|", item.Tags.ToArray());
|
||||
cmd.Parameters.Add(cmd, "@ItemKeywords", DbType.String).Value = string.Join("|", item.Keywords.ToArray());
|
||||
cmd.Parameters.Add(cmd, "@ItemStudios", DbType.String).Value = string.Join("|", item.Studios.ToArray());
|
||||
cmd.Parameters.Add(cmd, "@ItemProductionYear", DbType.Int32).Value = item.ProductionYear ?? 0;
|
||||
cmd.Parameters.Add(cmd, "@SimilarItemId", DbType.Guid).Value = item.Id;
|
||||
|
||||
var excludeIds = query.ExcludeItemIds.ToList();
|
||||
excludeIds.Add(item.Id.ToString("N"));
|
||||
@@ -1862,7 +1881,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
||||
{
|
||||
if (query.User != null)
|
||||
{
|
||||
query.SortBy = new[] { "SimilarityScore", "IsUnplayed", "Random" };
|
||||
query.SortBy = new[] { "SimilarityScore", "IsPlayed", "Random" };
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2475,6 +2494,19 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
||||
cmd.Parameters.Add(cmd, "@NameLessThan", DbType.String).Value = query.NameLessThan.ToLower();
|
||||
}
|
||||
|
||||
if (query.ImageTypes.Length > 0 && _config.Configuration.SchemaVersion >= 87)
|
||||
{
|
||||
var requiredImageIndex = 0;
|
||||
|
||||
foreach (var requiredImage in query.ImageTypes)
|
||||
{
|
||||
var paramName = "@RequiredImageType" + requiredImageIndex;
|
||||
whereClauses.Add("(select path from images where ItemId=Guid and ImageType=" + paramName + " limit 1) not null");
|
||||
cmd.Parameters.Add(cmd, paramName, DbType.Int32).Value = (int)requiredImage;
|
||||
requiredImageIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
if (query.IsLiked.HasValue)
|
||||
{
|
||||
if (query.IsLiked.Value)
|
||||
@@ -2738,8 +2770,13 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
||||
var index = 0;
|
||||
foreach (var pair in query.ExcludeProviderIds)
|
||||
{
|
||||
if (string.Equals(pair.Key, MetadataProviders.TmdbCollection.ToString(), StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var paramName = "@ExcludeProviderId" + index;
|
||||
excludeIds.Add("(COALESCE((select value from ProviderIds where ItemId=Guid and Name = 'Imdb'), '') <> " + paramName + ")");
|
||||
excludeIds.Add("(COALESCE((select value from ProviderIds where ItemId=Guid and Name = '" + pair.Key + "'), '') <> " + paramName + ")");
|
||||
cmd.Parameters.Add(cmd, paramName, DbType.String).Value = pair.Value;
|
||||
index++;
|
||||
}
|
||||
@@ -3180,6 +3217,11 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
||||
_deleteProviderIdsCommand.Transaction = transaction;
|
||||
_deleteProviderIdsCommand.ExecuteNonQuery();
|
||||
|
||||
// Delete images
|
||||
_deleteImagesCommand.GetParameter(0).Value = id;
|
||||
_deleteImagesCommand.Transaction = transaction;
|
||||
_deleteImagesCommand.ExecuteNonQuery();
|
||||
|
||||
// Delete the item
|
||||
_deleteItemCommand.GetParameter(0).Value = id;
|
||||
_deleteItemCommand.Transaction = transaction;
|
||||
@@ -3396,6 +3438,52 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
||||
return list;
|
||||
}
|
||||
|
||||
private void UpdateImages(Guid itemId, List<ItemImageInfo> images, IDbTransaction transaction)
|
||||
{
|
||||
if (itemId == Guid.Empty)
|
||||
{
|
||||
throw new ArgumentNullException("itemId");
|
||||
}
|
||||
|
||||
if (images == null)
|
||||
{
|
||||
throw new ArgumentNullException("images");
|
||||
}
|
||||
|
||||
CheckDisposed();
|
||||
|
||||
// First delete
|
||||
_deleteImagesCommand.GetParameter(0).Value = itemId;
|
||||
_deleteImagesCommand.Transaction = transaction;
|
||||
|
||||
_deleteImagesCommand.ExecuteNonQuery();
|
||||
|
||||
var index = 0;
|
||||
foreach (var image in images)
|
||||
{
|
||||
_saveImagesCommand.GetParameter(0).Value = itemId;
|
||||
_saveImagesCommand.GetParameter(1).Value = image.Type;
|
||||
_saveImagesCommand.GetParameter(2).Value = image.Path;
|
||||
|
||||
if (image.DateModified == default(DateTime))
|
||||
{
|
||||
_saveImagesCommand.GetParameter(3).Value = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
_saveImagesCommand.GetParameter(3).Value = image.DateModified;
|
||||
}
|
||||
|
||||
_saveImagesCommand.GetParameter(4).Value = image.IsPlaceholder;
|
||||
_saveImagesCommand.GetParameter(5).Value = index;
|
||||
|
||||
_saveImagesCommand.Transaction = transaction;
|
||||
|
||||
_saveImagesCommand.ExecuteNonQuery();
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateProviderIds(Guid itemId, Dictionary<string, string> values, IDbTransaction transaction)
|
||||
{
|
||||
if (itemId == Guid.Empty)
|
||||
@@ -3405,7 +3493,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
||||
|
||||
if (values == null)
|
||||
{
|
||||
throw new ArgumentNullException("keys");
|
||||
throw new ArgumentNullException("values");
|
||||
}
|
||||
|
||||
CheckDisposed();
|
||||
|
||||
@@ -5,7 +5,9 @@ using MediaBrowser.Model.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
@@ -300,6 +302,52 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
||||
}
|
||||
}
|
||||
|
||||
public UserItemData GetUserData(Guid userId, List<string> keys)
|
||||
{
|
||||
if (userId == Guid.Empty)
|
||||
{
|
||||
throw new ArgumentNullException("userId");
|
||||
}
|
||||
if (keys == null)
|
||||
{
|
||||
throw new ArgumentNullException("keys");
|
||||
}
|
||||
|
||||
using (var cmd = _connection.CreateCommand())
|
||||
{
|
||||
var index = 0;
|
||||
var excludeIds = new List<string>();
|
||||
var builder = new StringBuilder();
|
||||
foreach (var key in keys)
|
||||
{
|
||||
var paramName = "@Key" + index;
|
||||
excludeIds.Add("Key =" + paramName);
|
||||
cmd.Parameters.Add(cmd, paramName, DbType.String).Value = key;
|
||||
builder.Append(" WHEN Key=" + paramName + " THEN " + index);
|
||||
index++;
|
||||
}
|
||||
|
||||
var keyText = string.Join(" OR ", excludeIds.ToArray());
|
||||
|
||||
cmd.CommandText = "select key,userid,rating,played,playCount,isFavorite,playbackPositionTicks,lastPlayedDate,AudioStreamIndex,SubtitleStreamIndex from userdata where userId=@userId AND (" + keyText + ") ";
|
||||
|
||||
cmd.CommandText += " ORDER BY (Case " + builder + " Else " + keys.Count.ToString(CultureInfo.InvariantCulture) + " End )";
|
||||
cmd.CommandText += " LIMIT 1";
|
||||
|
||||
cmd.Parameters.Add(cmd, "@userId", DbType.Guid).Value = userId;
|
||||
|
||||
using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult | CommandBehavior.SingleRow))
|
||||
{
|
||||
if (reader.Read())
|
||||
{
|
||||
return ReadRow(reader);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return all user-data associated with the given user
|
||||
/// </summary>
|
||||
|
||||
@@ -111,24 +111,6 @@ namespace MediaBrowser.Server.Implementations.TV
|
||||
.Select(i => GetNextUp(i, currentUser))
|
||||
// Include if an episode was found, and either the series is not unwatched or the specific series was requested
|
||||
.Where(i => i.Item1 != null && (!i.Item3 || !string.IsNullOrWhiteSpace(request.SeriesId)))
|
||||
//.OrderByDescending(i =>
|
||||
//{
|
||||
// var episode = i.Item1;
|
||||
|
||||
// var seriesUserData = _userDataManager.GetUserData(user, episode.Series);
|
||||
|
||||
// if (seriesUserData.IsFavorite)
|
||||
// {
|
||||
// return 2;
|
||||
// }
|
||||
|
||||
// if (seriesUserData.Likes.HasValue)
|
||||
// {
|
||||
// return seriesUserData.Likes.Value ? 1 : -1;
|
||||
// }
|
||||
|
||||
// return 0;
|
||||
//})
|
||||
.OrderByDescending(i => i.Item2)
|
||||
.ThenByDescending(i => i.Item1.PremiereDate ?? DateTime.MinValue)
|
||||
.Select(i => i.Item1);
|
||||
@@ -143,9 +125,8 @@ namespace MediaBrowser.Server.Implementations.TV
|
||||
private Tuple<Episode, DateTime, bool> GetNextUp(Series series, User user)
|
||||
{
|
||||
// Get them in display order, then reverse
|
||||
var allEpisodes = series.GetSeasons(user, true, true)
|
||||
.Where(i => !i.IndexNumber.HasValue || i.IndexNumber.Value != 0)
|
||||
.SelectMany(i => i.GetEpisodes(user))
|
||||
var allEpisodes = series.GetEpisodes(user, false, false)
|
||||
.Where(i => !i.ParentIndexNumber.HasValue || i.ParentIndexNumber.Value != 0)
|
||||
.Reverse()
|
||||
.ToList();
|
||||
|
||||
@@ -153,7 +134,7 @@ namespace MediaBrowser.Server.Implementations.TV
|
||||
var lastWatchedDate = DateTime.MinValue;
|
||||
Episode nextUp = null;
|
||||
|
||||
var includeMissing = user.Configuration.DisplayMissingEpisodes;
|
||||
var unplayedEpisodes = new List<Episode>();
|
||||
|
||||
// Go back starting with the most recent episodes
|
||||
foreach (var episode in allEpisodes)
|
||||
@@ -172,10 +153,9 @@ namespace MediaBrowser.Server.Implementations.TV
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!episode.IsVirtualUnaired && (includeMissing || !episode.IsMissingEpisode))
|
||||
{
|
||||
nextUp = episode;
|
||||
}
|
||||
unplayedEpisodes.Add(episode);
|
||||
|
||||
nextUp = episode;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -184,7 +164,15 @@ namespace MediaBrowser.Server.Implementations.TV
|
||||
return new Tuple<Episode, DateTime, bool>(nextUp, lastWatchedDate, false);
|
||||
}
|
||||
|
||||
var firstEpisode = allEpisodes.LastOrDefault(i => !i.IsVirtualUnaired && (includeMissing || !i.IsMissingEpisode) && !i.IsPlayed(user));
|
||||
Episode firstEpisode = null;
|
||||
// Find the first unplayed episode. Start from the back of the list since they're in reverse order
|
||||
for (var i = unplayedEpisodes.Count - 1; i >= 0; i--)
|
||||
{
|
||||
var unplayedEpisode = unplayedEpisodes[i];
|
||||
|
||||
firstEpisode = unplayedEpisode;
|
||||
break;
|
||||
}
|
||||
|
||||
// Return the first episode
|
||||
return new Tuple<Episode, DateTime, bool>(firstEpisode, DateTime.MinValue, true);
|
||||
|
||||
Reference in New Issue
Block a user