add playback of in-progress recordings

This commit is contained in:
Luke Pulverenti 2016-10-09 03:18:43 -04:00
parent b3595eab6a
commit daaae69df5
49 changed files with 570 additions and 397 deletions

View file

@ -835,14 +835,14 @@ namespace MediaBrowser.Api.Library
: (Folder)_libraryManager.RootFolder)
: _libraryManager.GetItemById(request.Id);
while (GetThemeSongIds(item).Count == 0 && request.InheritFromParent && item.GetParent() != null)
while (item.ThemeSongIds.Count == 0 && request.InheritFromParent && item.GetParent() != null)
{
item = item.GetParent();
}
var dtoOptions = GetDtoOptions(request);
var dtos = GetThemeSongIds(item).Select(_libraryManager.GetItemById)
var dtos = item.ThemeSongIds.Select(_libraryManager.GetItemById)
.Where(i => i != null)
.OrderBy(i => i.SortName)
.Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user, item));
@ -879,14 +879,14 @@ namespace MediaBrowser.Api.Library
: (Folder)_libraryManager.RootFolder)
: _libraryManager.GetItemById(request.Id);
while (GetThemeVideoIds(item).Count == 0 && request.InheritFromParent && item.GetParent() != null)
while (item.ThemeVideoIds.Count == 0 && request.InheritFromParent && item.GetParent() != null)
{
item = item.GetParent();
}
var dtoOptions = GetDtoOptions(request);
var dtos = GetThemeVideoIds(item).Select(_libraryManager.GetItemById)
var dtos = item.ThemeVideoIds.Select(_libraryManager.GetItemById)
.Where(i => i != null)
.OrderBy(i => i.SortName)
.Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user, item));
@ -901,30 +901,6 @@ namespace MediaBrowser.Api.Library
};
}
private List<Guid> GetThemeVideoIds(BaseItem item)
{
var i = item as IHasThemeMedia;
if (i != null)
{
return i.ThemeVideoIds;
}
return new List<Guid>();
}
private List<Guid> GetThemeSongIds(BaseItem item)
{
var i = item as IHasThemeMedia;
if (i != null)
{
return i.ThemeSongIds;
}
return new List<Guid>();
}
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
public object Get(GetYearIndex request)

View file

@ -677,6 +677,12 @@ namespace MediaBrowser.Api.LiveTv
public string Container { get; set; }
}
[Route("/LiveTv/LiveRecordings/{Id}/stream", "GET", Summary = "Gets a live tv channel")]
public class GetLiveRecordingFile
{
public string Id { get; set; }
}
public class LiveTvService : BaseApiService
{
private readonly ILiveTvManager _liveTvManager;
@ -698,13 +704,32 @@ namespace MediaBrowser.Api.LiveTv
_fileSystem = fileSystem;
}
public async Task<object> Get(GetLiveRecordingFile request)
{
var path = EmbyTV.Current.GetActiveRecordingPath(request.Id);
if (path == null)
{
throw new FileNotFoundException();
}
var outputHeaders = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
outputHeaders["Content-Type"] = Model.Net.MimeTypes.GetMimeType(path);
var streamSource = new ProgressiveFileCopier(_fileSystem, path, outputHeaders, null, Logger, CancellationToken.None)
{
AllowEndOfFile = false
};
return ResultFactory.GetAsyncStreamWriter(streamSource);
}
public async Task<object> Get(GetLiveStreamFile request)
{
var directStreamProvider = (await EmbyTV.Current.GetLiveStream(request.Id).ConfigureAwait(false)) as IDirectStreamProvider;
var outputHeaders = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
// TODO: Don't hardcode this
outputHeaders["Content-Type"] = Model.Net.MimeTypes.GetMimeType("file.ts");
outputHeaders["Content-Type"] = Model.Net.MimeTypes.GetMimeType("file." + request.Container);
var streamSource = new ProgressiveFileCopier(directStreamProvider, outputHeaders, null, Logger, CancellationToken.None)
{

View file

@ -134,15 +134,5 @@ namespace MediaBrowser.Controller.Channels
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>BaseItemDto.</returns>
Task<BaseItemDto> GetChannelFolder(string userId, CancellationToken cancellationToken);
/// <summary>
/// Downloads the channel item.
/// </summary>
/// <param name="item">The item.</param>
/// <param name="destinationPath">The destination path.</param>
/// <param name="progress">The progress.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
Task DownloadChannelItem(BaseItem item, string destinationPath, IProgress<double> progress, CancellationToken cancellationToken);
}
}

View file

