diff --git a/MediaBrowser.Api/ItemUpdateService.cs b/MediaBrowser.Api/ItemUpdateService.cs
index cda7ce0c67..64b6b18d6f 100644
--- a/MediaBrowser.Api/ItemUpdateService.cs
+++ b/MediaBrowser.Api/ItemUpdateService.cs
@@ -243,11 +243,7 @@ namespace MediaBrowser.Api
hasBudget.Revenue = request.Revenue;
}
- var hasOriginalTitle = item as IHasOriginalTitle;
- if (hasOriginalTitle != null)
- {
- hasOriginalTitle.OriginalTitle = hasOriginalTitle.OriginalTitle;
- }
+ item.OriginalTitle = string.IsNullOrWhiteSpace(request.OriginalTitle) ? null : request.OriginalTitle;
var hasCriticRating = item as IHasCriticRating;
if (hasCriticRating != null)
diff --git a/MediaBrowser.Api/LiveTv/LiveTvService.cs b/MediaBrowser.Api/LiveTv/LiveTvService.cs
index 5b821df0bd..ecc17374f8 100644
--- a/MediaBrowser.Api/LiveTv/LiveTvService.cs
+++ b/MediaBrowser.Api/LiveTv/LiveTvService.cs
@@ -386,6 +386,8 @@ namespace MediaBrowser.Api.LiveTv
[ApiMember(Name = "EnableUserData", Description = "Optional, include user data", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")]
public bool? EnableUserData { get; set; }
+ public string SeriesTimerId { get; set; }
+
///
/// Fields to return within the items, in addition to basic information
///
@@ -985,6 +987,7 @@ namespace MediaBrowser.Api.LiveTv
query.IsSeries = request.IsSeries;
query.IsKids = request.IsKids;
query.IsSports = request.IsSports;
+ query.SeriesTimerId = request.SeriesTimerId;
query.Genres = (request.Genres ?? String.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
var result = await _liveTvManager.GetPrograms(query, GetDtoOptions(request), CancellationToken.None).ConfigureAwait(false);
diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs
index 30e0f3ee72..492058f98a 100644
--- a/MediaBrowser.Controller/Entities/BaseItem.cs
+++ b/MediaBrowser.Controller/Entities/BaseItem.cs
@@ -256,7 +256,10 @@ namespace MediaBrowser.Controller.Entities
}
[IgnoreDataMember]
- public string ExternalSeriesId
+ public string ExternalSeriesId { get; set; }
+
+ [IgnoreDataMember]
+ public string ExternalSeriesIdLegacy
{
get { return this.GetProviderId("ProviderExternalSeriesId"); }
set
diff --git a/MediaBrowser.Controller/Entities/InternalItemsQuery.cs b/MediaBrowser.Controller/Entities/InternalItemsQuery.cs
index 5e70cd5879..60af2c56af 100644
--- a/MediaBrowser.Controller/Entities/InternalItemsQuery.cs
+++ b/MediaBrowser.Controller/Entities/InternalItemsQuery.cs
@@ -139,6 +139,7 @@ namespace MediaBrowser.Controller.Entities
public DayOfWeek[] AirDays { get; set; }
public SeriesStatus[] SeriesStatuses { get; set; }
public string AlbumArtistStartsWithOrGreater { get; set; }
+ public string ExternalSeriesId { get; set; }
public string[] AlbumNames { get; set; }
public string[] ArtistNames { get; set; }
diff --git a/MediaBrowser.Controller/LiveTv/SeriesTimerInfo.cs b/MediaBrowser.Controller/LiveTv/SeriesTimerInfo.cs
index a828e22e30..5c73ed833f 100644
--- a/MediaBrowser.Controller/LiveTv/SeriesTimerInfo.cs
+++ b/MediaBrowser.Controller/LiveTv/SeriesTimerInfo.cs
@@ -27,6 +27,8 @@ namespace MediaBrowser.Controller.LiveTv
///
public string Name { get; set; }
+ public string ServiceName { get; set; }
+
///
/// Description of the recording.
///
diff --git a/MediaBrowser.Dlna/Main/DlnaEntryPoint.cs b/MediaBrowser.Dlna/Main/DlnaEntryPoint.cs
index 5d2231da88..51e115cc2a 100644
--- a/MediaBrowser.Dlna/Main/DlnaEntryPoint.cs
+++ b/MediaBrowser.Dlna/Main/DlnaEntryPoint.cs
@@ -339,12 +339,9 @@ namespace MediaBrowser.Dlna.Main
if (_Publisher != null)
{
var devices = _Publisher.Devices.ToList();
+ var tasks = devices.Select(i => _Publisher.RemoveDevice(i)).ToArray();
- foreach (var device in devices)
- {
- var task = _Publisher.RemoveDevice(device);
- Task.WaitAll(task);
- }
+ Task.WaitAll(tasks);
//foreach (var device in devices)
//{
// try
diff --git a/MediaBrowser.Model/LiveTv/ProgramQuery.cs b/MediaBrowser.Model/LiveTv/ProgramQuery.cs
index 7886342e77..ad57d14732 100644
--- a/MediaBrowser.Model/LiveTv/ProgramQuery.cs
+++ b/MediaBrowser.Model/LiveTv/ProgramQuery.cs
@@ -41,6 +41,7 @@ namespace MediaBrowser.Model.LiveTv
///
/// The user identifier.
public string UserId { get; set; }
+ public string SeriesTimerId { get; set; }
///
/// The earliest date for which a program starts to return
diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs
index f736307f05..025f5a1626 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs
@@ -565,6 +565,12 @@ namespace MediaBrowser.Server.Implementations.LiveTv
};
}
+ var seriesId = info.SeriesId;
+ if (string.IsNullOrWhiteSpace(seriesId) && info.IsSeries)
+ {
+ seriesId = info.Name.GetMD5().ToString("N");
+ }
+
if (!item.ParentId.Equals(channel.Id))
{
forceUpdate = true;
@@ -584,7 +590,14 @@ namespace MediaBrowser.Server.Implementations.LiveTv
item.EpisodeTitle = info.EpisodeTitle;
item.ExternalId = info.Id;
- item.ExternalSeriesId = info.SeriesId;
+ item.ExternalSeriesIdLegacy = seriesId;
+
+ if (!string.IsNullOrWhiteSpace(seriesId) && !string.Equals(item.ExternalSeriesId, seriesId, StringComparison.Ordinal))
+ {
+ forceUpdate = true;
+ }
+ item.ExternalSeriesId = seriesId;
+
item.Genres = info.Genres;
item.IsHD = info.IsHD;
item.IsKids = info.IsKids;
@@ -825,7 +838,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
var dto = _dtoService.GetBaseItemDto(program, new DtoOptions(), user);
var list = new List>();
- list.Add(new Tuple(dto, program.ServiceName, program.ExternalId, program.ExternalSeriesId));
+ list.Add(new Tuple(dto, program.ServiceName, program.ExternalId, program.ExternalSeriesIdLegacy));
await AddRecordingInfo(list, cancellationToken).ConfigureAwait(false);
@@ -866,6 +879,27 @@ namespace MediaBrowser.Server.Implementations.LiveTv
TopParentIds = new[] { topFolder.Id.ToString("N") }
};
+ if (!string.IsNullOrWhiteSpace(query.SeriesTimerId))
+ {
+ var seriesTimers = await GetSeriesTimersInternal(new SeriesTimerQuery {}, cancellationToken).ConfigureAwait(false);
+ var seriesTimer = seriesTimers.Items.FirstOrDefault(i => string.Equals(_tvDtoService.GetInternalSeriesTimerId(i.ServiceName, i.Id).ToString("N"), query.SeriesTimerId, StringComparison.OrdinalIgnoreCase));
+ if (seriesTimer != null)
+ {
+ internalQuery.ExternalSeriesId = seriesTimer.SeriesId;
+
+ if (string.IsNullOrWhiteSpace(seriesTimer.SeriesId))
+ {
+ // Better to return nothing than every program in the database
+ return new QueryResult();
+ }
+ }
+ else
+ {
+ // Better to return nothing than every program in the database
+ return new QueryResult();
+ }
+ }
+
if (query.HasAired.HasValue)
{
if (query.HasAired.Value)
@@ -1730,7 +1764,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
dto.ServiceName = serviceName;
}
- recordingTuples.Add(new Tuple(dto, serviceName, program.ExternalId, program.ExternalSeriesId));
+ recordingTuples.Add(new Tuple(dto, serviceName, program.ExternalId, program.ExternalSeriesIdLegacy));
}
await AddRecordingInfo(recordingTuples, CancellationToken.None).ConfigureAwait(false);
@@ -2005,6 +2039,56 @@ namespace MediaBrowser.Server.Implementations.LiveTv
return results.Items.FirstOrDefault(i => string.Equals(i.Id, id, StringComparison.OrdinalIgnoreCase));
}
+ private async Task> GetSeriesTimersInternal(SeriesTimerQuery query, CancellationToken cancellationToken)
+ {
+ var tasks = _services.Select(async i =>
+ {
+ try
+ {
+ var recs = await i.GetSeriesTimersAsync(cancellationToken).ConfigureAwait(false);
+ return recs.Select(r =>
+ {
+ r.ServiceName = i.Name;
+ return new Tuple(r, i);
+ });
+ }
+ catch (Exception ex)
+ {
+ _logger.ErrorException("Error getting recordings", ex);
+ return new List>();
+ }
+ });
+ var results = await Task.WhenAll(tasks).ConfigureAwait(false);
+ var timers = results.SelectMany(i => i.ToList());
+
+ if (string.Equals(query.SortBy, "Priority", StringComparison.OrdinalIgnoreCase))
+ {
+ timers = query.SortOrder == SortOrder.Descending ?
+ timers.OrderBy(i => i.Item1.Priority).ThenByStringDescending(i => i.Item1.Name) :
+ timers.OrderByDescending(i => i.Item1.Priority).ThenByString(i => i.Item1.Name);
+ }
+ else
+ {
+ timers = query.SortOrder == SortOrder.Descending ?
+ timers.OrderByStringDescending(i => i.Item1.Name) :
+ timers.OrderByString(i => i.Item1.Name);
+ }
+
+ var returnArray = timers
+ .Select(i =>
+ {
+ return i.Item1;
+
+ })
+ .ToArray();
+
+ return new QueryResult
+ {
+ Items = returnArray,
+ TotalRecordCount = returnArray.Length
+ };
+ }
+
public async Task> GetSeriesTimers(SeriesTimerQuery query, CancellationToken cancellationToken)
{
var tasks = _services.Select(async i =>
diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs
index 672cd1bc21..c843ab596d 100644
--- a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs
+++ b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs
@@ -270,6 +270,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
_connection.AddColumn(Logger, "TypedBaseItems", "SeasonId", "GUID");
_connection.AddColumn(Logger, "TypedBaseItems", "SeriesId", "GUID");
_connection.AddColumn(Logger, "TypedBaseItems", "SeriesSortName", "Text");
+ _connection.AddColumn(Logger, "TypedBaseItems", "ExternalSeriesId", "Text");
_connection.AddColumn(Logger, "UserDataKeys", "Priority", "INT");
_connection.AddColumn(Logger, "ItemValues", "CleanValue", "Text");
@@ -413,7 +414,8 @@ namespace MediaBrowser.Server.Implementations.Persistence
"SeriesSortName",
"PresentationUniqueKey",
"InheritedParentalRatingValue",
- "InheritedTags"
+ "InheritedTags",
+ "ExternalSeriesId"
};
private readonly string[] _mediaStreamSaveColumns =
@@ -535,7 +537,8 @@ namespace MediaBrowser.Server.Implementations.Persistence
"SeasonName",
"SeasonId",
"SeriesId",
- "SeriesSortName"
+ "SeriesSortName",
+ "ExternalSeriesId"
};
_saveItemCommand = _connection.CreateCommand();
_saveItemCommand.CommandText = "replace into TypedBaseItems (" + string.Join(",", saveColumns.ToArray()) + ") values (";
@@ -975,6 +978,8 @@ namespace MediaBrowser.Server.Implementations.Persistence
_saveItemCommand.GetParameter(index++).Value = null;
}
+ _saveItemCommand.GetParameter(index++).Value = item.ExternalSeriesId;
+
_saveItemCommand.Transaction = transaction;
_saveItemCommand.ExecuteNonQuery();
@@ -1466,6 +1471,12 @@ namespace MediaBrowser.Server.Implementations.Persistence
}
index++;
+ if (!reader.IsDBNull(index))
+ {
+ item.ExternalSeriesId = reader.GetString(index);
+ }
+ index++;
+
return item;
}
@@ -2852,6 +2863,12 @@ namespace MediaBrowser.Server.Implementations.Persistence
cmd.Parameters.Add(cmd, "@MinSortName", DbType.String).Value = query.MinSortName;
}
+ if (!string.IsNullOrWhiteSpace(query.ExternalSeriesId))
+ {
+ whereClauses.Add("ExternalSeriesId=@ExternalSeriesId");
+ cmd.Parameters.Add(cmd, "@ExternalSeriesId", DbType.String).Value = query.ExternalSeriesId;
+ }
+
if (!string.IsNullOrWhiteSpace(query.Name))
{
whereClauses.Add("CleanName=@Name");