Merge pull request #1409 from MediaBrowser/beta

merge from beta
This commit is contained in:
Luke
2016-01-19 14:54:07 -05:00
112 changed files with 2830 additions and 1124 deletions

View File

@@ -310,7 +310,7 @@ namespace MediaBrowser.Server.Implementations.Dto
{
try
{
AttachPrimaryImageAspectRatio(dto, item, fields);
AttachPrimaryImageAspectRatio(dto, item);
}
catch (Exception ex)
{
@@ -1742,15 +1742,19 @@ namespace MediaBrowser.Server.Implementations.Dto
/// </summary>
/// <param name="dto">The dto.</param>
/// <param name="item">The item.</param>
/// <param name="fields">The fields.</param>
/// <returns>Task.</returns>
public void AttachPrimaryImageAspectRatio(IItemDto dto, IHasImages item, List<ItemFields> fields)
public void AttachPrimaryImageAspectRatio(IItemDto dto, IHasImages item)
{
dto.PrimaryImageAspectRatio = GetPrimaryImageAspectRatio(item);
}
public double? GetPrimaryImageAspectRatio(IHasImages item)
{
var imageInfo = item.GetImageInfo(ImageType.Primary, 0);
if (imageInfo == null || !imageInfo.IsLocalFile)
{
return;
return null;
}
ImageSize size;
@@ -1762,7 +1766,7 @@ namespace MediaBrowser.Server.Implementations.Dto
catch (Exception ex)
{
//_logger.ErrorException("Failed to determine primary image aspect ratio for {0}", ex, path);
return;
return null;
}
var supportedEnhancers = _imageProcessor.GetSupportedEnhancers(item, ImageType.Primary).ToList();
@@ -1781,8 +1785,9 @@ namespace MediaBrowser.Server.Implementations.Dto
if (size.Width > 0 && size.Height > 0)
{
dto.PrimaryImageAspectRatio = size.Width / size.Height;
return size.Width / size.Height;
}
return null;
}
}
}

View File