@ -34,6 +34,12 @@ namespace MediaBrowser.Controller.Entities
}
}
[IgnoreDataMember]
public override bool IsPhysicalRoot
{
get { return true; }
}
public override bool CanDelete()
{
return false;

View file

@ -62,7 +62,7 @@ namespace MediaBrowser.Controller.Entities.Audio
[IgnoreDataMember]
public override bool SupportsAddingToPlaylist
{
get { return LocationType == LocationType.FileSystem && RunTimeTicks.HasValue; }
get { return true; }
}
[IgnoreDataMember]

View file

@ -37,6 +37,8 @@ namespace MediaBrowser.Controller.Entities
{
protected BaseItem()
{
ThemeSongIds = new List<Guid>();
ThemeVideoIds = new List<Guid>();
Keywords = new List<string>();
Tags = new List<string>();
Genres = new List<string>();
@ -45,6 +47,7 @@ namespace MediaBrowser.Controller.Entities
LockedFields = new List<MetadataFields>();
ImageInfos = new List<ItemImageInfo>();
InheritedTags = new List<string>();
ProductionLocations = new List<string>();
}
public static readonly char[] SlugReplaceChars = { '?', '/', '&' };
@ -65,6 +68,9 @@ namespace MediaBrowser.Controller.Entities
public static string ThemeSongFilename = "theme";
public static string ThemeVideosFolderName = "backdrops";
public List<Guid> ThemeSongIds { get; set; }
public List<Guid> ThemeVideoIds { get; set; }
[IgnoreDataMember]
public string PreferredMetadataCountryCode { get; set; }
[IgnoreDataMember]
@ -876,6 +882,7 @@ namespace MediaBrowser.Controller.Entities
public List<string> Tags { get; set; }
public List<string> Keywords { get; set; }
public List<string> ProductionLocations { get; set; }
/// <summary>
/// Gets or sets the home page URL.
@ -991,7 +998,7 @@ namespace MediaBrowser.Controller.Entities
/// Loads the theme songs.
/// </summary>
/// <returns>List{Audio.Audio}.</returns>
private IEnumerable<Audio.Audio> LoadThemeSongs(List<FileSystemMetadata> fileSystemChildren, IDirectoryService directoryService)
private static IEnumerable<Audio.Audio> LoadThemeSongs(List<FileSystemMetadata> fileSystemChildren, IDirectoryService directoryService)
{
var files = fileSystemChildren.Where(i => i.IsDirectory)
.Where(i => string.Equals(i.Name, ThemeSongsFolderName, StringComparison.OrdinalIgnoreCase))
@ -1027,7 +1034,7 @@ namespace MediaBrowser.Controller.Entities
/// Loads the video backdrops.
/// </summary>
/// <returns>List{Video}.</returns>
private IEnumerable<Video> LoadThemeVideos(IEnumerable<FileSystemMetadata> fileSystemChildren, IDirectoryService directoryService)
private static IEnumerable<Video> LoadThemeVideos(IEnumerable<FileSystemMetadata> fileSystemChildren, IDirectoryService directoryService)
{
var files = fileSystemChildren.Where(i => i.IsDirectory)
.Where(i => string.Equals(i.Name, ThemeVideosFolderName, StringComparison.OrdinalIgnoreCase))
@ -1113,6 +1120,12 @@ namespace MediaBrowser.Controller.Entities
get { return true; }
}
[IgnoreDataMember]
public virtual bool SupportsThemeMedia
{
get { return false; }
}
/// <summary>
/// Refreshes owned items such as trailers, theme videos, special features, etc.
/// Returns true or false indicating if changes were found.
@ -1131,14 +1144,13 @@ namespace MediaBrowser.Controller.Entities
if (LocationType == LocationType.FileSystem && GetParent() != null)
{
var hasThemeMedia = this as IHasThemeMedia;
if (hasThemeMedia != null)
if (SupportsThemeMedia)
{
if (!DetectIsInMixedFolder())
{
themeSongsChanged = await RefreshThemeSongs(hasThemeMedia, options, fileSystemChildren, cancellationToken).ConfigureAwait(false);
themeSongsChanged = await RefreshThemeSongs(this, options, fileSystemChildren, cancellationToken).ConfigureAwait(false);
themeVideosChanged = await RefreshThemeVideos(hasThemeMedia, options, fileSystemChildren, cancellationToken).ConfigureAwait(false);
themeVideosChanged = await RefreshThemeVideos(this, options, fileSystemChildren, cancellationToken).ConfigureAwait(false);
}
}
@ -1176,7 +1188,7 @@ namespace MediaBrowser.Controller.Entities
return itemsChanged;
}
private async Task<bool> RefreshThemeVideos(IHasThemeMedia item, MetadataRefreshOptions options, IEnumerable<FileSystemMetadata> fileSystemChildren, CancellationToken cancellationToken)
private static async Task<bool> RefreshThemeVideos(BaseItem item, MetadataRefreshOptions options, IEnumerable<FileSystemMetadata> fileSystemChildren, CancellationToken cancellationToken)
{
var newThemeVideos = LoadThemeVideos(fileSystemChildren, options.DirectoryService).ToList();
@ -1207,7 +1219,7 @@ namespace MediaBrowser.Controller.Entities
/// <summary>
/// Refreshes the theme songs.
/// </summary>
private async Task<bool> RefreshThemeSongs(IHasThemeMedia item, MetadataRefreshOptions options, List<FileSystemMetadata> fileSystemChildren, CancellationToken cancellationToken)
private static async Task<bool> RefreshThemeSongs(BaseItem item, MetadataRefreshOptions options, List<FileSystemMetadata> fileSystemChildren, CancellationToken cancellationToken)
{
var newThemeSongs = LoadThemeSongs(fileSystemChildren, options.DirectoryService).ToList();
var newThemeSongIds = newThemeSongs.Select(i => i.Id).ToList();

View file

@ -22,13 +22,18 @@ namespace MediaBrowser.Controller.Entities
/// <summary>
/// Class Folder
/// </summary>
public class Folder : BaseItem, IHasThemeMedia
public class Folder : BaseItem
{
public static IUserManager UserManager { get; set; }
public static IUserViewManager UserViewManager { get; set; }
public List<Guid> ThemeSongIds { get; set; }
public List<Guid> ThemeVideoIds { get; set; }
/// <summary>
/// Gets or sets a value indicating whether this instance is root.
/// </summary>
/// <value><c>true</c> if this instance is root; otherwise, <c>false</c>.</value>
public bool IsRoot { get; set; }
public virtual List<LinkedChild> LinkedChildren { get; set; }
[IgnoreDataMember]
public DateTime? DateLastMediaAdded { get; set; }
@ -36,9 +41,12 @@ namespace MediaBrowser.Controller.Entities
public Folder()
{
LinkedChildren = new List<LinkedChild>();
}
ThemeSongIds = new List<Guid>();
ThemeVideoIds = new List<Guid>();
[IgnoreDataMember]
public override bool SupportsThemeMedia
{
get { return true; }
}
[IgnoreDataMember]
@ -47,6 +55,12 @@ namespace MediaBrowser.Controller.Entities
get { return false; }
}
[IgnoreDataMember]
public virtual bool IsPhysicalRoot
{
get { return false; }
}
/// <summary>
/// Gets a value indicating whether this instance is folder.
/// </summary>
@ -117,19 +131,6 @@ namespace MediaBrowser.Controller.Entities
return true;
}
/// <summary>
/// Gets or sets a value indicating whether this instance is physical root.
/// </summary>
/// <value><c>true</c> if this instance is physical root; otherwise, <c>false</c>.</value>
public bool IsPhysicalRoot { get; set; }
/// <summary>
/// Gets or sets a value indicating whether this instance is root.
/// </summary>
/// <value><c>true</c> if this instance is root; otherwise, <c>false</c>.</value>
public bool IsRoot { get; set; }
public virtual List<LinkedChild> LinkedChildren { get; set; }
[IgnoreDataMember]
protected virtual bool SupportsShortcutChildren
{
@ -178,8 +179,6 @@ namespace MediaBrowser.Controller.Entities
item.SetParent(null);
}
#region Indexing
/// <summary>
/// Returns the valid set of index by options for this folder type.
/// Override or extend to modify.
@ -207,8 +206,6 @@ namespace MediaBrowser.Controller.Entities
get { return GetIndexByOptions(); }
}
#endregion
/// <summary>
/// Gets the actual children.
/// </summary>

View file

@ -8,11 +8,8 @@ using System.Runtime.Serialization;
namespace MediaBrowser.Controller.Entities
{
public class Game : BaseItem, IHasTrailers, IHasThemeMedia, IHasScreenshots, ISupportsPlaceHolders, IHasLookupInfo<GameInfo>
public class Game : BaseItem, IHasTrailers, IHasScreenshots, ISupportsPlaceHolders, IHasLookupInfo<GameInfo>
{
public List<Guid> ThemeSongIds { get; set; }
public List<Guid> ThemeVideoIds { get; set; }
public Game()
{
MultiPartGameFiles = new List<string>();
@ -39,6 +36,12 @@ namespace MediaBrowser.Controller.Entities
get { return true; }
}
[IgnoreDataMember]
public override bool SupportsThemeMedia
{
get { return true; }
}
/// <summary>
/// Gets or sets the remote trailers.
/// </summary>

View file

@ -1,23 +0,0 @@
using System;
using System.Collections.Generic;
namespace MediaBrowser.Controller.Entities
{
/// <summary>
/// Interface IHasThemeMedia
/// </summary>
public interface IHasThemeMedia
{
/// <summary>
/// Gets or sets the theme song ids.
/// </summary>
/// <value>The theme song ids.</value>
List<Guid> ThemeSongIds { get; set; }
/// <summary>
/// Gets or sets the theme video ids.
/// </summary>
/// <value>The theme video ids.</value>
List<Guid> ThemeVideoIds { get; set; }
}
}

View file

@ -165,6 +165,7 @@ namespace MediaBrowser.Controller.Entities
{
switch (name)
{
case ItemFields.ProductionLocations:
case ItemFields.Keywords:
case ItemFields.Taglines:
case ItemFields.ShortOverview:

View file

@ -15,21 +15,16 @@ namespace MediaBrowser.Controller.Entities.Movies
/// <summary>
/// Class Movie
/// </summary>
public class Movie : Video, IHasCriticRating, IHasSpecialFeatures, IHasBudget, IHasTrailers, IHasThemeMedia, IHasAwards, IHasMetascore, IHasLookupInfo<MovieInfo>, ISupportsBoxSetGrouping, IHasOriginalTitle
public class Movie : Video, IHasCriticRating, IHasSpecialFeatures, IHasBudget, IHasTrailers, IHasAwards, IHasMetascore, IHasLookupInfo<MovieInfo>, ISupportsBoxSetGrouping, IHasOriginalTitle
{
public List<Guid> SpecialFeatureIds { get; set; }
public List<Guid> ThemeSongIds { get; set; }
public List<Guid> ThemeVideoIds { get; set; }
public Movie()
{
SpecialFeatureIds = new List<Guid>();
RemoteTrailers = new List<MediaUrl>();
LocalTrailerIds = new List<Guid>();
RemoteTrailerIds = new List<Guid>();
ThemeSongIds = new List<Guid>();
ThemeVideoIds = new List<Guid>();
Taglines = new List<string>();
}

View file

@ -154,8 +154,6 @@ namespace MediaBrowser.Controller.Entities.TV
Func<BaseItem, bool> filter = i => UserViewBuilder.Filter(i, user, query, UserDataManager, LibraryManager);
var id = Guid.NewGuid().ToString("N");
var items = GetEpisodes(user).Where(filter);
var result = PostFilterAndSort(items, query, false, false);

View file

@ -13,7 +13,6 @@ namespace MediaBrowser.Controller.Entities
public class UserView : Folder
{
public string ViewType { get; set; }
public Guid ParentId { get; set; }
public Guid DisplayParentId { get; set; }
public Guid? UserId { get; set; }

View file

@ -1497,13 +1497,7 @@ namespace MediaBrowser.Controller.Entities
{
var filterValue = query.HasThemeSong.Value;
var themeCount = 0;
var iHasThemeMedia = item as IHasThemeMedia;
if (iHasThemeMedia != null)
{
themeCount = iHasThemeMedia.ThemeSongIds.Count;
}
var themeCount = item.ThemeSongIds.Count;
var ok = filterValue ? themeCount > 0 : themeCount == 0;
if (!ok)
@ -1516,13 +1510,7 @@ namespace MediaBrowser.Controller.Entities
{
var filterValue = query.HasThemeVideo.Value;
var themeCount = 0;
var iHasThemeMedia = item as IHasThemeMedia;
if (iHasThemeMedia != null)
{
themeCount = iHasThemeMedia.ThemeVideoIds.Count;
}
var themeCount = item.ThemeVideoIds.Count;
var ok = filterValue ? themeCount > 0 : themeCount == 0;
if (!ok)

View file

@ -63,6 +63,12 @@ namespace MediaBrowser.Controller.Entities
}
}
[IgnoreDataMember]
public override bool SupportsThemeMedia
{
get { return true; }
}
public int? TotalBitrate { get; set; }
public ExtraType? ExtraType { get; set; }
@ -164,7 +170,7 @@ namespace MediaBrowser.Controller.Entities
[IgnoreDataMember]
public override bool SupportsAddingToPlaylist
{
get { return LocationType == LocationType.FileSystem && RunTimeTicks.HasValue; }
get { return true; }
}
[IgnoreDataMember]

View file

@ -301,18 +301,12 @@ namespace MediaBrowser.Controller.LiveTv
/// <summary>
/// Gets the recording media sources.
/// </summary>
/// <param name="id">The identifier.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task&lt;IEnumerable&lt;MediaSourceInfo&gt;&gt;.</returns>
Task<IEnumerable<MediaSourceInfo>> GetRecordingMediaSources(string id, CancellationToken cancellationToken);
Task<IEnumerable<MediaSourceInfo>> GetRecordingMediaSources(IHasMediaSources item, CancellationToken cancellationToken);
/// <summary>
/// Gets the channel media sources.
/// </summary>
/// <param name="id">The identifier.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task&lt;IEnumerable&lt;MediaSourceInfo&gt;&gt;.</returns>
Task<IEnumerable<MediaSourceInfo>> GetChannelMediaSources(string id, CancellationToken cancellationToken);
Task<IEnumerable<MediaSourceInfo>> GetChannelMediaSources(IHasMediaSources item, CancellationToken cancellationToken);
/// <summary>
/// Adds the information to recording dto.

View file

@ -33,6 +33,7 @@ namespace MediaBrowser.Controller.LiveTv
bool CanDelete(User user);
string SeriesTimerId { get; set; }
string TimerId { get; set; }
RecordingStatus Status { get; set; }
DateTime? EndDate { get; set; }
DateTime DateLastSaved { get; set; }

View file

@ -20,6 +20,7 @@ namespace MediaBrowser.Controller.LiveTv
[IgnoreDataMember]
public bool IsSeries { get; set; }
public string SeriesTimerId { get; set; }
public string TimerId { get; set; }
[IgnoreDataMember]
public DateTime StartDate { get; set; }
public RecordingStatus Status { get; set; }
@ -112,7 +113,7 @@ namespace MediaBrowser.Controller.LiveTv
public override bool CanDelete()
{
return true;
return Status == RecordingStatus.Completed;
}
public override bool IsAuthorizedToDelete(User user)

View file

@ -19,6 +19,7 @@ namespace MediaBrowser.Controller.LiveTv
[IgnoreDataMember]
public bool IsSeries { get; set; }
public string SeriesTimerId { get; set; }
public string TimerId { get; set; }
[IgnoreDataMember]
public DateTime StartDate { get; set; }
public RecordingStatus Status { get; set; }
@ -111,7 +112,7 @@ namespace MediaBrowser.Controller.LiveTv
public override bool CanDelete()
{
return true;
return Status == RecordingStatus.Completed;
}
public override bool IsAuthorizedToDelete(User user)

View file

@ -149,7 +149,6 @@
<Compile Include="Entities\IHasShortOverview.cs" />
<Compile Include="Entities\IHasSpecialFeatures.cs" />
<Compile Include="Entities\IHasStartDate.cs" />
<Compile Include="Entities\IHasThemeMedia.cs" />
<Compile Include="Entities\IHasTrailers.cs" />
<Compile Include="Entities\IHasUserData.cs" />
<Compile Include="Entities\IHiddenFromDisplay.cs" />

View file

@ -347,7 +347,7 @@ namespace MediaBrowser.Controller.Providers
var person = item as Person;
if (person != null)
{
person.PlaceOfBirth = val;
person.ProductionLocations = new List<string> { val };
}
}
@ -790,7 +790,7 @@ namespace MediaBrowser.Controller.Providers
}
default:
{
{
string readerName = reader.Name;
string providerIdValue;
if (_validProviderIds.TryGetValue(readerName, out providerIdValue))

View file

@ -428,14 +428,6 @@ namespace MediaBrowser.Dlna.ContentDirectory
return ApplyPaging(result, startIndex, limit);
}
if (stubType.Value == StubType.Folder)
{
var movie = item as Movie;
if (movie != null)
{
return ApplyPaging(await GetMovieItems(movie).ConfigureAwait(false), startIndex, limit);
}
}
var person = item as Person;
if (person != null)
@ -468,14 +460,11 @@ namespace MediaBrowser.Dlna.ContentDirectory
}).ConfigureAwait(false);
var options = _config.GetDlnaConfiguration();
var serverItems = queryResult
.Items
.Select(i => new ServerItem
{
Item = i,
StubType = GetDisplayStubType(i, item, options)
Item = i
})
.ToArray();
@ -519,29 +508,6 @@ namespace MediaBrowser.Dlna.ContentDirectory
return result;
}
private StubType? GetDisplayStubType(BaseItem item, BaseItem context, DlnaOptions options)
{
if (context == null || context.IsFolder)
{
var movie = item as Movie;
if (movie != null && options.EnableMovieFolders)
{
if (movie.GetTrailerIds().Count > 0 ||
movie.SpecialFeatureIds.Count > 0)
{
return StubType.Folder;
}
if (EnablePeopleDisplay(item))
{
return StubType.Folder;
}
}
}
return null;
}
private bool EnablePeopleDisplay(BaseItem item)
{
if (_libraryManager.GetPeopleNames(new InternalPeopleQuery
@ -556,31 +522,6 @@ namespace MediaBrowser.Dlna.ContentDirectory
return false;
}
private Task<QueryResult<ServerItem>> GetMovieItems(Movie item)
{
var list = new List<BaseItem>();
list.Add(item);
list.AddRange(item.GetTrailerIds().Select(i => _libraryManager.GetItemById(i)).Where(i => i != null));
list.AddRange(item.SpecialFeatureIds.Select(i => _libraryManager.GetItemById(i)).Where(i => i != null));
var serverItems = list.Select(i => new ServerItem { Item = i, StubType = null })
.ToList();
serverItems.Add(new ServerItem
{
Item = item,
StubType = StubType.People
});
return Task.FromResult(new QueryResult<ServerItem>
{
Items = serverItems.ToArray(),
TotalRecordCount = serverItems.Count
});
}
private ServerItem GetItemFromObjectId(string id, User user)
{
return DidlBuilder.IsIdRoot(id)

View file

@ -220,7 +220,7 @@ namespace MediaBrowser.Dlna.Main
return;
}
var cacheLength = _config.GetDlnaConfiguration().BlastAliveMessageIntervalSeconds * 2;
var cacheLength = _config.GetDlnaConfiguration().BlastAliveMessageIntervalSeconds;
_Publisher.SupportPnpRootDevice = false;
var addresses = (await _appHost.GetLocalIpAddresses().ConfigureAwait(false)).ToList();

View file

@ -66,9 +66,9 @@ namespace MediaBrowser.LocalMetadata.Savers
XmlSaverHelpers.AddCommonNodes(person, _libraryManager, builder);
if (!string.IsNullOrEmpty(person.PlaceOfBirth))
if (person.ProductionLocations.Count > 0)
{
builder.Append("<PlaceOfBirth>" + SecurityElement.Escape(person.PlaceOfBirth) + "</PlaceOfBirth>");
builder.Append("<PlaceOfBirth>" + SecurityElement.Escape(person.ProductionLocations[0]) + "</PlaceOfBirth>");
}
builder.Append("</Item>");

View file

@ -10,7 +10,6 @@ namespace MediaBrowser.Model.Configuration
public int ClientDiscoveryIntervalSeconds { get; set; }
public int BlastAliveMessageIntervalSeconds { get; set; }
public string DefaultUserId { get; set; }
public bool EnableMovieFolders { get; set; }
public DlnaOptions()
{

View file

@ -1213,7 +1213,6 @@ namespace MediaBrowser.Model.Dto
/// </summary>
/// <value>The timer identifier.</value>
public string TimerId { get; set; }
public RecordingStatus TimerStatus { get; set; }
/// <summary>
/// Gets or sets the current program.
/// </summary>

View file

@ -7,7 +7,6 @@ namespace MediaBrowser.Model.LiveTv
Scheduled,
InProgress,
Completed,
Aborted,
Cancelled,
ConflictedOk,
ConflictedNotOk,

View file

@ -68,6 +68,30 @@ namespace MediaBrowser.Model.LiveTv
{
get { return ImageTags != null && ImageTags.ContainsKey(ImageType.Primary); }
}
/// <summary>
/// Gets or sets the parent thumb item id.
/// </summary>
/// <value>The parent thumb item id.</value>
public string ParentThumbItemId { get; set; }
/// <summary>
/// Gets or sets the parent thumb image tag.
/// </summary>
/// <value>The parent thumb image tag.</value>
public string ParentThumbImageTag { get; set; }
/// <summary>
/// Gets or sets the parent primary image item identifier.
/// </summary>
/// <value>The parent primary image item identifier.</value>
public string ParentPrimaryImageItemId { get; set; }
/// <summary>
/// Gets or sets the parent primary image tag.
/// </summary>
/// <value>The parent primary image tag.</value>
public string ParentPrimaryImageTag { get; set; }
}
public enum KeepUntil

View file

@ -154,8 +154,6 @@
/// </summary>
People,
PlaceOfBirth,
/// <summary>
/// The production locations
/// </summary>

View file

@ -170,6 +170,14 @@ namespace MediaBrowser.Providers.Manager
}
}
if (!lockedFields.Contains(MetadataFields.ProductionLocations))
{
if (replaceData || target.ProductionLocations.Count == 0)
{
target.ProductionLocations = source.ProductionLocations;
}
}
if (replaceData || !target.VoteCount.HasValue)
{
target.VoteCount = source.VoteCount;

View file

@ -148,14 +148,10 @@ namespace MediaBrowser.Providers.Movies
if (movieData.production_countries != null)
{
//var hasProductionLocations = movie as IHasProductionLocations;
//if (hasProductionLocations != null)
//{
// hasProductionLocations.ProductionLocations = movieData
// .production_countries
// .Select(i => i.name)
// .ToList();
//}
movie.ProductionLocations = movieData
.production_countries
.Select(i => i.name)
.ToList();
}
movie.SetProviderId(MetadataProviders.Tmdb, movieData.id.ToString(_usCulture));

View file

@ -179,7 +179,11 @@ namespace MediaBrowser.Providers.People
item.Name = info.name;
item.HomePageUrl = info.homepage;
item.PlaceOfBirth = info.place_of_birth;
if (!string.IsNullOrWhiteSpace(info.place_of_birth))
{
item.ProductionLocations = new List<string> { info.place_of_birth };
}
item.Overview = info.biography;
DateTime date;

View file

@ -15,14 +15,6 @@ namespace MediaBrowser.Providers.People
protected override void MergeData(MetadataResult<Person> source, MetadataResult<Person> target, List<MetadataFields> lockedFields, bool replaceData, bool mergeMetadataSettings)
{
ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
var sourceItem = source.Item;
var targetItem = target.Item;
if (replaceData || string.IsNullOrEmpty(targetItem.PlaceOfBirth))
{
targetItem.PlaceOfBirth = sourceItem.PlaceOfBirth;
}
}
public PersonMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IFileSystem fileSystem, IUserDataManager userDataManager, ILibraryManager libraryManager) : base(serverConfigurationManager, logger, providerManager, fileSystem, userDataManager, libraryManager)

View file

@ -1577,97 +1577,5 @@ namespace MediaBrowser.Server.Implementations.Channels
return await _libraryManager.GetNamedView(name, "channels", "zz_" + name, cancellationToken).ConfigureAwait(false);
}
public async Task DownloadChannelItem(BaseItem item, string destination,
IProgress<double> progress, CancellationToken cancellationToken)
{
var sources = await GetDynamicMediaSources(item, cancellationToken)
.ConfigureAwait(false);
var list = sources.Where(i => i.Protocol == MediaProtocol.Http).ToList();
foreach (var source in list)
{
await TryDownloadChannelItem(source, item, destination, progress, cancellationToken).ConfigureAwait(false);
return;
}
}
private async Task TryDownloadChannelItem(MediaSourceInfo source,
BaseItem item,
string destination,
IProgress<double> progress,
CancellationToken cancellationToken)
{
var options = new HttpRequestOptions
{
CancellationToken = cancellationToken,
Url = source.Path,
Progress = new Progress<double>()
};
var channel = GetChannel(item.ChannelId);
var channelProvider = GetChannelProvider(channel);
var features = channelProvider.GetChannelFeatures();
if (!features.SupportsContentDownloading)
{
throw new ArgumentException("The channel does not support downloading.");
}
var limit = features.DailyDownloadLimit;
foreach (var header in source.RequiredHttpHeaders)
{
options.RequestHeaders[header.Key] = header.Value;
}
_fileSystem.CreateDirectory(Path.GetDirectoryName(destination));
// Determine output extension
var response = await _httpClient.GetTempFileResponse(options).ConfigureAwait(false);
if (response.ContentType.StartsWith("text/html"))
{
throw new HttpException("File not found")
{
StatusCode = HttpStatusCode.NotFound
};
}
if (string.Equals(item.MediaType, MediaType.Video, StringComparison.OrdinalIgnoreCase) && response.ContentType.StartsWith("video/", StringComparison.OrdinalIgnoreCase))
{
var extension = response.ContentType.Split('/')
.Last()
.Replace("quicktime", "mov", StringComparison.OrdinalIgnoreCase);
destination += "." + extension;
}
else if (string.Equals(item.MediaType, MediaType.Audio, StringComparison.OrdinalIgnoreCase) && response.ContentType.StartsWith("audio/", StringComparison.OrdinalIgnoreCase))
{
var extension = response.ContentType.Replace("audio/mpeg", "audio/mp3", StringComparison.OrdinalIgnoreCase)
.Split('/')
.Last();
destination += "." + extension;
}
else
{
_fileSystem.DeleteFile(response.TempFilePath);
throw new ApplicationException("Unexpected response type encountered: " + response.ContentType);
}
_fileSystem.CopyFile(response.TempFilePath, destination, true);
try
{
_fileSystem.DeleteFile(response.TempFilePath);
}
catch
{
}
}
}
}

View file

@ -907,15 +907,6 @@ namespace MediaBrowser.Server.Implementations.Dto
dto.Keywords = item.Keywords;
}
if (fields.Contains(ItemFields.PlaceOfBirth))
{
var person = item as Person;
if (person != null)
{
dto.PlaceOfBirth = person.PlaceOfBirth;
}
}
var hasAspectRatio = item as IHasAspectRatio;
if (hasAspectRatio != null)
{
@ -1432,10 +1423,9 @@ namespace MediaBrowser.Server.Implementations.Dto
SetBookProperties(dto, book);
}
var movie = item as Movie;
if (movie != null)
if (item.ProductionLocations.Count > 0 || item is Movie)
{
dto.ProductionLocations = new string[] { };
dto.ProductionLocations = item.ProductionLocations.ToArray();
}
var photo = item as Photo;

View file

@ -17,7 +17,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer.SocketSharp
public Container Container { get; set; }
private readonly HttpListenerRequest request;
private readonly IHttpResponse response;
private IMemoryStreamProvider _memoryStreamProvider;
private readonly IMemoryStreamProvider _memoryStreamProvider;
public WebSocketSharpRequest(HttpListenerContext httpContext, string operationName, RequestAttributes requestAttributes, ILogger logger, IMemoryStreamProvider memoryStreamProvider)
{

View file

@ -335,15 +335,6 @@ namespace MediaBrowser.Server.Implementations.Library
}
}
/// <summary>
/// Updates the item in library cache.
/// </summary>
/// <param name="item">The item.</param>
private void UpdateItemInLibraryCache(BaseItem item)
{
RegisterItem(item);
}
public void RegisterItem(BaseItem item)
{
if (item == null)
@ -1777,7 +1768,7 @@ namespace MediaBrowser.Server.Implementations.Library
foreach (var item in list)
{
UpdateItemInLibraryCache(item);
RegisterItem(item);
}
if (ItemAdded != null)
@ -1818,7 +1809,7 @@ namespace MediaBrowser.Server.Implementations.Library
await ItemRepository.SaveItem(item, cancellationToken).ConfigureAwait(false);
UpdateItemInLibraryCache(item);
RegisterItem(item);
if (ItemUpdated != null)
{

View file

@ -54,8 +54,8 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Audio
if (!args.IsDirectory) return null;
// Avoid mis-identifying top folders
if (args.Parent.IsRoot) return null;
if (args.HasParent<MusicAlbum>()) return null;
if (args.Parent.IsRoot) return null;
var collectionType = args.GetCollectionType();

View file

@ -51,9 +51,6 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Audio
{
if (!args.IsDirectory) return null;
// Avoid mis-identifying top folders
if (args.Parent.IsRoot) return null;
// Don't allow nested artists
if (args.HasParent<MusicArtist>() || args.HasParent<MusicAlbum>())
{
@ -70,12 +67,9 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Audio
return null;
}
if (args.IsDirectory)
if (args.ContainsFileSystemEntryByName("artist.nfo"))
{
if (args.ContainsFileSystemEntryByName("artist.nfo"))
{
return new MusicArtist();
}
return new MusicArtist();
}
if (_config.Configuration.EnableSimpleArtistDetection)
@ -83,6 +77,9 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Audio
return null;
}
// Avoid mis-identifying top folders
if (args.Parent.IsRoot) return null;
var directoryService = args.DirectoryService;
var albumResolver = new MusicAlbumResolver(_logger, _fileSystem, _libraryManager);

View file

@ -51,7 +51,6 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers
base.SetInitialItemValues(item, args);
item.IsRoot = args.Parent == null;
item.IsPhysicalRoot = args.IsPhysicalRoot;
}
}
}

