mirror of
https://github.com/jellyfin/jellyfin.git
synced 2026-04-27 20:45:03 +01:00
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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à carregant. Si et plau, tornau-ho a provar de nou en breu."
|
||||
}
|
||||
@@ -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" />
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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>
|
||||
Reference in New Issue
Block a user