aboutsummaryrefslogtreecommitdiff
path: root/Emby.Server.Implementations
diff options
context:
space:
mode:
Diffstat (limited to 'Emby.Server.Implementations')
-rw-r--r--Emby.Server.Implementations/Connect/ConnectManager.cs2
-rw-r--r--Emby.Server.Implementations/Data/SqliteItemRepository.cs13
-rw-r--r--Emby.Server.Implementations/Dto/DtoService.cs5
-rw-r--r--Emby.Server.Implementations/Emby.Server.Implementations.csproj4
-rw-r--r--Emby.Server.Implementations/Library/LibraryManager.cs31
-rw-r--r--Emby.Server.Implementations/Library/Resolvers/Audio/MusicArtistResolver.cs21
-rw-r--r--Emby.Server.Implementations/Library/Resolvers/TV/EpisodeResolver.cs6
-rw-r--r--Emby.Server.Implementations/Library/SearchEngine.cs2
-rw-r--r--Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs165
-rw-r--r--Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs5
-rw-r--r--Emby.Server.Implementations/LiveTv/EmbyTV/RecordingHelper.cs1
-rw-r--r--Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs286
-rw-r--r--Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs55
-rw-r--r--Emby.Server.Implementations/LiveTv/LiveTvManager.cs34
-rw-r--r--Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs54
-rw-r--r--Emby.Server.Implementations/LiveTv/TunerHosts/MulticastStream.cs37
-rw-r--r--Emby.Server.Implementations/LiveTv/TunerHosts/QueueStream.cs16
-rw-r--r--Emby.Server.Implementations/Migrations/GuideMigration.cs2
-rw-r--r--Emby.Server.Implementations/TV/TVSeriesManager.cs7
-rw-r--r--Emby.Server.Implementations/Udp/UdpServer.cs3
-rw-r--r--Emby.Server.Implementations/packages.config2
21 files changed, 377 insertions, 374 deletions
diff --git a/Emby.Server.Implementations/Connect/ConnectManager.cs b/Emby.Server.Implementations/Connect/ConnectManager.cs
index 7e6755f6a..8aac2a8c4 100644
--- a/Emby.Server.Implementations/Connect/ConnectManager.cs
+++ b/Emby.Server.Implementations/Connect/ConnectManager.cs
@@ -995,7 +995,7 @@ namespace Emby.Server.Implementations.Connect
if (changed)
{
- await _providerManager.SaveImage(user, imageUrl, null, ImageType.Primary, null, CancellationToken.None).ConfigureAwait(false);
+ await _providerManager.SaveImage(user, imageUrl, ImageType.Primary, null, CancellationToken.None).ConfigureAwait(false);
await user.RefreshMetadata(new MetadataRefreshOptions(_fileSystem)
{
diff --git a/Emby.Server.Implementations/Data/SqliteItemRepository.cs b/Emby.Server.Implementations/Data/SqliteItemRepository.cs
index c158f2e51..4a4a1a6bf 100644
--- a/Emby.Server.Implementations/Data/SqliteItemRepository.cs
+++ b/Emby.Server.Implementations/Data/SqliteItemRepository.cs
@@ -257,7 +257,6 @@ namespace Emby.Server.Implementations.Data
AddColumn(db, "TypedBaseItems", "SeriesId", "GUID", existingColumnNames);
AddColumn(db, "TypedBaseItems", "SeriesSortName", "Text", existingColumnNames);
AddColumn(db, "TypedBaseItems", "ExternalSeriesId", "Text", existingColumnNames);
- AddColumn(db, "TypedBaseItems", "ShortOverview", "Text", existingColumnNames);
AddColumn(db, "TypedBaseItems", "Tagline", "Text", existingColumnNames);
AddColumn(db, "TypedBaseItems", "Keywords", "Text", existingColumnNames);
AddColumn(db, "TypedBaseItems", "ProviderIds", "Text", existingColumnNames);
@@ -466,7 +465,6 @@ namespace Emby.Server.Implementations.Data
"InheritedParentalRatingValue",
"InheritedTags",
"ExternalSeriesId",
- "ShortOverview",
"Tagline",
"Keywords",
"ProviderIds",
@@ -598,7 +596,6 @@ namespace Emby.Server.Implementations.Data
"SeriesId",
"SeriesSortName",
"ExternalSeriesId",
- "ShortOverview",
"Tagline",
"Keywords",
"ProviderIds",
@@ -1038,7 +1035,6 @@ namespace Emby.Server.Implementations.Data
}
saveItemStatement.TryBind("@ExternalSeriesId", item.ExternalSeriesId);
- saveItemStatement.TryBind("@ShortOverview", item.ShortOverview);
saveItemStatement.TryBind("@Tagline", item.Tagline);
if (item.Keywords.Count > 0)
@@ -1893,15 +1889,6 @@ namespace Emby.Server.Implementations.Data
}
index++;
- if (query.HasField(ItemFields.ShortOverview))
- {
- if (!reader.IsDBNull(index))
- {
- item.ShortOverview = reader.GetString(index);
- }
- index++;
- }
-
if (query.HasField(ItemFields.Taglines))
{
if (!reader.IsDBNull(index))
diff --git a/Emby.Server.Implementations/Dto/DtoService.cs b/Emby.Server.Implementations/Dto/DtoService.cs
index f866c34de..9c50ad5da 100644
--- a/Emby.Server.Implementations/Dto/DtoService.cs
+++ b/Emby.Server.Implementations/Dto/DtoService.cs
@@ -1052,11 +1052,6 @@ namespace Emby.Server.Implementations.Dto
dto.OriginalTitle = item.OriginalTitle;
}
- if (fields.Contains(ItemFields.ShortOverview))
- {
- dto.ShortOverview = item.ShortOverview;
- }
-
if (fields.Contains(ItemFields.ParentId))
{
var displayParentId = item.DisplayParentId;
diff --git a/Emby.Server.Implementations/Emby.Server.Implementations.csproj b/Emby.Server.Implementations/Emby.Server.Implementations.csproj
index e3cd96894..195d24b21 100644
--- a/Emby.Server.Implementations/Emby.Server.Implementations.csproj
+++ b/Emby.Server.Implementations/Emby.Server.Implementations.csproj
@@ -309,8 +309,8 @@
<Project>{4f26d5d8-a7b0-42b3-ba42-7cb7d245934e}</Project>
<Name>SocketHttpListener.Portable</Name>
</ProjectReference>
- <Reference Include="Emby.XmlTv, Version=1.0.6193.39741, Culture=neutral, processorArchitecture=MSIL">
- <HintPath>..\packages\Emby.XmlTv.1.0.3\lib\portable-net45+win8\Emby.XmlTv.dll</HintPath>
+ <Reference Include="Emby.XmlTv, Version=1.0.6241.4924, Culture=neutral, processorArchitecture=MSIL">
+ <HintPath>..\packages\Emby.XmlTv.1.0.5\lib\portable-net45+win8\Emby.XmlTv.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="MediaBrowser.Naming, Version=1.0.6201.24431, Culture=neutral, processorArchitecture=MSIL">
diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs
index c59a22884..de3a1664e 100644
--- a/Emby.Server.Implementations/Library/LibraryManager.cs
+++ b/Emby.Server.Implementations/Library/LibraryManager.cs
@@ -1927,11 +1927,18 @@ namespace Emby.Server.Implementations.Library
return ItemRepository.RetrieveItem(id);
}
- public IEnumerable<Folder> GetCollectionFolders(BaseItem item)
+ public List<Folder> GetCollectionFolders(BaseItem item)
{
- while (!(item.GetParent() is AggregateFolder) && item.GetParent() != null)
+ while (item != null)
{
- item = item.GetParent();
+ var parent = item.GetParent();
+
+ if (parent == null || parent is AggregateFolder)
+ {
+ break;
+ }
+
+ item = parent;
}
if (item == null)
@@ -1941,7 +1948,8 @@ namespace Emby.Server.Implementations.Library
return GetUserRootFolder().Children
.OfType<Folder>()
- .Where(i => string.Equals(i.Path, item.Path, StringComparison.OrdinalIgnoreCase) || i.PhysicalLocations.Contains(item.Path, StringComparer.OrdinalIgnoreCase));
+ .Where(i => string.Equals(i.Path, item.Path, StringComparison.OrdinalIgnoreCase) || i.PhysicalLocations.Contains(item.Path, StringComparer.OrdinalIgnoreCase))
+ .ToList();
}
public LibraryOptions GetLibraryOptions(BaseItem item)
@@ -2619,18 +2627,6 @@ namespace Emby.Server.Implementations.Library
}
}
- foreach (var map in ConfigurationManager.Configuration.PathSubstitutions)
- {
- if (!string.IsNullOrWhiteSpace(map.From))
- {
- var substitutionResult = SubstitutePathInternal(path, map.From, map.To);
- if (substitutionResult.Item2)
- {
- return substitutionResult.Item1;
- }
- }
- }
-
return path;
}
@@ -2764,7 +2760,6 @@ namespace Emby.Server.Implementations.Library
return ItemRepository.UpdatePeople(item.Id, people);
}
- private readonly SemaphoreSlim _dynamicImageResourcePool = new SemaphoreSlim(1, 1);
public async Task<ItemImageInfo> ConvertImageToLocal(IHasImages item, ItemImageInfo image, int imageIndex)
{
foreach (var url in image.Path.Split('|'))
@@ -2773,7 +2768,7 @@ namespace Emby.Server.Implementations.Library
{
_logger.Debug("ConvertImageToLocal item {0} - image url: {1}", item.Id, url);
- await _providerManagerFactory().SaveImage(item, url, _dynamicImageResourcePool, image.Type, imageIndex, CancellationToken.None).ConfigureAwait(false);
+ await _providerManagerFactory().SaveImage(item, url, image.Type, imageIndex, CancellationToken.None).ConfigureAwait(false);
var newImage = item.GetImageInfo(image.Type, imageIndex);
diff --git a/Emby.Server.Implementations/Library/Resolvers/Audio/MusicArtistResolver.cs b/Emby.Server.Implementations/Library/Resolvers/Audio/MusicArtistResolver.cs
index 2971405b9..6cf201990 100644
--- a/Emby.Server.Implementations/Library/Resolvers/Audio/MusicArtistResolver.cs
+++ b/Emby.Server.Implementations/Library/Resolvers/Audio/MusicArtistResolver.cs
@@ -74,20 +74,21 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio
return new MusicArtist();
}
- if (_config.Configuration.EnableSimpleArtistDetection)
- {
- return null;
- }
+ return null;
+ //if (_config.Configuration.EnableSimpleArtistDetection)
+ //{
+ // return null;
+ //}
- // Avoid mis-identifying top folders
- if (args.Parent.IsRoot) return null;
+ //// Avoid mis-identifying top folders
+ //if (args.Parent.IsRoot) return null;
- var directoryService = args.DirectoryService;
+ //var directoryService = args.DirectoryService;
- var albumResolver = new MusicAlbumResolver(_logger, _fileSystem, _libraryManager);
+ //var albumResolver = new MusicAlbumResolver(_logger, _fileSystem, _libraryManager);
- // If we contain an album assume we are an artist folder
- return args.FileSystemChildren.Where(i => i.IsDirectory).Any(i => albumResolver.IsMusicAlbum(i.FullName, directoryService, args.GetLibraryOptions())) ? new MusicArtist() : null;
+ //// If we contain an album assume we are an artist folder
+ //return args.FileSystemChildren.Where(i => i.IsDirectory).Any(i => albumResolver.IsMusicAlbum(i.FullName, directoryService, args.GetLibraryOptions())) ? new MusicArtist() : null;
}
}
diff --git a/Emby.Server.Implementations/Library/Resolvers/TV/EpisodeResolver.cs b/Emby.Server.Implementations/Library/Resolvers/TV/EpisodeResolver.cs
index 2a4cc49b7..cf37366fb 100644
--- a/Emby.Server.Implementations/Library/Resolvers/TV/EpisodeResolver.cs
+++ b/Emby.Server.Implementations/Library/Resolvers/TV/EpisodeResolver.cs
@@ -64,6 +64,12 @@ namespace Emby.Server.Implementations.Library.Resolvers.TV
episode.SeasonId = season.Id;
episode.SeasonName = season.Name;
}
+
+ // Assume season 1 if there's no season folder and a season number could not be determined
+ if (season == null && !episode.ParentIndexNumber.HasValue && (episode.IndexNumber.HasValue || episode.PremiereDate.HasValue))
+ {
+ episode.ParentIndexNumber = 1;
+ }
}
return episode;
diff --git a/Emby.Server.Implementations/Library/SearchEngine.cs b/Emby.Server.Implementations/Library/SearchEngine.cs
index e6c88aa1a..a47a3322e 100644
--- a/Emby.Server.Implementations/Library/SearchEngine.cs
+++ b/Emby.Server.Implementations/Library/SearchEngine.cs
@@ -176,7 +176,7 @@ namespace Emby.Server.Implementations.Library
return new Tuple<BaseItem, string, int>(item, index.Item1, index.Item2);
}));
- var returnValue = hints.Where(i => i.Item3 >= 0).OrderBy(i => i.Item3).Select(i => new SearchHintInfo
+ var returnValue = hints.Where(i => i.Item3 >= 0).OrderBy(i => i.Item3).ThenBy(i => i.Item1.SortName).Select(i => new SearchHintInfo
{
Item = i.Item1,
MatchedTerm = i.Item2
diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
index 5e0b4ff34..89ef87c8e 100644
--- a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
+++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
@@ -393,7 +393,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
{
try
{
- await provider.Item1.AddMetadata(provider.Item2, enabledChannels, cancellationToken).ConfigureAwait(false);
+ await AddMetadata(provider.Item1, provider.Item2, enabledChannels, enableCache, cancellationToken).ConfigureAwait(false);
}
catch (NotSupportedException)
{
@@ -409,6 +409,120 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
return list;
}
+ private async Task AddMetadata(IListingsProvider provider, ListingsProviderInfo info, List<ChannelInfo> tunerChannels, bool enableCache, CancellationToken cancellationToken)
+ {
+ var epgChannels = await GetEpgChannels(provider, info, enableCache, cancellationToken).ConfigureAwait(false);
+
+ foreach (var tunerChannel in tunerChannels)
+ {
+ var epgChannel = GetEpgChannelFromTunerChannel(info, tunerChannel, epgChannels);
+
+ if (epgChannel != null)
+ {
+ if (!string.IsNullOrWhiteSpace(epgChannel.Name))
+ {
+ tunerChannel.Name = epgChannel.Name;
+ }
+ }
+ }
+ }
+
+ private readonly ConcurrentDictionary<string, List<ChannelInfo>> _epgChannels =
+ new ConcurrentDictionary<string, List<ChannelInfo>>(StringComparer.OrdinalIgnoreCase);
+
+ private async Task<List<ChannelInfo>> GetEpgChannels(IListingsProvider provider, ListingsProviderInfo info, bool enableCache, CancellationToken cancellationToken)
+ {
+ List<ChannelInfo> result;
+ if (!enableCache || !_epgChannels.TryGetValue(info.Id, out result))
+ {
+ result = await provider.GetChannels(info, cancellationToken).ConfigureAwait(false);
+
+ _epgChannels.AddOrUpdate(info.Id, result, (k, v) => result);
+ }
+
+ return result;
+ }
+
+ private async Task<ChannelInfo> GetEpgChannelFromTunerChannel(IListingsProvider provider, ListingsProviderInfo info, ChannelInfo tunerChannel, CancellationToken cancellationToken)
+ {
+ var epgChannels = await GetEpgChannels(provider, info, true, cancellationToken).ConfigureAwait(false);
+
+ return GetEpgChannelFromTunerChannel(info, tunerChannel, epgChannels);
+ }
+
+ private string GetMappedChannel(string channelId, List<NameValuePair> mappings)
+ {
+ foreach (NameValuePair mapping in mappings)
+ {
+ if (StringHelper.EqualsIgnoreCase(mapping.Name, channelId))
+ {
+ return mapping.Value;
+ }
+ }
+ return channelId;
+ }
+
+ private ChannelInfo GetEpgChannelFromTunerChannel(ListingsProviderInfo info, ChannelInfo tunerChannel, List<ChannelInfo> epgChannels)
+ {
+ return GetEpgChannelFromTunerChannel(info.ChannelMappings.ToList(), tunerChannel, epgChannels);
+ }
+
+ public ChannelInfo GetEpgChannelFromTunerChannel(List<NameValuePair> mappings, ChannelInfo tunerChannel, List<ChannelInfo> epgChannels)
+ {
+ if (!string.IsNullOrWhiteSpace(tunerChannel.TunerChannelId))
+ {
+ var tunerChannelId = GetMappedChannel(tunerChannel.TunerChannelId, mappings);
+
+ if (string.IsNullOrWhiteSpace(tunerChannelId))
+ {
+ tunerChannelId = tunerChannel.TunerChannelId;
+ }
+
+ var channel = epgChannels.FirstOrDefault(i => string.Equals(tunerChannelId, i.Id, StringComparison.OrdinalIgnoreCase));
+
+ if (channel != null)
+ {
+ return channel;
+ }
+ }
+
+ if (!string.IsNullOrWhiteSpace(tunerChannel.Number))
+ {
+ var tunerChannelNumber = GetMappedChannel(tunerChannel.Number, mappings);
+
+ if (string.IsNullOrWhiteSpace(tunerChannelNumber))
+ {
+ tunerChannelNumber = tunerChannel.Number;
+ }
+
+ var channel = epgChannels.FirstOrDefault(i => string.Equals(tunerChannelNumber, i.Number, StringComparison.OrdinalIgnoreCase));
+
+ if (channel != null)
+ {
+ return channel;
+ }
+ }
+
+ if (!string.IsNullOrWhiteSpace(tunerChannel.Name))
+ {
+ var normalizedName = NormalizeName(tunerChannel.Name);
+
+ var channel = epgChannels.FirstOrDefault(i => string.Equals(normalizedName, NormalizeName(i.Name ?? string.Empty), StringComparison.OrdinalIgnoreCase));
+
+ if (channel != null)
+ {
+ return channel;
+ }
+ }
+
+ return null;
+ }
+
+ private string NormalizeName(string value)
+ {
+ return value.Replace(" ", string.Empty).Replace("-", string.Empty);
+ }
+
public async Task<List<ChannelInfo>> GetChannelsForListingsProvider(ListingsProviderInfo listingsProvider, CancellationToken cancellationToken)
{
var list = new List<ChannelInfo>();
@@ -663,7 +777,6 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
existingTimer.ProductionYear = updatedTimer.ProductionYear;
existingTimer.ProgramId = updatedTimer.ProgramId;
existingTimer.SeasonNumber = updatedTimer.SeasonNumber;
- existingTimer.ShortOverview = updatedTimer.ShortOverview;
existingTimer.StartDate = updatedTimer.StartDate;
existingTimer.ShowId = updatedTimer.ShowId;
}
@@ -846,49 +959,37 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
_logger.Debug("Getting programs for channel {0}-{1} from {2}-{3}", channel.Number, channel.Name, provider.Item1.Name, provider.Item2.ListingsId ?? string.Empty);
- var channelMappings = GetChannelMappings(provider.Item2);
- var channelNumber = channel.Number;
- string mappedChannelNumber;
- if (channelMappings.TryGetValue(channelNumber, out mappedChannelNumber))
- {
- _logger.Debug("Found mapped channel on provider {0}. Tuner channel number: {1}, Mapped channel number: {2}", provider.Item1.Name, channelNumber, mappedChannelNumber);
- channelNumber = mappedChannelNumber;
- }
+ var epgChannel = await GetEpgChannelFromTunerChannel(provider.Item1, provider.Item2, channel, cancellationToken).ConfigureAwait(false);
- var programs = await provider.Item1.GetProgramsAsync(provider.Item2, channelNumber, channel.Name, startDateUtc, endDateUtc, cancellationToken)
- .ConfigureAwait(false);
+ List<ProgramInfo> programs;
- var list = programs.ToList();
+ if (epgChannel == null)
+ {
+ programs = new List<ProgramInfo>();
+ }
+ else
+ {
+ programs = (await provider.Item1.GetProgramsAsync(provider.Item2, epgChannel.Id, startDateUtc, endDateUtc, cancellationToken)
+ .ConfigureAwait(false)).ToList();
+ }
// Replace the value that came from the provider with a normalized value
- foreach (var program in list)
+ foreach (var program in programs)
{
program.ChannelId = channelId;
}
- if (list.Count > 0)
+ if (programs.Count > 0)
{
- SaveEpgDataForChannel(channelId, list);
+ SaveEpgDataForChannel(channelId, programs);
- return list;
+ return programs;
}
}
return new List<ProgramInfo>();
}
- private Dictionary<string, string> GetChannelMappings(ListingsProviderInfo info)
- {
- var dict = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
-
- foreach (var mapping in info.ChannelMappings)
- {
- dict[mapping.Name] = mapping.Value;
- }
-
- return dict;
- }
-
private List<Tuple<IListingsProvider, ListingsProviderInfo>> GetListingProviders()
{
return GetConfiguration().ListingProviders
@@ -1755,7 +1856,6 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
{
Name = timer.Name,
HomePageUrl = timer.HomePageUrl,
- ShortOverview = timer.ShortOverview,
Overview = timer.Overview,
Genres = timer.Genres,
CommunityRating = timer.CommunityRating,
@@ -1959,11 +2059,6 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
writer.WriteElementString("genre", genre);
}
- if (!string.IsNullOrWhiteSpace(item.ShortOverview))
- {
- writer.WriteElementString("outline", item.ShortOverview);
- }
-
if (!string.IsNullOrWhiteSpace(item.HomePageUrl))
{
writer.WriteElementString("website", item.HomePageUrl);
diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs
index beb08cc25..1f739b3c6 100644
--- a/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs
+++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs
@@ -154,7 +154,10 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
var durationParam = " -t " + _mediaEncoder.GetTimeParameter(duration.Ticks);
var inputModifiers = "-fflags +genpts -async 1 -vsync -1";
- var commandLineArgs = "-i \"{0}\"{4} -sn {2} -map_metadata -1 -threads 0 {3} -y \"{1}\"";
+ var mapArgs = string.Equals(OutputFormat, "mkv", StringComparison.OrdinalIgnoreCase) ? "-map 0" : "-sn";
+ // temporary
+ mapArgs = "-sn";
+ var commandLineArgs = "-i \"{0}\"{4} " + mapArgs + " {2} -map_metadata -1 -threads 0 {3} -y \"{1}\"";
long startTimeTicks = 0;
//if (mediaSource.DateLiveStreamOpened.HasValue)
diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/RecordingHelper.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/RecordingHelper.cs
index 84f802d76..17de93a3c 100644
--- a/Emby.Server.Implementations/LiveTv/EmbyTV/RecordingHelper.cs
+++ b/Emby.Server.Implementations/LiveTv/EmbyTV/RecordingHelper.cs
@@ -61,7 +61,6 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
timerInfo.HomePageUrl = programInfo.HomePageUrl;
timerInfo.CommunityRating = programInfo.CommunityRating;
timerInfo.Overview = programInfo.Overview;
- timerInfo.ShortOverview = programInfo.ShortOverview;
timerInfo.OfficialRating = programInfo.OfficialRating;
timerInfo.IsRepeat = programInfo.IsRepeat;
timerInfo.SeriesId = programInfo.SeriesId;
diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs
index 46b914232..1b7a1c8c6 100644
--- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs
+++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs
@@ -15,6 +15,7 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using MediaBrowser.Model.Extensions;
namespace Emby.Server.Implementations.LiveTv.Listings
{
@@ -60,8 +61,16 @@ namespace Emby.Server.Implementations.LiveTv.Listings
return dates;
}
- public async Task<IEnumerable<ProgramInfo>> GetProgramsAsync(ListingsProviderInfo info, string channelNumber, string channelName, DateTime startDateUtc, DateTime endDateUtc, CancellationToken cancellationToken)
+ public async Task<IEnumerable<ProgramInfo>> GetProgramsAsync(ListingsProviderInfo info, string channelId, DateTime startDateUtc, DateTime endDateUtc, CancellationToken cancellationToken)
{
+ if (string.IsNullOrWhiteSpace(channelId))
+ {
+ throw new ArgumentNullException("channelId");
+ }
+
+ // Normalize incoming input
+ channelId = channelId.Replace(".json.schedulesdirect.org", string.Empty, StringComparison.OrdinalIgnoreCase).TrimStart('I');
+
List<ProgramInfo> programsInfo = new List<ProgramInfo>();
var token = await GetToken(info, cancellationToken).ConfigureAwait(false);
@@ -80,15 +89,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
var dates = GetScheduleRequestDates(startDateUtc, endDateUtc);
- ScheduleDirect.Station station = GetStation(info.ListingsId, channelNumber, channelName);
-
- if (station == null)
- {
- _logger.Info("No Schedules Direct Station found for channel {0} with name {1}", channelNumber, channelName);
- return programsInfo;
- }
-
- string stationID = station.stationID;
+ string stationID = channelId;
_logger.Info("Channel Station ID is: " + stationID);
List<ScheduleDirect.RequestScheduleForChannel> requestList =
@@ -122,7 +123,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
StreamReader reader = new StreamReader(response.Content);
string responseString = reader.ReadToEnd();
var dailySchedules = _jsonSerializer.DeserializeFromString<List<ScheduleDirect.Day>>(responseString);
- _logger.Debug("Found " + dailySchedules.Count + " programs on " + channelNumber + " ScheduleDirect");
+ _logger.Debug("Found " + dailySchedules.Count + " programs on " + stationID + " ScheduleDirect");
httpOptions = new HttpRequestOptions()
{
@@ -180,7 +181,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
}
}
- programsInfo.Add(GetProgram(channelNumber, schedule, programDict[schedule.programID]));
+ programsInfo.Add(GetProgram(channelId, schedule, programDict[schedule.programID]));
}
}
}
@@ -202,183 +203,24 @@ namespace Emby.Server.Implementations.LiveTv.Listings
return 0;
}
- private readonly object _channelCacheLock = new object();
- private ScheduleDirect.Station GetStation(string listingsId, string channelNumber, string channelName)
+ private string GetChannelNumber(ScheduleDirect.Map map)
{
- lock (_channelCacheLock)
- {
- Dictionary<string, ScheduleDirect.Station> channelPair;
- if (_channelPairingCache.TryGetValue(listingsId, out channelPair))
- {
- ScheduleDirect.Station station;
-
- if (!string.IsNullOrWhiteSpace(channelNumber) && channelPair.TryGetValue(channelNumber, out station))
- {
- return station;
- }
-
- if (!string.IsNullOrWhiteSpace(channelName))
- {
- channelName = NormalizeName(channelName);
-
- var result = channelPair.Values.FirstOrDefault(i => string.Equals(NormalizeName(i.callsign ?? string.Empty), channelName, StringComparison.OrdinalIgnoreCase));
-
- if (result != null)
- {
- return result;
- }
- }
+ var channelNumber = map.logicalChannelNumber;
- if (!string.IsNullOrWhiteSpace(channelNumber))
- {
- return channelPair.Values.FirstOrDefault(i => string.Equals(NormalizeName(i.stationID ?? string.Empty), channelNumber, StringComparison.OrdinalIgnoreCase));
- }
- }
-
- return null;
- }
- }
-
- private void AddToChannelPairCache(string listingsId, string channelNumber, ScheduleDirect.Station schChannel)
- {
- lock (_channelCacheLock)
- {
- Dictionary<string, ScheduleDirect.Station> cache;
- if (_channelPairingCache.TryGetValue(listingsId, out cache))
- {
- cache[channelNumber] = schChannel;
- }
- else
- {
- cache = new Dictionary<string, ScheduleDirect.Station>();
- cache[channelNumber] = schChannel;
- _channelPairingCache[listingsId] = cache;
- }
- }
- }
-
- private void ClearPairCache(string listingsId)
- {
- lock (_channelCacheLock)
+ if (string.IsNullOrWhiteSpace(channelNumber))
{
- Dictionary<string, ScheduleDirect.Station> cache;
- if (_channelPairingCache.TryGetValue(listingsId, out cache))
- {
- cache.Clear();
- }
+ channelNumber = map.channel;
}
- }
-
- private int GetChannelPairCacheCount(string listingsId)
- {
- lock (_channelCacheLock)
+ if (string.IsNullOrWhiteSpace(channelNumber))
{
- Dictionary<string, ScheduleDirect.Station> cache;
- if (_channelPairingCache.TryGetValue(listingsId, out cache))
- {
- return cache.Count;
- }
-
- return 0;
+ channelNumber = map.atscMajor + "." + map.atscMinor;
}
- }
+ channelNumber = channelNumber.TrimStart('0');
- private string NormalizeName(string value)
- {
- return value.Replace(" ", string.Empty).Replace("-", string.Empty);
+ return channelNumber;
}
- public async Task AddMetadata(ListingsProviderInfo info, List<ChannelInfo> channels,
- CancellationToken cancellationToken)
- {
- var listingsId = info.ListingsId;
- if (string.IsNullOrWhiteSpace(listingsId))
- {
- throw new Exception("ListingsId required");
- }
-
- var token = await GetToken(info, cancellationToken);
-
- if (string.IsNullOrWhiteSpace(token))
- {
- throw new Exception("token required");
- }
-
- ClearPairCache(listingsId);
-
- var httpOptions = new HttpRequestOptions()
- {
- Url = ApiUrl + "/lineups/" + listingsId,
- UserAgent = UserAgent,
- CancellationToken = cancellationToken,
- LogErrorResponseBody = true,
- // The data can be large so give it some extra time
- TimeoutMs = 60000
- };
-
- httpOptions.RequestHeaders["token"] = token;
-
- using (var response = await Get(httpOptions, true, info).ConfigureAwait(false))
- {
- var root = _jsonSerializer.DeserializeFromStream<ScheduleDirect.Channel>(response);
-
- foreach (ScheduleDirect.Map map in root.map)
- {
- var channelNumber = map.logicalChannelNumber;
-
- if (string.IsNullOrWhiteSpace(channelNumber))
- {
- channelNumber = map.channel;
- }
- if (string.IsNullOrWhiteSpace(channelNumber))
- {
- channelNumber = map.atscMajor + "." + map.atscMinor;
- }
- channelNumber = channelNumber.TrimStart('0');
-
- _logger.Debug("Found channel: " + channelNumber + " in Schedules Direct");
-
- var schChannel = (root.stations ?? new List<ScheduleDirect.Station>()).FirstOrDefault(item => string.Equals(item.stationID, map.stationID, StringComparison.OrdinalIgnoreCase));
- if (schChannel != null)
- {
- AddToChannelPairCache(listingsId, channelNumber, schChannel);
- }
- else
- {
- AddToChannelPairCache(listingsId, channelNumber, new ScheduleDirect.Station
- {
- stationID = map.stationID
- });
- }
- }
-
- foreach (ChannelInfo channel in channels)
- {
- var station = GetStation(listingsId, channel.Number, channel.Name);
-
- if (station != null)
- {
- if (station.logo != null)
- {
- channel.ImageUrl = station.logo.URL;
- channel.HasImage = true;
- }
-
- if (!string.IsNullOrWhiteSpace(station.name))
- {
- channel.Name = station.name;
- }
- }
- else
- {
- _logger.Info("Schedules Direct doesnt have data for channel: " + channel.Number + " " + channel.Name);
- }
- }
- }
- }
-
- private ProgramInfo GetProgram(string channel, ScheduleDirect.Program programInfo,
- ScheduleDirect.ProgramDetails details)
+ private ProgramInfo GetProgram(string channelId, ScheduleDirect.Program programInfo, ScheduleDirect.ProgramDetails details)
{
//_logger.Debug("Show type is: " + (details.showType ?? "No ShowType"));
DateTime startAt = GetDate(programInfo.airDateTime);
@@ -386,7 +228,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
ProgramAudio audioType = ProgramAudio.Stereo;
bool repeat = programInfo.@new == null;
- string newID = programInfo.programID + "T" + startAt.Ticks + "C" + channel;
+ string newID = programInfo.programID + "T" + startAt.Ticks + "C" + channelId;
if (programInfo.audioProperties != null)
{
@@ -422,7 +264,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
var info = new ProgramInfo
{
- ChannelId = channel,
+ ChannelId = channelId,
Id = newID,
StartDate = startAt,
EndDate = endAt,
@@ -479,7 +321,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
}
else if (details.descriptions.description100 != null)
{
- info.ShortOverview = details.descriptions.description100[0].description;
+ info.Overview = details.descriptions.description100[0].description;
}
}
@@ -969,8 +811,6 @@ namespace Emby.Server.Implementations.LiveTv.Listings
throw new Exception("ListingsId required");
}
- await AddMetadata(info, new List<ChannelInfo>(), cancellationToken).ConfigureAwait(false);
-
var token = await GetToken(info, cancellationToken);
if (string.IsNullOrWhiteSpace(token))
@@ -997,39 +837,81 @@ namespace Emby.Server.Implementations.LiveTv.Listings
var root = _jsonSerializer.DeserializeFromStream<ScheduleDirect.Channel>(response);
_logger.Info("Found " + root.map.Count + " channels on the lineup on ScheduleDirect");
_logger.Info("Mapping Stations to Channel");
+
+ var allStations = root.stations ?? new List<ScheduleDirect.Station>();
+
foreach (ScheduleDirect.Map map in root.map)
{
- var channelNumber = map.logicalChannelNumber;
-
- if (string.IsNullOrWhiteSpace(channelNumber))
+ var channelNumber = GetChannelNumber(map);
+
+ var station = allStations.FirstOrDefault(item => string.Equals(item.stationID, map.stationID, StringComparison.OrdinalIgnoreCase));
+ if (station == null)
{
- channelNumber = map.channel;
- }
- if (string.IsNullOrWhiteSpace(channelNumber))
- {
- channelNumber = map.atscMajor + "." + map.atscMinor;
+ station = new ScheduleDirect.Station
+ {
+ stationID = map.stationID
+ };
}
- channelNumber = channelNumber.TrimStart('0');
var name = channelNumber;
- var station = GetStation(listingsId, channelNumber, null);
- if (station != null && !string.IsNullOrWhiteSpace(station.name))
- {
- name = station.name;
- }
-
- list.Add(new ChannelInfo
+ var channelInfo = new ChannelInfo
{
Number = channelNumber,
Name = name
- });
+ };
+
+ if (station != null)
+ {
+ if (!string.IsNullOrWhiteSpace(station.name))
+ {
+ channelInfo.Name = station.name;
+ }
+
+ channelInfo.Id = station.stationID;
+ channelInfo.CallSign = station.callsign;
+
+ if (station.logo != null)
+ {
+ channelInfo.ImageUrl = station.logo.URL;
+ channelInfo.HasImage = true;
+ }
+ }
+
+ list.Add(channelInfo);
}
}
return list;
}
+ private ScheduleDirect.Station GetStation(List<ScheduleDirect.Station> allStations, string channelNumber, string channelName)
+ {
+ if (!string.IsNullOrWhiteSpace(channelName))
+ {
+ channelName = NormalizeName(channelName);
+
+ var result = allStations.FirstOrDefault(i => string.Equals(NormalizeName(i.callsign ?? string.Empty), channelName, StringComparison.OrdinalIgnoreCase));
+
+ if (result != null)
+ {
+ return result;
+ }
+ }
+
+ if (!string.IsNullOrWhiteSpace(channelNumber))
+ {
+ return allStations.FirstOrDefault(i => string.Equals(NormalizeName(i.stationID ?? string.Empty), channelNumber, StringComparison.OrdinalIgnoreCase));
+ }
+
+ return null;
+ }
+
+ private string NormalizeName(string value)
+ {
+ return value.Replace(" ", string.Empty).Replace("-", string.Empty);
+ }
+
public class ScheduleDirect
{
public class Token
diff --git a/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs b/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs
index 57307aa73..d7803f9e3 100644
--- a/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs
+++ b/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs
@@ -106,8 +106,13 @@ namespace Emby.Server.Implementations.LiveTv.Listings
return cacheFile;
}
- public async Task<IEnumerable<ProgramInfo>> GetProgramsAsync(ListingsProviderInfo info, string channelNumber, string channelName, DateTime startDateUtc, DateTime endDateUtc, CancellationToken cancellationToken)
+ public async Task<IEnumerable<ProgramInfo>> GetProgramsAsync(ListingsProviderInfo info, string channelId, DateTime startDateUtc, DateTime endDateUtc, CancellationToken cancellationToken)
{
+ if (string.IsNullOrWhiteSpace(channelId))
+ {
+ throw new ArgumentNullException("channelId");
+ }
+
if (!await EmbyTV.EmbyTVRegistration.Instance.EnableXmlTv().ConfigureAwait(false))
{
var length = endDateUtc - startDateUtc;
@@ -120,7 +125,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
var path = await GetXml(info.Path, cancellationToken).ConfigureAwait(false);
var reader = new XmlTvReader(path, GetLanguage());
- var results = reader.GetProgrammes(channelNumber, startDateUtc, endDateUtc, cancellationToken);
+ var results = reader.GetProgrammes(channelId, startDateUtc, endDateUtc, cancellationToken);
return results.Select(p => GetProgramInfo(p, info));
}
@@ -139,7 +144,6 @@ namespace Emby.Server.Implementations.LiveTv.Listings
StartDate = GetDate(p.StartDate),
Name = p.Title,
Overview = p.Description,
- ShortOverview = p.Description,
ProductionYear = !p.CopyrightDate.HasValue ? (int?)null : p.CopyrightDate.Value.Year,
SeasonNumber = p.Episode == null ? null : p.Episode.Series,
IsSeries = p.Episode != null,
@@ -153,10 +157,29 @@ namespace Emby.Server.Implementations.LiveTv.Listings
HasImage = p.Icon != null && !String.IsNullOrEmpty(p.Icon.Source),
OfficialRating = p.Rating != null && !String.IsNullOrEmpty(p.Rating.Value) ? p.Rating.Value : null,
CommunityRating = p.StarRating.HasValue ? p.StarRating.Value : (float?)null,
- SeriesId = p.Episode != null ? p.Title.GetMD5().ToString("N") : null,
- ShowId = ((p.Title ?? string.Empty) + (episodeTitle ?? string.Empty)).GetMD5().ToString("N")
+ SeriesId = p.Episode != null ? p.Title.GetMD5().ToString("N") : null
};
+ if (!string.IsNullOrWhiteSpace(p.ProgramId))
+ {
+ programInfo.ShowId = p.ProgramId;
+ }
+ else
+ {
+ var uniqueString = (p.Title ?? string.Empty) + (episodeTitle ?? string.Empty) + (p.IceTvEpisodeNumber ?? string.Empty);
+
+ if (programInfo.SeasonNumber.HasValue)
+ {
+ uniqueString = "-" + programInfo.SeasonNumber.Value.ToString(CultureInfo.InvariantCulture);
+ }
+ if (programInfo.EpisodeNumber.HasValue)
+ {
+ uniqueString = "-" + programInfo.EpisodeNumber.Value.ToString(CultureInfo.InvariantCulture);
+ }
+
+ programInfo.ShowId = uniqueString.GetMD5().ToString("N");
+ }
+
if (programInfo.IsMovie)
{
programInfo.IsSeries = false;
@@ -176,28 +199,6 @@ namespace Emby.Server.Implementations.LiveTv.Listings
return date;
}
- public async Task AddMetadata(ListingsProviderInfo info, List<ChannelInfo> channels, CancellationToken cancellationToken)
- {
- // Add the channel image url
- var path = await GetXml(info.Path, cancellationToken).ConfigureAwait(false);
- var reader = new XmlTvReader(path, GetLanguage());
- var results = reader.GetChannels().ToList();
-
- if (channels != null)
- {
- foreach (var c in channels)
- {
- var channelNumber = info.GetMappedChannel(c.Number);
- var match = results.FirstOrDefault(r => string.Equals(r.Id, channelNumber, StringComparison.OrdinalIgnoreCase));
-
- if (match != null && match.Icon != null && !String.IsNullOrEmpty(match.Icon.Source))
- {
- c.ImageUrl = match.Icon.Source;
- }
- }
- }
- }
-
public Task Validate(ListingsProviderInfo info, bool validateLogin, bool validateListings)
{
// Assume all urls are valid. check files for existence
diff --git a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs
index ff76f6bef..e59a8f93c 100644
--- a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs
+++ b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs
@@ -2112,7 +2112,7 @@ namespace Emby.Server.Implementations.LiveTv
if (timer == null)
{
- throw new ResourceNotFoundException(string.Format("Timer with Id {0} not found", id));
+ throw new ResourceNotFoundException(string.Format("SeriesTimer with Id {0} not found", id));
}
var service = GetService(timer.ServiceName);
@@ -2884,20 +2884,20 @@ namespace Emby.Server.Implementations.LiveTv
_taskManager.CancelIfRunningAndQueue<RefreshChannelsScheduledTask>();
}
- public async Task<TunerChannelMapping> SetChannelMapping(string providerId, string tunerChannelNumber, string providerChannelNumber)
+ public async Task<TunerChannelMapping> SetChannelMapping(string providerId, string tunerChannelId, string providerChannelId)
{
var config = GetConfiguration();
var listingsProviderInfo = config.ListingProviders.First(i => string.Equals(providerId, i.Id, StringComparison.OrdinalIgnoreCase));
- listingsProviderInfo.ChannelMappings = listingsProviderInfo.ChannelMappings.Where(i => !string.Equals(i.Name, tunerChannelNumber, StringComparison.OrdinalIgnoreCase)).ToArray();
+ listingsProviderInfo.ChannelMappings = listingsProviderInfo.ChannelMappings.Where(i => !string.Equals(i.Name, tunerChannelId, StringComparison.OrdinalIgnoreCase)).ToArray();
- if (!string.Equals(tunerChannelNumber, providerChannelNumber, StringComparison.OrdinalIgnoreCase))
+ if (!string.Equals(tunerChannelId, providerChannelId, StringComparison.OrdinalIgnoreCase))
{
var list = listingsProviderInfo.ChannelMappings.ToList();
list.Add(new NameValuePair
{
- Name = tunerChannelNumber,
- Value = providerChannelNumber
+ Name = tunerChannelId,
+ Value = providerChannelId
});
listingsProviderInfo.ChannelMappings = list.ToArray();
}
@@ -2917,31 +2917,33 @@ namespace Emby.Server.Implementations.LiveTv
_taskManager.CancelIfRunningAndQueue<RefreshChannelsScheduledTask>();
- return tunerChannelMappings.First(i => string.Equals(i.Number, tunerChannelNumber, StringComparison.OrdinalIgnoreCase));
+ return tunerChannelMappings.First(i => string.Equals(i.Id, tunerChannelId, StringComparison.OrdinalIgnoreCase));
}
- public TunerChannelMapping GetTunerChannelMapping(ChannelInfo channel, List<NameValuePair> mappings, List<ChannelInfo> providerChannels)
+ public TunerChannelMapping GetTunerChannelMapping(ChannelInfo tunerChannel, List<NameValuePair> mappings, List<ChannelInfo> epgChannels)
{
var result = new TunerChannelMapping
{
- Name = channel.Number + " " + channel.Name,
- Number = channel.Number
+ Name = tunerChannel.Name,
+ Id = tunerChannel.TunerChannelId
};
- var mapping = mappings.FirstOrDefault(i => string.Equals(i.Name, channel.Number, StringComparison.OrdinalIgnoreCase));
- var providerChannelNumber = channel.Number;
+ if (!string.IsNullOrWhiteSpace(tunerChannel.Number))
+ {
+ result.Name = tunerChannel.Number + " " + result.Name;
+ }
- if (mapping != null)
+ if (string.IsNullOrWhiteSpace(result.Id))
{
- providerChannelNumber = mapping.Value;
+ result.Id = tunerChannel.Id;
}
- var providerChannel = providerChannels.FirstOrDefault(i => string.Equals(i.Number, providerChannelNumber, StringComparison.OrdinalIgnoreCase));
+ var providerChannel = EmbyTV.EmbyTV.Current.GetEpgChannelFromTunerChannel(mappings, tunerChannel, epgChannels);
if (providerChannel != null)
{
- result.ProviderChannelNumber = providerChannel.Number;
result.ProviderChannelName = providerChannel.Name;
+ result.ProviderChannelId = providerChannel.Id;
}
return result;
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs
index 5e191ada9..34d0dd853 100644
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs
+++ b/Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs
@@ -76,6 +76,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
var channels = new List<M3UChannel>();
string line;
string extInf = "";
+
while ((line = reader.ReadLine()) != null)
{
line = line.Trim();
@@ -111,6 +112,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
extInf = "";
}
}
+
return channels;
}
@@ -134,9 +136,11 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
channel.Name = GetChannelName(extInf, attributes);
channel.Number = GetChannelNumber(extInf, attributes, mediaUrl);
- if (attributes.TryGetValue("tvg-id", out value))
+ var channelId = GetTunerChannelId(attributes);
+ if (!string.IsNullOrWhiteSpace(channelId))
{
- channel.Id = value;
+ channel.Id = channelId;
+ channel.TunerChannelId = channelId;
}
return channel;
@@ -172,9 +176,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
numberString = numberString.Trim();
}
- if (string.IsNullOrWhiteSpace(numberString) ||
- string.Equals(numberString, "-1", StringComparison.OrdinalIgnoreCase) ||
- string.Equals(numberString, "0", StringComparison.OrdinalIgnoreCase))
+ if (!IsValidChannelNumber(numberString))
{
string value;
if (attributes.TryGetValue("tvg-id", out value))
@@ -192,9 +194,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
numberString = numberString.Trim();
}
- if (string.IsNullOrWhiteSpace(numberString) ||
- string.Equals(numberString, "-1", StringComparison.OrdinalIgnoreCase) ||
- string.Equals(numberString, "0", StringComparison.OrdinalIgnoreCase))
+ if (!IsValidChannelNumber(numberString))
{
string value;
if (attributes.TryGetValue("channel-id", out value))
@@ -208,9 +208,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
numberString = numberString.Trim();
}
- if (string.IsNullOrWhiteSpace(numberString) ||
- string.Equals(numberString, "-1", StringComparison.OrdinalIgnoreCase) ||
- string.Equals(numberString, "0", StringComparison.OrdinalIgnoreCase))
+ if (!IsValidChannelNumber(numberString))
{
numberString = null;
}
@@ -225,8 +223,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
{
numberString = Path.GetFileNameWithoutExtension(mediaUrl.Split('/').Last());
- double value;
- if (!double.TryParse(numberString, NumberStyles.Any, CultureInfo.InvariantCulture, out value))
+ if (!IsValidChannelNumber(numberString))
{
numberString = null;
}
@@ -236,6 +233,24 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
return numberString;
}
+ private bool IsValidChannelNumber(string numberString)
+ {
+ if (string.IsNullOrWhiteSpace(numberString) ||
+ string.Equals(numberString, "-1", StringComparison.OrdinalIgnoreCase) ||
+ string.Equals(numberString, "0", StringComparison.OrdinalIgnoreCase))
+ {
+ return false;
+ }
+
+ double value;
+ if (!double.TryParse(numberString, NumberStyles.Any, CultureInfo.InvariantCulture, out value))
+ {
+ return false;
+ }
+
+ return true;
+ }
+
private string GetChannelName(string extInf, Dictionary<string, string> attributes)
{
var nameParts = extInf.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
@@ -281,6 +296,19 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
return name;
}
+ private string GetTunerChannelId(Dictionary<string, string> attributes)
+ {
+ string result;
+ attributes.TryGetValue("tvg-id", out result);
+
+ if (string.IsNullOrWhiteSpace(result))
+ {
+ attributes.TryGetValue("channel-id", out result);
+ }
+
+ return result;
+ }
+
private Dictionary<string, string> ParseExtInf(string line, out string remaining)
{
var dict = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/MulticastStream.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/MulticastStream.cs
index 7b88be19c..a7e1b3cf3 100644
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/MulticastStream.cs
+++ b/Emby.Server.Implementations/LiveTv/TunerHosts/MulticastStream.cs
@@ -1,4 +1,5 @@
using System;
+using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
@@ -11,10 +12,11 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
{
public class MulticastStream
{
- private readonly List<QueueStream> _outputStreams = new List<QueueStream>();
+ private readonly ConcurrentDictionary<Guid,QueueStream> _outputStreams = new ConcurrentDictionary<Guid, QueueStream>();
private const int BufferSize = 81920;
private CancellationToken _cancellationToken;
private readonly ILogger _logger;
+ private readonly ConcurrentQueue<byte[]> _sharedBuffer = new ConcurrentQueue<byte[]>();
public MulticastStream(ILogger logger)
{
@@ -35,17 +37,19 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
{
byte[] copy = new byte[bytesRead];
Buffer.BlockCopy(buffer, 0, copy, 0, bytesRead);
-
- List<QueueStream> streams = null;
- lock (_outputStreams)
+ _sharedBuffer.Enqueue(copy);
+
+ while (_sharedBuffer.Count > 3000)
{
- streams = _outputStreams.ToList();
+ byte[] bytes;
+ _sharedBuffer.TryDequeue(out bytes);
}
- foreach (var stream in streams)
+ var allStreams = _outputStreams.ToList();
+ foreach (var stream in allStreams)
{
- stream.Queue(copy);
+ stream.Value.Queue(copy);
}
if (onStarted != null)
@@ -70,11 +74,20 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
OnFinished = OnFinished
};
- lock (_outputStreams)
+ var initial = _sharedBuffer.ToList();
+ var list = new List<byte>();
+
+ foreach (var bytes in initial)
{
- _outputStreams.Add(result);
+ list.AddRange(bytes);
}
+ _logger.Info("QueueStream started with {0} initial bytes", list.Count);
+
+ result.Queue(list.ToArray());
+
+ _outputStreams.TryAdd(result.Id, result);
+
result.Start(_cancellationToken);
return result.TaskCompletion.Task;
@@ -82,10 +95,8 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
public void RemoveOutputStream(QueueStream stream)
{
- lock (_outputStreams)
- {
- _outputStreams.Remove(stream);
- }
+ QueueStream removed;
+ _outputStreams.TryRemove(stream.Id, out removed);
}
private void OnFinished(QueueStream queueStream)
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/QueueStream.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/QueueStream.cs
index bd6f31906..7b48ce21a 100644
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/QueueStream.cs
+++ b/Emby.Server.Implementations/LiveTv/TunerHosts/QueueStream.cs
@@ -19,7 +19,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
public Action<QueueStream> OnFinished { get; set; }
private readonly ILogger _logger;
- private bool _isActive;
+ public Guid Id = Guid.NewGuid();
public QueueStream(Stream outputStream, ILogger logger)
{
@@ -30,10 +30,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
public void Queue(byte[] bytes)
{
- if (_isActive)
- {
- _queue.Enqueue(bytes);
- }
+ _queue.Enqueue(bytes);
}
public void Start(CancellationToken cancellationToken)
@@ -59,10 +56,8 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
try
{
- while (!cancellationToken.IsCancellationRequested)
+ while (true)
{
- _isActive = true;
-
var bytes = Dequeue();
if (bytes != null)
{
@@ -73,9 +68,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
await Task.Delay(50, cancellationToken).ConfigureAwait(false);
}
}
-
- TaskCompletion.TrySetResult(true);
- _logger.Debug("QueueStream complete");
}
catch (OperationCanceledException)
{
@@ -89,8 +81,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
}
finally
{
- _isActive = false;
-
if (OnFinished != null)
{
OnFinished(this);
diff --git a/Emby.Server.Implementations/Migrations/GuideMigration.cs b/Emby.Server.Implementations/Migrations/GuideMigration.cs
index 71286b282..99b2942dc 100644
--- a/Emby.Server.Implementations/Migrations/GuideMigration.cs
+++ b/Emby.Server.Implementations/Migrations/GuideMigration.cs
@@ -27,7 +27,7 @@ namespace Emby.Server.Implementations.Migrations
public async Task Run()
{
- var name = "GuideRefresh2";
+ var name = "GuideRefresh3";
if (!_config.Configuration.Migrations.Contains(name, StringComparer.OrdinalIgnoreCase))
{
diff --git a/Emby.Server.Implementations/TV/TVSeriesManager.cs b/Emby.Server.Implementations/TV/TVSeriesManager.cs
index 6bf412525..9dfaa102a 100644
--- a/Emby.Server.Implementations/TV/TVSeriesManager.cs
+++ b/Emby.Server.Implementations/TV/TVSeriesManager.cs
@@ -144,12 +144,19 @@ namespace Emby.Server.Implementations.TV
// If viewing all next up for all series, remove first episodes
// But if that returns empty, keep those first episodes (avoid completely empty view)
var alwaysEnableFirstEpisode = !string.IsNullOrWhiteSpace(request.SeriesId);
+ var anyFound = false;
return allNextUp
.Where(i =>
{
if (alwaysEnableFirstEpisode || i.Item1 != DateTime.MinValue)
{
+ anyFound = true;
+ return true;
+ }
+
+ if (!anyFound && i.Item1 == DateTime.MinValue)
+ {
return true;
}
diff --git a/Emby.Server.Implementations/Udp/UdpServer.cs b/Emby.Server.Implementations/Udp/UdpServer.cs
index 79a1e4640..691ff0699 100644
--- a/Emby.Server.Implementations/Udp/UdpServer.cs
+++ b/Emby.Server.Implementations/Udp/UdpServer.cs
@@ -6,6 +6,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
+using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Model.Events;
using MediaBrowser.Model.Net;
@@ -246,7 +247,7 @@ namespace Emby.Server.Implementations.Udp
try
{
- await _udpClient.SendAsync(bytes, bytes.Length, remoteEndPoint).ConfigureAwait(false);
+ await _udpClient.SendAsync(bytes, bytes.Length, remoteEndPoint, CancellationToken.None).ConfigureAwait(false);
_logger.Info("Udp message sent to {0}", remoteEndPoint);
}
diff --git a/Emby.Server.Implementations/packages.config b/Emby.Server.Implementations/packages.config
index fcce67b33..5249577e6 100644
--- a/Emby.Server.Implementations/packages.config
+++ b/Emby.Server.Implementations/packages.config
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
- <package id="Emby.XmlTv" version="1.0.3" targetFramework="portable45-net45+win8" />
+ <package id="Emby.XmlTv" version="1.0.5" targetFramework="portable45-net45+win8" />
<package id="MediaBrowser.Naming" version="1.0.4" targetFramework="portable45-net45+win8" />
<package id="SQLitePCL.pretty" version="1.1.0" targetFramework="portable45-net45+win8" />
<package id="SQLitePCLRaw.core" version="1.1.1" targetFramework="portable45-net45+win8" />