View file

@ -59,6 +59,15 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.TV
return null;
}
if (args.ContainsFileSystemEntryByName("tvshow.nfo"))
{
return new Series
{
Path = args.Path,
Name = Path.GetFileName(args.Path)
};
}
var collectionType = args.GetCollectionType();
if (string.Equals(collectionType, CollectionType.TvShows, StringComparison.OrdinalIgnoreCase))
{
@ -72,23 +81,20 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.TV
};
}
}
else
else if (string.IsNullOrWhiteSpace(collectionType))
{
if (string.IsNullOrWhiteSpace(collectionType))
if (args.Parent.IsRoot)
{
if (args.Parent.IsRoot)
return null;
}
if (IsSeriesFolder(args.Path, args.FileSystemChildren, args.DirectoryService, _fileSystem, _logger, _libraryManager, args.GetLibraryOptions(), false))
{
return new Series
{
return null;
}
if (IsSeriesFolder(args.Path, args.FileSystemChildren, args.DirectoryService, _fileSystem, _logger, _libraryManager, args.GetLibraryOptions(), false) ||
args.ContainsFileSystemEntryByName("tvshow.nfo"))
{
return new Series
{
Path = args.Path,
Name = Path.GetFileName(args.Path)
};
}
Path = args.Path,
Name = Path.GetFileName(args.Path)
};
}
}
}