@@ -74,42 +74,52 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
if (!string.IsNullOrEmpty(seriesName))
{
var season = episodeInfo.SeasonNumber;
var seasonNumber = episodeInfo.SeasonNumber;
result.ExtractedSeasonNumber = season;
result.ExtractedSeasonNumber = seasonNumber;
if (season.HasValue)
{
// Passing in true will include a few extra regex's
var episode = episodeInfo.EpisodeNumber;
// Passing in true will include a few extra regex's
var episodeNumber = episodeInfo.EpisodeNumber;
result.ExtractedEpisodeNumber = episode;
result.ExtractedEpisodeNumber = episodeNumber;
if (episode.HasValue)
{
_logger.Debug("Extracted information from {0}. Series name {1}, Season {2}, Episode {3}", path, seriesName, season, episode);
var premiereDate = episodeInfo.IsByDate ?
new DateTime(episodeInfo.Year.Value, episodeInfo.Month.Value, episodeInfo.Day.Value) :
(DateTime?)null;
var endingEpisodeNumber = episodeInfo.EndingEpsiodeNumber;
if (episodeInfo.IsByDate || (seasonNumber.HasValue && episodeNumber.HasValue))
{
if (episodeInfo.IsByDate)
{
_logger.Debug("Extracted information from {0}. Series name {1}, Date {2}", path, seriesName, premiereDate.Value);
}
else
{
_logger.Debug("Extracted information from {0}. Series name {1}, Season {2}, Episode {3}", path, seriesName, seasonNumber, episodeNumber);
}
result.ExtractedEndingEpisodeNumber = endingEpisodeNumber;
var endingEpisodeNumber = episodeInfo.EndingEpsiodeNumber;
await OrganizeEpisode(path, seriesName, season.Value, episode.Value, endingEpisodeNumber, options, overwriteExisting, result, cancellationToken).ConfigureAwait(false);
}
else
{
var msg = string.Format("Unable to determine episode number from {0}", path);
result.Status = FileSortingStatus.Failure;
result.StatusMessage = msg;
_logger.Warn(msg);
}
}
else
{
var msg = string.Format("Unable to determine season number from {0}", path);
result.Status = FileSortingStatus.Failure;
result.StatusMessage = msg;
_logger.Warn(msg);
}
result.ExtractedEndingEpisodeNumber = endingEpisodeNumber;
await OrganizeEpisode(path,
seriesName,
seasonNumber,
episodeNumber,
endingEpisodeNumber,
premiereDate,
options,
overwriteExisting,
result,
cancellationToken).ConfigureAwait(false);
}
else
{
var msg = string.Format("Unable to determine episode number from {0}", path);
result.Status = FileSortingStatus.Failure;
result.StatusMessage = msg;
_logger.Warn(msg);
}
}
else
{
@@ -141,14 +151,32 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
var series = (Series)_libraryManager.GetItemById(new Guid(request.SeriesId));
await OrganizeEpisode(result.OriginalPath, series, request.SeasonNumber, request.EpisodeNumber, request.EndingEpisodeNumber, options, true, result, cancellationToken).ConfigureAwait(false);
await OrganizeEpisode(result.OriginalPath,
series,
request.SeasonNumber,
request.EpisodeNumber,
request.EndingEpisodeNumber,
null,
options,
true,
result,
cancellationToken).ConfigureAwait(false);
await _organizationService.SaveResult(result, CancellationToken.None).ConfigureAwait(false);
return result;
}
private Task OrganizeEpisode(string sourcePath, string seriesName, int seasonNumber, int episodeNumber, int? endingEpiosdeNumber, TvFileOrganizationOptions options, bool overwriteExisting, FileOrganizationResult result, CancellationToken cancellationToken)
private Task OrganizeEpisode(string sourcePath,
string seriesName,
int? seasonNumber,
int? episodeNumber,
int? endingEpiosdeNumber,
DateTime? premiereDate,
TvFileOrganizationOptions options,
bool overwriteExisting,
FileOrganizationResult result,
CancellationToken cancellationToken)
{
var series = GetMatchingSeries(seriesName, result);
@@ -161,15 +189,33 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
return Task.FromResult(true);
}
return OrganizeEpisode(sourcePath, series, seasonNumber, episodeNumber, endingEpiosdeNumber, options, overwriteExisting, result, cancellationToken);
return OrganizeEpisode(sourcePath,
series,
seasonNumber,
episodeNumber,
endingEpiosdeNumber,
premiereDate,
options,
overwriteExisting,
result,
cancellationToken);
}
private async Task OrganizeEpisode(string sourcePath, Series series, int seasonNumber, int episodeNumber, int? endingEpiosdeNumber, TvFileOrganizationOptions options, bool overwriteExisting, FileOrganizationResult result, CancellationToken cancellationToken)
private async Task OrganizeEpisode(string sourcePath,
Series series,
int? seasonNumber,
int? episodeNumber,
int? endingEpiosdeNumber,
DateTime? premiereDate,
TvFileOrganizationOptions options,
bool overwriteExisting,
FileOrganizationResult result,
CancellationToken cancellationToken)
{
_logger.Info("Sorting file {0} into series {1}", sourcePath, series.Path);
// Proceed to sort the file
var newPath = await GetNewPath(sourcePath, series, seasonNumber, episodeNumber, endingEpiosdeNumber, options, cancellationToken).ConfigureAwait(false);
var newPath = await GetNewPath(sourcePath, series, seasonNumber, episodeNumber, endingEpiosdeNumber, premiereDate, options, cancellationToken).ConfigureAwait(false);
if (string.IsNullOrEmpty(newPath))
{
@@ -278,8 +324,18 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
}
}
private List<string> GetOtherDuplicatePaths(string targetPath, Series series, int seasonNumber, int episodeNumber, int? endingEpisodeNumber)
private List<string> GetOtherDuplicatePaths(string targetPath,
Series series,
int? seasonNumber,
int? episodeNumber,
int? endingEpisodeNumber)
{
// TODO: Support date-naming?
if (!seasonNumber.HasValue || episodeNumber.HasValue)
{
return new List<string> ();
}
var episodePaths = series.GetRecursiveChildren()
.OfType<Episode>()
.Where(i =>
@@ -408,7 +464,14 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
/// <param name="endingEpisodeNumber">The ending episode number.</param>
/// <param name="options">The options.</param>
/// <returns>System.String.</returns>
private async Task<string> GetNewPath(string sourcePath, Series series, int seasonNumber, int episodeNumber, int? endingEpisodeNumber, TvFileOrganizationOptions options, CancellationToken cancellationToken)
private async Task<string> GetNewPath(string sourcePath,
Series series,
int? seasonNumber,
int? episodeNumber,
int? endingEpisodeNumber,
DateTime? premiereDate,
TvFileOrganizationOptions options,
CancellationToken cancellationToken)
{
var episodeInfo = new EpisodeInfo
{
@@ -417,7 +480,8 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
MetadataCountryCode = series.GetPreferredMetadataCountryCode(),
MetadataLanguage = series.GetPreferredMetadataLanguage(),
ParentIndexNumber = seasonNumber,
SeriesProviderIds = series.ProviderIds
SeriesProviderIds = series.ProviderIds,
PremiereDate = premiereDate
};
var searchResults = await _providerManager.GetRemoteSearchResults<Episode, EpisodeInfo>(new RemoteSearchQuery<EpisodeInfo>
@@ -427,14 +491,24 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
}, cancellationToken).ConfigureAwait(false);
var episode = searchResults.FirstOrDefault();
string episodeName = string.Empty;
if (episode == null)
{
_logger.Warn("No provider metadata found for {0} season {1} episode {2}", series.Name, seasonNumber, episodeNumber);
return null;
var msg = string.Format("No provider metadata found for {0} season {1} episode {2}", series.Name, seasonNumber, episodeNumber);
_logger.Warn(msg);
//throw new Exception(msg);
}
else
{
episodeName = episode.Name;
}
var newPath = GetSeasonFolderPath(series, seasonNumber, options);
seasonNumber = seasonNumber ?? episode.ParentIndexNumber;
episodeNumber = episodeNumber ?? episode.IndexNumber;
var newPath = GetSeasonFolderPath(series, seasonNumber.Value, options);
// MAX_PATH - trailing <NULL> charachter - drive component: 260 - 1 - 3 = 256
// Usually newPath would include the drive component, but use 256 to be sure
@@ -449,7 +523,7 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
// Remove additional 4 chars to prevent PathTooLongException for downloaded subtitles (eg. filename.ext.eng.srt)
maxFilenameLength -= 4;
var episodeFileName = GetEpisodeFileName(sourcePath, series.Name, seasonNumber, episodeNumber, endingEpisodeNumber, episode.Name, options, maxFilenameLength);
var episodeFileName = GetEpisodeFileName(sourcePath, series.Name, seasonNumber.Value, episodeNumber.Value, endingEpisodeNumber, episodeName, options, maxFilenameLength);
if (string.IsNullOrEmpty(episodeFileName))
{
@@ -505,7 +579,7 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
{
seriesName = _fileSystem.GetValidFilename(seriesName).Trim();
if (episodeTitle == null)
if (string.IsNullOrEmpty(episodeTitle))
{
episodeTitle = string.Empty;
}

View File

@@ -19,6 +19,7 @@ using System.Linq;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Common.Net;
using MediaBrowser.Common.Security;
namespace MediaBrowser.Server.Implementations.HttpServer
@@ -39,40 +40,20 @@ namespace MediaBrowser.Server.Implementations.HttpServer
public event EventHandler<WebSocketConnectEventArgs> WebSocketConnected;
public event EventHandler<WebSocketConnectingEventArgs> WebSocketConnecting;
private readonly List<string> _localEndpoints = new List<string>();
private readonly ReaderWriterLockSlim _localEndpointLock = new ReaderWriterLockSlim();
public string CertificatePath { get; private set; }
private readonly IServerConfigurationManager _config;
/// <summary>
/// Gets the local end points.
/// </summary>
/// <value>The local end points.</value>
public IEnumerable<string> LocalEndPoints
{
get
{
_localEndpointLock.EnterReadLock();
var list = _localEndpoints.ToList();
_localEndpointLock.ExitReadLock();
return list;
}
}
private readonly INetworkManager _networkManager;
public HttpListenerHost(IApplicationHost applicationHost,
ILogManager logManager,
IServerConfigurationManager config,
string serviceName,
string defaultRedirectPath, params Assembly[] assembliesWithServices)
string defaultRedirectPath, INetworkManager networkManager, params Assembly[] assembliesWithServices)
: base(serviceName, assembliesWithServices)
{
DefaultRedirectPath = defaultRedirectPath;
_networkManager = networkManager;
_config = config;
_logger = logManager.GetLogger("HttpServer");
@@ -175,26 +156,6 @@ namespace MediaBrowser.Server.Implementations.HttpServer
private void OnRequestReceived(string localEndPoint)
{
var ignore = localEndPoint.IndexOf("::", StringComparison.OrdinalIgnoreCase) != -1 ||
localEndPoint.StartsWith("127.", StringComparison.OrdinalIgnoreCase) ||
localEndPoint.StartsWith("localhost", StringComparison.OrdinalIgnoreCase) ||
localEndPoint.StartsWith("169.", StringComparison.OrdinalIgnoreCase);
if (ignore)
{
return;
}
if (_localEndpointLock.TryEnterWriteLock(100))
{
var list = _localEndpoints.ToList();
list.Remove(localEndPoint);
list.Insert(0, localEndPoint);
_localEndpointLock.ExitWriteLock();
}
}
/// <summary>

View File

@@ -58,7 +58,10 @@ namespace MediaBrowser.Server.Implementations.HttpServer
if (hasOptions != null)
{
hasOptions.Options["Server"] = "Mono-HTTPAPI/1.1";
if (!hasOptions.Options.ContainsKey("Server"))
{
hasOptions.Options["Server"] = "Mono-HTTPAPI/1.1, UPnP/1.0 DLNADOC/1.50";
}
// Content length has to be explicitly set on on HttpListenerResponse or it won't be happy
string contentLength;

View File

@@ -1,4 +1,5 @@
using MediaBrowser.Common;
using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Net;
using MediaBrowser.Model.Logging;
@@ -17,18 +18,20 @@ namespace MediaBrowser.Server.Implementations.HttpServer
/// <param name="applicationHost">The application host.</param>
/// <param name="logManager">The log manager.</param>
/// <param name="config">The configuration.</param>
/// <param name="_networkmanager">The _networkmanager.</param>
/// <param name="serverName">Name of the server.</param>
/// <param name="defaultRedirectpath">The default redirectpath.</param>
/// <returns>IHttpServer.</returns>
public static IHttpServer CreateServer(IApplicationHost applicationHost,
ILogManager logManager,
IServerConfigurationManager config,
INetworkManager _networkmanager,
string serverName,
string defaultRedirectpath)
{
LogManager.LogFactory = new ServerLogFactory(logManager);
return new HttpListenerHost(applicationHost, logManager, config, serverName, defaultRedirectpath);
return new HttpListenerHost(applicationHost, logManager, config, serverName, defaultRedirectpath, _networkmanager);
}
}
}

View File

@@ -0,0 +1,941 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Text;
namespace MediaBrowser.Server.Implementations.HttpServer.SocketSharp
{
public static class MyHttpUtility
{
sealed class HttpQSCollection : NameValueCollection
{
public override string ToString()
{
int count = Count;
if (count == 0)
return "";
StringBuilder sb = new StringBuilder();
string[] keys = AllKeys;
for (int i = 0; i < count; i++)
{
sb.AppendFormat("{0}={1}&", keys[i], this[keys[i]]);
}
if (sb.Length > 0)
sb.Length--;
return sb.ToString();
}
}
// Must be sorted
static readonly long[] entities = new long[] {
(long)'A' << 56 | (long)'E' << 48 | (long)'l' << 40 | (long)'i' << 32 | (long)'g' << 24,
(long)'A' << 56 | (long)'a' << 48 | (long)'c' << 40 | (long)'u' << 32 | (long)'t' << 24 | (long)'e' << 16,
(long)'A' << 56 | (long)'c' << 48 | (long)'i' << 40 | (long)'r' << 32 | (long)'c' << 24,
(long)'A' << 56 | (long)'g' << 48 | (long)'r' << 40 | (long)'a' << 32 | (long)'v' << 24 | (long)'e' << 16,
(long)'A' << 56 | (long)'l' << 48 | (long)'p' << 40 | (long)'h' << 32 | (long)'a' << 24,
(long)'A' << 56 | (long)'r' << 48 | (long)'i' << 40 | (long)'n' << 32 | (long)'g' << 24,
(long)'A' << 56 | (long)'t' << 48 | (long)'i' << 40 | (long)'l' << 32 | (long)'d' << 24 | (long)'e' << 16,
(long)'A' << 56 | (long)'u' << 48 | (long)'m' << 40 | (long)'l' << 32,
(long)'B' << 56 | (long)'e' << 48 | (long)'t' << 40 | (long)'a' << 32,
(long)'C' << 56 | (long)'c' << 48 | (long)'e' << 40 | (long)'d' << 32 | (long)'i' << 24 | (long)'l' << 16,
(long)'C' << 56 | (long)'h' << 48 | (long)'i' << 40,
(long)'D' << 56 | (long)'a' << 48 | (long)'g' << 40 | (long)'g' << 32 | (long)'e' << 24 | (long)'r' << 16,
(long)'D' << 56 | (long)'e' << 48 | (long)'l' << 40 | (long)'t' << 32 | (long)'a' << 24,
(long)'E' << 56 | (long)'T' << 48 | (long)'H' << 40,
(long)'E' << 56 | (long)'a' << 48 | (long)'c' << 40 | (long)'u' << 32 | (long)'t' << 24 | (long)'e' << 16,
(long)'E' << 56 | (long)'c' << 48 | (long)'i' << 40 | (long)'r' << 32 | (long)'c' << 24,
(long)'E' << 56 | (long)'g' << 48 | (long)'r' << 40 | (long)'a' << 32 | (long)'v' << 24 | (long)'e' << 16,
(long)'E' << 56 | (long)'p' << 48 | (long)'s' << 40 | (long)'i' << 32 | (long)'l' << 24 | (long)'o' << 16 | (long)'n' << 8,
(long)'E' << 56 | (long)'t' << 48 | (long)'a' << 40,
(long)'E' << 56 | (long)'u' << 48 | (long)'m' << 40 | (long)'l' << 32,
(long)'G' << 56 | (long)'a' << 48 | (long)'m' << 40 | (long)'m' << 32 | (long)'a' << 24,
(long)'I' << 56 | (long)'a' << 48 | (long)'c' << 40 | (long)'u' << 32 | (long)'t' << 24 | (long)'e' << 16,
(long)'I' << 56 | (long)'c' << 48 | (long)'i' << 40 | (long)'r' << 32 | (long)'c' << 24,
(long)'I' << 56 | (long)'g' << 48 | (long)'r' << 40 | (long)'a' << 32 | (long)'v' << 24 | (long)'e' << 16,
(long)'I' << 56 | (long)'o' << 48 | (long)'t' << 40 | (long)'a' << 32,
(long)'I' << 56 | (long)'u' << 48 | (long)'m' << 40 | (long)'l' << 32,
(long)'K' << 56 | (long)'a' << 48 | (long)'p' << 40 | (long)'p' << 32 | (long)'a' << 24,
(long)'L' << 56 | (long)'a' << 48 | (long)'m' << 40 | (long)'b' << 32 | (long)'d' << 24 | (long)'a' << 16,
(long)'M' << 56 | (long)'u' << 48,
(long)'N' << 56 | (long)'t' << 48 | (long)'i' << 40 | (long)'l' << 32 | (long)'d' << 24 | (long)'e' << 16,
(long)'N' << 56 | (long)'u' << 48,
(long)'O' << 56 | (long)'E' << 48 | (long)'l' << 40 | (long)'i' << 32 | (long)'g' << 24,
(long)'O' << 56 | (long)'a' << 48 | (long)'c' << 40 | (long)'u' << 32 | (long)'t' << 24 | (long)'e' << 16,
(long)'O' << 56 | (long)'c' << 48 | (long)'i' << 40 | (long)'r' << 32 | (long)'c' << 24,
(long)'O' << 56 | (long)'g' << 48 | (long)'r' << 40 | (long)'a' << 32 | (long)'v' << 24 | (long)'e' << 16,
(long)'O' << 56 | (long)'m' << 48 | (long)'e' << 40 | (long)'g' << 32 | (long)'a' << 24,
(long)'O' << 56 | (long)'m' << 48 | (long)'i' << 40 | (long)'c' << 32 | (long)'r' << 24 | (long)'o' << 16 | (long)'n' << 8,
(long)'O' << 56 | (long)'s' << 48 | (long)'l' << 40 | (long)'a' << 32 | (long)'s' << 24 | (long)'h' << 16,
(long)'O' << 56 | (long)'t' << 48 | (long)'i' << 40 | (long)'l' << 32 | (long)'d' << 24 | (long)'e' << 16,
(long)'O' << 56 | (long)'u' << 48 | (long)'m' << 40 | (long)'l' << 32,
(long)'P' << 56 | (long)'h' << 48 | (long)'i' << 40,
(long)'P' << 56 | (long)'i' << 48,
(long)'P' << 56 | (long)'r' << 48 | (long)'i' << 40 | (long)'m' << 32 | (long)'e' << 24,
(long)'P' << 56 | (long)'s' << 48 | (long)'i' << 40,
(long)'R' << 56 | (long)'h' << 48 | (long)'o' << 40,
(long)'S' << 56 | (long)'c' << 48 | (long)'a' << 40 | (long)'r' << 32 | (long)'o' << 24 | (long)'n' << 16,
(long)'S' << 56 | (long)'i' << 48 | (long)'g' << 40 | (long)'m' << 32 | (long)'a' << 24,
(long)'T' << 56 | (long)'H' << 48 | (long)'O' << 40 | (long)'R' << 32 | (long)'N' << 24,
(long)'T' << 56 | (long)'a' << 48 | (long)'u' << 40,
(long)'T' << 56 | (long)'h' << 48 | (long)'e' << 40 | (long)'t' << 32 | (long)'a' << 24,
(long)'U' << 56 | (long)'a' << 48 | (long)'c' << 40 | (long)'u' << 32 | (long)'t' << 24 | (long)'e' << 16,
(long)'U' << 56 | (long)'c' << 48 | (long)'i' << 40 | (long)'r' << 32 | (long)'c' << 24,
(long)'U' << 56 | (long)'g' << 48 | (long)'r' << 40 | (long)'a' << 32 | (long)'v' << 24 | (long)'e' << 16,
(long)'U' << 56 | (long)'p' << 48 | (long)'s' << 40 | (long)'i' << 32 | (long)'l' << 24 | (long)'o' << 16 | (long)'n' << 8,
(long)'U' << 56 | (long)'u' << 48 | (long)'m' << 40 | (long)'l' << 32,
(long)'X' << 56 | (long)'i' << 48,
(long)'Y' << 56 | (long)'a' << 48 | (long)'c' << 40 | (long)'u' << 32 | (long)'t' << 24 | (long)'e' << 16,
(long)'Y' << 56 | (long)'u' << 48 | (long)'m' << 40 | (long)'l' << 32,
(long)'Z' << 56 | (long)'e' << 48 | (long)'t' << 40 | (long)'a' << 32,
(long)'a' << 56 | (long)'a' << 48 | (long)'c' << 40 | (long)'u' << 32 | (long)'t' << 24 | (long)'e' << 16,
(long)'a' << 56 | (long)'c' << 48 | (long)'i' << 40 | (long)'r' << 32 | (long)'c' << 24,
(long)'a' << 56 | (long)'c' << 48 | (long)'u' << 40 | (long)'t' << 32 | (long)'e' << 24,
(long)'a' << 56 | (long)'e' << 48 | (long)'l' << 40 | (long)'i' << 32 | (long)'g' << 24,
(long)'a' << 56 | (long)'g' << 48 | (long)'r' << 40 | (long)'a' << 32 | (long)'v' << 24 | (long)'e' << 16,
(long)'a' << 56 | (long)'l' << 48 | (long)'e' << 40 | (long)'f' << 32 | (long)'s' << 24 | (long)'y' << 16 | (long)'m' << 8,
(long)'a' << 56 | (long)'l' << 48 | (long)'p' << 40 | (long)'h' << 32 | (long)'a' << 24,
(long)'a' << 56 | (long)'m' << 48 | (long)'p' << 40,
(long)'a' << 56 | (long)'n' << 48 | (long)'d' << 40,
(long)'a' << 56 | (long)'n' << 48 | (long)'g' << 40,
(long)'a' << 56 | (long)'p' << 48 | (long)'o' << 40 | (long)'s' << 32,
(long)'a' << 56 | (long)'r' << 48 | (long)'i' << 40 | (long)'n' << 32 | (long)'g' << 24,
(long)'a' << 56 | (long)'s' << 48 | (long)'y' << 40 | (long)'m' << 32 | (long)'p' << 24,
(long)'a' << 56 | (long)'t' << 48 | (long)'i' << 40 | (long)'l' << 32 | (long)'d' << 24 | (long)'e' << 16,
(long)'a' << 56 | (long)'u' << 48 | (long)'m' << 40 | (long)'l' << 32,
(long)'b' << 56 | (long)'d' << 48 | (long)'q' << 40 | (long)'u' << 32 | (long)'o' << 24,
(long)'b' << 56 | (long)'e' << 48 | (long)'t' << 40 | (long)'a' << 32,
(long)'b' << 56 | (long)'r' << 48 | (long)'v' << 40 | (long)'b' << 32 | (long)'a' << 24 | (long)'r' << 16,
(long)'b' << 56 | (long)'u' << 48 | (long)'l' << 40 | (long)'l' << 32,
(long)'c' << 56 | (long)'a' << 48 | (long)'p' << 40,
(long)'c' << 56 | (long)'c' << 48 | (long)'e' << 40 | (long)'d' << 32 | (long)'i' << 24 | (long)'l' << 16,
(long)'c' << 56 | (long)'e' << 48 | (long)'d' << 40 | (long)'i' << 32 | (long)'l' << 24,
(long)'c' << 56 | (long)'e' << 48 | (long)'n' << 40 | (long)'t' << 32,
(long)'c' << 56 | (long)'h' << 48 | (long)'i' << 40,
(long)'c' << 56 | (long)'i' << 48 | (long)'r' << 40 | (long)'c' << 32,
(long)'c' << 56 | (long)'l' << 48 | (long)'u' << 40 | (long)'b' << 32 | (long)'s' << 24,
(long)'c' << 56 | (long)'o' << 48 | (long)'n' << 40 | (long)'g' << 32,
(long)'c' << 56 | (long)'o' << 48 | (long)'p' << 40 | (long)'y' << 32,
(long)'c' << 56 | (long)'r' << 48 | (long)'a' << 40 | (long)'r' << 32 | (long)'r' << 24,
(long)'c' << 56 | (long)'u' << 48 | (long)'p' << 40,
(long)'c' << 56 | (long)'u' << 48 | (long)'r' << 40 | (long)'r' << 32 | (long)'e' << 24 | (long)'n' << 16,
(long)'d' << 56 | (long)'A' << 48 | (long)'r' << 40 | (long)'r' << 32,
(long)'d' << 56 | (long)'a' << 48 | (long)'g' << 40 | (long)'g' << 32 | (long)'e' << 24 | (long)'r' << 16,
(long)'d' << 56 | (long)'a' << 48 | (long)'r' << 40 | (long)'r' << 32,
(long)'d' << 56 | (long)'e' << 48 | (long)'g' << 40,
(long)'d' << 56 | (long)'e' << 48 | (long)'l' << 40 | (long)'t' << 32 | (long)'a' << 24,
(long)'d' << 56 | (long)'i' << 48 | (long)'a' << 40 | (long)'m' << 32 | (long)'s' << 24,
(long)'d' << 56 | (long)'i' << 48 | (long)'v' << 40 | (long)'i' << 32 | (long)'d' << 24 | (long)'e' << 16,
(long)'e' << 56 | (long)'a' << 48 | (long)'c' << 40 | (long)'u' << 32 | (long)'t' << 24 | (long)'e' << 16,
(long)'e' << 56 | (long)'c' << 48 | (long)'i' << 40 | (long)'r' << 32 | (long)'c' << 24,
(long)'e' << 56 | (long)'g' << 48 | (long)'r' << 40 | (long)'a' << 32 | (long)'v' << 24 | (long)'e' << 16,
(long)'e' << 56 | (long)'m' << 48 | (long)'p' << 40 | (long)'t' << 32 | (long)'y' << 24,
(long)'e' << 56 | (long)'m' << 48 | (long)'s' << 40 | (long)'p' << 32,
(long)'e' << 56 | (long)'n' << 48 | (long)'s' << 40 | (long)'p' << 32,
(long)'e' << 56 | (long)'p' << 48 | (long)'s' << 40 | (long)'i' << 32 | (long)'l' << 24 | (long)'o' << 16 | (long)'n' << 8,
(long)'e' << 56 | (long)'q' << 48 | (long)'u' << 40 | (long)'i' << 32 | (long)'v' << 24,
(long)'e' << 56 | (long)'t' << 48 | (long)'a' << 40,
(long)'e' << 56 | (long)'t' << 48 | (long)'h' << 40,
(long)'e' << 56 | (long)'u' << 48 | (long)'m' << 40 | (long)'l' << 32,
(long)'e' << 56 | (long)'u' << 48 | (long)'r' << 40 | (long)'o' << 32,
(long)'e' << 56 | (long)'x' << 48 | (long)'i' << 40 | (long)'s' << 32 | (long)'t' << 24,
(long)'f' << 56 | (long)'n' << 48 | (long)'o' << 40 | (long)'f' << 32,
(long)'f' << 56 | (long)'o' << 48 | (long)'r' << 40 | (long)'a' << 32 | (long)'l' << 24 | (long)'l' << 16,
(long)'f' << 56 | (long)'r' << 48 | (long)'a' << 40 | (long)'c' << 32 | (long)'1' << 24 | (long)'2' << 16,
(long)'f' << 56 | (long)'r' << 48 | (long)'a' << 40 | (long)'c' << 32 | (long)'1' << 24 | (long)'4' << 16,
(long)'f' << 56 | (long)'r' << 48 | (long)'a' << 40 | (long)'c' << 32 | (long)'3' << 24 | (long)'4' << 16,
(long)'f' << 56 | (long)'r' << 48 | (long)'a' << 40 | (long)'s' << 32 | (long)'l' << 24,
(long)'g' << 56 | (long)'a' << 48 | (long)'m' << 40 | (long)'m' << 32 | (long)'a' << 24,
(long)'g' << 56 | (long)'e' << 48,
(long)'g' << 56 | (long)'t' << 48,
(long)'h' << 56 | (long)'A' << 48 | (long)'r' << 40 | (long)'r' << 32,
(long)'h' << 56 | (long)'a' << 48 | (long)'r' << 40 | (long)'r' << 32,
(long)'h' << 56 | (long)'e' << 48 | (long)'a' << 40 | (long)'r' << 32 | (long)'t' << 24 | (long)'s' << 16,
(long)'h' << 56 | (long)'e' << 48 | (long)'l' << 40 | (long)'l' << 32 | (long)'i' << 24 | (long)'p' << 16,
(long)'i' << 56 | (long)'a' << 48 | (long)'c' << 40 | (long)'u' << 32 | (long)'t' << 24 | (long)'e' << 16,
(long)'i' << 56 | (long)'c' << 48 | (long)'i' << 40 | (long)'r' << 32 | (long)'c' << 24,
(long)'i' << 56 | (long)'e' << 48 | (long)'x' << 40 | (long)'c' << 32 | (long)'l' << 24,
(long)'i' << 56 | (long)'g' << 48 | (long)'r' << 40 | (long)'a' << 32 | (long)'v' << 24 | (long)'e' << 16,
(long)'i' << 56 | (long)'m' << 48 | (long)'a' << 40 | (long)'g' << 32 | (long)'e' << 24,
(long)'i' << 56 | (long)'n' << 48 | (long)'f' << 40 | (long)'i' << 32 | (long)'n' << 24,
(long)'i' << 56 | (long)'n' << 48 | (long)'t' << 40,
(long)'i' << 56 | (long)'o' << 48 | (long)'t' << 40 | (long)'a' << 32,
(long)'i' << 56 | (long)'q' << 48 | (long)'u' << 40 | (long)'e' << 32 | (long)'s' << 24 | (long)'t' << 16,
(long)'i' << 56 | (long)'s' << 48 | (long)'i' << 40 | (long)'n' << 32,
(long)'i' << 56 | (long)'u' << 48 | (long)'m' << 40 | (long)'l' << 32,
(long)'k' << 56 | (long)'a' << 48 | (long)'p' << 40 | (long)'p' << 32 | (long)'a' << 24,
(long)'l' << 56 | (long)'A' << 48 | (long)'r' << 40 | (long)'r' << 32,
(long)'l' << 56 | (long)'a' << 48 | (long)'m' << 40 | (long)'b' << 32 | (long)'d' << 24 | (long)'a' << 16,
(long)'l' << 56 | (long)'a' << 48 | (long)'n' << 40 | (long)'g' << 32,
(long)'l' << 56 | (long)'a' << 48 | (long)'q' << 40 | (long)'u' << 32 | (long)'o' << 24,
(long)'l' << 56 | (long)'a' << 48 | (long)'r' << 40 | (long)'r' << 32,
(long)'l' << 56 | (long)'c' << 48 | (long)'e' << 40 | (long)'i' << 32 | (long)'l' << 24,
(long)'l' << 56 | (long)'d' << 48 | (long)'q' << 40 | (long)'u' << 32 | (long)'o' << 24,
(long)'l' << 56 | (long)'e' << 48,
(long)'l' << 56 | (long)'f' << 48 | (long)'l' << 40 | (long)'o' << 32 | (long)'o' << 24 | (long)'r' << 16,
(long)'l' << 56 | (long)'o' << 48 | (long)'w' << 40 | (long)'a' << 32 | (long)'s' << 24 | (long)'t' << 16,
(long)'l' << 56 | (long)'o' << 48 | (long)'z' << 40,
(long)'l' << 56 | (long)'r' << 48 | (long)'m' << 40,
(long)'l' << 56 | (long)'s' << 48 | (long)'a' << 40 | (long)'q' << 32 | (long)'u' << 24 | (long)'o' << 16,
(long)'l' << 56 | (long)'s' << 48 | (long)'q' << 40 | (long)'u' << 32 | (long)'o' << 24,
(long)'l' << 56 | (long)'t' << 48,
(long)'m' << 56 | (long)'a' << 48 | (long)'c' << 40 | (long)'r' << 32,
(long)'m' << 56 | (long)'d' << 48 | (long)'a' << 40 | (long)'s' << 32 | (long)'h' << 24,
(long)'m' << 56 | (long)'i' << 48 | (long)'c' << 40 | (long)'r' << 32 | (long)'o' << 24,
(long)'m' << 56 | (long)'i' << 48 | (long)'d' << 40 | (long)'d' << 32 | (long)'o' << 24 | (long)'t' << 16,
(long)'m' << 56 | (long)'i' << 48 | (long)'n' << 40 | (long)'u' << 32 | (long)'s' << 24,
(long)'m' << 56 | (long)'u' << 48,
(long)'n' << 56 | (long)'a' << 48 | (long)'b' << 40 | (long)'l' << 32 | (long)'a' << 24,
(long)'n' << 56 | (long)'b' << 48 | (long)'s' << 40 | (long)'p' << 32,
(long)'n' << 56 | (long)'d' << 48 | (long)'a' << 40 | (long)'s' << 32 | (long)'h' << 24,
(long)'n' << 56 | (long)'e' << 48,
(long)'n' << 56 | (long)'i' << 48,
(long)'n' << 56 | (long)'o' << 48 | (long)'t' << 40,
(long)'n' << 56 | (long)'o' << 48 | (long)'t' << 40 | (long)'i' << 32 | (long)'n' << 24,
(long)'n' << 56 | (long)'s' << 48 | (long)'u' << 40 | (long)'b' << 32,
(long)'n' << 56 | (long)'t' << 48 | (long)'i' << 40 | (long)'l' << 32 | (long)'d' << 24 | (long)'e' << 16,
(long)'n' << 56 | (long)'u' << 48,
(long)'o' << 56 | (long)'a' << 48 | (long)'c' << 40 | (long)'u' << 32 | (long)'t' << 24 | (long)'e' << 16,
(long)'o' << 56 | (long)'c' << 48 | (long)'i' << 40 | (long)'r' << 32 | (long)'c' << 24,
(long)'o' << 56 | (long)'e' << 48 | (long)'l' << 40 | (long)'i' << 32 | (long)'g' << 24,
(long)'o' << 56 | (long)'g' << 48 | (long)'r' << 40 | (long)'a' << 32 | (long)'v' << 24 | (long)'e' << 16,
(long)'o' << 56 | (long)'l' << 48 | (long)'i' << 40 | (long)'n' << 32 | (long)'e' << 24,
(long)'o' << 56 | (long)'m' << 48 | (long)'e' << 40 | (long)'g' << 32 | (long)'a' << 24,
(long)'o' << 56 | (long)'m' << 48 | (long)'i' << 40 | (long)'c' << 32 | (long)'r' << 24 | (long)'o' << 16 | (long)'n' << 8,
(long)'o' << 56 | (long)'p' << 48 | (long)'l' << 40 | (long)'u' << 32 | (long)'s' << 24,
(long)'o' << 56 | (long)'r' << 48,
(long)'o' << 56 | (long)'r' << 48 | (long)'d' << 40 | (long)'f' << 32,
(long)'o' << 56 | (long)'r' << 48 | (long)'d' << 40 | (long)'m' << 32,
(long)'o' << 56 | (long)'s' << 48 | (long)'l' << 40 | (long)'a' << 32 | (long)'s' << 24 | (long)'h' << 16,
(long)'o' << 56 | (long)'t' << 48 | (long)'i' << 40 | (long)'l' << 32 | (long)'d' << 24 | (long)'e' << 16,
(long)'o' << 56 | (long)'t' << 48 | (long)'i' << 40 | (long)'m' << 32 | (long)'e' << 24 | (long)'s' << 16,
(long)'o' << 56 | (long)'u' << 48 | (long)'m' << 40 | (long)'l' << 32,
(long)'p' << 56 | (long)'a' << 48 | (long)'r' << 40 | (long)'a' << 32,
(long)'p' << 56 | (long)'a' << 48 | (long)'r' << 40 | (long)'t' << 32,
(long)'p' << 56 | (long)'e' << 48 | (long)'r' << 40 | (long)'m' << 32 | (long)'i' << 24 | (long)'l' << 16,
(long)'p' << 56 | (long)'e' << 48 | (long)'r' << 40 | (long)'p' << 32,
(long)'p' << 56 | (long)'h' << 48 | (long)'i' << 40,
(long)'p' << 56 | (long)'i' << 48,
(long)'p' << 56 | (long)'i' << 48 | (long)'v' << 40,
(long)'p' << 56 | (long)'l' << 48 | (long)'u' << 40 | (long)'s' << 32 | (long)'m' << 24 | (long)'n' << 16,
(long)'p' << 56 | (long)'o' << 48 | (long)'u' << 40 | (long)'n' << 32 | (long)'d' << 24,
(long)'p' << 56 | (long)'r' << 48 | (long)'i' << 40 | (long)'m' << 32 | (long)'e' << 24,
(long)'p' << 56 | (long)'r' << 48 | (long)'o' << 40 | (long)'d' << 32,
(long)'p' << 56 | (long)'r' << 48 | (long)'o' << 40 | (long)'p' << 32,
(long)'p' << 56 | (long)'s' << 48 | (long)'i' << 40,
(long)'q' << 56 | (long)'u' << 48 | (long)'o' << 40 | (long)'t' << 32,
(long)'r' << 56 | (long)'A' << 48 | (long)'r' << 40 | (long)'r' << 32,
(long)'r' << 56 | (long)'a' << 48 | (long)'d' << 40 | (long)'i' << 32 | (long)'c' << 24,
(long)'r' << 56 | (long)'a' << 48 | (long)'n' << 40 | (long)'g' << 32,
(long)'r' << 56 | (long)'a' << 48 | (long)'q' << 40 | (long)'u' << 32 | (long)'o' << 24,
(long)'r' << 56 | (long)'a' << 48 | (long)'r' << 40 | (long)'r' << 32,
(long)'r' << 56 | (long)'c' << 48 | (long)'e' << 40 | (long)'i' << 32 | (long)'l' << 24,
(long)'r' << 56 | (long)'d' << 48 | (long)'q' << 40 | (long)'u' << 32 | (long)'o' << 24,
(long)'r' << 56 | (long)'e' << 48 | (long)'a' << 40 | (long)'l' << 32,
(long)'r' << 56 | (long)'e' << 48 | (long)'g' << 40,
(long)'r' << 56 | (long)'f' << 48 | (long)'l' << 40 | (long)'o' << 32 | (long)'o' << 24 | (long)'r' << 16,
(long)'r' << 56 | (long)'h' << 48 | (long)'o' << 40,
(long)'r' << 56 | (long)'l' << 48 | (long)'m' << 40,
(long)'r' << 56 | (long)'s' << 48 | (long)'a' << 40 | (long)'q' << 32 | (long)'u' << 24 | (long)'o' << 16,
(long)'r' << 56 | (long)'s' << 48 | (long)'q' << 40 | (long)'u' << 32 | (long)'o' << 24,
(long)'s' << 56 | (long)'b' << 48 | (long)'q' << 40 | (long)'u' << 32 | (long)'o' << 24,
(long)'s' << 56 | (long)'c' << 48 | (long)'a' << 40 | (long)'r' << 32 | (long)'o' << 24 | (long)'n' << 16,
(long)'s' << 56 | (long)'d' << 48 | (long)'o' << 40 | (long)'t' << 32,
(long)'s' << 56 | (long)'e' << 48 | (long)'c' << 40 | (long)'t' << 32,
(long)'s' << 56 | (long)'h' << 48 | (long)'y' << 40,
(long)'s' << 56 | (long)'i' << 48 | (long)'g' << 40 | (long)'m' << 32 | (long)'a' << 24,
(long)'s' << 56 | (long)'i' << 48 | (long)'g' << 40 | (long)'m' << 32 | (long)'a' << 24 | (long)'f' << 16,
(long)'s' << 56 | (long)'i' << 48 | (long)'m' << 40,
(long)'s' << 56 | (long)'p' << 48 | (long)'a' << 40 | (long)'d' << 32 | (long)'e' << 24 | (long)'s' << 16,
(long)'s' << 56 | (long)'u' << 48 | (long)'b' << 40,
(long)'s' << 56 | (long)'u' << 48 | (long)'b' << 40 | (long)'e' << 32,
(long)'s' << 56 | (long)'u' << 48 | (long)'m' << 40,
(long)'s' << 56 | (long)'u' << 48 | (long)'p' << 40,
(long)'s' << 56 | (long)'u' << 48 | (long)'p' << 40 | (long)'1' << 32,
(long)'s' << 56 | (long)'u' << 48 | (long)'p' << 40 | (long)'2' << 32,
(long)'s' << 56 | (long)'u' << 48 | (long)'p' << 40 | (long)'3' << 32,
(long)'s' << 56 | (long)'u' << 48 | (long)'p' << 40 | (long)'e' << 32,
(long)'s' << 56 | (long)'z' << 48 | (long)'l' << 40 | (long)'i' << 32 | (long)'g' << 24,
(long)'t' << 56 | (long)'a' << 48 | (long)'u' << 40,
(long)'t' << 56 | (long)'h' << 48 | (long)'e' << 40 | (long)'r' << 32 | (long)'e' << 24 | (long)'4' << 16,
(long)'t' << 56 | (long)'h' << 48 | (long)'e' << 40 | (long)'t' << 32 | (long)'a' << 24,
(long)'t' << 56 | (long)'h' << 48 | (long)'e' << 40 | (long)'t' << 32 | (long)'a' << 24 | (long)'s' << 16 | (long)'y' << 8 | (long)'m' << 0,
(long)'t' << 56 | (long)'h' << 48 | (long)'i' << 40 | (long)'n' << 32 | (long)'s' << 24 | (long)'p' << 16,
(long)'t' << 56 | (long)'h' << 48 | (long)'o' << 40 | (long)'r' << 32 | (long)'n' << 24,
(long)'t' << 56 | (long)'i' << 48 | (long)'l' << 40 | (long)'d' << 32 | (long)'e' << 24,
(long)'t' << 56 | (long)'i' << 48 | (long)'m' << 40 | (long)'e' << 32 | (long)'s' << 24,
(long)'t' << 56 | (long)'r' << 48 | (long)'a' << 40 | (long)'d' << 32 | (long)'e' << 24,
(long)'u' << 56 | (long)'A' << 48 | (long)'r' << 40 | (long)'r' << 32,
(long)'u' << 56 | (long)'a' << 48 | (long)'c' << 40 | (long)'u' << 32 | (long)'t' << 24 | (long)'e' << 16,
(long)'u' << 56 | (long)'a' << 48 | (long)'r' << 40 | (long)'r' << 32,
(long)'u' << 56 | (long)'c' << 48 | (long)'i' << 40 | (long)'r' << 32 | (long)'c' << 24,
(long)'u' << 56 | (long)'g' << 48 | (long)'r' << 40 | (long)'a' << 32 | (long)'v' << 24 | (long)'e' << 16,
(long)'u' << 56 | (long)'m' << 48 | (long)'l' << 40,
(long)'u' << 56 | (long)'p' << 48 | (long)'s' << 40 | (long)'i' << 32 | (long)'h' << 24,
(long)'u' << 56 | (long)'p' << 48 | (long)'s' << 40 | (long)'i' << 32 | (long)'l' << 24 | (long)'o' << 16 | (long)'n' << 8,
(long)'u' << 56 | (long)'u' << 48 | (long)'m' << 40 | (long)'l' << 32,
(long)'w' << 56 | (long)'e' << 48 | (long)'i' << 40 | (long)'e' << 32 | (long)'r' << 24 | (long)'p' << 16,
(long)'x' << 56 | (long)'i' << 48,
(long)'y' << 56 | (long)'a' << 48 | (long)'c' << 40 | (long)'u' << 32 | (long)'t' << 24 | (long)'e' << 16,
(long)'y' << 56 | (long)'e' << 48 | (long)'n' << 40,
(long)'y' << 56 | (long)'u' << 48 | (long)'m' << 40 | (long)'l' << 32,
(long)'z' << 56 | (long)'e' << 48 | (long)'t' << 40 | (long)'a' << 32,
(long)'z' << 56 | (long)'w' << 48 | (long)'j' << 40,
(long)'z' << 56 | (long)'w' << 48 | (long)'n' << 40 | (long)'j' << 32
};
static readonly char[] entities_values = new char[] {
'\u00C6',
'\u00C1',
'\u00C2',
'\u00C0',
'\u0391',
'\u00C5',
'\u00C3',
'\u00C4',
'\u0392',
'\u00C7',
'\u03A7',
'\u2021',
'\u0394',
'\u00D0',
'\u00C9',
'\u00CA',
'\u00C8',
'\u0395',
'\u0397',
'\u00CB',
'\u0393',
'\u00CD',
'\u00CE',
'\u00CC',
'\u0399',
'\u00CF',
'\u039A',
'\u039B',
'\u039C',
'\u00D1',
'\u039D',
'\u0152',
'\u00D3',
'\u00D4',
'\u00D2',
'\u03A9',
'\u039F',
'\u00D8',
'\u00D5',
'\u00D6',
'\u03A6',
'\u03A0',
'\u2033',
'\u03A8',
'\u03A1',
'\u0160',
'\u03A3',
'\u00DE',
'\u03A4',
'\u0398',
'\u00DA',
'\u00DB',
'\u00D9',
'\u03A5',
'\u00DC',
'\u039E',
'\u00DD',
'\u0178',
'\u0396',
'\u00E1',
'\u00E2',
'\u00B4',
'\u00E6',
'\u00E0',
'\u2135',
'\u03B1',
'\u0026',
'\u2227',
'\u2220',
'\u0027',
'\u00E5',
'\u2248',
'\u00E3',
'\u00E4',
'\u201E',
'\u03B2',
'\u00A6',
'\u2022',
'\u2229',
'\u00E7',
'\u00B8',
'\u00A2',
'\u03C7',
'\u02C6',
'\u2663',
'\u2245',
'\u00A9',
'\u21B5',
'\u222A',
'\u00A4',
'\u21D3',
'\u2020',
'\u2193',
'\u00B0',
'\u03B4',
'\u2666',
'\u00F7',
'\u00E9',
'\u00EA',
'\u00E8',
'\u2205',
'\u2003',
'\u2002',
'\u03B5',
'\u2261',
'\u03B7',
'\u00F0',
'\u00EB',
'\u20AC',
'\u2203',
'\u0192',
'\u2200',
'\u00BD',
'\u00BC',
'\u00BE',
'\u2044',
'\u03B3',
'\u2265',
'\u003E',
'\u21D4',
'\u2194',
'\u2665',
'\u2026',
'\u00ED',
'\u00EE',
'\u00A1',
'\u00EC',
'\u2111',
'\u221E',
'\u222B',
'\u03B9',
'\u00BF',
'\u2208',
'\u00EF',
'\u03BA',
'\u21D0',
'\u03BB',
'\u2329',
'\u00AB',
'\u2190',
'\u2308',
'\u201C',
'\u2264',
'\u230A',
'\u2217',
'\u25CA',
'\u200E',
'\u2039',
'\u2018',
'\u003C',
'\u00AF',
'\u2014',
'\u00B5',
'\u00B7',
'\u2212',
'\u03BC',
'\u2207',
'\u00A0',
'\u2013',
'\u2260',
'\u220B',
'\u00AC',
'\u2209',
'\u2284',
'\u00F1',
'\u03BD',
'\u00F3',
'\u00F4',
'\u0153',
'\u00F2',
'\u203E',
'\u03C9',
'\u03BF',
'\u2295',
'\u2228',
'\u00AA',
'\u00BA',
'\u00F8',
'\u00F5',
'\u2297',
'\u00F6',
'\u00B6',
'\u2202',
'\u2030',
'\u22A5',
'\u03C6',
'\u03C0',
'\u03D6',
'\u00B1',
'\u00A3',
'\u2032',
'\u220F',
'\u221D',
'\u03C8',
'\u0022',
'\u21D2',
'\u221A',
'\u232A',
'\u00BB',
'\u2192',
'\u2309',
'\u201D',
'\u211C',
'\u00AE',
'\u230B',
'\u03C1',
'\u200F',
'\u203A',
'\u2019',
'\u201A',
'\u0161',
'\u22C5',
'\u00A7',
'\u00AD',
'\u03C3',
'\u03C2',
'\u223C',
'\u2660',
'\u2282',
'\u2286',
'\u2211',
'\u2283',
'\u00B9',
'\u00B2',
'\u00B3',
'\u2287',
'\u00DF',
'\u03C4',
'\u2234',
'\u03B8',
'\u03D1',
'\u2009',
'\u00FE',
'\u02DC',
'\u00D7',
'\u2122',
'\u21D1',
'\u00FA',
'\u2191',
'\u00FB',
'\u00F9',
'\u00A8',
'\u03D2',
'\u03C5',
'\u00FC',
'\u2118',
'\u03BE',
'\u00FD',
'\u00A5',
'\u00FF',
'\u03B6',
'\u200D',
'\u200C'
};
#region Methods
static void WriteCharBytes(IList buf, char ch, Encoding e)
{
if (ch > 255)
{
foreach (byte b in e.GetBytes(new char[] { ch }))
buf.Add(b);
}
else
buf.Add((byte)ch);
}
public static string UrlDecode(string s, Encoding e)
{
if (null == s)
return null;
if (s.IndexOf('%') == -1 && s.IndexOf('+') == -1)
return s;
if (e == null)
e = Encoding.UTF8;
long len = s.Length;
var bytes = new List<byte>();
int xchar;
char ch;
for (int i = 0; i < len; i++)
{
ch = s[i];
if (ch == '%' && i + 2 < len && s[i + 1] != '%')
{
if (s[i + 1] == 'u' && i + 5 < len)
{
// unicode hex sequence
xchar = GetChar(s, i + 2, 4);
if (xchar != -1)
{
WriteCharBytes(bytes, (char)xchar, e);
i += 5;
}
else
WriteCharBytes(bytes, '%', e);
}
else if ((xchar = GetChar(s, i + 1, 2)) != -1)
{
WriteCharBytes(bytes, (char)xchar, e);
i += 2;
}
else
{
WriteCharBytes(bytes, '%', e);
}
continue;
}
if (ch == '+')
WriteCharBytes(bytes, ' ', e);
else
WriteCharBytes(bytes, ch, e);
}
byte[] buf = bytes.ToArray();
bytes = null;
return e.GetString(buf);
}
static int GetInt(byte b)
{
char c = (char)b;
if (c >= '0' && c <= '9')
return c - '0';
if (c >= 'a' && c <= 'f')
return c - 'a' + 10;
if (c >= 'A' && c <= 'F')
return c - 'A' + 10;
return -1;
}
static int GetChar(string str, int offset, int length)
{
int val = 0;
int end = length + offset;
for (int i = offset; i < end; i++)
{
char c = str[i];
if (c > 127)
return -1;
int current = GetInt((byte)c);
if (current == -1)
return -1;
val = (val << 4) + current;
}
return val;
}
static bool TryConvertKeyToEntity(string key, out char value)
{
var token = CalculateKeyValue(key);
if (token == 0)
{
value = '\0';
return false;
}
var idx = Array.BinarySearch(entities, token);
if (idx < 0)
{
value = '\0';
return false;
}
value = entities_values[idx];
return true;
}
static long CalculateKeyValue(string s)
{
if (s.Length > 8)
return 0;
long key = 0;
for (int i = 0; i < s.Length; ++i)
{
long ch = s[i];
if (ch > 'z' || ch < '0')
return 0;
key |= ch << ((7 - i) * 8);
}
return key;
}
/// <summary>
/// Decodes an HTML-encoded string and returns the decoded string.
/// </summary>
/// <param name="s">The HTML string to decode. </param>
/// <returns>The decoded text.</returns>
public static string HtmlDecode(string s)
{
if (s == null)
throw new ArgumentNullException("s");
if (s.IndexOf('&') == -1)
return s;
StringBuilder entity = new StringBuilder();
StringBuilder output = new StringBuilder();
int len = s.Length;
// 0 -> nothing,
// 1 -> right after '&'
// 2 -> between '&' and ';' but no '#'
// 3 -> '#' found after '&' and getting numbers
int state = 0;
int number = 0;
int digit_start = 0;
bool hex_number = false;
for (int i = 0; i < len; i++)
{
char c = s[i];
if (state == 0)
{
if (c == '&')
{
entity.Append(c);
state = 1;
}
else
{
output.Append(c);
}
continue;
}
if (c == '&')
{
state = 1;
if (digit_start > 0)
{
entity.Append(s, digit_start, i - digit_start);
digit_start = 0;
}
output.Append(entity.ToString());
entity.Length = 0;
entity.Append('&');
continue;
}
switch (state)
{
case 1:
if (c == ';')
{
state = 0;
output.Append(entity.ToString());
output.Append(c);
entity.Length = 0;
break;
}
number = 0;
hex_number = false;
if (c != '#')
{
state = 2;
}
else
{
state = 3;
}
entity.Append(c);
break;
case 2:
entity.Append(c);
if (c == ';')
{
string key = entity.ToString();
state = 0;
entity.Length = 0;
if (key.Length > 1)
{
var skey = key.Substring(1, key.Length - 2);
if (TryConvertKeyToEntity(skey, out c))
{
output.Append(c);
break;
}
}
output.Append(key);
}
break;
case 3:
if (c == ';')
{
if (number < 0x10000)
{
output.Append((char)number);
}
else
{
output.Append((char)(0xd800 + ((number - 0x10000) >> 10)));
output.Append((char)(0xdc00 + ((number - 0x10000) & 0x3ff)));
}
state = 0;
entity.Length = 0;
digit_start = 0;
break;
}
if (c == 'x' || c == 'X' && !hex_number)
{
digit_start = i;
hex_number = true;
break;
}
if (Char.IsDigit(c))
{
if (digit_start == 0)
digit_start = i;
number = number * (hex_number ? 16 : 10) + ((int)c - '0');
break;
}
if (hex_number)
{
if (c >= 'a' && c <= 'f')
{
number = number * 16 + 10 + ((int)c - 'a');
break;
}
if (c >= 'A' && c <= 'F')
{
number = number * 16 + 10 + ((int)c - 'A');
break;
}
}
state = 2;
if (digit_start > 0)
{
entity.Append(s, digit_start, i - digit_start);
digit_start = 0;
}
entity.Append(c);
break;
}
}
if (entity.Length > 0)
{
output.Append(entity);
}
else if (digit_start > 0)
{
output.Append(s, digit_start, s.Length - digit_start);
}
return output.ToString();
}
public static NameValueCollection ParseQueryString(string query)
{
return ParseQueryString(query, Encoding.UTF8);
}
public static NameValueCollection ParseQueryString(string query, Encoding encoding)
{
if (query == null)
throw new ArgumentNullException("query");
if (encoding == null)
throw new ArgumentNullException("encoding");
if (query.Length == 0 || (query.Length == 1 && query[0] == '?'))
return new NameValueCollection();
if (query[0] == '?')
query = query.Substring(1);
NameValueCollection result = new HttpQSCollection();
ParseQueryString(query, encoding, result);
return result;
}
internal static void ParseQueryString(string query, Encoding encoding, NameValueCollection result)
{
if (query.Length == 0)
return;
string decoded = HtmlDecode(query);
int decodedLength = decoded.Length;
int namePos = 0;
bool first = true;
while (namePos <= decodedLength)
{
int valuePos = -1, valueEnd = -1;
for (int q = namePos; q < decodedLength; q++)
{
if (valuePos == -1 && decoded[q] == '=')
{
valuePos = q + 1;
}
else if (decoded[q] == '&')
{
valueEnd = q;
break;
}
}
if (first)
{
first = false;
if (decoded[namePos] == '?')
namePos++;
}
string name, value;
if (valuePos == -1)
{
name = null;
valuePos = namePos;
}
else
{
name = UrlDecode(decoded.Substring(namePos, valuePos - namePos - 1), encoding);
}
if (valueEnd < 0)
{
namePos = -1;
valueEnd = decoded.Length;
}
else
{
namePos = valueEnd + 1;
}
value = UrlDecode(decoded.Substring(valuePos, valueEnd - valuePos), encoding);
result.Add(name, value);
if (namePos == -1)
break;
}
}
#endregion // Methods
}
}

View File

@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Web;
using Funq;
using MediaBrowser.Model.Logging;
using ServiceStack;
@@ -236,7 +237,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer.SocketSharp
private NameValueCollectionWrapper queryString;
public INameValueCollection QueryString
{
get { return queryString ?? (queryString = new NameValueCollectionWrapper(HttpUtility.ParseQueryString(request.Url.Query))); }
get { return queryString ?? (queryString = new NameValueCollectionWrapper(MyHttpUtility.ParseQueryString(request.Url.Query))); }
}
private NameValueCollectionWrapper formData;

View File

@@ -403,10 +403,7 @@ namespace MediaBrowser.Server.Implementations.Library
try
{
_dtoServiceFactory().AttachPrimaryImageAspectRatio(dto, user, new List<ItemFields>
{
ItemFields.PrimaryImageAspectRatio
});
_dtoServiceFactory().AttachPrimaryImageAspectRatio(dto, user);
}
catch (Exception ex)
{

View File

@@ -1,59 +0,0 @@
using MediaBrowser.Common.Net;
using MediaBrowser.Controller.LiveTv;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.LiveTv;
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Model.Serialization;
namespace MediaBrowser.Server.Implementations.LiveTv.Listings.Emby
{
public class EmbyGuide : IListingsProvider
{
private readonly IHttpClient _httpClient;
private readonly IJsonSerializer _jsonSerializer;
public EmbyGuide(IHttpClient httpClient, IJsonSerializer jsonSerializer)
{
_httpClient = httpClient;
_jsonSerializer = jsonSerializer;
}
public string Name
{
get { return "Emby Guide"; }
}
public string Type
{
get { return "emby"; }
}
public Task<IEnumerable<ProgramInfo>> GetProgramsAsync(ListingsProviderInfo info, string channelNumber, string channelName, DateTime startDateUtc, DateTime endDateUtc, CancellationToken cancellationToken)
{
return GetListingsProvider(info.Country).GetProgramsAsync(info, channelNumber, startDateUtc, endDateUtc, cancellationToken);
}
public Task AddMetadata(ListingsProviderInfo info, List<ChannelInfo> channels, CancellationToken cancellationToken)
{
return GetListingsProvider(info.Country).AddMetadata(info, channels, cancellationToken);
}
public Task Validate(ListingsProviderInfo info, bool validateLogin, bool validateListings)
{
return GetListingsProvider(info.Country).Validate(info, validateLogin, validateListings);
}
public Task<List<NameIdPair>> GetLineups(ListingsProviderInfo info, string country, string location)
{
return GetListingsProvider(country).GetLineups(country, location);
}
private IEmbyListingProvider GetListingsProvider(string country)
{
return new EmbyListingsNorthAmerica(_httpClient, _jsonSerializer);
}
}
}

View File

@@ -1,366 +0,0 @@
using MediaBrowser.Common.Net;
using MediaBrowser.Controller.LiveTv;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.LiveTv;
using MediaBrowser.Model.Serialization;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace MediaBrowser.Server.Implementations.LiveTv.Listings.Emby
{
public class EmbyListingsNorthAmerica : IEmbyListingProvider
{
private readonly IHttpClient _httpClient;
private readonly IJsonSerializer _jsonSerializer;
public EmbyListingsNorthAmerica(IHttpClient httpClient, IJsonSerializer jsonSerializer)
{
_httpClient = httpClient;
_jsonSerializer = jsonSerializer;
}
public async Task<IEnumerable<ProgramInfo>> GetProgramsAsync(ListingsProviderInfo info, string channelNumber, DateTime startDateUtc, DateTime endDateUtc, CancellationToken cancellationToken)
{
channelNumber = NormalizeNumber(channelNumber);
var url = "https://data.emby.media/service/listings?id=" + info.ListingsId;
// Normalize
startDateUtc = startDateUtc.Date;
endDateUtc = startDateUtc.AddDays(7);
url += "&start=" + startDateUtc.ToString("s", CultureInfo.InvariantCulture) + "Z";
url += "&end=" + endDateUtc.ToString("s", CultureInfo.InvariantCulture) + "Z";
var response = await GetResponse<ListingInfo[]>(url).ConfigureAwait(false);
return response.Where(i => IncludeInResults(i, channelNumber)).Select(GetProgramInfo).OrderBy(i => i.StartDate);
}
private ProgramInfo GetProgramInfo(ListingInfo info)
{
var showType = info.showType ?? string.Empty;
var program = new ProgramInfo
{
Id = info.listingID.ToString(CultureInfo.InvariantCulture),
Name = GetStringValue(info.showName),
HomePageUrl = GetStringValue(info.webLink),
Overview = info.description,
IsHD = info.hd,
IsLive = info.live,
IsPremiere = info.seasonPremiere || info.seriesPremiere,
IsMovie = showType.IndexOf("Movie", StringComparison.OrdinalIgnoreCase) != -1,
IsKids = showType.IndexOf("Children", StringComparison.OrdinalIgnoreCase) != -1,
IsNews = showType.IndexOf("News", StringComparison.OrdinalIgnoreCase) != -1,
IsSports = showType.IndexOf("Sports", StringComparison.OrdinalIgnoreCase) != -1
};
if (!string.IsNullOrWhiteSpace(info.listDateTime))
{
program.StartDate = DateTime.ParseExact(info.listDateTime, "yyyy'-'MM'-'dd' 'HH':'mm':'ss", CultureInfo.InvariantCulture);
program.StartDate = DateTime.SpecifyKind(program.StartDate, DateTimeKind.Utc);
program.EndDate = program.StartDate.AddMinutes(info.duration);
}
if (info.starRating > 0)
{
program.CommunityRating = info.starRating*2;
}
if (!string.IsNullOrWhiteSpace(info.rating))
{
// They don't have dashes so try to normalize
program.OfficialRating = info.rating.Replace("TV", "TV-").Replace("--", "-");
var invalid = new[] { "N/A", "Approved", "Not Rated" };
if (invalid.Contains(program.OfficialRating, StringComparer.OrdinalIgnoreCase))
{
program.OfficialRating = null;
}
}
if (!string.IsNullOrWhiteSpace(info.year))
{
program.ProductionYear = int.Parse(info.year, CultureInfo.InvariantCulture);
}
if (info.showID > 0)
{
program.ShowId = info.showID.ToString(CultureInfo.InvariantCulture);
}
if (info.seriesID > 0)
{
program.SeriesId = info.seriesID.ToString(CultureInfo.InvariantCulture);
program.IsSeries = true;
program.IsRepeat = info.repeat;
program.EpisodeTitle = GetStringValue(info.episodeTitle);
if (string.Equals(program.Name, program.EpisodeTitle, StringComparison.OrdinalIgnoreCase))
{
program.EpisodeTitle = null;
}
}
if (info.starRating > 0)
{
program.CommunityRating = info.starRating * 2;
}
if (string.Equals(info.showName, "Movie", StringComparison.OrdinalIgnoreCase))
{
// Sometimes the movie title will be in here
if (!string.IsNullOrWhiteSpace(info.episodeTitle))
{
program.Name = info.episodeTitle;
}
}
return program;
}
private string GetStringValue(string s)
{
return string.IsNullOrWhiteSpace(s) ? null : s;
}
private bool IncludeInResults(ListingInfo info, string itemNumber)
{
if (string.Equals(itemNumber, NormalizeNumber(info.number), StringComparison.OrdinalIgnoreCase))
{
return true;
}
var channelNumber = info.channelNumber.ToString(CultureInfo.InvariantCulture);
if (info.subChannelNumber > 0)
{
channelNumber += "." + info.subChannelNumber.ToString(CultureInfo.InvariantCulture);
}
return string.Equals(channelNumber, itemNumber, StringComparison.OrdinalIgnoreCase);
}
public async Task AddMetadata(ListingsProviderInfo info, List<ChannelInfo> channels, CancellationToken cancellationToken)
{
var response = await GetResponse<LineupDetailResponse>("https://data.emby.media/service/lineups?id=" + info.ListingsId).ConfigureAwait(false);
foreach (var channel in channels)
{
var station = response.stations.FirstOrDefault(i =>
{
var itemNumber = NormalizeNumber(channel.Number);
if (string.Equals(itemNumber, NormalizeNumber(i.number), StringComparison.OrdinalIgnoreCase))
{
return true;
}
var channelNumber = i.channelNumber.ToString(CultureInfo.InvariantCulture);
if (i.subChannelNumber > 0)
{
channelNumber += "." + i.subChannelNumber.ToString(CultureInfo.InvariantCulture);
}
return string.Equals(channelNumber, itemNumber, StringComparison.OrdinalIgnoreCase);
});
if (station != null)
{
//channel.Name = station.name;
if (!string.IsNullOrWhiteSpace(station.logoFilename))
{
channel.HasImage = true;
channel.ImageUrl = "http://cdn.tvpassport.com/image/station/100x100/" + station.logoFilename;
}
}
}
}
private string NormalizeNumber(string number)
{
return number.Replace('-', '.');
}
public Task Validate(ListingsProviderInfo info, bool validateLogin, bool validateListings)
{
return Task.FromResult(true);
}
public async Task<List<NameIdPair>> GetLineups(string country, string location)
{
// location = postal code
var response = await GetResponse<LineupInfo[]>("https://data.emby.media/service/lineups?postalCode=" + location).ConfigureAwait(false);
return response.Select(i => new NameIdPair
{
Name = GetName(i),
Id = i.lineupID
}).OrderBy(i => i.Name).ToList();
}
private string GetName(LineupInfo info)
{
var name = info.lineupName;
if (string.Equals(info.lineupType, "cab", StringComparison.OrdinalIgnoreCase))
{
name += " - Cable";
}
else if (string.Equals(info.lineupType, "sat", StringComparison.OrdinalIgnoreCase))
{
name += " - SAT";
}
else if (string.Equals(info.lineupType, "ota", StringComparison.OrdinalIgnoreCase))
{
name += " - OTA";
}
return name;
}
private async Task<T> GetResponse<T>(string url, Func<string, string> filter = null)
where T : class
{
using (var stream = await _httpClient.Get(new HttpRequestOptions
{
Url = url,
CacheLength = TimeSpan.FromDays(1),
CacheMode = CacheMode.Unconditional
}).ConfigureAwait(false))
{
using (var reader = new StreamReader(stream))
{
var path = await reader.ReadToEndAsync().ConfigureAwait(false);
using (var secondStream = await _httpClient.Get(new HttpRequestOptions
{
Url = "https://www.mb3admin.com" + path,
CacheLength = TimeSpan.FromDays(1),
CacheMode = CacheMode.Unconditional
}).ConfigureAwait(false))
{
return ParseResponse<T>(secondStream, filter);
}
}
}
}
private T ParseResponse<T>(Stream response, Func<string,string> filter)
{
using (var reader = new StreamReader(response))
{
var json = reader.ReadToEnd();
if (filter != null)
{
json = filter(json);
}
return _jsonSerializer.DeserializeFromString<T>(json);
}
}
private class LineupInfo
{
public string lineupID { get; set; }
public string lineupName { get; set; }
public string lineupType { get; set; }
public string providerID { get; set; }
public string providerName { get; set; }
public string serviceArea { get; set; }
public string country { get; set; }
}
private class Station
{
public string number { get; set; }
public int channelNumber { get; set; }
public int subChannelNumber { get; set; }
public int stationID { get; set; }
public string name { get; set; }
public string callsign { get; set; }
public string network { get; set; }
public string stationType { get; set; }
public int NTSC_TSID { get; set; }
public int DTV_TSID { get; set; }
public string webLink { get; set; }
public string logoFilename { get; set; }
}
private class LineupDetailResponse
{
public string lineupID { get; set; }
public string lineupName { get; set; }
public string lineupType { get; set; }
public string providerID { get; set; }
public string providerName { get; set; }
public string serviceArea { get; set; }
public string country { get; set; }
public List<Station> stations { get; set; }
}
private class ListingInfo
{
public string number { get; set; }
public int channelNumber { get; set; }
public int subChannelNumber { get; set; }
public int stationID { get; set; }
public string name { get; set; }
public string callsign { get; set; }
public string network { get; set; }
public string stationType { get; set; }
public string webLink { get; set; }
public string logoFilename { get; set; }
public int listingID { get; set; }
public string listDateTime { get; set; }
public int duration { get; set; }
public int showID { get; set; }
public int seriesID { get; set; }
public string showName { get; set; }
public string episodeTitle { get; set; }
public string episodeNumber { get; set; }
public int parts { get; set; }
public int partNum { get; set; }
public bool seriesPremiere { get; set; }
public bool seasonPremiere { get; set; }
public bool seriesFinale { get; set; }
public bool seasonFinale { get; set; }
public bool repeat { get; set; }
public bool @new { get; set; }
public string rating { get; set; }
public bool captioned { get; set; }
public bool educational { get; set; }
public bool blackWhite { get; set; }
public bool subtitled { get; set; }
public bool live { get; set; }
public bool hd { get; set; }
public bool descriptiveVideo { get; set; }
public bool inProgress { get; set; }
public string showTypeID { get; set; }
public int breakoutLevel { get; set; }
public string showType { get; set; }
public string year { get; set; }
public string guest { get; set; }
public string cast { get; set; }
public string director { get; set; }
public int starRating { get; set; }
public string description { get; set; }
public string league { get; set; }
public string team1 { get; set; }
public string team2 { get; set; }
public string @event { get; set; }
public string location { get; set; }
}
}
}

View File

@@ -1,18 +0,0 @@
using MediaBrowser.Controller.LiveTv;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.LiveTv;
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
namespace MediaBrowser.Server.Implementations.LiveTv.Listings.Emby
{
public interface IEmbyListingProvider
{
Task<IEnumerable<ProgramInfo>> GetProgramsAsync(ListingsProviderInfo info, string channelNumber, DateTime startDateUtc, DateTime endDateUtc, CancellationToken cancellationToken);
Task AddMetadata(ListingsProviderInfo info, List<ChannelInfo> channels, CancellationToken cancellationToken);
Task Validate(ListingsProviderInfo info, bool validateLogin, bool validateListings);
Task<List<NameIdPair>> GetLineups(string country, string location);
}
}

View File

@@ -114,7 +114,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings
var requestString = _jsonSerializer.SerializeToString(requestList);
_logger.Debug("Request string for schedules is: " + requestString);
httpOptions.RequestContent = requestString;
using (var response = await Post(httpOptions).ConfigureAwait(false))
using (var response = await Post(httpOptions, true, info).ConfigureAwait(false))
{
StreamReader reader = new StreamReader(response.Content);
string responseString = reader.ReadToEnd();
@@ -138,7 +138,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings
var requestBody = "[\"" + string.Join("\", \"", programsID) + "\"]";
httpOptions.RequestContent = requestBody;
using (var innerResponse = await Post(httpOptions).ConfigureAwait(false))
using (var innerResponse = await Post(httpOptions, true, info).ConfigureAwait(false))
{
StreamReader innerReader = new StreamReader(innerResponse.Content);
responseString = innerReader.ReadToEnd();
@@ -148,7 +148,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings
responseString);
var programDict = programDetails.ToDictionary(p => p.programID, y => y);
var images = await GetImageForPrograms(programDetails.Where(p => p.hasImageArtwork).Select(p => p.programID).ToList(), cancellationToken);
var images = await GetImageForPrograms(info, programDetails.Where(p => p.hasImageArtwork).Select(p => p.programID).ToList(), cancellationToken);
var schedules = dailySchedules.SelectMany(d => d.programs);
foreach (ScheduleDirect.Program schedule in schedules)
@@ -229,7 +229,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings
httpOptions.RequestHeaders["token"] = token;
using (var response = await Get(httpOptions).ConfigureAwait(false))
using (var response = await Get(httpOptions, true, info).ConfigureAwait(false))
{
var root = _jsonSerializer.DeserializeFromStream<ScheduleDirect.Channel>(response);
_logger.Info("Found " + root.map.Count() + " channels on the lineup on ScheduleDirect");
@@ -447,7 +447,9 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings
return url;
}
private async Task<List<ScheduleDirect.ShowImages>> GetImageForPrograms(List<string> programIds,
private async Task<List<ScheduleDirect.ShowImages>> GetImageForPrograms(
ListingsProviderInfo info,
List<string> programIds,
CancellationToken cancellationToken)
{
var imageIdString = "[";
@@ -472,7 +474,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings
TimeoutMs = 60000
};
List<ScheduleDirect.ShowImages> images;
using (var innerResponse2 = await Post(httpOptions).ConfigureAwait(false))
using (var innerResponse2 = await Post(httpOptions, true, info).ConfigureAwait(false))
{
images = _jsonSerializer.DeserializeFromStream<List<ScheduleDirect.ShowImages>>(
innerResponse2.Content);
@@ -504,7 +506,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings
try
{
using (Stream responce = await Get(options).ConfigureAwait(false))
using (Stream responce = await Get(options, false, info).ConfigureAwait(false))
{
var root = _jsonSerializer.DeserializeFromStream<List<ScheduleDirect.Headends>>(responce);
@@ -606,30 +608,58 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings
}
}
private async Task<HttpResponseInfo> Post(HttpRequestOptions options)
private async Task<HttpResponseInfo> Post(HttpRequestOptions options,
bool enableRetry,
ListingsProviderInfo providerInfo)
{
try
{
return await _httpClient.Post(options).ConfigureAwait(false);
}
catch
{
_tokens.Clear();
throw;
}
}
catch (HttpException ex)
{
_tokens.Clear();
if (!ex.StatusCode.HasValue || (int)ex.StatusCode.Value >= 500)
{
enableRetry = false;
}
if (!enableRetry) {
throw;
}
}
var newToken = await GetToken (providerInfo, options.CancellationToken).ConfigureAwait (false);
options.RequestHeaders ["token"] = newToken;
return await Post (options, false, providerInfo).ConfigureAwait (false);
}
private async Task<Stream> Get(HttpRequestOptions options)
private async Task<Stream> Get(HttpRequestOptions options,
bool enableRetry,
ListingsProviderInfo providerInfo)
{
try
{
return await _httpClient.Get(options).ConfigureAwait(false);
}
catch
{
_tokens.Clear();
throw;
}
}
catch (HttpException ex)
{
_tokens.Clear();
if (!ex.StatusCode.HasValue || (int)ex.StatusCode.Value >= 500)
{
enableRetry = false;
}
if (!enableRetry) {
throw;
}
}
var newToken = await GetToken (providerInfo, options.CancellationToken).ConfigureAwait (false);
options.RequestHeaders ["token"] = newToken;
return await Get (options, false, providerInfo).ConfigureAwait (false);
}
private async Task<string> GetTokenInternal(string username, string password,
@@ -646,7 +676,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings
//_logger.Info("Obtaining token from Schedules Direct from addres: " + httpOptions.Url + " with body " +
// httpOptions.RequestContent);
using (var responce = await Post(httpOptions).ConfigureAwait(false))
using (var responce = await Post(httpOptions, false, null).ConfigureAwait(false))
{
var root = _jsonSerializer.DeserializeFromStream<ScheduleDirect.Token>(responce.Content);
if (root.message == "OK")
@@ -728,7 +758,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings
try
{
using (var response = await Get(options).ConfigureAwait(false))
using (var response = await Get(options, false, null).ConfigureAwait(false))
{
var root = _jsonSerializer.DeserializeFromStream<ScheduleDirect.Lineups>(response);

View File

@@ -231,10 +231,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
{
dto.ImageTags[ImageType.Primary] = imageTag;
_dtoService.AttachPrimaryImageAspectRatio(dto, info, new List<ItemFields>
{
ItemFields.PrimaryImageAspectRatio
});
_dtoService.AttachPrimaryImageAspectRatio(dto, info);
}
if (currentProgram != null)

View File

@@ -0,0 +1,54 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Controller.LiveTv;
using MediaBrowser.Controller.MediaEncoding;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.LiveTv;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Serialization;
namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
{
public class SatIp : BaseTunerHost
{
public SatIp(IConfigurationManager config, ILogger logger, IJsonSerializer jsonSerializer, IMediaEncoder mediaEncoder)
: base(config, logger, jsonSerializer, mediaEncoder)
{
}
protected override Task<IEnumerable<ChannelInfo>> GetChannelsInternal(TunerHostInfo tuner, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
public override string Type
{
get { return "SatIp"; }
}
protected override Task<List<MediaSourceInfo>> GetChannelStreamMediaSources(TunerHostInfo tuner, string channelId, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
protected override Task<MediaSourceInfo> GetChannelStream(TunerHostInfo tuner, string channelId, string streamId, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
protected override Task<bool> IsAvailableInternal(TunerHostInfo tuner, string channelId, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
protected override bool IsValidChannelId(string channelId)
{
throw new NotImplementedException();
}
}
}

View File

@@ -71,7 +71,7 @@
"ViewTypeTvShowSeries": "S\u00e8ries:",
"ViewTypeTvGenres": "G\u00e8neres",
"ViewTypeTvFavoriteSeries": "S\u00e8ries Preferides",
"ViewTypeTvFavoriteEpisodes": "Episodis preferits",
"ViewTypeTvFavoriteEpisodes": "Episodis Preferits",
"ViewTypeMovieResume": "Resume",
"ViewTypeMovieLatest": "Darrers",
"ViewTypeMovieMovies": "Pel\u00b7l\u00edcules",
@@ -173,5 +173,5 @@
"HeaderWriter": "Escriptors",
"HeaderParentalRatings": "Parental Ratings",
"HeaderCommunityRatings": "Qualificacions de la comunitat",
"StartupEmbyServerIsLoading": "El servidor d'Emby s'est\u00e0 carregant. Si us plau, torneu-ho a provar de nou en breu."
"StartupEmbyServerIsLoading": "El servidor d'Emby s'est&agrave; carregant. Si et plau, tornau-ho a provar de nou en breu."
}

View File

@@ -43,7 +43,7 @@
<ItemGroup>
<Reference Include="CommonIO, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\CommonIO.1.0.0.5\lib\net45\CommonIO.dll</HintPath>
<HintPath>..\packages\CommonIO.1.0.0.7\lib\net45\CommonIO.dll</HintPath>
</Reference>
<Reference Include="Interfaces.IO">
<HintPath>..\packages\Interfaces.IO.1.0.0.5\lib\portable-net45+sl4+wp71+win8+wpa81\Interfaces.IO.dll</HintPath>
@@ -52,15 +52,18 @@
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\MediaBrowser.Naming.1.0.0.41\lib\portable-net45+sl4+wp71+win8+wpa81\MediaBrowser.Naming.dll</HintPath>
</Reference>
<Reference Include="MoreLinq">
<HintPath>..\packages\morelinq.1.4.0\lib\net35\MoreLinq.dll</HintPath>
</Reference>
<Reference Include="Patterns.Logging">
<HintPath>..\packages\Patterns.Logging.1.0.0.2\lib\portable-net45+sl4+wp71+win8+wpa81\Patterns.Logging.dll</HintPath>
</Reference>
<Reference Include="ServiceStack.Api.Swagger">
<HintPath>..\ThirdParty\ServiceStack\ServiceStack.Api.Swagger.dll</HintPath>
</Reference>
<Reference Include="SocketHttpListener, Version=1.0.5754.42244, Culture=neutral, processorArchitecture=MSIL">
<Reference Include="SocketHttpListener, Version=1.0.5840.28948, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\SocketHttpListener.1.0.0.10\lib\net45\SocketHttpListener.dll</HintPath>
<HintPath>..\packages\SocketHttpListener.1.0.0.25\lib\net45\SocketHttpListener.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
@@ -70,6 +73,7 @@
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net" />
<Reference Include="System.Runtime.Serialization" />
<Reference Include="System.Security" />
<Reference Include="System.Web" />
<Reference Include="System.Xml" />
@@ -94,9 +98,6 @@
<Reference Include="Mono.Nat">
<HintPath>..\packages\Mono.Nat.1.2.24.0\lib\net40\Mono.Nat.dll</HintPath>
</Reference>
<Reference Include="MoreLinq">
<HintPath>..\packages\morelinq.1.1.1\lib\net35\MoreLinq.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="..\SharedVersion.cs">
@@ -160,6 +161,7 @@
<Compile Include="HttpServer\ServerLogFactory.cs" />
<Compile Include="HttpServer\ServerLogger.cs" />
<Compile Include="HttpServer\Security\SessionContext.cs" />
<Compile Include="HttpServer\SocketSharp\HttpUtility.cs" />
<Compile Include="HttpServer\SocketSharp\SharpWebSocket.cs" />
<Compile Include="HttpServer\StreamWriter.cs" />
<Compile Include="HttpServer\SwaggerService.cs" />
@@ -216,9 +218,6 @@
<Compile Include="LiveTv\EmbyTV\RecordingHelper.cs" />
<Compile Include="LiveTv\EmbyTV\SeriesTimerManager.cs" />
<Compile Include="LiveTv\EmbyTV\TimerManager.cs" />
<Compile Include="LiveTv\Listings\Emby\EmbyListings.cs" />
<Compile Include="LiveTv\Listings\Emby\EmbyListingsNorthAmerica.cs" />
<Compile Include="LiveTv\Listings\Emby\IEmbyListingProvider.cs" />
<Compile Include="LiveTv\Listings\SchedulesDirect.cs" />
<Compile Include="LiveTv\Listings\XmlTv.cs" />
<Compile Include="LiveTv\LiveTvConfigurationFactory.cs" />

View File

@@ -72,7 +72,7 @@ namespace MediaBrowser.Server.Implementations.ScheduledTasks
try
{
await _installationManager.InstallPackage(i, new Progress<double>(), cancellationToken).ConfigureAwait(false);
await _installationManager.InstallPackage(i, true, new Progress<double>(), cancellationToken).ConfigureAwait(false);
}
catch (OperationCanceledException)
{

View File

@@ -1,10 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="CommonIO" version="1.0.0.5" targetFramework="net45" />
<package id="CommonIO" version="1.0.0.7" targetFramework="net45" />
<package id="Interfaces.IO" version="1.0.0.5" targetFramework="net45" />
<package id="MediaBrowser.Naming" version="1.0.0.41" targetFramework="net45" />
<package id="Mono.Nat" version="1.2.24.0" targetFramework="net45" />
<package id="morelinq" version="1.1.1" targetFramework="net45" />
<package id="morelinq" version="1.4.0" targetFramework="net45" />
<package id="Patterns.Logging" version="1.0.0.2" targetFramework="net45" />
<package id="SocketHttpListener" version="1.0.0.10" targetFramework="net45" />
<package id="SocketHttpListener" version="1.0.0.25" targetFramework="net45" />
</packages>