View file

@ -28,6 +28,7 @@ using System.Threading.Tasks;
using System.Xml;
using CommonIO;
using MediaBrowser.Common.Extensions;
using MediaBrowser.Controller;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Model.Configuration;
@ -38,7 +39,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
{
public class EmbyTV : ILiveTvService, ISupportsDirectStreamProvider, ISupportsNewTimerIds, IDisposable
{
private readonly IApplicationHost _appHpst;
private readonly IServerApplicationHost _appHost;
private readonly ILogger _logger;
private readonly IHttpClient _httpClient;
private readonly IServerConfigurationManager _config;
@ -64,11 +65,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
private readonly ConcurrentDictionary<string, ActiveRecordingInfo> _activeRecordings =
new ConcurrentDictionary<string, ActiveRecordingInfo>(StringComparer.OrdinalIgnoreCase);
public EmbyTV(IApplicationHost appHost, ILogger logger, IJsonSerializer jsonSerializer, IHttpClient httpClient, IServerConfigurationManager config, ILiveTvManager liveTvManager, IFileSystem fileSystem, ILibraryManager libraryManager, ILibraryMonitor libraryMonitor, IProviderManager providerManager, IFileOrganizationService organizationService, IMediaEncoder mediaEncoder)
public EmbyTV(IServerApplicationHost appHost, ILogger logger, IJsonSerializer jsonSerializer, IHttpClient httpClient, IServerConfigurationManager config, ILiveTvManager liveTvManager, IFileSystem fileSystem, ILibraryManager libraryManager, ILibraryMonitor libraryMonitor, IProviderManager providerManager, IFileOrganizationService organizationService, IMediaEncoder mediaEncoder)
{
Current = this;
_appHpst = appHost;
_appHost = appHost;
_logger = logger;
_httpClient = httpClient;
_config = config;
@ -293,7 +294,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
status.Tuners = list;
status.Status = LiveTvServiceStatus.Ok;
status.Version = _appHpst.ApplicationVersion.ToString();
status.Version = _appHost.ApplicationVersion.ToString();
status.IsVisible = false;
return status;
}
@ -659,7 +660,63 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
public async Task<IEnumerable<RecordingInfo>> GetRecordingsAsync(CancellationToken cancellationToken)
{
return new List<RecordingInfo>();
return _activeRecordings.Values.ToList().Select(GetRecordingInfo).ToList();
}
public string GetActiveRecordingPath(string id)
{
ActiveRecordingInfo info;
if (_activeRecordings.TryGetValue(id, out info))
{
return info.Path;
}
return null;
}
private RecordingInfo GetRecordingInfo(ActiveRecordingInfo info)
{
var timer = info.Timer;
var program = info.Program;
var result = new RecordingInfo
{
ChannelId = timer.ChannelId,
CommunityRating = timer.CommunityRating,
DateLastUpdated = DateTime.UtcNow,
EndDate = timer.EndDate,
EpisodeTitle = timer.EpisodeTitle,
Genres = timer.Genres,
Id = "recording" + timer.Id,
IsKids = timer.IsKids,
IsMovie = timer.IsMovie,
IsNews = timer.IsNews,
IsRepeat = timer.IsRepeat,
IsSeries = timer.IsProgramSeries,
IsSports = timer.IsSports,
Name = timer.Name,
OfficialRating = timer.OfficialRating,
OriginalAirDate = timer.OriginalAirDate,
Overview = timer.Overview,
ProgramId = timer.ProgramId,
SeriesTimerId = timer.SeriesTimerId,
StartDate = timer.StartDate,
Status = RecordingStatus.InProgress,
TimerId = timer.Id
};
if (program != null)
{
result.Audio = program.Audio;
result.ImagePath = program.ImagePath;
result.ImageUrl = program.ImageUrl;
result.IsHD = program.IsHD;
result.IsLive = program.IsLive;
result.IsPremiere = program.IsPremiere;
result.ShowId = program.ShowId;
}
return result;
}
public Task<IEnumerable<TimerInfo>> GetTimersAsync(CancellationToken cancellationToken)
@ -954,7 +1011,31 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
public Task<List<MediaSourceInfo>> GetRecordingStreamMediaSources(string recordingId, CancellationToken cancellationToken)
{
throw new NotImplementedException();
ActiveRecordingInfo info;
recordingId = recordingId.Replace("recording", string.Empty);
if (_activeRecordings.TryGetValue(recordingId, out info))
{
return Task.FromResult(new List<MediaSourceInfo>
{
new MediaSourceInfo
{
Path = _appHost.GetLocalApiUrl("localhost") + "/LiveTv/LiveRecordings/" + recordingId + "/stream",
Id = recordingId,
SupportsDirectPlay = false,
SupportsDirectStream = true,
SupportsTranscoding = true,
IsInfiniteStream = true,
RequiresOpening = false,
RequiresClosing = false,
Protocol = Model.MediaInfo.MediaProtocol.Http,
BufferMs = 0
}
});
}
throw new FileNotFoundException();
}
public async Task CloseLiveStream(string id, CancellationToken cancellationToken)
@ -1031,7 +1112,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
var activeRecordingInfo = new ActiveRecordingInfo
{
CancellationTokenSource = new CancellationTokenSource(),
TimerId = timer.Id
Timer = timer
};
if (_activeRecordings.TryAdd(timer.Id, activeRecordingInfo))
@ -1168,6 +1249,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
if (programInfo != null)
{
RecordingHelper.CopyProgramInfoToTimerInfo(programInfo, timer);
activeRecordingInfo.Program = programInfo;
}
string seriesPath = null;
@ -1394,7 +1476,10 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
return true;
}
var hasRecordingAtPath = _activeRecordings.Values.ToList().Any(i => string.Equals(i.Path, path, StringComparison.OrdinalIgnoreCase) && !string.Equals(i.TimerId, timerId, StringComparison.OrdinalIgnoreCase));
var hasRecordingAtPath = _activeRecordings
.Values
.ToList()
.Any(i => string.Equals(i.Path, path, StringComparison.OrdinalIgnoreCase) && !string.Equals(i.Timer.Id, timerId, StringComparison.OrdinalIgnoreCase));
if (hasRecordingAtPath)
{
@ -1878,7 +1963,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
class ActiveRecordingInfo
{
public string Path { get; set; }
public string TimerId { get; set; }
public TimerInfo Timer { get; set; }
public ProgramInfo Program { get; set; }
public CancellationTokenSource CancellationTokenSource { get; set; }
}
}

View file

@ -10,6 +10,7 @@ using MediaBrowser.Model.LiveTv;
using MediaBrowser.Model.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
@ -125,6 +126,34 @@ namespace MediaBrowser.Server.Implementations.LiveTv
dto.DayPattern = info.Days == null ? null : GetDayPattern(info.Days);
if (!string.IsNullOrWhiteSpace(info.SeriesId))
{
var program = _libraryManager.GetItemList(new InternalItemsQuery
{
IncludeItemTypes = new string[] { typeof(LiveTvProgram).Name },
ExternalSeriesId = info.SeriesId,
Limit = 1,
ImageTypes = new ImageType[] { ImageType.Primary }
}).FirstOrDefault();
if (program != null)
{
var image = program.GetImageInfo(ImageType.Primary, 0);
if (image != null)
{
try
{
dto.ParentPrimaryImageTag = _imageProcessor.GetImageCacheTag(program, image);
dto.ParentPrimaryImageItemId = program.Id.ToString("N");
}
catch (Exception ex)
{
}
}
}
}
return dto;
}

View file

@ -235,20 +235,20 @@ namespace MediaBrowser.Server.Implementations.LiveTv
return await GetLiveStream(id, mediaSourceId, true, cancellationToken).ConfigureAwait(false);
}
public async Task<IEnumerable<MediaSourceInfo>> GetRecordingMediaSources(string id, CancellationToken cancellationToken)
public async Task<IEnumerable<MediaSourceInfo>> GetRecordingMediaSources(IHasMediaSources item, CancellationToken cancellationToken)
{
var item = await GetInternalRecording(id, cancellationToken).ConfigureAwait(false);
var service = GetService(item);
var baseItem = (BaseItem)item;
var service = GetService(baseItem);
return await service.GetRecordingStreamMediaSources(id, cancellationToken).ConfigureAwait(false);
return await service.GetRecordingStreamMediaSources(baseItem.ExternalId, cancellationToken).ConfigureAwait(false);
}
public async Task<IEnumerable<MediaSourceInfo>> GetChannelMediaSources(string id, CancellationToken cancellationToken)
public async Task<IEnumerable<MediaSourceInfo>> GetChannelMediaSources(IHasMediaSources item, CancellationToken cancellationToken)
{
var item = GetInternalChannel(id);
var service = GetService(item);
var baseItem = (LiveTvChannel)item;
var service = GetService(baseItem);
var sources = await service.GetChannelStreamMediaSources(item.ExternalId, cancellationToken).ConfigureAwait(false);
var sources = await service.GetChannelStreamMediaSources(baseItem.ExternalId, cancellationToken).ConfigureAwait(false);
if (sources.Count == 0)
{
@ -259,7 +259,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
foreach (var source in list)
{
Normalize(source, service, item.ChannelType == ChannelType.TV);
Normalize(source, service, baseItem.ChannelType == ChannelType.TV);
}
return list;
@ -738,6 +738,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
recording.IsRepeat = info.IsRepeat;
recording.IsSports = info.IsSports;
recording.SeriesTimerId = info.SeriesTimerId;
recording.TimerId = info.TimerId;
recording.StartDate = info.StartDate;
if (!dataChanged)
@ -1083,10 +1084,13 @@ namespace MediaBrowser.Server.Implementations.LiveTv
if (timer != null)
{
program.TimerId = _tvDtoService.GetInternalTimerId(serviceName, timer.Id)
.ToString("N");
if (timer.Status != RecordingStatus.Cancelled && timer.Status != RecordingStatus.Error)
{
program.TimerId = _tvDtoService.GetInternalTimerId(serviceName, timer.Id)
.ToString("N");
program.TimerStatus = timer.Status;
program.Status = timer.Status.ToString();
}
if (!string.IsNullOrEmpty(timer.SeriesTimerId))
{
@ -1432,7 +1436,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
private DateTime _lastRecordingRefreshTime;
private async Task RefreshRecordings(CancellationToken cancellationToken)
{
const int cacheMinutes = 5;
const int cacheMinutes = 3;
if ((DateTime.UtcNow - _lastRecordingRefreshTime).TotalMinutes < cacheMinutes)
{
@ -1482,7 +1486,12 @@ namespace MediaBrowser.Server.Implementations.LiveTv
private QueryResult<BaseItem> GetEmbyRecordings(RecordingQuery query, DtoOptions dtoOptions, User user)
{
if (user == null || (query.IsInProgress ?? false))
if (user == null)
{
return new QueryResult<BaseItem>();
}
if ((query.IsInProgress ?? false))
{
return new QueryResult<BaseItem>();
}
@ -1628,7 +1637,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
return new QueryResult<BaseItem>();
}
if (_services.Count == 1)
if (_services.Count == 1 && !(query.IsInProgress ?? false))
{
return GetEmbyRecordings(query, new DtoOptions(), user);
}
@ -1824,6 +1833,10 @@ namespace MediaBrowser.Server.Implementations.LiveTv
? null
: _tvDtoService.GetInternalSeriesTimerId(service.Name, info.SeriesTimerId).ToString("N");
dto.TimerId = string.IsNullOrEmpty(info.TimerId)
? null
: _tvDtoService.GetInternalTimerId(service.Name, info.TimerId).ToString("N");
dto.StartDate = info.StartDate;
dto.RecordingStatus = info.Status;
dto.IsRepeat = info.IsRepeat;

View file

@ -65,12 +65,12 @@ namespace MediaBrowser.Server.Implementations.LiveTv
{
if (item is ILiveTvRecording)
{
sources = await _liveTvManager.GetRecordingMediaSources(item.Id.ToString("N"), cancellationToken)
sources = await _liveTvManager.GetRecordingMediaSources(item, cancellationToken)
.ConfigureAwait(false);
}
else
{
sources = await _liveTvManager.GetChannelMediaSources(item.Id.ToString("N"), cancellationToken)
sources = await _liveTvManager.GetChannelMediaSources(item, cancellationToken)
.ConfigureAwait(false);
}
}

View file

@ -21,10 +21,13 @@ using System.Threading.Tasks;
using MediaBrowser.Common.Extensions;
using MediaBrowser.Common.IO;
using MediaBrowser.Controller.Channels;
using MediaBrowser.Controller.Collections;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Playlists;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.LiveTv;
using MediaBrowser.Server.Implementations.Devices;
using MediaBrowser.Server.Implementations.Playlists;
namespace MediaBrowser.Server.Implementations.Persistence
{
@ -279,6 +282,9 @@ namespace MediaBrowser.Server.Implementations.Persistence
_connection.AddColumn(Logger, "TypedBaseItems", "Keywords", "Text");
_connection.AddColumn(Logger, "TypedBaseItems", "ProviderIds", "Text");
_connection.AddColumn(Logger, "TypedBaseItems", "Images", "Text");
_connection.AddColumn(Logger, "TypedBaseItems", "ProductionLocations", "Text");
_connection.AddColumn(Logger, "TypedBaseItems", "ThemeSongIds", "Text");
_connection.AddColumn(Logger, "TypedBaseItems", "ThemeVideoIds", "Text");
_connection.AddColumn(Logger, "UserDataKeys", "Priority", "INT");
_connection.AddColumn(Logger, "ItemValues", "CleanValue", "Text");
@ -428,7 +434,10 @@ namespace MediaBrowser.Server.Implementations.Persistence
"Tagline",
"Keywords",
"ProviderIds",
"Images"
"Images",
"ProductionLocations",
"ThemeSongIds",
"ThemeVideoIds"
};
private readonly string[] _mediaStreamSaveColumns =
@ -556,7 +565,10 @@ namespace MediaBrowser.Server.Implementations.Persistence
"Tagline",
"Keywords",
"ProviderIds",
"Images"
"Images",
"ProductionLocations",
"ThemeSongIds",
"ThemeVideoIds"
};
_saveItemCommand = _connection.CreateCommand();
_saveItemCommand.CommandText = "replace into TypedBaseItems (" + string.Join(",", saveColumns.ToArray()) + ") values (";
@ -1007,10 +1019,46 @@ namespace MediaBrowser.Server.Implementations.Persistence
_saveItemCommand.GetParameter(index++).Value = item.ExternalSeriesId;
_saveItemCommand.GetParameter(index++).Value = item.ShortOverview;
_saveItemCommand.GetParameter(index++).Value = item.Tagline;
_saveItemCommand.GetParameter(index++).Value = string.Join("|", item.Keywords.ToArray());
if (item.Keywords.Count > 0)
{
_saveItemCommand.GetParameter(index++).Value = string.Join("|", item.Keywords.ToArray());
}
else
{
_saveItemCommand.GetParameter(index++).Value = null;
}
_saveItemCommand.GetParameter(index++).Value = SerializeProviderIds(item);
_saveItemCommand.GetParameter(index++).Value = SerializeImages(item);
if (item.ProductionLocations.Count > 0)
{
_saveItemCommand.GetParameter(index++).Value = string.Join("|", item.ProductionLocations.ToArray());
}
else
{
_saveItemCommand.GetParameter(index++).Value = null;
}
if (item.ThemeSongIds.Count > 0)
{
_saveItemCommand.GetParameter(index++).Value = string.Join("|", item.ThemeSongIds.Select(i => i.ToString("N")).ToArray());
}
else
{
_saveItemCommand.GetParameter(index++).Value = null;
}
if (item.ThemeVideoIds.Count > 0)
{
_saveItemCommand.GetParameter(index++).Value = string.Join("|", item.ThemeVideoIds.Select(i => i.ToString("N")).ToArray());
}
else
{
_saveItemCommand.GetParameter(index++).Value = null;
}
_saveItemCommand.Transaction = transaction;
_saveItemCommand.ExecuteNonQuery();
@ -1217,6 +1265,46 @@ namespace MediaBrowser.Server.Implementations.Persistence
{
return false;
}
if (type == typeof(Person))
{
return false;
}
if (type == typeof(RecordingGroup))
{
return false;
}
if (type == typeof(Channel))
{
return false;
}
if (type == typeof(ManualCollectionsFolder))
{
return false;
}
if (type == typeof(CameraUploadsFolder))
{
return false;
}
if (type == typeof(PlaylistsFolder))
{
return false;
}
if (type == typeof(UserRootFolder))
{
return false;
}
if (type == typeof(PhotoAlbum))
{
return false;
}
if (type == typeof(Season))
{
return false;
}
if (type == typeof(MusicArtist))
{
return false;
}
}
if (_config.Configuration.SkipDeserializationForPrograms)
{
@ -1775,6 +1863,27 @@ namespace MediaBrowser.Server.Implementations.Persistence
}
index++;
if (query.HasField(ItemFields.ProductionLocations))
{
if (!reader.IsDBNull(index))
{
item.ProductionLocations = reader.GetString(index).Split('|').Where(i => !string.IsNullOrWhiteSpace(i)).ToList();
}
index++;
}
if (!reader.IsDBNull(index))
{
item.ThemeSongIds = reader.GetString(index).Split('|').Where(i => !string.IsNullOrWhiteSpace(i)).Select(i => new Guid(i)).ToList();
}
index++;
if (!reader.IsDBNull(index))
{
item.ThemeVideoIds = reader.GetString(index).Split('|').Where(i => !string.IsNullOrWhiteSpace(i)).Select(i => new Guid(i)).ToList();
}
index++;
if (string.IsNullOrWhiteSpace(item.Tagline))
{
var movie = item as Movie;
@ -1784,6 +1893,15 @@ namespace MediaBrowser.Server.Implementations.Persistence
}
}
if (type == typeof(Person) && item.ProductionLocations.Count == 0)
{
var person = (Person)item;
if (!string.IsNullOrWhiteSpace(person.PlaceOfBirth))
{
item.ProductionLocations = new List<string> { person.PlaceOfBirth };
}
}
return item;
}

View file

@ -377,6 +377,7 @@ namespace MediaBrowser.Server.Startup.Common
ServiceStack.Text.JsConfig<Movie>.ExcludePropertyNames = new[] { "Keywords" };
ServiceStack.Text.JsConfig<Trailer>.ExcludePropertyNames = new[] { "ShortOverview" };
ServiceStack.Text.JsConfig<Series>.ExcludePropertyNames = new[] { "ShortOverview" };
ServiceStack.Text.JsConfig<Person>.ExcludePropertyNames = new[] { "PlaceOfBirth" };
ServiceStack.Text.JsConfig<LiveTvProgram>.ExcludePropertyNames = new[] { "ProviderIds" };
ServiceStack.Text.JsConfig<LiveTvChannel>.ExcludePropertyNames = new[] { "ProviderIds" };
@ -448,6 +449,111 @@ namespace MediaBrowser.Server.Startup.Common
ServiceStack.Text.JsConfig<Channel>.ExcludePropertyNames = new[] { "ImageInfos" };
ServiceStack.Text.JsConfig<AggregateFolder>.ExcludePropertyNames = new[] { "ImageInfos" };
ServiceStack.Text.JsConfig<LiveTvProgram>.ExcludePropertyNames = new[] { "ProductionLocations" };
ServiceStack.Text.JsConfig<LiveTvChannel>.ExcludePropertyNames = new[] { "ProductionLocations" };
ServiceStack.Text.JsConfig<LiveTvVideoRecording>.ExcludePropertyNames = new[] { "ProductionLocations" };
ServiceStack.Text.JsConfig<LiveTvAudioRecording>.ExcludePropertyNames = new[] { "ProductionLocations" };
ServiceStack.Text.JsConfig<Series>.ExcludePropertyNames = new[] { "ProductionLocations" };
ServiceStack.Text.JsConfig<Audio>.ExcludePropertyNames = new[] { "ProductionLocations" };
ServiceStack.Text.JsConfig<MusicAlbum>.ExcludePropertyNames = new[] { "ProductionLocations" };
ServiceStack.Text.JsConfig<MusicArtist>.ExcludePropertyNames = new[] { "ProductionLocations" };
ServiceStack.Text.JsConfig<MusicGenre>.ExcludePropertyNames = new[] { "ProductionLocations" };
ServiceStack.Text.JsConfig<MusicVideo>.ExcludePropertyNames = new[] { "ProductionLocations" };
ServiceStack.Text.JsConfig<Movie>.ExcludePropertyNames = new[] { "ProductionLocations" };
ServiceStack.Text.JsConfig<Playlist>.ExcludePropertyNames = new[] { "ProductionLocations" };
ServiceStack.Text.JsConfig<AudioPodcast>.ExcludePropertyNames = new[] { "ProductionLocations" };
ServiceStack.Text.JsConfig<Trailer>.ExcludePropertyNames = new[] { "ProductionLocations" };
ServiceStack.Text.JsConfig<BoxSet>.ExcludePropertyNames = new[] { "ProductionLocations" };
ServiceStack.Text.JsConfig<Episode>.ExcludePropertyNames = new[] { "ProductionLocations" };
ServiceStack.Text.JsConfig<Season>.ExcludePropertyNames = new[] { "ProductionLocations" };
ServiceStack.Text.JsConfig<Book>.ExcludePropertyNames = new[] { "ProductionLocations" };
ServiceStack.Text.JsConfig<CollectionFolder>.ExcludePropertyNames = new[] { "ProductionLocations" };
ServiceStack.Text.JsConfig<Folder>.ExcludePropertyNames = new[] { "ProductionLocations" };
ServiceStack.Text.JsConfig<Game>.ExcludePropertyNames = new[] { "ProductionLocations" };
ServiceStack.Text.JsConfig<GameGenre>.ExcludePropertyNames = new[] { "ProductionLocations" };
ServiceStack.Text.JsConfig<GameSystem>.ExcludePropertyNames = new[] { "ProductionLocations" };
ServiceStack.Text.JsConfig<Genre>.ExcludePropertyNames = new[] { "ProductionLocations" };
ServiceStack.Text.JsConfig<Person>.ExcludePropertyNames = new[] { "ProductionLocations" };
ServiceStack.Text.JsConfig<Photo>.ExcludePropertyNames = new[] { "ProductionLocations" };
ServiceStack.Text.JsConfig<PhotoAlbum>.ExcludePropertyNames = new[] { "ProductionLocations" };
ServiceStack.Text.JsConfig<Studio>.ExcludePropertyNames = new[] { "ProductionLocations" };
ServiceStack.Text.JsConfig<UserRootFolder>.ExcludePropertyNames = new[] { "ProductionLocations" };
ServiceStack.Text.JsConfig<UserView>.ExcludePropertyNames = new[] { "ProductionLocations" };
ServiceStack.Text.JsConfig<Video>.ExcludePropertyNames = new[] { "ProductionLocations" };
ServiceStack.Text.JsConfig<Year>.ExcludePropertyNames = new[] { "ProductionLocations" };
ServiceStack.Text.JsConfig<Channel>.ExcludePropertyNames = new[] { "ProductionLocations" };
ServiceStack.Text.JsConfig<AggregateFolder>.ExcludePropertyNames = new[] { "ProductionLocations" };
ServiceStack.Text.JsConfig<LiveTvProgram>.ExcludePropertyNames = new[] { "ThemeSongIds" };
ServiceStack.Text.JsConfig<LiveTvChannel>.ExcludePropertyNames = new[] { "ThemeSongIds" };
ServiceStack.Text.JsConfig<LiveTvVideoRecording>.ExcludePropertyNames = new[] { "ThemeSongIds" };
ServiceStack.Text.JsConfig<LiveTvAudioRecording>.ExcludePropertyNames = new[] { "ThemeSongIds" };
ServiceStack.Text.JsConfig<Series>.ExcludePropertyNames = new[] { "ThemeSongIds" };
ServiceStack.Text.JsConfig<Audio>.ExcludePropertyNames = new[] { "ThemeSongIds" };
ServiceStack.Text.JsConfig<MusicAlbum>.ExcludePropertyNames = new[] { "ThemeSongIds" };
ServiceStack.Text.JsConfig<MusicArtist>.ExcludePropertyNames = new[] { "ThemeSongIds" };
ServiceStack.Text.JsConfig<MusicGenre>.ExcludePropertyNames = new[] { "ThemeSongIds" };
ServiceStack.Text.JsConfig<MusicVideo>.ExcludePropertyNames = new[] { "ThemeSongIds" };
ServiceStack.Text.JsConfig<Movie>.ExcludePropertyNames = new[] { "ThemeSongIds" };
ServiceStack.Text.JsConfig<Playlist>.ExcludePropertyNames = new[] { "ThemeSongIds" };
ServiceStack.Text.JsConfig<AudioPodcast>.ExcludePropertyNames = new[] { "ThemeSongIds" };
ServiceStack.Text.JsConfig<Trailer>.ExcludePropertyNames = new[] { "ThemeSongIds" };
ServiceStack.Text.JsConfig<BoxSet>.ExcludePropertyNames = new[] { "ThemeSongIds" };
ServiceStack.Text.JsConfig<Episode>.ExcludePropertyNames = new[] { "ThemeSongIds" };
ServiceStack.Text.JsConfig<Season>.ExcludePropertyNames = new[] { "ThemeSongIds" };
ServiceStack.Text.JsConfig<Book>.ExcludePropertyNames = new[] { "ThemeSongIds" };
ServiceStack.Text.JsConfig<CollectionFolder>.ExcludePropertyNames = new[] { "ThemeSongIds" };
ServiceStack.Text.JsConfig<Folder>.ExcludePropertyNames = new[] { "ThemeSongIds" };
ServiceStack.Text.JsConfig<Game>.ExcludePropertyNames = new[] { "ThemeSongIds" };
ServiceStack.Text.JsConfig<GameGenre>.ExcludePropertyNames = new[] { "ThemeSongIds" };
ServiceStack.Text.JsConfig<GameSystem>.ExcludePropertyNames = new[] { "ThemeSongIds" };
ServiceStack.Text.JsConfig<Genre>.ExcludePropertyNames = new[] { "ThemeSongIds" };
ServiceStack.Text.JsConfig<Person>.ExcludePropertyNames = new[] { "ThemeSongIds" };
ServiceStack.Text.JsConfig<Photo>.ExcludePropertyNames = new[] { "ThemeSongIds" };
ServiceStack.Text.JsConfig<PhotoAlbum>.ExcludePropertyNames = new[] { "ThemeSongIds" };
ServiceStack.Text.JsConfig<Studio>.ExcludePropertyNames = new[] { "ThemeSongIds" };
ServiceStack.Text.JsConfig<UserRootFolder>.ExcludePropertyNames = new[] { "ThemeSongIds" };
ServiceStack.Text.JsConfig<UserView>.ExcludePropertyNames = new[] { "ThemeSongIds" };
ServiceStack.Text.JsConfig<Video>.ExcludePropertyNames = new[] { "ThemeSongIds" };
ServiceStack.Text.JsConfig<Year>.ExcludePropertyNames = new[] { "ThemeSongIds" };
ServiceStack.Text.JsConfig<Channel>.ExcludePropertyNames = new[] { "ThemeSongIds" };
ServiceStack.Text.JsConfig<AggregateFolder>.ExcludePropertyNames = new[] { "ThemeSongIds" };
ServiceStack.Text.JsConfig<LiveTvProgram>.ExcludePropertyNames = new[] { "ThemeVideoIds" };
ServiceStack.Text.JsConfig<LiveTvChannel>.ExcludePropertyNames = new[] { "ThemeVideoIds" };
ServiceStack.Text.JsConfig<LiveTvVideoRecording>.ExcludePropertyNames = new[] { "ThemeVideoIds" };
ServiceStack.Text.JsConfig<LiveTvAudioRecording>.ExcludePropertyNames = new[] { "ThemeVideoIds" };
ServiceStack.Text.JsConfig<Series>.ExcludePropertyNames = new[] { "ThemeVideoIds" };
ServiceStack.Text.JsConfig<Audio>.ExcludePropertyNames = new[] { "ThemeVideoIds" };
ServiceStack.Text.JsConfig<MusicAlbum>.ExcludePropertyNames = new[] { "ThemeVideoIds" };
ServiceStack.Text.JsConfig<MusicArtist>.ExcludePropertyNames = new[] { "ThemeVideoIds" };
ServiceStack.Text.JsConfig<MusicGenre>.ExcludePropertyNames = new[] { "ThemeVideoIds" };
ServiceStack.Text.JsConfig<MusicVideo>.ExcludePropertyNames = new[] { "ThemeVideoIds" };
ServiceStack.Text.JsConfig<Movie>.ExcludePropertyNames = new[] { "ThemeVideoIds" };
ServiceStack.Text.JsConfig<Playlist>.ExcludePropertyNames = new[] { "ThemeVideoIds" };
ServiceStack.Text.JsConfig<AudioPodcast>.ExcludePropertyNames = new[] { "ThemeVideoIds" };
ServiceStack.Text.JsConfig<Trailer>.ExcludePropertyNames = new[] { "ThemeVideoIds" };
ServiceStack.Text.JsConfig<BoxSet>.ExcludePropertyNames = new[] { "ThemeVideoIds" };
ServiceStack.Text.JsConfig<Episode>.ExcludePropertyNames = new[] { "ThemeVideoIds" };
ServiceStack.Text.JsConfig<Season>.ExcludePropertyNames = new[] { "ThemeVideoIds" };
ServiceStack.Text.JsConfig<Book>.ExcludePropertyNames = new[] { "ThemeVideoIds" };
ServiceStack.Text.JsConfig<CollectionFolder>.ExcludePropertyNames = new[] { "ThemeVideoIds" };
ServiceStack.Text.JsConfig<Folder>.ExcludePropertyNames = new[] { "ThemeVideoIds" };
ServiceStack.Text.JsConfig<Game>.ExcludePropertyNames = new[] { "ThemeVideoIds" };
ServiceStack.Text.JsConfig<GameGenre>.ExcludePropertyNames = new[] { "ThemeVideoIds" };
ServiceStack.Text.JsConfig<GameSystem>.ExcludePropertyNames = new[] { "ThemeVideoIds" };
ServiceStack.Text.JsConfig<Genre>.ExcludePropertyNames = new[] { "ThemeVideoIds" };
ServiceStack.Text.JsConfig<Person>.ExcludePropertyNames = new[] { "ThemeVideoIds" };
ServiceStack.Text.JsConfig<Photo>.ExcludePropertyNames = new[] { "ThemeVideoIds" };
ServiceStack.Text.JsConfig<PhotoAlbum>.ExcludePropertyNames = new[] { "ThemeVideoIds" };
ServiceStack.Text.JsConfig<Studio>.ExcludePropertyNames = new[] { "ThemeVideoIds" };
ServiceStack.Text.JsConfig<UserRootFolder>.ExcludePropertyNames = new[] { "ThemeVideoIds" };
ServiceStack.Text.JsConfig<UserView>.ExcludePropertyNames = new[] { "ThemeVideoIds" };
ServiceStack.Text.JsConfig<Video>.ExcludePropertyNames = new[] { "ThemeVideoIds" };
ServiceStack.Text.JsConfig<Year>.ExcludePropertyNames = new[] { "ThemeVideoIds" };
ServiceStack.Text.JsConfig<Channel>.ExcludePropertyNames = new[] { "ThemeVideoIds" };
ServiceStack.Text.JsConfig<AggregateFolder>.ExcludePropertyNames = new[] { "ThemeVideoIds" };
return result;
}

View file

@ -505,9 +505,10 @@ namespace MediaBrowser.XbmcMetadata.Parsers
if (!string.IsNullOrWhiteSpace(val))
{
//var countries = val.Split('/')
// .Select(i => i.Trim())
// .Where(i => !string.IsNullOrWhiteSpace(i));
item.ProductionLocations = val.Split('/')
.Select(i => i.Trim())
.Where(i => !string.IsNullOrWhiteSpace(i))
.ToList();
}
break;
}

View file

@ -80,7 +80,7 @@ namespace MediaBrowser.XbmcMetadata.Savers
"imdbid",
"imdb_id",
"plotkeyword",
//"country",
"country",
"audiodbalbumid",
"audiodbartistid",
"awardsummary",
@ -723,10 +723,10 @@ namespace MediaBrowser.XbmcMetadata.Savers
writer.WriteElementString("tagline", item.Tagline);
}
//foreach (var country in hasProductionLocations.ProductionLocations)
//{
// writer.WriteElementString("country", country);
//}
foreach (var country in item.ProductionLocations)
{
writer.WriteElementString("country", country);
}
foreach (var genre in item.Genres)
{