copy dashboard to the output folder and load from the file system, instead of using embedded resources
|
@ -63,9 +63,32 @@ namespace MediaBrowser.Api
|
||||||
public static Dictionary<string, string> GetAuthorization(IHttpRequest httpReq)
|
public static Dictionary<string, string> GetAuthorization(IHttpRequest httpReq)
|
||||||
{
|
{
|
||||||
var auth = httpReq.Headers[HttpHeaders.Authorization];
|
var auth = httpReq.Headers[HttpHeaders.Authorization];
|
||||||
if (auth == null) return null;
|
|
||||||
|
|
||||||
var parts = auth.Split(' ');
|
return GetAuthorization(auth);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the authorization.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="httpReq">The HTTP req.</param>
|
||||||
|
/// <returns>Dictionary{System.StringSystem.String}.</returns>
|
||||||
|
public static Dictionary<string, string> GetAuthorization(IRequestContext httpReq)
|
||||||
|
{
|
||||||
|
var auth = httpReq.GetHeader("Authorization");
|
||||||
|
|
||||||
|
return GetAuthorization(auth);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the authorization.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="authorizationHeader">The authorization header.</param>
|
||||||
|
/// <returns>Dictionary{System.StringSystem.String}.</returns>
|
||||||
|
private static Dictionary<string, string> GetAuthorization(string authorizationHeader)
|
||||||
|
{
|
||||||
|
if (authorizationHeader == null) return null;
|
||||||
|
|
||||||
|
var parts = authorizationHeader.Split(' ');
|
||||||
|
|
||||||
// There should be at least to parts
|
// There should be at least to parts
|
||||||
if (parts.Length < 2) return null;
|
if (parts.Length < 2) return null;
|
||||||
|
@ -77,8 +100,8 @@ namespace MediaBrowser.Api
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove uptil the first space
|
// Remove uptil the first space
|
||||||
auth = auth.Substring(auth.IndexOf(' '));
|
authorizationHeader = authorizationHeader.Substring(authorizationHeader.IndexOf(' '));
|
||||||
parts = auth.Split(',');
|
parts = authorizationHeader.Split(',');
|
||||||
|
|
||||||
var result = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
var result = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||||
|
|
||||||
|
|
|
@ -250,14 +250,14 @@ namespace MediaBrowser.Api.Images
|
||||||
/// <param name="request">The request.</param>
|
/// <param name="request">The request.</param>
|
||||||
public void Post(PostUserImage request)
|
public void Post(PostUserImage request)
|
||||||
{
|
{
|
||||||
var pathInfo = PathInfo.Parse(Request.PathInfo);
|
var pathInfo = PathInfo.Parse(RequestContext.PathInfo);
|
||||||
var id = new Guid(pathInfo.GetArgumentValue<string>(1));
|
var id = new Guid(pathInfo.GetArgumentValue<string>(1));
|
||||||
|
|
||||||
request.Type = (ImageType)Enum.Parse(typeof(ImageType), pathInfo.GetArgumentValue<string>(3), true);
|
request.Type = (ImageType)Enum.Parse(typeof(ImageType), pathInfo.GetArgumentValue<string>(3), true);
|
||||||
|
|
||||||
var item = _userManager.Users.First(i => i.Id == id);
|
var item = _userManager.Users.First(i => i.Id == id);
|
||||||
|
|
||||||
var task = PostImage(item, request.RequestStream, request.Type, Request.ContentType);
|
var task = PostImage(item, request.RequestStream, request.Type, RequestContext.ContentType);
|
||||||
|
|
||||||
Task.WaitAll(task);
|
Task.WaitAll(task);
|
||||||
}
|
}
|
||||||
|
|
|
@ -624,7 +624,7 @@ namespace MediaBrowser.Api.Playback
|
||||||
|
|
||||||
var media = (IHasMediaStreams)item;
|
var media = (IHasMediaStreams)item;
|
||||||
|
|
||||||
var url = Request.PathInfo;
|
var url = RequestContext.PathInfo;
|
||||||
|
|
||||||
if (!request.AudioCodec.HasValue)
|
if (!request.AudioCodec.HasValue)
|
||||||
{
|
{
|
||||||
|
|
|
@ -40,7 +40,7 @@ namespace MediaBrowser.Api.Playback.Hls
|
||||||
|
|
||||||
public object Get(GetHlsAudioSegment request)
|
public object Get(GetHlsAudioSegment request)
|
||||||
{
|
{
|
||||||
var file = SegmentFilePrefix + request.SegmentId + Path.GetExtension(Request.PathInfo);
|
var file = SegmentFilePrefix + request.SegmentId + Path.GetExtension(RequestContext.PathInfo);
|
||||||
|
|
||||||
file = Path.Combine(ApplicationPaths.EncodedMediaCachePath, file);
|
file = Path.Combine(ApplicationPaths.EncodedMediaCachePath, file);
|
||||||
|
|
||||||
|
|
|
@ -32,7 +32,7 @@ namespace MediaBrowser.Api.Playback.Hls
|
||||||
|
|
||||||
public object Get(GetHlsVideoSegment request)
|
public object Get(GetHlsVideoSegment request)
|
||||||
{
|
{
|
||||||
var file = SegmentFilePrefix + request.SegmentId + Path.GetExtension(Request.PathInfo);
|
var file = SegmentFilePrefix + request.SegmentId + Path.GetExtension(RequestContext.PathInfo);
|
||||||
|
|
||||||
file = Path.Combine(ApplicationPaths.EncodedMediaCachePath, file);
|
file = Path.Combine(ApplicationPaths.EncodedMediaCachePath, file);
|
||||||
|
|
||||||
|
|
|
@ -87,15 +87,15 @@ namespace MediaBrowser.Api.Playback.Progressive
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private bool AddDlnaHeaders(StreamState state)
|
private bool AddDlnaHeaders(StreamState state)
|
||||||
{
|
{
|
||||||
var headers = Request.Headers;
|
var timeSeek = RequestContext.GetHeader("TimeSeekRange.dlna.org");
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(headers["TimeSeekRange.dlna.org"]))
|
if (!string.IsNullOrEmpty(timeSeek))
|
||||||
{
|
{
|
||||||
Response.StatusCode = 406;
|
Response.StatusCode = 406;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
var transferMode = headers["transferMode.dlna.org"];
|
var transferMode = RequestContext.GetHeader("transferMode.dlna.org");
|
||||||
Response.AddHeader("transferMode.dlna.org", string.IsNullOrEmpty(transferMode) ? "Streaming" : transferMode);
|
Response.AddHeader("transferMode.dlna.org", string.IsNullOrEmpty(transferMode) ? "Streaming" : transferMode);
|
||||||
|
|
||||||
var contentFeatures = string.Empty;
|
var contentFeatures = string.Empty;
|
||||||
|
|
|
@ -252,7 +252,7 @@ namespace MediaBrowser.Api
|
||||||
{
|
{
|
||||||
// We need to parse this manually because we told service stack not to with IRequiresRequestStream
|
// We need to parse this manually because we told service stack not to with IRequiresRequestStream
|
||||||
// https://code.google.com/p/servicestack/source/browse/trunk/Common/ServiceStack.Text/ServiceStack.Text/Controller/PathInfo.cs
|
// https://code.google.com/p/servicestack/source/browse/trunk/Common/ServiceStack.Text/ServiceStack.Text/Controller/PathInfo.cs
|
||||||
var pathInfo = PathInfo.Parse(Request.PathInfo);
|
var pathInfo = PathInfo.Parse(RequestContext.PathInfo);
|
||||||
var id = new Guid(pathInfo.GetArgumentValue<string>(1));
|
var id = new Guid(pathInfo.GetArgumentValue<string>(1));
|
||||||
|
|
||||||
var plugin = _appHost.Plugins.First(p => p.Id == id);
|
var plugin = _appHost.Plugins.First(p => p.Id == id);
|
||||||
|
|
|
@ -182,7 +182,7 @@ namespace MediaBrowser.Api.ScheduledTasks
|
||||||
{
|
{
|
||||||
// We need to parse this manually because we told service stack not to with IRequiresRequestStream
|
// We need to parse this manually because we told service stack not to with IRequiresRequestStream
|
||||||
// https://code.google.com/p/servicestack/source/browse/trunk/Common/ServiceStack.Text/ServiceStack.Text/Controller/PathInfo.cs
|
// https://code.google.com/p/servicestack/source/browse/trunk/Common/ServiceStack.Text/ServiceStack.Text/Controller/PathInfo.cs
|
||||||
var pathInfo = PathInfo.Parse(Request.PathInfo);
|
var pathInfo = PathInfo.Parse(RequestContext.PathInfo);
|
||||||
var id = new Guid(pathInfo.GetArgumentValue<string>(1));
|
var id = new Guid(pathInfo.GetArgumentValue<string>(1));
|
||||||
|
|
||||||
var task = TaskManager.ScheduledTasks.FirstOrDefault(i => i.Id == id);
|
var task = TaskManager.ScheduledTasks.FirstOrDefault(i => i.Id == id);
|
||||||
|
|
|
@ -474,7 +474,7 @@ namespace MediaBrowser.Api.UserLibrary
|
||||||
{
|
{
|
||||||
// We need to parse this manually because we told service stack not to with IRequiresRequestStream
|
// We need to parse this manually because we told service stack not to with IRequiresRequestStream
|
||||||
// https://code.google.com/p/servicestack/source/browse/trunk/Common/ServiceStack.Text/ServiceStack.Text/Controller/PathInfo.cs
|
// https://code.google.com/p/servicestack/source/browse/trunk/Common/ServiceStack.Text/ServiceStack.Text/Controller/PathInfo.cs
|
||||||
var pathInfo = PathInfo.Parse(Request.PathInfo);
|
var pathInfo = PathInfo.Parse(RequestContext.PathInfo);
|
||||||
var userId = new Guid(pathInfo.GetArgumentValue<string>(1));
|
var userId = new Guid(pathInfo.GetArgumentValue<string>(1));
|
||||||
var itemId = pathInfo.GetArgumentValue<string>(3);
|
var itemId = pathInfo.GetArgumentValue<string>(3);
|
||||||
|
|
||||||
|
@ -595,7 +595,7 @@ namespace MediaBrowser.Api.UserLibrary
|
||||||
|
|
||||||
var item = DtoBuilder.GetItemByClientId(request.Id, _userManager, _libraryManager, user.Id);
|
var item = DtoBuilder.GetItemByClientId(request.Id, _userManager, _libraryManager, user.Id);
|
||||||
|
|
||||||
var auth = RequestFilterAttribute.GetAuthorization(Request);
|
var auth = RequestFilterAttribute.GetAuthorization(RequestContext);
|
||||||
|
|
||||||
if (auth != null)
|
if (auth != null)
|
||||||
{
|
{
|
||||||
|
@ -613,7 +613,7 @@ namespace MediaBrowser.Api.UserLibrary
|
||||||
|
|
||||||
var item = DtoBuilder.GetItemByClientId(request.Id, _userManager, _libraryManager, user.Id);
|
var item = DtoBuilder.GetItemByClientId(request.Id, _userManager, _libraryManager, user.Id);
|
||||||
|
|
||||||
var auth = RequestFilterAttribute.GetAuthorization(Request);
|
var auth = RequestFilterAttribute.GetAuthorization(RequestContext);
|
||||||
|
|
||||||
if (auth != null)
|
if (auth != null)
|
||||||
{
|
{
|
||||||
|
@ -633,7 +633,7 @@ namespace MediaBrowser.Api.UserLibrary
|
||||||
|
|
||||||
var item = DtoBuilder.GetItemByClientId(request.Id, _userManager, _libraryManager, user.Id);
|
var item = DtoBuilder.GetItemByClientId(request.Id, _userManager, _libraryManager, user.Id);
|
||||||
|
|
||||||
var auth = RequestFilterAttribute.GetAuthorization(Request);
|
var auth = RequestFilterAttribute.GetAuthorization(RequestContext);
|
||||||
|
|
||||||
if (auth != null)
|
if (auth != null)
|
||||||
{
|
{
|
||||||
|
|
|
@ -274,7 +274,7 @@ namespace MediaBrowser.Api
|
||||||
{
|
{
|
||||||
// We need to parse this manually because we told service stack not to with IRequiresRequestStream
|
// We need to parse this manually because we told service stack not to with IRequiresRequestStream
|
||||||
// https://code.google.com/p/servicestack/source/browse/trunk/Common/ServiceStack.Text/ServiceStack.Text/Controller/PathInfo.cs
|
// https://code.google.com/p/servicestack/source/browse/trunk/Common/ServiceStack.Text/ServiceStack.Text/Controller/PathInfo.cs
|
||||||
var pathInfo = PathInfo.Parse(Request.PathInfo);
|
var pathInfo = PathInfo.Parse(RequestContext.PathInfo);
|
||||||
var id = new Guid(pathInfo.GetArgumentValue<string>(1));
|
var id = new Guid(pathInfo.GetArgumentValue<string>(1));
|
||||||
|
|
||||||
var dtoUser = request;
|
var dtoUser = request;
|
||||||
|
|
|
@ -261,7 +261,15 @@ namespace MediaBrowser.Model.Configuration
|
||||||
[ProtoMember(57)]
|
[ProtoMember(57)]
|
||||||
public bool EnableDeveloperTools { get; set; }
|
public bool EnableDeveloperTools { get; set; }
|
||||||
|
|
||||||
// Next Proto number ====> 61
|
/// <summary>
|
||||||
|
/// Gets or sets a value indicating whether [enable dashboard response caching].
|
||||||
|
/// Allows potential contributors without visual studio to modify production dashboard code and test changes.
|
||||||
|
/// </summary>
|
||||||
|
/// <value><c>true</c> if [enable dashboard response caching]; otherwise, <c>false</c>.</value>
|
||||||
|
[ProtoMember(61)]
|
||||||
|
public bool EnableDashboardResponseCaching { get; set; }
|
||||||
|
|
||||||
|
// Next Proto number ====> 62
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="ServerConfiguration" /> class.
|
/// Initializes a new instance of the <see cref="ServerConfiguration" /> class.
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
using System.Net;
|
using MediaBrowser.Common.Extensions;
|
||||||
using MediaBrowser.Common.Extensions;
|
|
||||||
using MediaBrowser.Common.IO;
|
using MediaBrowser.Common.IO;
|
||||||
using MediaBrowser.Common.Net;
|
using MediaBrowser.Common.Net;
|
||||||
using MediaBrowser.Model.Logging;
|
using MediaBrowser.Model.Logging;
|
||||||
|
@ -11,7 +10,7 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Net;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using MimeTypes = MediaBrowser.Common.Net.MimeTypes;
|
using MimeTypes = MediaBrowser.Common.Net.MimeTypes;
|
||||||
|
|
||||||
|
@ -36,7 +35,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return Request.Headers.AllKeys.Contains("Range");
|
return !string.IsNullOrEmpty(RequestContext.GetHeader("Range"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,8 +54,6 @@ namespace MediaBrowser.Server.Implementations.HttpServer
|
||||||
throw new ArgumentNullException("result");
|
throw new ArgumentNullException("result");
|
||||||
}
|
}
|
||||||
|
|
||||||
Response.AddHeader("Vary", "Accept-Encoding");
|
|
||||||
|
|
||||||
return RequestContext.ToOptimizedResult(result);
|
return RequestContext.ToOptimizedResult(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -200,11 +197,6 @@ namespace MediaBrowser.Server.Implementations.HttpServer
|
||||||
|
|
||||||
var compress = ShouldCompressResponse(contentType);
|
var compress = ShouldCompressResponse(contentType);
|
||||||
|
|
||||||
if (compress)
|
|
||||||
{
|
|
||||||
Response.AddHeader("Vary", "Accept-Encoding");
|
|
||||||
}
|
|
||||||
|
|
||||||
return ToStaticResult(contentType, factoryFn, compress, headersOnly).Result;
|
return ToStaticResult(contentType, factoryFn, compress, headersOnly).Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -266,7 +258,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer
|
||||||
|
|
||||||
if (IsRangeRequest)
|
if (IsRangeRequest)
|
||||||
{
|
{
|
||||||
return new RangeRequestWriter(Request.Headers, httpListenerResponse, stream, headersOnly);
|
return new RangeRequestWriter(RequestContext.GetHeader("Range"), httpListenerResponse, stream, headersOnly);
|
||||||
}
|
}
|
||||||
|
|
||||||
httpListenerResponse.ContentLength64 = stream.Length;
|
httpListenerResponse.ContentLength64 = stream.Length;
|
||||||
|
@ -332,22 +324,26 @@ namespace MediaBrowser.Server.Implementations.HttpServer
|
||||||
{
|
{
|
||||||
var isNotModified = true;
|
var isNotModified = true;
|
||||||
|
|
||||||
if (Request.Headers.AllKeys.Contains("If-Modified-Since"))
|
var ifModifiedSinceHeader = RequestContext.GetHeader("If-Modified-Since");
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(ifModifiedSinceHeader))
|
||||||
{
|
{
|
||||||
DateTime ifModifiedSince;
|
DateTime ifModifiedSince;
|
||||||
|
|
||||||
if (DateTime.TryParse(Request.Headers["If-Modified-Since"], out ifModifiedSince))
|
if (DateTime.TryParse(ifModifiedSinceHeader, out ifModifiedSince))
|
||||||
{
|
{
|
||||||
isNotModified = IsNotModified(ifModifiedSince.ToUniversalTime(), cacheDuration, lastDateModified);
|
isNotModified = IsNotModified(ifModifiedSince.ToUniversalTime(), cacheDuration, lastDateModified);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var ifNoneMatchHeader = RequestContext.GetHeader("If-None-Match");
|
||||||
|
|
||||||
// Validate If-None-Match
|
// Validate If-None-Match
|
||||||
if (isNotModified && (cacheKey.HasValue || !string.IsNullOrEmpty(Request.Headers["If-None-Match"])))
|
if (isNotModified && (cacheKey.HasValue || !string.IsNullOrEmpty(ifNoneMatchHeader)))
|
||||||
{
|
{
|
||||||
Guid ifNoneMatch;
|
Guid ifNoneMatch;
|
||||||
|
|
||||||
if (Guid.TryParse(Request.Headers["If-None-Match"] ?? string.Empty, out ifNoneMatch))
|
if (Guid.TryParse(ifNoneMatchHeader ?? string.Empty, out ifNoneMatch))
|
||||||
{
|
{
|
||||||
if (cacheKey.HasValue && cacheKey.Value == ifNoneMatch)
|
if (cacheKey.HasValue && cacheKey.Value == ifNoneMatch)
|
||||||
{
|
{
|
||||||
|
|
|
@ -162,9 +162,18 @@ namespace MediaBrowser.Server.Implementations.HttpServer
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(exception.Message))
|
if (!string.IsNullOrEmpty(exception.Message))
|
||||||
{
|
{
|
||||||
res.AddHeader("X-Application-Error-Code", exception.Message);
|
res.AddHeader("X-Application-Error-Code", exception.Message.Replace(Environment.NewLine, " "));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (dto is CompressedResult)
|
||||||
|
{
|
||||||
|
// Per Google PageSpeed
|
||||||
|
// This instructs the proxies to cache two versions of the resource: one compressed, and one uncompressed.
|
||||||
|
// The correct version of the resource is delivered based on the client request header.
|
||||||
|
// This is a good choice for applications that are singly homed and depend on public proxies for user locality.
|
||||||
|
res.AddHeader("Vary", "Accept-Encoding");
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
using ServiceStack.Service;
|
using ServiceStack.Service;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Specialized;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
@ -17,19 +16,19 @@ namespace MediaBrowser.Server.Implementations.HttpServer
|
||||||
/// <value>The source stream.</value>
|
/// <value>The source stream.</value>
|
||||||
private Stream SourceStream { get; set; }
|
private Stream SourceStream { get; set; }
|
||||||
private HttpListenerResponse Response { get; set; }
|
private HttpListenerResponse Response { get; set; }
|
||||||
private NameValueCollection RequestHeaders { get; set; }
|
private string RangeHeader { get; set; }
|
||||||
private bool IsHeadRequest { get; set; }
|
private bool IsHeadRequest { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="StreamWriter" /> class.
|
/// Initializes a new instance of the <see cref="StreamWriter" /> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="requestHeaders">The request headers.</param>
|
/// <param name="rangeHeader">The range header.</param>
|
||||||
/// <param name="response">The response.</param>
|
/// <param name="response">The response.</param>
|
||||||
/// <param name="source">The source.</param>
|
/// <param name="source">The source.</param>
|
||||||
/// <param name="isHeadRequest">if set to <c>true</c> [is head request].</param>
|
/// <param name="isHeadRequest">if set to <c>true</c> [is head request].</param>
|
||||||
public RangeRequestWriter(NameValueCollection requestHeaders, HttpListenerResponse response, Stream source, bool isHeadRequest)
|
public RangeRequestWriter(string rangeHeader, HttpListenerResponse response, Stream source, bool isHeadRequest)
|
||||||
{
|
{
|
||||||
RequestHeaders = requestHeaders;
|
RangeHeader = rangeHeader;
|
||||||
Response = response;
|
Response = response;
|
||||||
SourceStream = source;
|
SourceStream = source;
|
||||||
IsHeadRequest = isHeadRequest;
|
IsHeadRequest = isHeadRequest;
|
||||||
|
@ -52,7 +51,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer
|
||||||
_requestedRanges = new List<KeyValuePair<long, long?>>();
|
_requestedRanges = new List<KeyValuePair<long, long?>>();
|
||||||
|
|
||||||
// Example: bytes=0-,32-63
|
// Example: bytes=0-,32-63
|
||||||
var ranges = RequestHeaders["Range"].Split('=')[1].Split(',');
|
var ranges = RangeHeader.Split('=')[1].Split(',');
|
||||||
|
|
||||||
foreach (var range in ranges)
|
foreach (var range in ranges)
|
||||||
{
|
{
|
||||||
|
|
|
@ -404,6 +404,9 @@ xcopy "$(TargetDir)x86" "$(SolutionDir)..\Deploy\Server\System\x86" /y
|
||||||
mkdir "$(SolutionDir)..\Deploy\Server\System\CorePlugins"
|
mkdir "$(SolutionDir)..\Deploy\Server\System\CorePlugins"
|
||||||
xcopy "$(TargetDir)CorePlugins" "$(SolutionDir)..\Deploy\Server\System\CorePlugins" /y
|
xcopy "$(TargetDir)CorePlugins" "$(SolutionDir)..\Deploy\Server\System\CorePlugins" /y
|
||||||
|
|
||||||
|
mkdir "$(SolutionDir)..\Deploy\Server\System\dashboard-ui"
|
||||||
|
xcopy "$(TargetDir)dashboard-ui" "$(SolutionDir)..\Deploy\Server\System\dashboard-ui" /y
|
||||||
|
|
||||||
del "$(SolutionDir)..\Deploy\MBServer.zip"
|
del "$(SolutionDir)..\Deploy\MBServer.zip"
|
||||||
"$(SolutionDir)ThirdParty\7zip\7za" a -tzip "$(SolutionDir)..\Deploy\MBServer.zip" "$(SolutionDir)..\Deploy\Server\*"
|
"$(SolutionDir)ThirdParty\7zip\7za" a -tzip "$(SolutionDir)..\Deploy\MBServer.zip" "$(SolutionDir)..\Deploy\Server\*"
|
||||||
)</PostBuildEvent>
|
)</PostBuildEvent>
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
using System.Reflection;
|
using System.Diagnostics;
|
||||||
using MediaBrowser.Common.Extensions;
|
using MediaBrowser.Common.Extensions;
|
||||||
|
using MediaBrowser.Common.IO;
|
||||||
using MediaBrowser.Common.Net;
|
using MediaBrowser.Common.Net;
|
||||||
using MediaBrowser.Common.ScheduledTasks;
|
using MediaBrowser.Common.ScheduledTasks;
|
||||||
using MediaBrowser.Controller;
|
using MediaBrowser.Controller;
|
||||||
|
using MediaBrowser.Controller.Configuration;
|
||||||
using MediaBrowser.Controller.Library;
|
using MediaBrowser.Controller.Library;
|
||||||
using MediaBrowser.Controller.Plugins;
|
using MediaBrowser.Controller.Plugins;
|
||||||
using MediaBrowser.Model.Logging;
|
using MediaBrowser.Model.Logging;
|
||||||
|
@ -14,7 +16,7 @@ using System.Collections.Generic;
|
||||||
using System.ComponentModel.Composition;
|
using System.ComponentModel.Composition;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net;
|
using System.Reflection;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
@ -90,20 +92,31 @@ namespace MediaBrowser.WebDashboard.Api
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private readonly IUserManager _userManager;
|
private readonly IUserManager _userManager;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The _app host
|
||||||
|
/// </summary>
|
||||||
private readonly IServerApplicationHost _appHost;
|
private readonly IServerApplicationHost _appHost;
|
||||||
|
/// <summary>
|
||||||
|
/// The _library manager
|
||||||
|
/// </summary>
|
||||||
private readonly ILibraryManager _libraryManager;
|
private readonly ILibraryManager _libraryManager;
|
||||||
|
|
||||||
|
private readonly IServerConfigurationManager _serverConfigurationManager;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="DashboardService" /> class.
|
/// Initializes a new instance of the <see cref="DashboardService" /> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="taskManager">The task manager.</param>
|
/// <param name="taskManager">The task manager.</param>
|
||||||
/// <param name="userManager">The user manager.</param>
|
/// <param name="userManager">The user manager.</param>
|
||||||
public DashboardService(ITaskManager taskManager, IUserManager userManager, IServerApplicationHost appHost, ILibraryManager libraryManager)
|
/// <param name="appHost">The app host.</param>
|
||||||
|
/// <param name="libraryManager">The library manager.</param>
|
||||||
|
public DashboardService(ITaskManager taskManager, IUserManager userManager, IServerApplicationHost appHost, ILibraryManager libraryManager, IServerConfigurationManager serverConfigurationManager)
|
||||||
{
|
{
|
||||||
_taskManager = taskManager;
|
_taskManager = taskManager;
|
||||||
_userManager = userManager;
|
_userManager = userManager;
|
||||||
_appHost = appHost;
|
_appHost = appHost;
|
||||||
_libraryManager = libraryManager;
|
_libraryManager = libraryManager;
|
||||||
|
_serverConfigurationManager = serverConfigurationManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -119,9 +132,11 @@ namespace MediaBrowser.WebDashboard.Api
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the dashboard info.
|
/// Gets the dashboard info.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="appHost">The app host.</param>
|
||||||
/// <param name="logger">The logger.</param>
|
/// <param name="logger">The logger.</param>
|
||||||
/// <param name="taskManager">The task manager.</param>
|
/// <param name="taskManager">The task manager.</param>
|
||||||
/// <param name="userManager">The user manager.</param>
|
/// <param name="userManager">The user manager.</param>
|
||||||
|
/// <param name="libraryManager">The library manager.</param>
|
||||||
/// <returns>DashboardInfo.</returns>
|
/// <returns>DashboardInfo.</returns>
|
||||||
public static async Task<DashboardInfo> GetDashboardInfo(IServerApplicationHost appHost, ILogger logger, ITaskManager taskManager, IUserManager userManager, ILibraryManager libraryManager)
|
public static async Task<DashboardInfo> GetDashboardInfo(IServerApplicationHost appHost, ILogger logger, ITaskManager taskManager, IUserManager userManager, ILibraryManager libraryManager)
|
||||||
{
|
{
|
||||||
|
@ -188,6 +203,14 @@ namespace MediaBrowser.WebDashboard.Api
|
||||||
|
|
||||||
var contentType = MimeTypes.GetMimeType(path);
|
var contentType = MimeTypes.GetMimeType(path);
|
||||||
|
|
||||||
|
// Don't cache if not configured to do so
|
||||||
|
// But always cache images to simulate production
|
||||||
|
if (!_serverConfigurationManager.Configuration.EnableDashboardResponseCaching && !contentType.StartsWith("image/", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
Response.ContentType = contentType;
|
||||||
|
return GetResourceStream(path).Result;
|
||||||
|
}
|
||||||
|
|
||||||
TimeSpan? cacheDuration = null;
|
TimeSpan? cacheDuration = null;
|
||||||
|
|
||||||
// Cache images unconditionally - updates to image files will require new filename
|
// Cache images unconditionally - updates to image files will require new filename
|
||||||
|
@ -199,7 +222,9 @@ namespace MediaBrowser.WebDashboard.Api
|
||||||
|
|
||||||
var assembly = GetType().Assembly.GetName();
|
var assembly = GetType().Assembly.GetName();
|
||||||
|
|
||||||
return ToStaticResult(assembly.Version.ToString().GetMD5(), null, cacheDuration, contentType, () => GetResourceStream(path));
|
var cacheKey = (assembly.Version + path).GetMD5();
|
||||||
|
|
||||||
|
return ToStaticResult(cacheKey, null, cacheDuration, contentType, () => GetResourceStream(path));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -217,7 +242,7 @@ namespace MediaBrowser.WebDashboard.Api
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
resourceStream = GetType().Assembly.GetManifestResourceStream("MediaBrowser.WebDashboard.Html." + ConvertUrlToResourcePath(path));
|
resourceStream = GetRawResourceStream(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (resourceStream != null)
|
if (resourceStream != null)
|
||||||
|
@ -236,32 +261,20 @@ namespace MediaBrowser.WebDashboard.Api
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Redirects the specified CTX.
|
/// Gets the raw resource stream.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="ctx">The CTX.</param>
|
/// <param name="path">The path.</param>
|
||||||
/// <param name="url">The URL.</param>
|
/// <returns>Task{Stream}.</returns>
|
||||||
private void Redirect(HttpListenerContext ctx, string url)
|
private Stream GetRawResourceStream(string path)
|
||||||
{
|
{
|
||||||
// Try to prevent the browser from caching the redirect response (the right way)
|
var runningDirectory = Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName);
|
||||||
ctx.Response.Headers[HttpResponseHeader.CacheControl] = "no-cache, no-store, must-revalidate";
|
|
||||||
ctx.Response.Headers[HttpResponseHeader.Pragma] = "no-cache, no-store, must-revalidate";
|
|
||||||
ctx.Response.Headers[HttpResponseHeader.Expires] = "-1";
|
|
||||||
|
|
||||||
ctx.Response.Redirect(url);
|
path = Path.Combine(runningDirectory, "dashboard-ui", path.Replace('/', '\\'));
|
||||||
ctx.Response.Close();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
return new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, StreamDefaults.DefaultFileStreamBufferSize, true);
|
||||||
/// Preserves the current query string when redirecting
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="request">The request.</param>
|
|
||||||
/// <param name="newUrl">The new URL.</param>
|
|
||||||
/// <returns>System.String.</returns>
|
|
||||||
private string GetRedirectUrl(HttpListenerRequest request, string newUrl)
|
|
||||||
{
|
|
||||||
var query = request.Url.Query;
|
|
||||||
|
|
||||||
return string.IsNullOrEmpty(query) ? newUrl : newUrl + query;
|
// This code is used when the files are embedded resources
|
||||||
|
//return GetType().Assembly.GetManifestResourceStream("MediaBrowser.WebDashboard.Html." + ConvertUrlToResourcePath(path));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -454,13 +467,21 @@ namespace MediaBrowser.WebDashboard.Api
|
||||||
|
|
||||||
foreach (var file in scriptFiles)
|
foreach (var file in scriptFiles)
|
||||||
{
|
{
|
||||||
await AppendResource(assembly, memoryStream, resourcePrefix + file, newLineBytes).ConfigureAwait(false);
|
await AppendResource(memoryStream, "scripts/" + file, newLineBytes).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
memoryStream.Position = 0;
|
memoryStream.Position = 0;
|
||||||
return memoryStream;
|
return memoryStream;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Appends the resource.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="assembly">The assembly.</param>
|
||||||
|
/// <param name="outputStream">The output stream.</param>
|
||||||
|
/// <param name="path">The path.</param>
|
||||||
|
/// <param name="newLineBytes">The new line bytes.</param>
|
||||||
|
/// <returns>Task.</returns>
|
||||||
private async Task AppendResource(Assembly assembly, Stream outputStream, string path, byte[] newLineBytes)
|
private async Task AppendResource(Assembly assembly, Stream outputStream, string path, byte[] newLineBytes)
|
||||||
{
|
{
|
||||||
using (var stream = assembly.GetManifestResourceStream(path))
|
using (var stream = assembly.GetManifestResourceStream(path))
|
||||||
|
@ -471,6 +492,22 @@ namespace MediaBrowser.WebDashboard.Api
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Appends the resource.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="outputStream">The output stream.</param>
|
||||||
|
/// <param name="path">The path.</param>
|
||||||
|
/// <param name="newLineBytes">The new line bytes.</param>
|
||||||
|
/// <returns>Task.</returns>
|
||||||
|
private async Task AppendResource(Stream outputStream, string path, byte[] newLineBytes)
|
||||||
|
{
|
||||||
|
using (var stream = GetRawResourceStream(path))
|
||||||
|
{
|
||||||
|
await stream.CopyToAsync(outputStream).ConfigureAwait(false);
|
||||||
|
|
||||||
|
await outputStream.WriteAsync(newLineBytes, 0, newLineBytes.Length).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
window.MediaBrowser = {};
|
window.MediaBrowser = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
MediaBrowser.ApiClient = function ($, navigator) {
|
MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new api client instance
|
* Creates a new api client instance
|
||||||
|
@ -15,8 +15,9 @@ MediaBrowser.ApiClient = function ($, navigator) {
|
||||||
|
|
||||||
var self = this;
|
var self = this;
|
||||||
var deviceName = "Web Browser";
|
var deviceName = "Web Browser";
|
||||||
var deviceId = SHA1(navigator.userAgent + (navigator.cpuClass || ""));
|
var deviceId = MediaBrowser.SHA1(navigator.userAgent + (navigator.cpuClass || ""));
|
||||||
var currentUserId;
|
var currentUserId;
|
||||||
|
var webSocket;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the server host name.
|
* Gets the server host name.
|
||||||
|
@ -88,6 +89,55 @@ MediaBrowser.ApiClient = function ($, navigator) {
|
||||||
return url;
|
return url;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
self.openWebSocket = function (port) {
|
||||||
|
|
||||||
|
var url = "ws://" + serverHostName + ":" + port + "/mediabrowser";
|
||||||
|
|
||||||
|
webSocket = new WebSocket(url);
|
||||||
|
|
||||||
|
webSocket.onmessage = function (msg) {
|
||||||
|
msg = JSON.parse(msg.data);
|
||||||
|
$(self).trigger("websocketmessage", [msg]);
|
||||||
|
};
|
||||||
|
|
||||||
|
webSocket.onopen = function () {
|
||||||
|
setTimeout(function () {
|
||||||
|
$(self).trigger("websocketopen");
|
||||||
|
}, 500);
|
||||||
|
};
|
||||||
|
webSocket.onerror = function () {
|
||||||
|
setTimeout(function () {
|
||||||
|
$(self).trigger("websocketerror");
|
||||||
|
}, 0);
|
||||||
|
};
|
||||||
|
webSocket.onclose = function () {
|
||||||
|
setTimeout(function () {
|
||||||
|
$(self).trigger("websocketclose");
|
||||||
|
}, 0);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
self.sendWebSocketMessage = function (name, data) {
|
||||||
|
|
||||||
|
var msg = { MessageType: name };
|
||||||
|
|
||||||
|
if (data) {
|
||||||
|
msg.Data = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
msg = JSON.stringify(msg);
|
||||||
|
|
||||||
|
webSocket.send(msg);
|
||||||
|
};
|
||||||
|
|
||||||
|
self.isWebSocketOpen = function () {
|
||||||
|
return webSocket && webSocket.readyState === WebSocket.OPEN;
|
||||||
|
};
|
||||||
|
|
||||||
|
self.isWebSocketOpenOrConnecting = function () {
|
||||||
|
return webSocket && (webSocket.readyState === WebSocket.OPEN || webSocket.readyState === WebSocket.CONNECTING);
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets an item from the server
|
* Gets an item from the server
|
||||||
* Omit itemId to get the root folder.
|
* Omit itemId to get the root folder.
|
||||||
|
@ -1184,7 +1234,7 @@ MediaBrowser.ApiClient = function ($, navigator) {
|
||||||
var url = self.getUrl("Users/" + userId + "/authenticate");
|
var url = self.getUrl("Users/" + userId + "/authenticate");
|
||||||
|
|
||||||
var postData = {
|
var postData = {
|
||||||
password: SHA1(password || "")
|
password: MediaBrowser.SHA1(password || "")
|
||||||
};
|
};
|
||||||
|
|
||||||
return self.ajax({
|
return self.ajax({
|
||||||
|
@ -1214,7 +1264,7 @@ MediaBrowser.ApiClient = function ($, navigator) {
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
postData.currentPassword = SHA1(currentPassword);
|
postData.currentPassword = MediaBrowser.SHA1(currentPassword);
|
||||||
|
|
||||||
if (newPassword) {
|
if (newPassword) {
|
||||||
postData.newPassword = newPassword;
|
postData.newPassword = newPassword;
|
||||||
|
@ -1523,7 +1573,7 @@ MediaBrowser.ApiClient = function ($, navigator) {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
}(jQuery, navigator);
|
}(jQuery, navigator, JSON, window.WebSocket, setTimeout);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides a friendly way to create an api client instance using information from the browser's current url
|
* Provides a friendly way to create an api client instance using information from the browser's current url
|
||||||
|
@ -1534,3 +1584,176 @@ MediaBrowser.ApiClient.create = function (clientName) {
|
||||||
|
|
||||||
return new MediaBrowser.ApiClient(loc.protocol, loc.hostname, loc.port, clientName);
|
return new MediaBrowser.ApiClient(loc.protocol, loc.hostname, loc.port, clientName);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Secure Hash Algorithm (SHA1)
|
||||||
|
* http://www.webtoolkit.info/
|
||||||
|
*
|
||||||
|
**/
|
||||||
|
MediaBrowser.SHA1 = function (msg) {
|
||||||
|
|
||||||
|
function rotate_left(n, s) {
|
||||||
|
var t4 = (n << s) | (n >>> (32 - s));
|
||||||
|
return t4;
|
||||||
|
};
|
||||||
|
|
||||||
|
function lsb_hex(val) {
|
||||||
|
var str = "";
|
||||||
|
var i;
|
||||||
|
var vh;
|
||||||
|
var vl;
|
||||||
|
|
||||||
|
for (i = 0; i <= 6; i += 2) {
|
||||||
|
vh = (val >>> (i * 4 + 4)) & 0x0f;
|
||||||
|
vl = (val >>> (i * 4)) & 0x0f;
|
||||||
|
str += vh.toString(16) + vl.toString(16);
|
||||||
|
}
|
||||||
|
return str;
|
||||||
|
};
|
||||||
|
|
||||||
|
function cvt_hex(val) {
|
||||||
|
var str = "";
|
||||||
|
var i;
|
||||||
|
var v;
|
||||||
|
|
||||||
|
for (i = 7; i >= 0; i--) {
|
||||||
|
v = (val >>> (i * 4)) & 0x0f;
|
||||||
|
str += v.toString(16);
|
||||||
|
}
|
||||||
|
return str;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
function Utf8Encode(string) {
|
||||||
|
string = string.replace(/\r\n/g, "\n");
|
||||||
|
var utftext = "";
|
||||||
|
|
||||||
|
for (var n = 0; n < string.length; n++) {
|
||||||
|
|
||||||
|
var c = string.charCodeAt(n);
|
||||||
|
|
||||||
|
if (c < 128) {
|
||||||
|
utftext += String.fromCharCode(c);
|
||||||
|
}
|
||||||
|
else if ((c > 127) && (c < 2048)) {
|
||||||
|
utftext += String.fromCharCode((c >> 6) | 192);
|
||||||
|
utftext += String.fromCharCode((c & 63) | 128);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
utftext += String.fromCharCode((c >> 12) | 224);
|
||||||
|
utftext += String.fromCharCode(((c >> 6) & 63) | 128);
|
||||||
|
utftext += String.fromCharCode((c & 63) | 128);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return utftext;
|
||||||
|
};
|
||||||
|
|
||||||
|
var blockstart;
|
||||||
|
var i, j;
|
||||||
|
var W = new Array(80);
|
||||||
|
var H0 = 0x67452301;
|
||||||
|
var H1 = 0xEFCDAB89;
|
||||||
|
var H2 = 0x98BADCFE;
|
||||||
|
var H3 = 0x10325476;
|
||||||
|
var H4 = 0xC3D2E1F0;
|
||||||
|
var A, B, C, D, E;
|
||||||
|
var temp;
|
||||||
|
|
||||||
|
msg = Utf8Encode(msg);
|
||||||
|
|
||||||
|
var msg_len = msg.length;
|
||||||
|
|
||||||
|
var word_array = new Array();
|
||||||
|
for (i = 0; i < msg_len - 3; i += 4) {
|
||||||
|
j = msg.charCodeAt(i) << 24 | msg.charCodeAt(i + 1) << 16 |
|
||||||
|
msg.charCodeAt(i + 2) << 8 | msg.charCodeAt(i + 3);
|
||||||
|
word_array.push(j);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (msg_len % 4) {
|
||||||
|
case 0:
|
||||||
|
i = 0x080000000;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
i = msg.charCodeAt(msg_len - 1) << 24 | 0x0800000;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
i = msg.charCodeAt(msg_len - 2) << 24 | msg.charCodeAt(msg_len - 1) << 16 | 0x08000;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 3:
|
||||||
|
i = msg.charCodeAt(msg_len - 3) << 24 | msg.charCodeAt(msg_len - 2) << 16 | msg.charCodeAt(msg_len - 1) << 8 | 0x80;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
word_array.push(i);
|
||||||
|
|
||||||
|
while ((word_array.length % 16) != 14) word_array.push(0);
|
||||||
|
|
||||||
|
word_array.push(msg_len >>> 29);
|
||||||
|
word_array.push((msg_len << 3) & 0x0ffffffff);
|
||||||
|
|
||||||
|
|
||||||
|
for (blockstart = 0; blockstart < word_array.length; blockstart += 16) {
|
||||||
|
|
||||||
|
for (i = 0; i < 16; i++) W[i] = word_array[blockstart + i];
|
||||||
|
for (i = 16; i <= 79; i++) W[i] = rotate_left(W[i - 3] ^ W[i - 8] ^ W[i - 14] ^ W[i - 16], 1);
|
||||||
|
|
||||||
|
A = H0;
|
||||||
|
B = H1;
|
||||||
|
C = H2;
|
||||||
|
D = H3;
|
||||||
|
E = H4;
|
||||||
|
|
||||||
|
for (i = 0; i <= 19; i++) {
|
||||||
|
temp = (rotate_left(A, 5) + ((B & C) | (~B & D)) + E + W[i] + 0x5A827999) & 0x0ffffffff;
|
||||||
|
E = D;
|
||||||
|
D = C;
|
||||||
|
C = rotate_left(B, 30);
|
||||||
|
B = A;
|
||||||
|
A = temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 20; i <= 39; i++) {
|
||||||
|
temp = (rotate_left(A, 5) + (B ^ C ^ D) + E + W[i] + 0x6ED9EBA1) & 0x0ffffffff;
|
||||||
|
E = D;
|
||||||
|
D = C;
|
||||||
|
C = rotate_left(B, 30);
|
||||||
|
B = A;
|
||||||
|
A = temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 40; i <= 59; i++) {
|
||||||
|
temp = (rotate_left(A, 5) + ((B & C) | (B & D) | (C & D)) + E + W[i] + 0x8F1BBCDC) & 0x0ffffffff;
|
||||||
|
E = D;
|
||||||
|
D = C;
|
||||||
|
C = rotate_left(B, 30);
|
||||||
|
B = A;
|
||||||
|
A = temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 60; i <= 79; i++) {
|
||||||
|
temp = (rotate_left(A, 5) + (B ^ C ^ D) + E + W[i] + 0xCA62C1D6) & 0x0ffffffff;
|
||||||
|
E = D;
|
||||||
|
D = C;
|
||||||
|
C = rotate_left(B, 30);
|
||||||
|
B = A;
|
||||||
|
A = temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
H0 = (H0 + A) & 0x0ffffffff;
|
||||||
|
H1 = (H1 + B) & 0x0ffffffff;
|
||||||
|
H2 = (H2 + C) & 0x0ffffffff;
|
||||||
|
H3 = (H3 + D) & 0x0ffffffff;
|
||||||
|
H4 = (H4 + E) & 0x0ffffffff;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
var temp = cvt_hex(H0) + cvt_hex(H1) + cvt_hex(H2) + cvt_hex(H3) + cvt_hex(H4);
|
||||||
|
|
||||||
|
return temp.toLowerCase();
|
||||||
|
};
|
|
@ -1,4 +0,0 @@
|
||||||
All static files such as html, images, etc, need to be marked as embedded resources.
|
|
||||||
|
|
||||||
Here is a link for more information regarding the Build Action property.
|
|
||||||
http://msdn.microsoft.com/en-us/library/0c6xyb66.aspx
|
|
|
@ -1,36 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title>About</title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="aboutPage" data-role="page" class="page type-interior">
|
|
||||||
|
|
||||||
<div data-role="content">
|
|
||||||
<div class="content-primary">
|
|
||||||
<div class="readOnlyContent">
|
|
||||||
<div data-role="controlgroup" data-type="horizontal" class="localnav" data-mini="true">
|
|
||||||
<a href="support.html" data-role="button">General</a>
|
|
||||||
<a href="log.html" data-role="button">View Log</a>
|
|
||||||
<a href="supporter.html" data-role="button">Become a Supporter</a>
|
|
||||||
<a href="supporterKey.html" data-role="button">Supporter Key</a>
|
|
||||||
<a href="about.html" data-role="button" class="ui-btn-active">About</a>
|
|
||||||
</div>
|
|
||||||
<p>
|
|
||||||
<img class="imgLogoIcon" src="css/images/mblogoicon.png" /><img class="imgLogoText" src="css/images/mblogotextblack.png" />
|
|
||||||
<br />
|
|
||||||
<br />
|
|
||||||
Version <span id="appVersionNumber"></span>
|
|
||||||
</p>
|
|
||||||
<hr/>
|
|
||||||
<br/>
|
|
||||||
<br/>
|
|
||||||
<p>
|
|
||||||
Utilizing <a href="http://www.pismotechnic.com/pfm/" target="_blank">Pismo File Mount</a> through a donated license.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
|
@ -1,83 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title></title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="addPluginPage" data-role="page" class="page type-interior pluginConfigurationPage">
|
|
||||||
|
|
||||||
<div data-role="content">
|
|
||||||
<div class="content-primary">
|
|
||||||
<p>
|
|
||||||
<a data-role="button" data-icon="arrow-left" data-inline="true" data-mini="true" data-theme="b" href="pluginCatalog.html">Plugin Catalog</a>
|
|
||||||
</p>
|
|
||||||
<form id="addPluginForm">
|
|
||||||
<p id="tagline" style="font-style: italic;"></p>
|
|
||||||
<p id="pPreviewImage" style="text-align: center; margin: 2em 0;"></p>
|
|
||||||
|
|
||||||
<p id="overview"></p>
|
|
||||||
|
|
||||||
<div data-role="collapsible" data-content-theme="c" data-collapsed="false" style="margin-top: 2em;" data-theme="a">
|
|
||||||
<h3>Install</h3>
|
|
||||||
<p id="pCurrentVersion">
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<label for="selectVersion">Select version to install:</label>
|
|
||||||
<select id="selectVersion" name="selectVersion"></select>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
<button id="btnInstall" type="submit" data-icon="download" data-theme="b">Install</button>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
|
|
||||||
<form name="_xclick" target="_blank" action="https://www.paypal.com/cgi-bin/webscr" method="post">
|
|
||||||
<div class="premiumPackage" data-role="collapsible" data-content-theme="c" data-collapsed="false" style="margin-top: 2em; display: none" data-theme="a">
|
|
||||||
<h3>Registration</h3>
|
|
||||||
<p id="regStatus">
|
|
||||||
</p>
|
|
||||||
<p id="regInfo">
|
|
||||||
</p>
|
|
||||||
<div class="premiumHasPrice" style="display: none">
|
|
||||||
<p id="regPrice">
|
|
||||||
</p>
|
|
||||||
<input type="hidden" name="cmd" value="_xclick">
|
|
||||||
<input type="hidden" id="payPalEmail" name="business" value="mb_1358534950_biz@reedsplace.com">
|
|
||||||
<input type="hidden" name="currency_code" value="USD">
|
|
||||||
<input type="hidden" id="featureName" name="item_name" value="MBSupporter">
|
|
||||||
<input type="hidden" id="amount" name="amount" value="10">
|
|
||||||
<input type="hidden" id="featureId" name="item_number" value="MBSupporter">
|
|
||||||
<input type="hidden" name="notify_url" value="http://mb3admin.com/admin/service/services/ppipn.php">
|
|
||||||
<input type="hidden" name="return" id ="paypalReturnUrl" value="#">
|
|
||||||
<a data-role="button" id="ppButton" onclick="_xclick.submit();"><img src="css/images/registerpp.png"/></a>
|
|
||||||
<p id="noEmail" style="display: none"><strong>This developer has not provided a PayPal email. Please see their
|
|
||||||
website for registration information.</strong>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div data-role="collapsible" data-content-theme="c" data-collapsed="false" style="margin-top: 2em;" data-theme="a">
|
|
||||||
<h3>Developer Info</h3>
|
|
||||||
<p id="developer"></p>
|
|
||||||
<p id="pViewWebsite" style="display: none;">
|
|
||||||
<a href="#" data-rel="external" target="_blank">View Website</a>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div data-role="collapsible" data-content-theme="c" style="margin-top: 2em;" data-theme="a">
|
|
||||||
<h3>Revision History</h3>
|
|
||||||
<div id="revisionHistory"></div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<script type="text/javascript">
|
|
||||||
$('#addPluginForm').on('submit', AddPluginPage.onSubmit);
|
|
||||||
</script>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
|
@ -1,64 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title>Advanced</title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="advancedConfigurationPage" data-role="page" class="page type-interior">
|
|
||||||
|
|
||||||
<div data-role="content">
|
|
||||||
<div class="content-primary">
|
|
||||||
<form id="advancedConfigurationForm">
|
|
||||||
|
|
||||||
<ul data-role="listview" class="ulForm">
|
|
||||||
<li>
|
|
||||||
<input type="checkbox" id="chkRunAtStartup" name="chkRunAtStartup" />
|
|
||||||
<label for="chkRunAtStartup">Run server at startup</label>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<label for="selectAutomaticUpdateLevel">Automatic update level</label>
|
|
||||||
<select name="selectAutomaticUpdateLevel" id="selectAutomaticUpdateLevel">
|
|
||||||
<option value="Release">Official Release</option>
|
|
||||||
<option value="Beta">Beta</option>
|
|
||||||
<option value="Dev">Dev</option>
|
|
||||||
</select>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<label for="txtPortNumber">Http server port number: </label>
|
|
||||||
<input type="number" id="txtPortNumber" name="txtPortNumber" pattern="[0-9]*" required="required" min="1" />
|
|
||||||
</li>
|
|
||||||
<li id="fldWebSocketPortNumber" style="display: none;">
|
|
||||||
<label for="txtWebSocketPortNumber">Web socket port number: </label>
|
|
||||||
<input type="number" id="txtWebSocketPortNumber" name="txtWebSocketPortNumber" pattern="[0-9]*" required="required" min="1" />
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<input type="checkbox" id="chkEnableDeveloperTools" name="chkEnableDeveloperTools" />
|
|
||||||
<label for="chkEnableDeveloperTools">Enable developer tools</label>
|
|
||||||
<div class="fieldDescription">
|
|
||||||
When enabled, developer tools will be available from the system tray.
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<input type="checkbox" id="chkDebugLog" name="chkDebugLog" />
|
|
||||||
<label for="chkDebugLog">Enable debug logging </label>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<button type="submit" data-theme="b" data-icon="ok">
|
|
||||||
Save
|
|
||||||
</button>
|
|
||||||
<button type="button" onclick="Dashboard.navigate('dashboard.html');" data-icon="delete">
|
|
||||||
Cancel
|
|
||||||
</button>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script type="text/javascript">
|
|
||||||
$('#advancedConfigurationForm').on('submit', AdvancedConfigurationPage.onSubmit);
|
|
||||||
</script>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
|
@ -1,40 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title>Metadata</title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="advancedMetadataConfigurationPage" data-role="page" class="page type-interior">
|
|
||||||
|
|
||||||
<div data-role="content">
|
|
||||||
|
|
||||||
<div class="content-primary">
|
|
||||||
<div data-role="controlgroup" data-type="horizontal" class="localnav" data-mini="true">
|
|
||||||
<a href="metadata.html" data-role="button">Basics</a>
|
|
||||||
<a href="metadataImages.html" data-role="button">Images</a>
|
|
||||||
<a href="advancedMetadata.html" data-role="button" class="ui-btn-active">Advanced</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<form id="advancedMetadataConfigurationForm">
|
|
||||||
<ul data-role="listview" class="ulForm">
|
|
||||||
<li>
|
|
||||||
<label>Disable internet providers for:</label>
|
|
||||||
<div id="divItemTypes"></div>
|
|
||||||
</li>
|
|
||||||
<li style="display: none;">
|
|
||||||
<button class="btnSubmit" type="submit" data-theme="b">
|
|
||||||
Save
|
|
||||||
</button>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script type="text/javascript">
|
|
||||||
$('#advancedMetadataConfigurationForm').on('submit', AdvancedMetadataConfigurationPage.onSubmit);
|
|
||||||
</script>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
Before Width: | Height: | Size: 2.9 KiB |
Before Width: | Height: | Size: 7.9 KiB |
Before Width: | Height: | Size: 2.7 KiB |
Before Width: | Height: | Size: 7.6 KiB |
Before Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 5.6 KiB |
Before Width: | Height: | Size: 26 KiB |
Before Width: | Height: | Size: 40 KiB |
Before Width: | Height: | Size: 390 KiB |
Before Width: | Height: | Size: 6.2 KiB |
Before Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 8.7 KiB |
Before Width: | Height: | Size: 2.6 KiB |
Before Width: | Height: | Size: 2.6 KiB |
Before Width: | Height: | Size: 3.6 KiB |
Before Width: | Height: | Size: 6.3 KiB |
Before Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 19 KiB |
Before Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 9.5 KiB |
Before Width: | Height: | Size: 6.1 KiB |
Before Width: | Height: | Size: 4.2 KiB |
Before Width: | Height: | Size: 4.0 KiB |
Before Width: | Height: | Size: 46 KiB |
Before Width: | Height: | Size: 23 KiB |
Before Width: | Height: | Size: 23 KiB |
Before Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 459 B |
Before Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 3.9 KiB |
Before Width: | Height: | Size: 2.0 KiB |
Before Width: | Height: | Size: 419 B |
Before Width: | Height: | Size: 2.7 KiB |
Before Width: | Height: | Size: 4.6 KiB |
Before Width: | Height: | Size: 916 B |
Before Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 4.2 KiB |
Before Width: | Height: | Size: 6.1 KiB |
Before Width: | Height: | Size: 2.3 KiB |
Before Width: | Height: | Size: 6.5 KiB |
Before Width: | Height: | Size: 4.2 KiB |
Before Width: | Height: | Size: 4.9 KiB |
Before Width: | Height: | Size: 9.2 KiB |
Before Width: | Height: | Size: 2.0 KiB |
Before Width: | Height: | Size: 3.4 KiB |
Before Width: | Height: | Size: 3.4 KiB |
Before Width: | Height: | Size: 4.6 KiB |
Before Width: | Height: | Size: 6.7 KiB |
Before Width: | Height: | Size: 5.1 KiB |
Before Width: | Height: | Size: 4.3 KiB |
|
@ -1,57 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title>Dashboard</title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="dashboardPage" data-role="page" class="page type-interior">
|
|
||||||
|
|
||||||
<div data-role="content">
|
|
||||||
<div class="content-primary">
|
|
||||||
<div class="readOnlyContent">
|
|
||||||
<div data-role="collapsible" data-content-theme="c" data-collapsed="false" style="margin-top: 2em;">
|
|
||||||
<h3>Server Information</h3>
|
|
||||||
<div>
|
|
||||||
<p>
|
|
||||||
Version <span id="appVersionNumber"></span>
|
|
||||||
</p>
|
|
||||||
<p id="pUpToDate" style="display: none;">
|
|
||||||
<img src="css/images/checkMarkGreen.png" style="height: 20px; margin-right: 3px; position: relative; top: 4px;" />
|
|
||||||
Media Browser Server is up to date
|
|
||||||
</p>
|
|
||||||
<div id="pUpdateNow" style="display: none;">
|
|
||||||
<p><strong>A new version of Media Browser Server is available!</strong></p>
|
|
||||||
<p id="newVersionNumber"></p>
|
|
||||||
<button id="btnUpdateApplication" type="button" data-icon="download" data-theme="b" onclick="DashboardPage.updateApplication();">Update Now</button>
|
|
||||||
</div>
|
|
||||||
<div id="pPluginUpdates"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="collapsiblePendingInstallations" data-role="collapsible" data-content-theme="c" data-collapsed="false" style="margin-top: 2em; display: none;">
|
|
||||||
<h3>Pending Installations</h3>
|
|
||||||
<p>The following components have been installed or updated:</p>
|
|
||||||
<div id="pendingInstallations">
|
|
||||||
</div>
|
|
||||||
<p>Please restart the server to finish applying updates.</p>
|
|
||||||
<button type="button" data-icon="refresh" data-theme="b" onclick="Dashboard.restartServer();">Restart Now</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div data-role="collapsible" data-content-theme="c" data-collapsed="false" style="margin-top: 2em;">
|
|
||||||
<h3>Active Users</h3>
|
|
||||||
<div id="divConnections">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div data-role="collapsible" data-content-theme="c" data-collapsed="false" style="margin-top: 2em;">
|
|
||||||
<h3>Running Tasks</h3>
|
|
||||||
<div id="divRunningTasks">
|
|
||||||
</div>
|
|
||||||
<p><a href="scheduledTasks.html">Manage Scheduled Tasks</a></p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
|
@ -1,63 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title></title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="editUserPage" data-role="page" class="page type-interior userProfilesConfigurationPage">
|
|
||||||
|
|
||||||
<div data-role="content">
|
|
||||||
<div class="content-primary">
|
|
||||||
<div data-role="controlgroup" data-type="horizontal" class="localnav" id="userProfileNavigation" style="display: none;" data-mini="true">
|
|
||||||
<a href="#" data-role="button" class="ui-btn-active">Profile</a>
|
|
||||||
<a href="#" data-role="button" onclick="Dashboard.navigate('userImage.html', true);">Image</a>
|
|
||||||
<a href="#" data-role="button" onclick="Dashboard.navigate('updatePassword.html', true);">Password</a>
|
|
||||||
<a href="#" data-role="button" onclick="Dashboard.navigate('library.html', true);">Media Library</a>
|
|
||||||
</div>
|
|
||||||
<form id="editUserProfileForm">
|
|
||||||
<ul data-role="listview" class="ulForm">
|
|
||||||
<li id="fldUserName">
|
|
||||||
<label for="txtUserName">Name: </label>
|
|
||||||
<input id="txtUserName" name="txtUserName" required="required" type="text" />
|
|
||||||
</li>
|
|
||||||
<li id="fldMaxParentalRating" style="display: none;">
|
|
||||||
<label for="selectMaxParentalRating">Max parental rating:</label>
|
|
||||||
<select name="selectMaxParentalRating" id="selectMaxParentalRating"></select>
|
|
||||||
</li>
|
|
||||||
<li id="fldIsAdmin" style="display: none;">
|
|
||||||
<input type="checkbox" id="chkIsAdmin" name="chkIsAdmin" />
|
|
||||||
<label for="chkIsAdmin">Allow this user to manage the server</label>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
<h2>Video Playback Settings</h2>
|
|
||||||
<ul data-role="listview" class="ulForm">
|
|
||||||
<li>
|
|
||||||
<label for="selectAudioLanguage">Audio language preference: </label>
|
|
||||||
<select name="selectAudioLanguage" id="selectAudioLanguage"></select>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<label for="selectSubtitleLanguage">Subtitle language preference: </label>
|
|
||||||
<select name="selectSubtitleLanguage" id="selectSubtitleLanguage"></select>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<input type="checkbox" id="chkForcedSubtitlesOnly" name="chkForcedSubtitlesOnly" />
|
|
||||||
<label for="chkForcedSubtitlesOnly">Display only forced subtitles</label>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<button type="submit" data-theme="b" data-icon="ok">
|
|
||||||
Save
|
|
||||||
</button>
|
|
||||||
<button type="button" onclick="history.back();" data-icon="delete">
|
|
||||||
Cancel
|
|
||||||
</button>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<script type="text/javascript">
|
|
||||||
$('#editUserProfileForm').on('submit', EditUserPage.onSubmit);
|
|
||||||
</script>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
Before Width: | Height: | Size: 143 KiB |
|
@ -1,33 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title>Media Browser</title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="indexPage" data-role="page" class="page type-home libraryPage" data-theme="a">
|
|
||||||
<div data-role="content">
|
|
||||||
<h1>What's New <a href="#" class="imageLink">
|
|
||||||
<img src="css/images/rightArrow.png" /></a></h1>
|
|
||||||
|
|
||||||
<div id="divWhatsNew"></div>
|
|
||||||
|
|
||||||
<div id="divResumable" style="display: none;">
|
|
||||||
<h1>Resume <a href="#" class="imageLink">
|
|
||||||
<img src="css/images/rightArrow.png" /></a></h1>
|
|
||||||
|
|
||||||
<div id="divResumableItems"></div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h1>My Library <a href="#" class="imageLink">
|
|
||||||
<img src="css/images/rightArrow.png" /></a></h1>
|
|
||||||
|
|
||||||
<div id="divMyLibrary"></div>
|
|
||||||
|
|
||||||
<h1>Collections <a href="#" class="imageLink">
|
|
||||||
<img src="css/images/rightArrow.png" /></a></h1>
|
|
||||||
|
|
||||||
<div id="divCollections"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
|
@ -1,66 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title></title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="itemDetailPage" data-role="page" class="page libraryPage" data-theme="a">
|
|
||||||
<div data-role="content" style="padding-top: 0;">
|
|
||||||
|
|
||||||
<h1 id="itemName" style="padding-left: 10px; margin: 0;"></h1>
|
|
||||||
|
|
||||||
<div style="padding: 10px;">
|
|
||||||
<div class="itemImageBlock">
|
|
||||||
<div id="itemMedia" style="position: relative;">
|
|
||||||
<div id="itemImage"></div>
|
|
||||||
<div id="playButtonShadow" style="display: none; height: 48px; position: absolute; bottom: 0; left: 0; right: 0; background: black; opacity: .75;">
|
|
||||||
</div>
|
|
||||||
<button id="btnPlay" type="button" class="imageButton" style="display: none; position: absolute; bottom: 5px; left: 10px;" data-role="none" title="Play" onclick="ItemDetailPage.play();">
|
|
||||||
<img src="css/images/media/playCircle.png" style="height: 28px;" />
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="itemDetailBlock">
|
|
||||||
|
|
||||||
<p id="itemTagline" style="font-style: italic;"></p>
|
|
||||||
<p id="itemOverview"></p>
|
|
||||||
<p id="itemCommunityRating"></p>
|
|
||||||
<p id="itemMiscInfo" style="color: #ddd; font-size: 14px;"></p>
|
|
||||||
|
|
||||||
<p id="itemGenres">
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p id="itemStudios">
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div data-role="collapsible" data-content-theme="a" id="mediaInfoCollapsible">
|
|
||||||
<h3>Media Info</h3>
|
|
||||||
<div id="mediaInfoContent"></div>
|
|
||||||
</div>
|
|
||||||
<div data-role="collapsible" data-content-theme="a" id="scenesCollapsible">
|
|
||||||
<h3>Scenes</h3>
|
|
||||||
<div id="scenesContent"></div>
|
|
||||||
</div>
|
|
||||||
<div data-role="collapsible" data-content-theme="a">
|
|
||||||
<h3>Special Features</h3>
|
|
||||||
<p>I'm the collapsible content. By default I'm closed, but you can click the header to open me.</p>
|
|
||||||
</div>
|
|
||||||
<div data-role="collapsible" data-content-theme="a">
|
|
||||||
<h3>Trailers</h3>
|
|
||||||
<p>I'm the collapsible content. By default I'm closed, but you can click the header to open me.</p>
|
|
||||||
</div>
|
|
||||||
<div data-role="collapsible" data-content-theme="a">
|
|
||||||
<h3>Cast & Crew</h3>
|
|
||||||
<p>I'm the collapsible content. By default I'm closed, but you can click the header to open me.</p>
|
|
||||||
</div>
|
|
||||||
<div data-role="collapsible" data-content-theme="a" id="galleryCollapsible">
|
|
||||||
<h3>Gallery</h3>
|
|
||||||
<div id="galleryContent"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
|
@ -1,23 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title></title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="itemListPage" data-role="page" class="page libraryPage" data-theme="a">
|
|
||||||
<div data-role="content" class="itemListContent">
|
|
||||||
<div style="text-align: right;">
|
|
||||||
<button type="button" onclick="$( '#optionsPanel', $.mobile.activePage ).panel( 'open' );" data-mini="true" data-inline="true">Options</button>
|
|
||||||
</div>
|
|
||||||
<h1 id="itemName" class="listHeader"></h1>
|
|
||||||
|
|
||||||
|
|
||||||
<div id="listItems"></div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div data-role="panel" id="optionsPanel" data-position="right" data-display="overlay" data-position-fixed="true" data-theme="a">
|
|
||||||
<div>Panel content</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
|
@ -1,57 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title> </title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="mediaLibraryPage" data-role="page" class="page type-interior mediaLibraryPage">
|
|
||||||
|
|
||||||
<div data-role="content">
|
|
||||||
<div class="content-primary">
|
|
||||||
<div data-role="controlgroup" data-type="horizontal" class="localnav" id="userProfileNavigation" style="display: none;" data-mini="true">
|
|
||||||
<a href="#" data-role="button" onclick="Dashboard.navigate('editUser.html', true);">Profile</a>
|
|
||||||
<a href="#" data-role="button" onclick="Dashboard.navigate('userImage.html', true);">Image</a>
|
|
||||||
<a href="#" data-role="button" onclick="Dashboard.navigate('updatePassword.html', true);">Password</a>
|
|
||||||
<a href="#" data-role="button" class="ui-btn-active">Media Library</a>
|
|
||||||
</div>
|
|
||||||
<div class="readOnlyContent">
|
|
||||||
<p id="fldUseDefaultLibrary" style="display: none;">
|
|
||||||
<input type="checkbox" id="chkUseDefaultLibrary" name="chkUseDefaultLibrary" onchange="MediaLibraryPage.setUseDefaultMediaLibrary(this.checked);" />
|
|
||||||
<label for="chkUseDefaultLibrary">Use default media library</label>
|
|
||||||
</p>
|
|
||||||
<div id="divMediaLibrary">
|
|
||||||
<p>Below are your media collections. Expand a collection to add or remove media locations assigned to it.</p>
|
|
||||||
<p>
|
|
||||||
<button type="button" data-icon="plus" onclick="MediaLibraryPage.addVirtualFolder();">Add media collection</button>
|
|
||||||
</p>
|
|
||||||
<div id="divVirtualFolders"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div data-role="popup" id="popupEnterText" class="ui-corner-all popup">
|
|
||||||
|
|
||||||
<div class="ui-corner-top ui-bar-a" style="text-align: center; padding: 0 20px;">
|
|
||||||
<h3>Rename</h3>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div data-role="content" class="ui-corner-bottom ui-content">
|
|
||||||
<form id="textEntryForm">
|
|
||||||
<label for="txtValue">New name:</label>
|
|
||||||
<input type="text" name="txtValue" id="txtValue" required="required" />
|
|
||||||
|
|
||||||
<p>
|
|
||||||
<button type="submit" data-theme="b" data-icon="ok">
|
|
||||||
Ok
|
|
||||||
</button>
|
|
||||||
<button type="button" data-icon="delete" onclick="$(this).parents('.popup').popup('close');">
|
|
||||||
Cancel
|
|
||||||
</button>
|
|
||||||
</p>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
|
@ -1,31 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title>Log File</title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="logPage" data-role="page" class="page type-interior">
|
|
||||||
|
|
||||||
<div data-role="content">
|
|
||||||
<div class="content-primary">
|
|
||||||
<div data-role="controlgroup" data-type="horizontal" class="localnav" data-mini="true">
|
|
||||||
<a href="support.html" data-role="button">General</a>
|
|
||||||
<a href="log.html" data-role="button" class="ui-btn-active">View Log</a>
|
|
||||||
<a href="supporter.html" data-role="button">Become a Supporter</a>
|
|
||||||
<a href="supporterKey.html" data-role="button">Supporter Key</a>
|
|
||||||
<a href="about.html" data-role="button">About</a>
|
|
||||||
</div>
|
|
||||||
<p>
|
|
||||||
<label for="chkAutoScroll">Auto-scroll</label>
|
|
||||||
<input type="checkbox" id="chkAutoScroll" onchange="LogPage.updateAutoScroll(this.checked);" name="chkAutoScroll" data-inline="true" />
|
|
||||||
</p>
|
|
||||||
<textarea id="logContents" class="pre" style="overflow-y:hidden;"></textarea>
|
|
||||||
<p>
|
|
||||||
<label for="chkAutoScrollBottom">Auto-scroll</label>
|
|
||||||
<input type="checkbox" id="chkAutoScrollBottom" name="chkAutoScrollBottom" onchange="LogPage.updateAutoScroll(this.checked);" data-inline="true" />
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
|
@ -1,39 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title>Sign In</title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="loginPage" data-role="page" class="page standalonePage">
|
|
||||||
|
|
||||||
<div data-role="content">
|
|
||||||
<div id="divUsers" style="margin: 50px 0px 20px; text-align: center;"></div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div data-role="popup" id="popupLogin" class="ui-corner-all popup">
|
|
||||||
<form id="loginForm">
|
|
||||||
<div class="ui-corner-top ui-bar-a" style="text-align: center;">
|
|
||||||
<h3>Please sign in</h3>
|
|
||||||
</div>
|
|
||||||
<div data-role="content" class="ui-corner-bottom ui-content">
|
|
||||||
<label for="pw" class="ui-hidden-accessible">Password:</label>
|
|
||||||
<input type="password" name="pw" id="pw" value="" placeholder="password" />
|
|
||||||
|
|
||||||
<p>
|
|
||||||
<button type="submit" data-theme="b" data-icon="ok">
|
|
||||||
Sign in
|
|
||||||
</button>
|
|
||||||
<button type="button" data-icon="delete" onclick="$(this).parents('.popup').popup('close');">
|
|
||||||
Cancel
|
|
||||||
</button>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script type="text/javascript">
|
|
||||||
$('#loginForm').on('submit', LoginPage.onSubmit);
|
|
||||||
</script>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
|
@ -1,56 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title>Metadata</title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="metadataConfigurationPage" data-role="page" class="page type-interior">
|
|
||||||
|
|
||||||
<div data-role="content">
|
|
||||||
|
|
||||||
<div class="content-primary">
|
|
||||||
<div data-role="controlgroup" data-type="horizontal" class="localnav" data-mini="true">
|
|
||||||
<a href="metadata.html" data-role="button" class="ui-btn-active">Basics</a>
|
|
||||||
<a href="metadataImages.html" data-role="button">Images</a>
|
|
||||||
<a href="advancedMetadata.html" data-role="button">Advanced</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<form id="metadataConfigurationForm">
|
|
||||||
<ul data-role="listview" class="ulForm">
|
|
||||||
<li>
|
|
||||||
<input type="checkbox" id="chkEnableInternetProviders" name="chkEnableInternetProviders" onchange="MetadataConfigurationPage.submit();" />
|
|
||||||
<label for="chkEnableInternetProviders">Download metadata from the internet </label>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<input type="checkbox" id="chkSaveLocal" name="chkSaveLocal" onchange="MetadataConfigurationPage.submit();" />
|
|
||||||
<label for="chkSaveLocal">Save metadata within media folders </label>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<label for="txtRefreshDays">Metadata refresh period (days): </label>
|
|
||||||
<input type="number" id="txtRefreshDays" name="txtRefreshDays" pattern="[0-9]*" required="required" min="1" onchange="MetadataConfigurationPage.submit();" />
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<label for="selectLanguage">Preferred language: </label>
|
|
||||||
<select name="selectLanguage" id="selectLanguage" onchange="MetadataConfigurationPage.submit();"></select>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<label for="selectCountry">Country: </label>
|
|
||||||
<select name="selectCountry" id="selectCountry" onchange="MetadataConfigurationPage.submit();"></select>
|
|
||||||
</li>
|
|
||||||
<li style="display: none;">
|
|
||||||
<button class="btnSubmit" type="submit" data-theme="b">
|
|
||||||
Save
|
|
||||||
</button>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script type="text/javascript">
|
|
||||||
$('#metadataConfigurationForm').on('submit', MetadataConfigurationPage.onSubmit);
|
|
||||||
</script>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
|
@ -1,164 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title>Metadata</title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="metadataImagesConfigurationPage" data-role="page" class="page type-interior">
|
|
||||||
|
|
||||||
<div data-role="content">
|
|
||||||
|
|
||||||
<div class="content-primary">
|
|
||||||
<div data-role="controlgroup" data-type="horizontal" class="localnav" data-mini="true">
|
|
||||||
<a href="metadata.html" data-role="button">Basics</a>
|
|
||||||
<a href="metadataImages.html" data-role="button" class="ui-btn-active">Images</a>
|
|
||||||
<a href="advancedMetadata.html" data-role="button">Advanced</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<form id="metadataImagesConfigurationForm">
|
|
||||||
<ul data-role="listview" class="ulForm">
|
|
||||||
<li>
|
|
||||||
<input type="checkbox" id="chkRefreshItemImages" name="chkRefreshItemImages" onchange="MetadataImagesPage.submit();" />
|
|
||||||
<label for="chkRefreshItemImages">Refresh existing images </label>
|
|
||||||
<div class="fieldDescription">
|
|
||||||
When enabled, images will be refreshed periodically
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<label for="txtNumbackdrops">Max number of backdrops per item: </label>
|
|
||||||
<input type="number" id="txtNumbackdrops" name="txtNumbackdrops" pattern="[0-9]*" required="required" min="1" onchange="MetadataImagesPage.submit();" />
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
<p>Enable additional image downloading:</p>
|
|
||||||
<div data-role="collapsible">
|
|
||||||
<h3>Movies</h3>
|
|
||||||
<div data-role="controlgroup">
|
|
||||||
<input type="checkbox" data-mini="true" id="chkDownloadMovieArt" name="chkDownloadMovieArt" onchange="MetadataImagesPage.submit();" />
|
|
||||||
<label for="chkDownloadMovieArt">Movie Art</label>
|
|
||||||
|
|
||||||
<input type="checkbox" data-mini="true" id="chkDownloadMovieBanner" name="chkDownloadMovieBanner" onchange="MetadataImagesPage.submit();" />
|
|
||||||
<label for="chkDownloadMovieBanner">Movie Banner</label>
|
|
||||||
|
|
||||||
<input type="checkbox" data-mini="true" id="chkDownloadMovieDisc" name="chkDownloadMovieDisc" onchange="MetadataImagesPage.submit();" />
|
|
||||||
<label for="chkDownloadMovieDisc">Movie Disc</label>
|
|
||||||
|
|
||||||
<input type="checkbox" data-mini="true" id="chkDownloadMovieLogo" name="chkDownloadMovieLogo" onchange="MetadataImagesPage.submit();" />
|
|
||||||
<label for="chkDownloadMovieLogo">Movie Logo</label>
|
|
||||||
|
|
||||||
<input type="checkbox" data-mini="true" id="chkDownloadMovieThumb" name="chkDownloadMovieThumb" onchange="MetadataImagesPage.submit();" />
|
|
||||||
<label for="chkDownloadMovieThumb">Movie Thumb</label>
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div data-role="collapsible">
|
|
||||||
<h3>TV Series</h3>
|
|
||||||
<div data-role="controlgroup">
|
|
||||||
<input type="checkbox" data-mini="true" id="chKDownloadTVArt" name="chKDownloadTVArt" onchange="MetadataImagesPage.submit();" />
|
|
||||||
<label for="chKDownloadTVArt">TV Series Art</label>
|
|
||||||
|
|
||||||
<input type="checkbox" data-mini="true" id="chkDownloadTVBanner" name="chkDownloadTVBanner" onchange="MetadataImagesPage.submit();" />
|
|
||||||
<label for="chkDownloadTVBanner">TV Series Banner</label>
|
|
||||||
|
|
||||||
<input type="checkbox" data-mini="true" id="chkDownloadTVLogo" name="chkDownloadTVLogo" onchange="MetadataImagesPage.submit();" />
|
|
||||||
<label for="chkDownloadTVLogo">TV Series Logo</label>
|
|
||||||
|
|
||||||
<input type="checkbox" data-mini="true" id="chkDownloadTVThumb" name="chkDownloadTVThumb" onchange="MetadataImagesPage.submit();" />
|
|
||||||
<label for="chkDownloadTVThumb">TV Series Thumb</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
<div data-role="collapsible">
|
|
||||||
<h3>TV Seasons</h3>
|
|
||||||
<div data-role="controlgroup">
|
|
||||||
<input type="checkbox" data-mini="true" id="chkDownloadSeasonBackdrops" name="chkDownloadSeasonBackdrops" onchange="MetadataImagesPage.submit();" />
|
|
||||||
<label for="chkDownloadSeasonBackdrops">TV Season Backdrops</label>
|
|
||||||
|
|
||||||
<input type="checkbox" data-mini="true" id="chkDownloadSeasonBanner" name="chkDownloadSeasonBanner" onchange="MetadataImagesPage.submit();" />
|
|
||||||
<label for="chkDownloadSeasonBanner">TV Season Banner</label>
|
|
||||||
|
|
||||||
<input type="checkbox" data-mini="true" id="chkDownloadSeasonThumb" name="chkDownloadSeasonThumb" onchange="MetadataImagesPage.submit();" />
|
|
||||||
<label for="chkDownloadSeasonThumb">TV Season Thumb</label>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div data-role="collapsible">
|
|
||||||
<h3>Music Artists</h3>
|
|
||||||
<div data-role="controlgroup">
|
|
||||||
<input type="checkbox" data-mini="true" id="chkDownloadArtistThumb" name="chkDownloadArtistThumb" onchange="MetadataImagesPage.submit();" />
|
|
||||||
<label for="chkDownloadArtistThumb">Music Artist Thumb (primary image)</label>
|
|
||||||
|
|
||||||
<input type="checkbox" data-mini="true" id="chkDownloadArtistBackdrops" name="chkDownloadArtistBackdrops" onchange="MetadataImagesPage.submit();" />
|
|
||||||
<label for="chkDownloadArtistBackdrops">Music Artist Backdrops</label>
|
|
||||||
|
|
||||||
<input type="checkbox" data-mini="true" id="chkDownloadArtistLogo" name="chkDownloadArtistLogo" onchange="MetadataImagesPage.submit();" />
|
|
||||||
<label for="chkDownloadArtistLogo">Music Artist Logo</label>
|
|
||||||
|
|
||||||
<input type="checkbox" data-mini="true" id="chkDownloadArtistBanner" name="chkDownloadArtistBanner" onchange="MetadataImagesPage.submit();" />
|
|
||||||
<label for="chkDownloadArtistBanner">Music Artist Banner</label>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<div data-role="collapsible">
|
|
||||||
<h3>Music Albums</h3>
|
|
||||||
<div data-role="controlgroup">
|
|
||||||
<input type="checkbox" data-mini="true" id="chkDownloadAlbumPrimary" name="chkDownloadAlbumPrimary" onchange="MetadataImagesPage.submit();" />
|
|
||||||
<label for="chkDownloadAlbumPrimary">Music Album Cover</label>
|
|
||||||
|
|
||||||
<input type="checkbox" data-mini="true" id="chkDownloadAlbumBackdrops" name="chkDownloadAlbumBackdrops" onchange="MetadataImagesPage.submit();" />
|
|
||||||
<label for="chkDownloadAlbumBackdrops">Music Album Backdrops</label>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<br />
|
|
||||||
<br />
|
|
||||||
<ul data-role="listview" class="ulForm">
|
|
||||||
<li>
|
|
||||||
<label for="selectTmdbPosterDownloadSize">Tmdb poster download size: </label>
|
|
||||||
<select id="selectTmdbPosterDownloadSize" name="selectTmdbPosterDownloadSize" onchange="MetadataImagesPage.submit();">
|
|
||||||
<option value="original">original</option>
|
|
||||||
<option value="w92">w92</option>
|
|
||||||
<option value="w154">w154</option>
|
|
||||||
<option value="w185">w185</option>
|
|
||||||
<option value="w342">w342</option>
|
|
||||||
<option value="w500">w500</option>
|
|
||||||
</select>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<label for="selectTmdbBackdropDownloadSize">Tmdb backdrop download size: </label>
|
|
||||||
<select id="selectTmdbBackdropDownloadSize" name="selectTmdbBackdropDownloadSize" onchange="MetadataImagesPage.submit();">
|
|
||||||
<option value="original">original</option>
|
|
||||||
<option value="w380">w380</option>
|
|
||||||
<option value="w780">w780</option>
|
|
||||||
<option value="w1280">w1280</option>
|
|
||||||
</select>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<label for="selectTmdbPersonImageDownloadSize">Tmdb person image download size: </label>
|
|
||||||
<select id="selectTmdbPersonImageDownloadSize" name="selectTmdbPersonImageDownloadSize" onchange="MetadataImagesPage.submit();">
|
|
||||||
<option value="original">original</option>
|
|
||||||
<option value="w45">w45</option>
|
|
||||||
<option value="w185">w185</option>
|
|
||||||
<option value="h632">h632</option>
|
|
||||||
</select>
|
|
||||||
</li>
|
|
||||||
<li style="display: none;">
|
|
||||||
<button class="btnSubmit" type="submit" data-theme="b">
|
|
||||||
Save
|
|
||||||
</button>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script type="text/javascript">
|
|
||||||
$('#metadataImagesConfigurationForm').on('submit', MetadataImagesPage.onSubmit);
|
|
||||||
</script>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
|
@ -1,22 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title>Plugins</title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="pluginCatalogPage" data-role="page" class="page type-interior pluginConfigurationPage">
|
|
||||||
|
|
||||||
<div data-role="content">
|
|
||||||
<div class="content-primary">
|
|
||||||
<div data-role="controlgroup" data-type="horizontal" class="localnav" data-mini="true">
|
|
||||||
<a href="plugins.html" data-role="button">Installed Plugins</a>
|
|
||||||
<a href="pluginCatalog.html" data-role="button" class="ui-btn-active">Plugin Catalog</a>
|
|
||||||
<a href="pluginUpdates.html" data-role="button">Automatic Updates</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="pluginTiles"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
|
@ -1,34 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title>Plugins</title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="pluginUpdatesPage" data-role="page" class="page type-interior pluginConfigurationPage">
|
|
||||||
|
|
||||||
<div data-role="content">
|
|
||||||
<div class="content-primary">
|
|
||||||
<div data-role="controlgroup" data-type="horizontal" class="localnav" data-mini="true">
|
|
||||||
<a href="plugins.html" data-role="button">Installed Plugins</a>
|
|
||||||
<a href="pluginCatalog.html" data-role="button">Plugin Catalog</a>
|
|
||||||
<a href="pluginUpdates.html" data-role="button" class="ui-btn-active">Automatic Updates</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<form id="pluginUpdatesForm">
|
|
||||||
|
|
||||||
<table id="tblPluginUpdates">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th></th>
|
|
||||||
<th>Automatic updates</th>
|
|
||||||
<th>Update level</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody id="tbodyPluginUpdates"></tbody>
|
|
||||||
</table>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
|
@ -1,24 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title>Plugins</title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="pluginsPage" data-role="page" class="page type-interior pluginConfigurationPage">
|
|
||||||
|
|
||||||
<div data-role="content">
|
|
||||||
<div class="content-primary">
|
|
||||||
<div data-role="controlgroup" data-type="horizontal" class="localnav" data-mini="true">
|
|
||||||
<a href="plugins.html" data-role="button" class="ui-btn-active">Installed Plugins</a>
|
|
||||||
<a href="pluginCatalog.html" data-role="button">Plugin Catalog</a>
|
|
||||||
<a href="pluginUpdates.html" data-role="button">Automatic Updates</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="readOnlyContent">
|
|
||||||
<ul id="ulInstalledPlugins" data-role="listview" data-inset="true" data-auto-enhanced="false" data-split-icon="minus"></ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
|
@ -1,90 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title></title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="scheduledTaskPage" data-role="page" class="page type-interior">
|
|
||||||
<div data-role="content">
|
|
||||||
<div class="content-primary">
|
|
||||||
<div class="readOnlyContent">
|
|
||||||
<p id="pTaskDescription"></p>
|
|
||||||
<p>
|
|
||||||
<button type="button" data-icon="plus" onclick="ScheduledTaskPage.showAddTriggerPopup();">
|
|
||||||
Add Task Trigger
|
|
||||||
</button>
|
|
||||||
</p>
|
|
||||||
<ul id="ulTaskTriggers" data-role="listview" data-inset="true" data-auto-enhanced="false" data-split-icon="minus"></ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div data-role="popup" id="popupAddTrigger" class="ui-corner-all popup" style="min-width: 300px;">
|
|
||||||
<form id="addTriggerForm">
|
|
||||||
<div class="ui-corner-top ui-bar-a" style="text-align: center; padding: 0 20px;">
|
|
||||||
<h3>Add Task Trigger</h3>
|
|
||||||
</div>
|
|
||||||
<div data-role="content" class="ui-corner-bottom ui-content">
|
|
||||||
|
|
||||||
<ul data-role="listview" class="ulForm">
|
|
||||||
<li>
|
|
||||||
<label for="selectTriggerType">Trigger Type:</label>
|
|
||||||
<select id="selectTriggerType" name="selectTriggerType" onchange="ScheduledTaskPage.refreshTriggerFields(this.value);">
|
|
||||||
<option value="DailyTrigger">Daily</option>
|
|
||||||
<option value="WeeklyTrigger">Weekly</option>
|
|
||||||
<option value="IntervalTrigger">On an interval</option>
|
|
||||||
<option value="StartupTrigger">On application startup</option>
|
|
||||||
<option value="SystemEventTrigger">After a system event</option>
|
|
||||||
</select>
|
|
||||||
</li>
|
|
||||||
<li id="fldDayOfWeek">
|
|
||||||
<label for="selectDayOfWeek">Day:</label>
|
|
||||||
<select id="selectDayOfWeek" name="selectDayOfWeek">
|
|
||||||
<option value="Sunday">Sunday</option>
|
|
||||||
<option value="Monday">Monday</option>
|
|
||||||
<option value="Tuesday">Tuesday</option>
|
|
||||||
<option value="Wednesday">Wednesday</option>
|
|
||||||
<option value="Thursday">Thursday</option>
|
|
||||||
<option value="Friday">Friday</option>
|
|
||||||
<option value="Saturday">Saturday</option>
|
|
||||||
</select>
|
|
||||||
</li>
|
|
||||||
<li id="fldTimeOfDay">
|
|
||||||
<label for="txtTimeOfDay">Time:</label>
|
|
||||||
<input type="time" id="txtTimeOfDay" name="txtTimeOfDay" required="required" />
|
|
||||||
</li>
|
|
||||||
<li id="fldSelectSystemEvent">
|
|
||||||
<label for="selectSystemEvent">Event:</label>
|
|
||||||
<select id="selectSystemEvent" name="selectSystemEvent">
|
|
||||||
<option value="WakeFromSleep">Wake from sleep</option>
|
|
||||||
</select>
|
|
||||||
</li>
|
|
||||||
<li id="fldSelectInterval">
|
|
||||||
<label for="selectInterval">Every:</label>
|
|
||||||
<select id="selectInterval" name="selectInterval">
|
|
||||||
<option value="9000000000">15 minutes</option>
|
|
||||||
<option value="18000000000">30 minutes</option>
|
|
||||||
<option value="27000000000">45 minutes</option>
|
|
||||||
<option value="36000000000">1 hour</option>
|
|
||||||
<option value="72000000000">2 hours</option>
|
|
||||||
<option value="108000000000">3 hours</option>
|
|
||||||
<option value="144000000000">4 hours</option>
|
|
||||||
<option value="216000000000">6 hours</option>
|
|
||||||
<option value="288000000000">8 hours</option>
|
|
||||||
<option value="432000000000">12 hours</option>
|
|
||||||
</select>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<button type="submit" data-theme="b" data-icon="ok">
|
|
||||||
Add
|
|
||||||
</button>
|
|
||||||
<button type="button" data-icon="delete" onclick="$(this).parents('.popup').popup('close');">
|
|
||||||
Cancel
|
|
||||||
</button>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
|
@ -1,18 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title>Scheduled Tasks</title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="scheduledTasksPage" data-role="page" class="page type-interior">
|
|
||||||
<div data-role="content">
|
|
||||||
<div class="content-primary">
|
|
||||||
<div class="readOnlyContent">
|
|
||||||
<p>Below are Media Browser's scheduled tasks. Click into a task to adjust it's schedule.</p>
|
|
||||||
<ul id="ulScheduledTasks" data-role="listview" data-inset="true" data-auto-enhanced="false" data-split-icon="Play"></ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
|
@ -1,249 +0,0 @@
|
||||||
var AddPluginPage = {
|
|
||||||
|
|
||||||
onPageShow: function () {
|
|
||||||
|
|
||||||
var page = this;
|
|
||||||
|
|
||||||
Dashboard.showLoadingMsg();
|
|
||||||
|
|
||||||
var name = getParameterByName('name');
|
|
||||||
|
|
||||||
var promise1 = ApiClient.getPackageInfo(name);
|
|
||||||
var promise2 = ApiClient.getInstalledPlugins();
|
|
||||||
var promise3 = ApiClient.getPluginSecurityInfo();
|
|
||||||
|
|
||||||
$.when(promise1, promise2, promise3).done(function (response1, response2, response3) {
|
|
||||||
|
|
||||||
AddPluginPage.renderPackage(response1[0], response2[0], response3[0], page);
|
|
||||||
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
renderPackage: function (pkg, installedPlugins, pluginSecurityInfo, page) {
|
|
||||||
|
|
||||||
var installedPlugin = installedPlugins.filter(function (ip) {
|
|
||||||
return ip.Name == pkg.name;
|
|
||||||
})[0];
|
|
||||||
|
|
||||||
AddPluginPage.populateVersions(pkg, page, installedPlugin);
|
|
||||||
AddPluginPage.populateHistory(pkg);
|
|
||||||
|
|
||||||
Dashboard.setPageTitle(pkg.name);
|
|
||||||
|
|
||||||
if (pkg.shortDescription) {
|
|
||||||
$('#tagline', page).show().html(pkg.shortDescription);
|
|
||||||
} else {
|
|
||||||
$('#tagline', page).hide();
|
|
||||||
}
|
|
||||||
|
|
||||||
$('#overview', page).html(pkg.overview || "");
|
|
||||||
|
|
||||||
|
|
||||||
$('#developer', page).html(pkg.owner);
|
|
||||||
|
|
||||||
if (pkg.isPremium) {
|
|
||||||
$('.premiumPackage', page).show();
|
|
||||||
|
|
||||||
// Fill in registration info
|
|
||||||
var regStatus = "<strong>";
|
|
||||||
if (pkg.isRegistered) {
|
|
||||||
regStatus += "You are currently registered for this feature";
|
|
||||||
} else {
|
|
||||||
if (new Date(pkg.expDate).getTime() < new Date(1970, 1, 1).getTime()) {
|
|
||||||
regStatus += "This feature has no registration information";
|
|
||||||
} else {
|
|
||||||
if (new Date(pkg.expDate).getTime() <= new Date().getTime()) {
|
|
||||||
regStatus += "The trial period for this feature has expired";
|
|
||||||
} else {
|
|
||||||
regStatus += "The trial period for this feature will expire in " + Math.round((new Date(pkg.expDate).getTime() - new Date().getTime()) / (86400000)) + " day(s)";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
regStatus += "</strong>";
|
|
||||||
$('#regStatus', page).html(regStatus);
|
|
||||||
|
|
||||||
if (pluginSecurityInfo.IsMBSupporter) {
|
|
||||||
$('#regInfo', page).html(pkg.regInfo || "");
|
|
||||||
if (pkg.price > 0) {
|
|
||||||
// Fill in PayPal info
|
|
||||||
$('premiumHasPrice', page).show();
|
|
||||||
$('#featureId', page).val(pkg.featureId);
|
|
||||||
$('#featureName', page).val(pkg.name);
|
|
||||||
$('#amount', page).val(pkg.price);
|
|
||||||
$('#regPrice', page).html("<h2>Price: $" + pkg.price.toFixed(2) + " (USD)</h2>");
|
|
||||||
var url = "http://mb3admin.com/admin/service/user/getPayPalEmail?id=" + pkg.owner;
|
|
||||||
$.getJSON(url).done(function(dev) {
|
|
||||||
if (dev.payPalEmail) {
|
|
||||||
$('#payPalEmail', page).val(dev.payPalEmail);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
$('#ppButton', page).hide();
|
|
||||||
$('#noEmail', page).show();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
// Supporter-only feature
|
|
||||||
$('premiumHasPrice', page).hide();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$('#regInfo', page).html("<h3>You must be a <a href='supporter.html'>Media Browser Supporter</a> in order to gain access to this feature.</h3>");
|
|
||||||
$('#ppButton', page).hide();
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
$('.premiumPackage', page).hide();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pkg.richDescUrl) {
|
|
||||||
$('#pViewWebsite', page).show();
|
|
||||||
$('#pViewWebsite a', page)[0].href = pkg.richDescUrl;
|
|
||||||
} else {
|
|
||||||
$('#pViewWebsite', page).hide();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pkg.previewImage) {
|
|
||||||
|
|
||||||
var color = pkg.tileColor || "#2572EB";
|
|
||||||
var img = pkg.previewImage ? pkg.previewImage : pkg.thumbImage;
|
|
||||||
$('#pPreviewImage', page).show().html("<img src='" + img + "' style='max-width: 100%;border-radius:10px;-moz-box-shadow: 0 0 20px 3px " + color + ";-webkit-box-shadow: 0 0 20px 3px " + color + ";box-shadow: 0 0 20px 3px " + color + ";' />");
|
|
||||||
} else {
|
|
||||||
$('#pPreviewImage', page).hide().html("");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (installedPlugin) {
|
|
||||||
$('#pCurrentVersion', page).show().html("You currently have version <strong>" + installedPlugin.Version + "</strong> installed.");
|
|
||||||
|
|
||||||
} else {
|
|
||||||
$('#pCurrentVersion', page).hide().html("");
|
|
||||||
}
|
|
||||||
|
|
||||||
Dashboard.hideLoadingMsg();
|
|
||||||
},
|
|
||||||
|
|
||||||
populateVersions: function (packageInfo, page, installedPlugin) {
|
|
||||||
|
|
||||||
var html = '';
|
|
||||||
|
|
||||||
for (var i = 0, length = packageInfo.versions.length; i < length; i++) {
|
|
||||||
|
|
||||||
var version = packageInfo.versions[i];
|
|
||||||
|
|
||||||
html += '<option value="' + version.versionStr + '|' + version.classification + '">' + version.versionStr + ' (' + version.classification + ')</option>';
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
var selectmenu = $('#selectVersion', page).html(html);
|
|
||||||
|
|
||||||
var packageVersion;
|
|
||||||
|
|
||||||
if (installedPlugin) {
|
|
||||||
|
|
||||||
// Select the first available package with the same update class as the installed version
|
|
||||||
packageVersion = packageInfo.versions.filter(function (current) {
|
|
||||||
|
|
||||||
return current.classification == installedPlugin.UpdateClass;
|
|
||||||
})[0];
|
|
||||||
|
|
||||||
|
|
||||||
} else {
|
|
||||||
$('#pCurrentVersion', page).hide().html("");
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we don't have a package version to select, pick the first release build
|
|
||||||
if (!packageVersion) {
|
|
||||||
|
|
||||||
// Select the first available package with the same update class as the installed version
|
|
||||||
packageVersion = packageInfo.versions.filter(function (current) {
|
|
||||||
|
|
||||||
return current.classification == "Release";
|
|
||||||
})[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we still don't have a package version to select, pick the first Beta build
|
|
||||||
if (!packageVersion) {
|
|
||||||
|
|
||||||
// Select the first available package with the same update class as the installed version
|
|
||||||
packageVersion = packageInfo.versions.filter(function (current) {
|
|
||||||
|
|
||||||
return current.classification == "Beta";
|
|
||||||
})[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (packageVersion) {
|
|
||||||
var val = packageVersion.versionStr + '|' + packageVersion.classification;
|
|
||||||
|
|
||||||
$('#selectVersion', page).val(val);
|
|
||||||
}
|
|
||||||
|
|
||||||
selectmenu.selectmenu('refresh');
|
|
||||||
},
|
|
||||||
|
|
||||||
populateHistory: function (packageInfo) {
|
|
||||||
|
|
||||||
var html = '';
|
|
||||||
|
|
||||||
for (var i = 0, length = Math.min(packageInfo.versions.length, 10) ; i < length; i++) {
|
|
||||||
|
|
||||||
var version = packageInfo.versions[i];
|
|
||||||
|
|
||||||
html += '<h2 style="margin:.5em 0;">' + version.versionStr + ' (' + version.classification + ')</h2>';
|
|
||||||
|
|
||||||
html += '<div style="margin-bottom:1.5em;">' + version.description + '</div>';
|
|
||||||
}
|
|
||||||
|
|
||||||
$('#revisionHistory', $.mobile.activePage).html(html);
|
|
||||||
},
|
|
||||||
|
|
||||||
onSubmit: function () {
|
|
||||||
|
|
||||||
Dashboard.showLoadingMsg();
|
|
||||||
|
|
||||||
$('#btnInstall', $.mobile.activePage).button('disable');
|
|
||||||
|
|
||||||
var name = getParameterByName('name');
|
|
||||||
|
|
||||||
ApiClient.getInstalledPlugins().done(function (plugins) {
|
|
||||||
|
|
||||||
var installedPlugin = plugins.filter(function (ip) {
|
|
||||||
return ip.Name == name;
|
|
||||||
})[0];
|
|
||||||
|
|
||||||
var vals = $('#selectVersion', $.mobile.activePage).val().split('|');
|
|
||||||
|
|
||||||
var version = vals[0];
|
|
||||||
|
|
||||||
if (installedPlugin && installedPlugin.Version == version) {
|
|
||||||
|
|
||||||
Dashboard.hideLoadingMsg();
|
|
||||||
|
|
||||||
Dashboard.confirm("Are you sure you wish to reinstall the same version you already have? In most cases this will not have any effect.", "Plugin Reinstallation", function (confirmResult) {
|
|
||||||
|
|
||||||
if (confirmResult) {
|
|
||||||
|
|
||||||
Dashboard.showLoadingMsg();
|
|
||||||
AddPluginPage.performInstallation(name, vals[1], version);
|
|
||||||
} else {
|
|
||||||
$('#btnInstall', $.mobile.activePage).button('enable');
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
AddPluginPage.performInstallation(name, vals[1], version);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
|
|
||||||
performInstallation: function (packageName, updateClass, version) {
|
|
||||||
|
|
||||||
ApiClient.installPlugin(packageName, updateClass, version).done(function () {
|
|
||||||
|
|
||||||
Dashboard.hideLoadingMsg();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
$(document).on('pageshow', "#addPluginPage", AddPluginPage.onPageShow);
|
|
|
@ -1,65 +0,0 @@
|
||||||
var AdvancedConfigurationPage = {
|
|
||||||
|
|
||||||
onPageShow: function () {
|
|
||||||
Dashboard.showLoadingMsg();
|
|
||||||
|
|
||||||
var promise1 = ApiClient.getServerConfiguration();
|
|
||||||
|
|
||||||
var promise2 = ApiClient.getSystemInfo();
|
|
||||||
|
|
||||||
$.when(promise1, promise2).done(function (response1, response2) {
|
|
||||||
|
|
||||||
AdvancedConfigurationPage.loadPage(response1[0], response2[0]);
|
|
||||||
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
loadPage: function (config, systemInfo) {
|
|
||||||
|
|
||||||
var page = $.mobile.activePage;
|
|
||||||
|
|
||||||
if (systemInfo.SupportsNativeWebSocket) {
|
|
||||||
|
|
||||||
$('#fldWebSocketPortNumber', page).hide();
|
|
||||||
} else {
|
|
||||||
$('#fldWebSocketPortNumber', page).show();
|
|
||||||
}
|
|
||||||
|
|
||||||
$('#selectAutomaticUpdateLevel', page).val(config.SystemUpdateLevel).selectmenu('refresh');
|
|
||||||
$('#txtWebSocketPortNumber', page).val(config.LegacyWebSocketPortNumber);
|
|
||||||
|
|
||||||
$('#txtPortNumber', page).val(config.HttpServerPortNumber);
|
|
||||||
$('#chkDebugLog', page).checked(config.EnableDebugLevelLogging).checkboxradio("refresh");
|
|
||||||
|
|
||||||
$('#chkEnableDeveloperTools', page).checked(config.EnableDeveloperTools).checkboxradio("refresh");
|
|
||||||
$('#chkRunAtStartup', page).checked(config.RunAtStartup).checkboxradio("refresh");
|
|
||||||
|
|
||||||
Dashboard.hideLoadingMsg();
|
|
||||||
},
|
|
||||||
|
|
||||||
onSubmit: function () {
|
|
||||||
|
|
||||||
Dashboard.showLoadingMsg();
|
|
||||||
|
|
||||||
var form = this;
|
|
||||||
|
|
||||||
ApiClient.getServerConfiguration().done(function (config) {
|
|
||||||
|
|
||||||
config.LegacyWebSocketPortNumber = $('#txtWebSocketPortNumber', form).val();
|
|
||||||
|
|
||||||
config.HttpServerPortNumber = $('#txtPortNumber', form).val();
|
|
||||||
config.EnableDebugLevelLogging = $('#chkDebugLog', form).checked();
|
|
||||||
|
|
||||||
config.EnableDeveloperTools = $('#chkEnableDeveloperTools', form).checked();
|
|
||||||
config.RunAtStartup = $('#chkRunAtStartup', form).checked();
|
|
||||||
config.SystemUpdateLevel = $('#selectAutomaticUpdateLevel', form).val();
|
|
||||||
|
|
||||||
ApiClient.updateServerConfiguration(config).done(Dashboard.processServerConfigurationUpdateResult);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Disable default form submission
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
$(document).on('pageshow', "#advancedConfigurationPage", AdvancedConfigurationPage.onPageShow);
|
|
|
@ -1,69 +0,0 @@
|
||||||
var AdvancedMetadataConfigurationPage = {
|
|
||||||
|
|
||||||
onPageShow: function () {
|
|
||||||
|
|
||||||
Dashboard.showLoadingMsg();
|
|
||||||
|
|
||||||
var page = this;
|
|
||||||
|
|
||||||
var promise1 = ApiClient.getServerConfiguration();
|
|
||||||
var promise2 = ApiClient.getItemTypes({ HasInternetProvider: true });
|
|
||||||
|
|
||||||
$.when(promise1, promise2).done(function (response1, response2) {
|
|
||||||
|
|
||||||
AdvancedMetadataConfigurationPage.load(page, response1[0], response2[0]);
|
|
||||||
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
load: function (page, config, itemTypes) {
|
|
||||||
|
|
||||||
AdvancedMetadataConfigurationPage.loadItemTypes(page, config, itemTypes);
|
|
||||||
Dashboard.hideLoadingMsg();
|
|
||||||
},
|
|
||||||
|
|
||||||
loadItemTypes: function (page, configuration, types) {
|
|
||||||
|
|
||||||
var html = '<div data-role="controlgroup">';
|
|
||||||
|
|
||||||
for (var i = 0, length = types.length; i < length; i++) {
|
|
||||||
|
|
||||||
var type = types[i];
|
|
||||||
var id = "checkbox-" + i + "a";
|
|
||||||
|
|
||||||
var checkedAttribute = configuration.InternetProviderExcludeTypes.indexOf(type) != -1 ? ' checked="checked"' : '';
|
|
||||||
|
|
||||||
html += '<input' + checkedAttribute + ' class="chkItemType" data-itemtype="' + type + '" type="checkbox" name="' + id + '" id="' + id + '" onchange="AdvancedMetadataConfigurationPage.submit();" />';
|
|
||||||
html += '<label for="' + id + '">' + type + '</label>';
|
|
||||||
}
|
|
||||||
|
|
||||||
html += "</div>";
|
|
||||||
|
|
||||||
$('#divItemTypes', page).html(html).trigger("create");
|
|
||||||
},
|
|
||||||
|
|
||||||
submit: function () {
|
|
||||||
|
|
||||||
$('.btnSubmit', $.mobile.activePage)[0].click();
|
|
||||||
|
|
||||||
},
|
|
||||||
|
|
||||||
onSubmit: function () {
|
|
||||||
var form = this;
|
|
||||||
|
|
||||||
ApiClient.getServerConfiguration().done(function (config) {
|
|
||||||
|
|
||||||
config.InternetProviderExcludeTypes = $.map($('.chkItemType:checked', form), function (currentCheckbox) {
|
|
||||||
|
|
||||||
return currentCheckbox.getAttribute('data-itemtype');
|
|
||||||
});
|
|
||||||
|
|
||||||
ApiClient.updateServerConfiguration(config);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Disable default form submission
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
$(document).on('pageshow', "#advancedMetadataConfigurationPage", AdvancedMetadataConfigurationPage.onPageShow);
|
|
|
@ -1,462 +0,0 @@
|
||||||
var DashboardPage = {
|
|
||||||
|
|
||||||
onPageShow: function () {
|
|
||||||
|
|
||||||
Dashboard.showLoadingMsg();
|
|
||||||
DashboardPage.pollForInfo();
|
|
||||||
DashboardPage.startInterval();
|
|
||||||
$(document).on("websocketmessage", DashboardPage.onWebSocketMessage).on("websocketopen", DashboardPage.onWebSocketConnectionChange).on("websocketerror", DashboardPage.onWebSocketConnectionChange).on("websocketclose", DashboardPage.onWebSocketConnectionChange);
|
|
||||||
|
|
||||||
DashboardPage.lastAppUpdateCheck = null;
|
|
||||||
DashboardPage.lastPluginUpdateCheck = null;
|
|
||||||
},
|
|
||||||
|
|
||||||
onPageHide: function () {
|
|
||||||
|
|
||||||
$(document).off("websocketmessage", DashboardPage.onWebSocketMessage).off("websocketopen", DashboardPage.onWebSocketConnectionChange).off("websocketerror", DashboardPage.onWebSocketConnectionChange).off("websocketclose", DashboardPage.onWebSocketConnectionChange);
|
|
||||||
DashboardPage.stopInterval();
|
|
||||||
},
|
|
||||||
|
|
||||||
startInterval: function () {
|
|
||||||
|
|
||||||
if (Dashboard.isWebSocketOpen()) {
|
|
||||||
Dashboard.sendWebSocketMessage("DashboardInfoStart", "0,1500");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
stopInterval: function () {
|
|
||||||
|
|
||||||
if (Dashboard.isWebSocketOpen()) {
|
|
||||||
Dashboard.sendWebSocketMessage("DashboardInfoStop");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
onWebSocketMessage: function (e, msg) {
|
|
||||||
|
|
||||||
if (msg.MessageType == "DashboardInfo") {
|
|
||||||
DashboardPage.renderInfo(msg.Data);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
onWebSocketConnectionChange: function () {
|
|
||||||
|
|
||||||
DashboardPage.stopInterval();
|
|
||||||
DashboardPage.startInterval();
|
|
||||||
},
|
|
||||||
|
|
||||||
pollForInfo: function () {
|
|
||||||
$.getJSON("dashboardInfo").done(DashboardPage.renderInfo);
|
|
||||||
},
|
|
||||||
|
|
||||||
renderInfo: function (dashboardInfo) {
|
|
||||||
|
|
||||||
DashboardPage.lastDashboardInfo = dashboardInfo;
|
|
||||||
|
|
||||||
DashboardPage.renderRunningTasks(dashboardInfo);
|
|
||||||
DashboardPage.renderSystemInfo(dashboardInfo);
|
|
||||||
DashboardPage.renderActiveConnections(dashboardInfo);
|
|
||||||
|
|
||||||
Dashboard.hideLoadingMsg();
|
|
||||||
},
|
|
||||||
|
|
||||||
renderActiveConnections: function (dashboardInfo) {
|
|
||||||
|
|
||||||
var page = $.mobile.activePage;
|
|
||||||
|
|
||||||
var html = '';
|
|
||||||
|
|
||||||
if (!dashboardInfo.ActiveConnections.length) {
|
|
||||||
html += '<p>There are no users currently connected.</p>';
|
|
||||||
$('#divConnections', page).html(html).trigger('create');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
html += '<table class="tblConnections" style="border-collapse:collapse;">';
|
|
||||||
|
|
||||||
for (var i = 0, length = dashboardInfo.ActiveConnections.length; i < length; i++) {
|
|
||||||
|
|
||||||
var connection = dashboardInfo.ActiveConnections[i];
|
|
||||||
|
|
||||||
var user = dashboardInfo.Users.filter(function (u) {
|
|
||||||
return u.Id == connection.UserId;
|
|
||||||
})[0];
|
|
||||||
|
|
||||||
html += '<tr>';
|
|
||||||
|
|
||||||
html += '<td style="text-align:center;">';
|
|
||||||
html += DashboardPage.getClientType(connection);
|
|
||||||
html += '</td>';
|
|
||||||
|
|
||||||
html += '<td>';
|
|
||||||
html += user.Name;
|
|
||||||
html += '</td>';
|
|
||||||
|
|
||||||
html += '<td>';
|
|
||||||
html += connection.DeviceName;
|
|
||||||
html += '</td>';
|
|
||||||
|
|
||||||
html += '<td>';
|
|
||||||
html += DashboardPage.getNowPlayingImage(connection.NowPlayingItem);
|
|
||||||
html += '</td>';
|
|
||||||
|
|
||||||
html += '<td>';
|
|
||||||
html += DashboardPage.getNowPlayingText(connection, connection.NowPlayingItem);
|
|
||||||
html += '</td>';
|
|
||||||
|
|
||||||
html += '</tr>';
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
html += '</table>';
|
|
||||||
|
|
||||||
$('#divConnections', page).html(html);
|
|
||||||
},
|
|
||||||
|
|
||||||
getClientType: function (connection) {
|
|
||||||
|
|
||||||
var clientLowered = connection.Client.toLowerCase();
|
|
||||||
|
|
||||||
if (clientLowered == "dashboard") {
|
|
||||||
|
|
||||||
return "<img src='css/images/clients/html5.png' alt='Dashboard' title='Dashboard' />";
|
|
||||||
}
|
|
||||||
if (clientLowered == "media browser classic") {
|
|
||||||
|
|
||||||
return "<img src='css/images/clients/mb.png' alt='Media Browser Classic' title='Media Browser Classic' />";
|
|
||||||
}
|
|
||||||
if (clientLowered == "media browser theater") {
|
|
||||||
|
|
||||||
return "<img src='css/images/clients/mb.png' alt='Media Browser Theater' title='Media Browser Theater' />";
|
|
||||||
}
|
|
||||||
if (clientLowered == "android") {
|
|
||||||
|
|
||||||
return "<img src='css/images/clients/android.png' alt='Android' title='Android' />";
|
|
||||||
}
|
|
||||||
if (clientLowered == "ios") {
|
|
||||||
|
|
||||||
return "<img src='css/images/clients/ios.png' alt='iOS' title='iOS' />";
|
|
||||||
}
|
|
||||||
if (clientLowered == "windows rt") {
|
|
||||||
|
|
||||||
return "<img src='css/images/clients/windowsrt.png' alt='Windows RT' title='Windows RT' />";
|
|
||||||
}
|
|
||||||
if (clientLowered == "windows phone") {
|
|
||||||
|
|
||||||
return "<img src='css/images/clients/windowsphone.png' alt='Windows Phone' title='Windows Phone' />";
|
|
||||||
}
|
|
||||||
if (clientLowered == "dlna") {
|
|
||||||
|
|
||||||
return "<img src='css/images/clients/dlna.png' alt='Dlna' title='Dlna' />";
|
|
||||||
}
|
|
||||||
|
|
||||||
return connection.Client;
|
|
||||||
},
|
|
||||||
|
|
||||||
getNowPlayingImage: function (item) {
|
|
||||||
|
|
||||||
if (item) {
|
|
||||||
|
|
||||||
if (item.BackdropImageTag) {
|
|
||||||
var url = ApiClient.getImageUrl(item.Id, {
|
|
||||||
type: "Backdrop",
|
|
||||||
height: 100,
|
|
||||||
tag: item.BackdropImageTag
|
|
||||||
});
|
|
||||||
|
|
||||||
return "<img class='clientNowPlayingImage' src='" + url + "' alt='" + item.Name + "' title='" + item.Name + "' />";
|
|
||||||
}
|
|
||||||
else if (item.PrimaryImageTag) {
|
|
||||||
|
|
||||||
var url = ApiClient.getImageUrl(item.Id, {
|
|
||||||
type: "Primary",
|
|
||||||
height: 100,
|
|
||||||
tag: item.PrimaryImageTag
|
|
||||||
});
|
|
||||||
|
|
||||||
return "<img class='clientNowPlayingImage' src='" + url + "' alt='" + item.Name + "' title='" + item.Name + "' />";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return "";
|
|
||||||
},
|
|
||||||
|
|
||||||
getNowPlayingText: function (connection, item) {
|
|
||||||
|
|
||||||
var html = "";
|
|
||||||
|
|
||||||
if (item) {
|
|
||||||
|
|
||||||
html += "<div>" + item.Name + "</div>";
|
|
||||||
|
|
||||||
html += "<div>";
|
|
||||||
|
|
||||||
if (item.RunTimeTicks) {
|
|
||||||
html += DashboardPage.getDisplayText(connection.NowPlayingPositionTicks || 0) + " / ";
|
|
||||||
|
|
||||||
html += DashboardPage.getDisplayText(item.RunTimeTicks);
|
|
||||||
}
|
|
||||||
|
|
||||||
html += "</div>";
|
|
||||||
}
|
|
||||||
|
|
||||||
return html;
|
|
||||||
},
|
|
||||||
|
|
||||||
getDisplayText: function (ticks) {
|
|
||||||
|
|
||||||
var ticksPerHour = 36000000000;
|
|
||||||
|
|
||||||
var parts = [];
|
|
||||||
|
|
||||||
var hours = ticks / ticksPerHour;
|
|
||||||
hours = parseInt(hours);
|
|
||||||
|
|
||||||
if (hours) {
|
|
||||||
parts.push(hours);
|
|
||||||
}
|
|
||||||
|
|
||||||
ticks -= (hours * ticksPerHour);
|
|
||||||
|
|
||||||
var ticksPerMinute = 600000000;
|
|
||||||
|
|
||||||
var minutes = ticks / ticksPerMinute;
|
|
||||||
minutes = parseInt(minutes);
|
|
||||||
|
|
||||||
ticks -= (minutes * ticksPerMinute);
|
|
||||||
|
|
||||||
if (minutes < 10) {
|
|
||||||
minutes = '0' + minutes;
|
|
||||||
}
|
|
||||||
parts.push(minutes);
|
|
||||||
|
|
||||||
var ticksPerSecond = 10000000;
|
|
||||||
|
|
||||||
var seconds = ticks / ticksPerSecond;
|
|
||||||
seconds = parseInt(seconds);
|
|
||||||
|
|
||||||
if (seconds < 10) {
|
|
||||||
seconds = '0' + seconds;
|
|
||||||
}
|
|
||||||
parts.push(seconds);
|
|
||||||
|
|
||||||
return parts.join(':');
|
|
||||||
},
|
|
||||||
|
|
||||||
renderRunningTasks: function (dashboardInfo) {
|
|
||||||
|
|
||||||
var page = $.mobile.activePage;
|
|
||||||
|
|
||||||
var html = '';
|
|
||||||
|
|
||||||
if (!dashboardInfo.RunningTasks.length) {
|
|
||||||
html += '<p>No tasks are currently running.</p>';
|
|
||||||
}
|
|
||||||
|
|
||||||
for (var i = 0, length = dashboardInfo.RunningTasks.length; i < length; i++) {
|
|
||||||
|
|
||||||
|
|
||||||
var task = dashboardInfo.RunningTasks[i];
|
|
||||||
|
|
||||||
html += '<p>';
|
|
||||||
|
|
||||||
html += task.Name;
|
|
||||||
|
|
||||||
if (task.State == "Running") {
|
|
||||||
var progress = Math.round(task.CurrentProgressPercentage || 0);
|
|
||||||
html += '<span style="color:#267F00;margin-right:5px;font-weight:bold;"> - ' + progress + '%</span>';
|
|
||||||
|
|
||||||
html += '<button type="button" data-icon="stop" data-iconpos="notext" data-inline="true" data-theme="b" data-mini="true" onclick="DashboardPage.stopTask(\'' + task.Id + '\');">Stop</button>';
|
|
||||||
}
|
|
||||||
else if (task.State == "Cancelling") {
|
|
||||||
html += '<span style="color:#cc0000;"> - Stopping</span>';
|
|
||||||
}
|
|
||||||
|
|
||||||
html += '</p>';
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
$('#divRunningTasks', page).html(html).trigger('create');
|
|
||||||
},
|
|
||||||
|
|
||||||
renderSystemInfo: function (dashboardInfo) {
|
|
||||||
|
|
||||||
Dashboard.updateSystemInfo(dashboardInfo.SystemInfo);
|
|
||||||
|
|
||||||
var page = $.mobile.activePage;
|
|
||||||
|
|
||||||
$('#appVersionNumber', page).html(dashboardInfo.SystemInfo.Version);
|
|
||||||
|
|
||||||
if (dashboardInfo.RunningTasks.filter(function (task) {
|
|
||||||
|
|
||||||
return task.Id == dashboardInfo.ApplicationUpdateTaskId;
|
|
||||||
|
|
||||||
}).length) {
|
|
||||||
|
|
||||||
$('#btnUpdateApplication', page).button('disable');
|
|
||||||
} else {
|
|
||||||
$('#btnUpdateApplication', page).button('enable');
|
|
||||||
}
|
|
||||||
|
|
||||||
DashboardPage.renderApplicationUpdateInfo(dashboardInfo);
|
|
||||||
DashboardPage.renderPluginUpdateInfo(dashboardInfo);
|
|
||||||
DashboardPage.renderPendingInstallations(dashboardInfo.SystemInfo);
|
|
||||||
},
|
|
||||||
|
|
||||||
renderApplicationUpdateInfo: function (dashboardInfo) {
|
|
||||||
|
|
||||||
var page = $.mobile.activePage;
|
|
||||||
|
|
||||||
if (dashboardInfo.SystemInfo.IsNetworkDeployed && !dashboardInfo.SystemInfo.HasPendingRestart) {
|
|
||||||
|
|
||||||
// Only check once every 10 mins
|
|
||||||
if (DashboardPage.lastAppUpdateCheck && (new Date().getTime() - DashboardPage.lastAppUpdateCheck) < 600000) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
DashboardPage.lastAppUpdateCheck = new Date().getTime();
|
|
||||||
|
|
||||||
ApiClient.getAvailableApplicationUpdate().done(function (packageInfo) {
|
|
||||||
|
|
||||||
var version = packageInfo[0];
|
|
||||||
|
|
||||||
if (!version) {
|
|
||||||
$('#pUpToDate', page).show();
|
|
||||||
$('#pUpdateNow', page).hide();
|
|
||||||
} else {
|
|
||||||
$('#pUpToDate', page).hide();
|
|
||||||
|
|
||||||
$('#pUpdateNow', page).show();
|
|
||||||
|
|
||||||
$('#newVersionNumber', page).html("Version " + version.versionStr + " is now available for download.");
|
|
||||||
}
|
|
||||||
|
|
||||||
}).fail(function () {
|
|
||||||
|
|
||||||
Dashboard.showFooterNotification({ html: '<img src="css/images/notifications/error.png" class="notificationIcon" />There was an error connecting to the remote Media Browser repository.', id: "MB3ConnectionError" });
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
if (dashboardInfo.SystemInfo.HasPendingRestart) {
|
|
||||||
$('#pUpToDate', page).hide();
|
|
||||||
} else {
|
|
||||||
$('#pUpToDate', page).show();
|
|
||||||
}
|
|
||||||
|
|
||||||
$('#pUpdateNow', page).hide();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
renderPendingInstallations: function (systemInfo) {
|
|
||||||
|
|
||||||
var page = $.mobile.activePage;
|
|
||||||
|
|
||||||
if (systemInfo.CompletedInstallations.length) {
|
|
||||||
|
|
||||||
$('#collapsiblePendingInstallations', page).show();
|
|
||||||
|
|
||||||
} else {
|
|
||||||
$('#collapsiblePendingInstallations', page).hide();
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var html = '';
|
|
||||||
|
|
||||||
for (var i = 0, length = systemInfo.CompletedInstallations.length; i < length; i++) {
|
|
||||||
|
|
||||||
var update = systemInfo.CompletedInstallations[i];
|
|
||||||
|
|
||||||
html += '<div><strong>' + update.Name + '</strong> (' + update.Version + ')</div>';
|
|
||||||
}
|
|
||||||
|
|
||||||
$('#pendingInstallations', page).html(html);
|
|
||||||
},
|
|
||||||
|
|
||||||
renderPluginUpdateInfo: function (dashboardInfo) {
|
|
||||||
|
|
||||||
// Only check once every 10 mins
|
|
||||||
if (DashboardPage.lastPluginUpdateCheck && (new Date().getTime() - DashboardPage.lastPluginUpdateCheck) < 600000) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
DashboardPage.lastPluginUpdateCheck = new Date().getTime();
|
|
||||||
|
|
||||||
var page = $.mobile.activePage;
|
|
||||||
|
|
||||||
ApiClient.getAvailablePluginUpdates().done(function (updates) {
|
|
||||||
|
|
||||||
var elem = $('#pPluginUpdates', page);
|
|
||||||
|
|
||||||
if (updates.length) {
|
|
||||||
|
|
||||||
elem.show();
|
|
||||||
|
|
||||||
} else {
|
|
||||||
elem.hide();
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var html = '';
|
|
||||||
|
|
||||||
for (var i = 0, length = updates.length; i < length; i++) {
|
|
||||||
|
|
||||||
var update = updates[i];
|
|
||||||
|
|
||||||
html += '<p><strong>A new version of ' + update.name + ' is available!</strong></p>';
|
|
||||||
|
|
||||||
html += '<button type="button" data-icon="download" data-theme="b" onclick="DashboardPage.installPluginUpdate(this);" data-name="' + update.name + '" data-version="' + update.versionStr + '" data-classification="' + update.classification + '">Update Now</button>';
|
|
||||||
}
|
|
||||||
|
|
||||||
elem.html(html).trigger('create');
|
|
||||||
|
|
||||||
}).fail(function () {
|
|
||||||
|
|
||||||
Dashboard.showFooterNotification({ html: '<img src="css/images/notifications/error.png" class="notificationIcon" />There was an error connecting to the remote Media Browser repository.', id: "MB3ConnectionError" });
|
|
||||||
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
installPluginUpdate: function (button) {
|
|
||||||
|
|
||||||
$(button).button('disable');
|
|
||||||
|
|
||||||
var name = button.getAttribute('data-name');
|
|
||||||
var version = button.getAttribute('data-version');
|
|
||||||
var classification = button.getAttribute('data-classification');
|
|
||||||
|
|
||||||
Dashboard.showLoadingMsg();
|
|
||||||
|
|
||||||
ApiClient.installPlugin(name, classification, version).done(function () {
|
|
||||||
|
|
||||||
Dashboard.hideLoadingMsg();
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
updateApplication: function () {
|
|
||||||
|
|
||||||
var page = $.mobile.activePage;
|
|
||||||
$('#btnUpdateApplication', page).button('disable');
|
|
||||||
|
|
||||||
Dashboard.showLoadingMsg();
|
|
||||||
|
|
||||||
ApiClient.startScheduledTask(DashboardPage.lastDashboardInfo.ApplicationUpdateTaskId).done(function () {
|
|
||||||
|
|
||||||
DashboardPage.pollForInfo();
|
|
||||||
|
|
||||||
Dashboard.hideLoadingMsg();
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
stopTask: function (id) {
|
|
||||||
|
|
||||||
ApiClient.stopScheduledTask(id).done(function () {
|
|
||||||
|
|
||||||
DashboardPage.pollForInfo();
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
$(document).on('pageshow', "#dashboardPage", DashboardPage.onPageShow).on('pagehide', "#dashboardPage", DashboardPage.onPageHide);
|
|
|
@ -1,46 +0,0 @@
|
||||||
var DisplaySettingsPage = {
|
|
||||||
|
|
||||||
onPageShow: function () {
|
|
||||||
Dashboard.showLoadingMsg();
|
|
||||||
|
|
||||||
var page = this;
|
|
||||||
|
|
||||||
ApiClient.getServerConfiguration().done(function (config) {
|
|
||||||
|
|
||||||
$('#txtWeatherLocation', page).val(config.WeatherLocation);
|
|
||||||
$('#txtMinResumePct', page).val(config.MinResumePct);
|
|
||||||
$('#txtMaxResumePct', page).val(config.MaxResumePct);
|
|
||||||
$('#txtMinResumeDuration', page).val(config.MinResumeDurationSeconds);
|
|
||||||
$('#selectWeatherUnit', page).val(config.WeatherUnit).selectmenu("refresh");
|
|
||||||
|
|
||||||
Dashboard.hideLoadingMsg();
|
|
||||||
});
|
|
||||||
|
|
||||||
},
|
|
||||||
|
|
||||||
submit: function() {
|
|
||||||
|
|
||||||
$('.btnSubmit', $.mobile.activePage)[0].click();
|
|
||||||
|
|
||||||
},
|
|
||||||
|
|
||||||
onSubmit: function () {
|
|
||||||
var form = this;
|
|
||||||
|
|
||||||
ApiClient.getServerConfiguration().done(function (config) {
|
|
||||||
|
|
||||||
config.WeatherLocation = $('#txtWeatherLocation', form).val();
|
|
||||||
config.WeatherUnit = $('#selectWeatherUnit', form).val();
|
|
||||||
config.MinResumePct = $('#txtMinResumePct', form).val();
|
|
||||||
config.MaxResumePct = $('#txtMaxResumePct', form).val();
|
|
||||||
config.MinResumeDurationSeconds = $('#txtMinResumeDuration', form).val();
|
|
||||||
|
|
||||||
ApiClient.updateServerConfiguration(config);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Disable default form submission
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
$(document).on('pageshow', "#displaySettingsPage", DisplaySettingsPage.onPageShow);
|
|
|
@ -1,175 +0,0 @@
|
||||||
var EditUserPage = {
|
|
||||||
|
|
||||||
onPageShow: function () {
|
|
||||||
Dashboard.showLoadingMsg();
|
|
||||||
|
|
||||||
var userId = getParameterByName("userId");
|
|
||||||
|
|
||||||
if (userId) {
|
|
||||||
$('#userProfileNavigation', this).show();
|
|
||||||
} else {
|
|
||||||
$('#userProfileNavigation', this).hide();
|
|
||||||
}
|
|
||||||
|
|
||||||
var promise4 = ApiClient.getCultures();
|
|
||||||
|
|
||||||
var promise3 = ApiClient.getParentalRatings();
|
|
||||||
|
|
||||||
var promise1;
|
|
||||||
|
|
||||||
if (!userId) {
|
|
||||||
|
|
||||||
var deferred = $.Deferred();
|
|
||||||
|
|
||||||
deferred.resolveWith(null, [{
|
|
||||||
Configuration: {}
|
|
||||||
}]);
|
|
||||||
|
|
||||||
promise1 = deferred.promise();
|
|
||||||
} else {
|
|
||||||
|
|
||||||
promise1 = ApiClient.getUser(userId);
|
|
||||||
}
|
|
||||||
|
|
||||||
var promise2 = Dashboard.getCurrentUser();
|
|
||||||
|
|
||||||
$.when(promise1, promise2, promise3, promise4).done(function (response1, response2, response3, response4) {
|
|
||||||
|
|
||||||
EditUserPage.loadUser(response1[0] || response1, response2[0], response3[0], response4[0]);
|
|
||||||
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
loadUser: function (user, loggedInUser, allParentalRatings, allCultures) {
|
|
||||||
|
|
||||||
var page = $($.mobile.activePage);
|
|
||||||
|
|
||||||
EditUserPage.populateLanguages($('#selectAudioLanguage', page), allCultures);
|
|
||||||
EditUserPage.populateLanguages($('#selectSubtitleLanguage', page), allCultures);
|
|
||||||
EditUserPage.populateRatings(allParentalRatings, page);
|
|
||||||
|
|
||||||
if (!loggedInUser.Configuration.IsAdministrator || user.Id == loggedInUser.Id) {
|
|
||||||
|
|
||||||
$('#fldIsAdmin', page).hide();
|
|
||||||
$('#fldMaxParentalRating', page).hide();
|
|
||||||
} else {
|
|
||||||
$('#fldIsAdmin', page).show();
|
|
||||||
$('#fldMaxParentalRating', page).show();
|
|
||||||
}
|
|
||||||
|
|
||||||
Dashboard.setPageTitle(user.Name || "Add User");
|
|
||||||
|
|
||||||
$('#txtUserName', page).val(user.Name);
|
|
||||||
|
|
||||||
var ratingValue = "";
|
|
||||||
|
|
||||||
if (user.Configuration.MaxParentalRating) {
|
|
||||||
|
|
||||||
for (var i = 0, length = allParentalRatings.length; i < length; i++) {
|
|
||||||
|
|
||||||
var rating = allParentalRatings[i];
|
|
||||||
|
|
||||||
if (user.Configuration.MaxParentalRating >= rating.Value) {
|
|
||||||
ratingValue = rating.Value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$('#selectMaxParentalRating', page).val(ratingValue).selectmenu("refresh");
|
|
||||||
|
|
||||||
$('#selectAudioLanguage', page).val(user.Configuration.AudioLanguagePreference || "").selectmenu("refresh");
|
|
||||||
$('#selectSubtitleLanguage', page).val(user.Configuration.SubtitleLanguagePreference || "").selectmenu("refresh");
|
|
||||||
|
|
||||||
$('#chkForcedSubtitlesOnly', page).checked(user.Configuration.UseForcedSubtitlesOnly || false).checkboxradio("refresh");
|
|
||||||
$('#chkIsAdmin', page).checked(user.Configuration.IsAdministrator || false).checkboxradio("refresh");
|
|
||||||
|
|
||||||
Dashboard.hideLoadingMsg();
|
|
||||||
},
|
|
||||||
|
|
||||||
populateLanguages: function (select, allCultures) {
|
|
||||||
|
|
||||||
var html = "";
|
|
||||||
|
|
||||||
html += "<option value=''>None</option>";
|
|
||||||
|
|
||||||
for (var i = 0, length = allCultures.length; i < length; i++) {
|
|
||||||
|
|
||||||
var culture = allCultures[i];
|
|
||||||
|
|
||||||
html += "<option value='" + culture.ThreeLetterISOLanguageName + "'>" + culture.DisplayName + "</option>";
|
|
||||||
}
|
|
||||||
|
|
||||||
select.html(html).selectmenu("refresh");
|
|
||||||
},
|
|
||||||
|
|
||||||
populateRatings: function (allParentalRatings, page) {
|
|
||||||
|
|
||||||
var html = "";
|
|
||||||
|
|
||||||
html += "<option value=''>None</option>";
|
|
||||||
|
|
||||||
for (var i = 0, length = allParentalRatings.length; i < length; i++) {
|
|
||||||
|
|
||||||
var rating = allParentalRatings[i];
|
|
||||||
|
|
||||||
html += "<option value='" + rating.Value + "'>" + rating.Name + "</option>";
|
|
||||||
}
|
|
||||||
|
|
||||||
$('#selectMaxParentalRating', page).html(html).selectmenu("refresh");
|
|
||||||
},
|
|
||||||
|
|
||||||
saveUser: function (user) {
|
|
||||||
|
|
||||||
var page = $($.mobile.activePage);
|
|
||||||
|
|
||||||
user.Name = $('#txtUserName', page).val();
|
|
||||||
user.Configuration.MaxParentalRating = $('#selectMaxParentalRating', page).val() || null;
|
|
||||||
|
|
||||||
user.Configuration.IsAdministrator = $('#chkIsAdmin', page).checked();
|
|
||||||
|
|
||||||
user.Configuration.AudioLanguagePreference = $('#selectAudioLanguage', page).val();
|
|
||||||
user.Configuration.SubtitleLanguagePreference = $('#selectSubtitleLanguage', page).val();
|
|
||||||
user.Configuration.UseForcedSubtitlesOnly = $('#chkForcedSubtitlesOnly', page).checked();
|
|
||||||
|
|
||||||
var userId = getParameterByName("userId");
|
|
||||||
|
|
||||||
if (userId) {
|
|
||||||
ApiClient.updateUser(user).done(EditUserPage.saveComplete);
|
|
||||||
} else {
|
|
||||||
ApiClient.createUser(user).done(EditUserPage.saveComplete);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
saveComplete: function () {
|
|
||||||
Dashboard.hideLoadingMsg();
|
|
||||||
|
|
||||||
var userId = getParameterByName("userId");
|
|
||||||
|
|
||||||
Dashboard.validateCurrentUser();
|
|
||||||
|
|
||||||
if (userId) {
|
|
||||||
Dashboard.alert("Settings saved.");
|
|
||||||
} else {
|
|
||||||
Dashboard.navigate("userProfiles.html");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
onSubmit: function () {
|
|
||||||
Dashboard.showLoadingMsg();
|
|
||||||
|
|
||||||
var userId = getParameterByName("userId");
|
|
||||||
|
|
||||||
if (!userId) {
|
|
||||||
EditUserPage.saveUser({
|
|
||||||
Configuration: {}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
ApiClient.getUser(userId).done(EditUserPage.saveUser);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Disable default form submission
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
$(document).on('pageshow', "#editUserPage", EditUserPage.onPageShow);
|
|
|
@ -1,506 +0,0 @@
|
||||||
// Array Remove - By John Resig (MIT Licensed)
|
|
||||||
Array.prototype.remove = function (from, to) {
|
|
||||||
var rest = this.slice((to || from) + 1 || this.length);
|
|
||||||
this.length = from < 0 ? this.length + from : from;
|
|
||||||
return this.push.apply(this, rest);
|
|
||||||
};
|
|
||||||
|
|
||||||
String.prototype.endsWith = function (suffix) {
|
|
||||||
return this.indexOf(suffix, this.length - suffix.length) !== -1;
|
|
||||||
};
|
|
||||||
|
|
||||||
$.fn.checked = function (value) {
|
|
||||||
if (value === true || value === false) {
|
|
||||||
// Set the value of the checkbox
|
|
||||||
return $(this).each(function () {
|
|
||||||
this.checked = value;
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
// Return check state
|
|
||||||
return $(this).is(':checked');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
var WebNotifications = {
|
|
||||||
|
|
||||||
show: function (data) {
|
|
||||||
if (window.webkitNotifications) {
|
|
||||||
if (!webkitNotifications.checkPermission()) {
|
|
||||||
var notif = webkitNotifications.createNotification(data.icon, data.title, data.body);
|
|
||||||
notif.show();
|
|
||||||
|
|
||||||
if (data.timeout) {
|
|
||||||
setTimeout(function () {
|
|
||||||
notif.cancel();
|
|
||||||
}, data.timeout);
|
|
||||||
}
|
|
||||||
|
|
||||||
return notif;
|
|
||||||
} else {
|
|
||||||
webkitNotifications.requestPermission(function () {
|
|
||||||
return WebNotifications.show(data);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (window.Notification) {
|
|
||||||
if (Notification.permissionLevel() === "granted") {
|
|
||||||
var notif = new Notification(data.title, data);
|
|
||||||
notif.show();
|
|
||||||
|
|
||||||
if (data.timeout) {
|
|
||||||
setTimeout(function () {
|
|
||||||
notif.cancel();
|
|
||||||
}, data.timeout);
|
|
||||||
}
|
|
||||||
|
|
||||||
return notif;
|
|
||||||
} else if (Notification.permissionLevel() === "default") {
|
|
||||||
Notification.requestPermission(function () {
|
|
||||||
return WebNotifications.show(data);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
requestPermission: function () {
|
|
||||||
if (window.webkitNotifications) {
|
|
||||||
if (!webkitNotifications.checkPermission()) {
|
|
||||||
} else {
|
|
||||||
webkitNotifications.requestPermission(function () {
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (window.Notification) {
|
|
||||||
if (Notification.permissionLevel() === "granted") {
|
|
||||||
} else if (Notification.permissionLevel() === "default") {
|
|
||||||
Notification.requestPermission(function () {
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Javascript Humane Dates
|
|
||||||
* Copyright (c) 2008 Dean Landolt (deanlandolt.com)
|
|
||||||
* Re-write by Zach Leatherman (zachleat.com)
|
|
||||||
*
|
|
||||||
* Adopted from the John Resig's pretty.js
|
|
||||||
* at http://ejohn.org/blog/javascript-pretty-date
|
|
||||||
* and henrah's proposed modification
|
|
||||||
* at http://ejohn.org/blog/javascript-pretty-date/#comment-297458
|
|
||||||
*
|
|
||||||
* Licensed under the MIT license.
|
|
||||||
*/
|
|
||||||
|
|
||||||
function humane_date(date_str) {
|
|
||||||
var time_formats = [[90, 'a minute'], // 60*1.5
|
|
||||||
[3600, 'minutes', 60], // 60*60, 60
|
|
||||||
[5400, 'an hour'], // 60*60*1.5
|
|
||||||
[86400, 'hours', 3600], // 60*60*24, 60*60
|
|
||||||
[129600, 'a day'], // 60*60*24*1.5
|
|
||||||
[604800, 'days', 86400], // 60*60*24*7, 60*60*24
|
|
||||||
[907200, 'a week'], // 60*60*24*7*1.5
|
|
||||||
[2628000, 'weeks', 604800], // 60*60*24*(365/12), 60*60*24*7
|
|
||||||
[3942000, 'a month'], // 60*60*24*(365/12)*1.5
|
|
||||||
[31536000, 'months', 2628000], // 60*60*24*365, 60*60*24*(365/12)
|
|
||||||
[47304000, 'a year'], // 60*60*24*365*1.5
|
|
||||||
[3153600000, 'years', 31536000] // 60*60*24*365*100, 60*60*24*365
|
|
||||||
];
|
|
||||||
|
|
||||||
var dt = new Date;
|
|
||||||
var date = parseISO8601Date(date_str, true);
|
|
||||||
|
|
||||||
var seconds = ((dt - date) / 1000);
|
|
||||||
var token = ' ago';
|
|
||||||
var i = 0;
|
|
||||||
var format;
|
|
||||||
|
|
||||||
if (seconds < 0) {
|
|
||||||
seconds = Math.abs(seconds);
|
|
||||||
token = '';
|
|
||||||
}
|
|
||||||
|
|
||||||
while (format = time_formats[i++]) {
|
|
||||||
if (seconds < format[0]) {
|
|
||||||
if (format.length == 2) {
|
|
||||||
return format[1] + token;
|
|
||||||
} else {
|
|
||||||
return Math.round(seconds / format[2]) + ' ' + format[1] + token;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// overflow for centuries
|
|
||||||
if (seconds > 4730400000)
|
|
||||||
return Math.round(seconds / 4730400000) + ' centuries' + token;
|
|
||||||
|
|
||||||
return date_str;
|
|
||||||
};
|
|
||||||
|
|
||||||
function humane_elapsed(firstDateStr, secondDateStr) {
|
|
||||||
var dt1 = new Date(firstDateStr);
|
|
||||||
var dt2 = new Date(secondDateStr);
|
|
||||||
var seconds = (dt2.getTime() - dt1.getTime()) / 1000;
|
|
||||||
var numdays = Math.floor((seconds % 31536000) / 86400);
|
|
||||||
var numhours = Math.floor(((seconds % 31536000) % 86400) / 3600);
|
|
||||||
var numminutes = Math.floor((((seconds % 31536000) % 86400) % 3600) / 60);
|
|
||||||
var numseconds = Math.round((((seconds % 31536000) % 86400) % 3600) % 60);
|
|
||||||
|
|
||||||
var elapsedStr = '';
|
|
||||||
elapsedStr += numdays == 1 ? numdays + ' day ' : '';
|
|
||||||
elapsedStr += numdays > 1 ? numdays + ' days ' : '';
|
|
||||||
elapsedStr += numhours == 1 ? numhours + ' hour ' : '';
|
|
||||||
elapsedStr += numhours > 1 ? numhours + ' hours ' : '';
|
|
||||||
elapsedStr += numminutes == 1 ? numminutes + ' minute ' : '';
|
|
||||||
elapsedStr += numminutes > 1 ? numminutes + ' minutes ' : '';
|
|
||||||
elapsedStr += elapsedStr.length > 0 ? 'and ' : '';
|
|
||||||
elapsedStr += numseconds == 1 ? numseconds + ' second' : '';
|
|
||||||
elapsedStr += numseconds == 0 || numseconds > 1 ? numseconds + ' seconds' : '';
|
|
||||||
|
|
||||||
return elapsedStr;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
function getParameterByName(name) {
|
|
||||||
name = name.replace(/[\[]/, "\\\[").replace(/[\]]/, "\\\]");
|
|
||||||
var regexS = "[\\?&]" + name + "=([^&#]*)";
|
|
||||||
var regex = new RegExp(regexS);
|
|
||||||
var results = regex.exec(window.location.search);
|
|
||||||
if (results == null)
|
|
||||||
return "";
|
|
||||||
else
|
|
||||||
return decodeURIComponent(results[1].replace(/\+/g, " "));
|
|
||||||
}
|
|
||||||
|
|
||||||
function parseISO8601Date(s, toLocal) {
|
|
||||||
|
|
||||||
// parenthese matches:
|
|
||||||
// year month day hours minutes seconds
|
|
||||||
// dotmilliseconds
|
|
||||||
// tzstring plusminus hours minutes
|
|
||||||
var re = /(\d{4})-(\d\d)-(\d\d)T(\d\d):(\d\d):(\d\d)(\.\d+)?(Z|([+-])(\d\d):(\d\d))/;
|
|
||||||
|
|
||||||
var d = [];
|
|
||||||
d = s.match(re);
|
|
||||||
|
|
||||||
// "2010-12-07T11:00:00.000-09:00" parses to:
|
|
||||||
// ["2010-12-07T11:00:00.000-09:00", "2010", "12", "07", "11",
|
|
||||||
// "00", "00", ".000", "-09:00", "-", "09", "00"]
|
|
||||||
// "2010-12-07T11:00:00.000Z" parses to:
|
|
||||||
// ["2010-12-07T11:00:00.000Z", "2010", "12", "07", "11",
|
|
||||||
// "00", "00", ".000", "Z", undefined, undefined, undefined]
|
|
||||||
|
|
||||||
if (!d) {
|
|
||||||
throw "Couldn't parse ISO 8601 date string '" + s + "'";
|
|
||||||
}
|
|
||||||
|
|
||||||
// parse strings, leading zeros into proper ints
|
|
||||||
var a = [1, 2, 3, 4, 5, 6, 10, 11];
|
|
||||||
for (var i in a) {
|
|
||||||
d[a[i]] = parseInt(d[a[i]], 10);
|
|
||||||
}
|
|
||||||
d[7] = parseFloat(d[7]);
|
|
||||||
|
|
||||||
// Date.UTC(year, month[, date[, hrs[, min[, sec[, ms]]]]])
|
|
||||||
// note that month is 0-11, not 1-12
|
|
||||||
// see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Date/UTC
|
|
||||||
var ms = Date.UTC(d[1], d[2] - 1, d[3], d[4], d[5], d[6]);
|
|
||||||
|
|
||||||
// if there are milliseconds, add them
|
|
||||||
if (d[7] > 0) {
|
|
||||||
ms += Math.round(d[7] * 1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
// if there's a timezone, calculate it
|
|
||||||
if (d[8] != "Z" && d[10]) {
|
|
||||||
var offset = d[10] * 60 * 60 * 1000;
|
|
||||||
if (d[11]) {
|
|
||||||
offset += d[11] * 60 * 1000;
|
|
||||||
}
|
|
||||||
if (d[9] == "-") {
|
|
||||||
ms -= offset;
|
|
||||||
} else {
|
|
||||||
ms += offset;
|
|
||||||
}
|
|
||||||
} else if (!toLocal) {
|
|
||||||
ms += new Date().getTimezoneOffset() * 60000;
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Date(ms);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* Secure Hash Algorithm (SHA1)
|
|
||||||
* http://www.webtoolkit.info/
|
|
||||||
*
|
|
||||||
**/
|
|
||||||
|
|
||||||
function SHA1(msg) {
|
|
||||||
|
|
||||||
function rotate_left(n, s) {
|
|
||||||
var t4 = (n << s) | (n >>> (32 - s));
|
|
||||||
return t4;
|
|
||||||
};
|
|
||||||
|
|
||||||
function lsb_hex(val) {
|
|
||||||
var str = "";
|
|
||||||
var i;
|
|
||||||
var vh;
|
|
||||||
var vl;
|
|
||||||
|
|
||||||
for (i = 0; i <= 6; i += 2) {
|
|
||||||
vh = (val >>> (i * 4 + 4)) & 0x0f;
|
|
||||||
vl = (val >>> (i * 4)) & 0x0f;
|
|
||||||
str += vh.toString(16) + vl.toString(16);
|
|
||||||
}
|
|
||||||
return str;
|
|
||||||
};
|
|
||||||
|
|
||||||
function cvt_hex(val) {
|
|
||||||
var str = "";
|
|
||||||
var i;
|
|
||||||
var v;
|
|
||||||
|
|
||||||
for (i = 7; i >= 0; i--) {
|
|
||||||
v = (val >>> (i * 4)) & 0x0f;
|
|
||||||
str += v.toString(16);
|
|
||||||
}
|
|
||||||
return str;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
function Utf8Encode(string) {
|
|
||||||
string = string.replace(/\r\n/g, "\n");
|
|
||||||
var utftext = "";
|
|
||||||
|
|
||||||
for (var n = 0; n < string.length; n++) {
|
|
||||||
|
|
||||||
var c = string.charCodeAt(n);
|
|
||||||
|
|
||||||
if (c < 128) {
|
|
||||||
utftext += String.fromCharCode(c);
|
|
||||||
}
|
|
||||||
else if ((c > 127) && (c < 2048)) {
|
|
||||||
utftext += String.fromCharCode((c >> 6) | 192);
|
|
||||||
utftext += String.fromCharCode((c & 63) | 128);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
utftext += String.fromCharCode((c >> 12) | 224);
|
|
||||||
utftext += String.fromCharCode(((c >> 6) & 63) | 128);
|
|
||||||
utftext += String.fromCharCode((c & 63) | 128);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return utftext;
|
|
||||||
};
|
|
||||||
|
|
||||||
var blockstart;
|
|
||||||
var i, j;
|
|
||||||
var W = new Array(80);
|
|
||||||
var H0 = 0x67452301;
|
|
||||||
var H1 = 0xEFCDAB89;
|
|
||||||
var H2 = 0x98BADCFE;
|
|
||||||
var H3 = 0x10325476;
|
|
||||||
var H4 = 0xC3D2E1F0;
|
|
||||||
var A, B, C, D, E;
|
|
||||||
var temp;
|
|
||||||
|
|
||||||
msg = Utf8Encode(msg);
|
|
||||||
|
|
||||||
var msg_len = msg.length;
|
|
||||||
|
|
||||||
var word_array = new Array();
|
|
||||||
for (i = 0; i < msg_len - 3; i += 4) {
|
|
||||||
j = msg.charCodeAt(i) << 24 | msg.charCodeAt(i + 1) << 16 |
|
|
||||||
msg.charCodeAt(i + 2) << 8 | msg.charCodeAt(i + 3);
|
|
||||||
word_array.push(j);
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (msg_len % 4) {
|
|
||||||
case 0:
|
|
||||||
i = 0x080000000;
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
i = msg.charCodeAt(msg_len - 1) << 24 | 0x0800000;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 2:
|
|
||||||
i = msg.charCodeAt(msg_len - 2) << 24 | msg.charCodeAt(msg_len - 1) << 16 | 0x08000;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 3:
|
|
||||||
i = msg.charCodeAt(msg_len - 3) << 24 | msg.charCodeAt(msg_len - 2) << 16 | msg.charCodeAt(msg_len - 1) << 8 | 0x80;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
word_array.push(i);
|
|
||||||
|
|
||||||
while ((word_array.length % 16) != 14) word_array.push(0);
|
|
||||||
|
|
||||||
word_array.push(msg_len >>> 29);
|
|
||||||
word_array.push((msg_len << 3) & 0x0ffffffff);
|
|
||||||
|
|
||||||
|
|
||||||
for (blockstart = 0; blockstart < word_array.length; blockstart += 16) {
|
|
||||||
|
|
||||||
for (i = 0; i < 16; i++) W[i] = word_array[blockstart + i];
|
|
||||||
for (i = 16; i <= 79; i++) W[i] = rotate_left(W[i - 3] ^ W[i - 8] ^ W[i - 14] ^ W[i - 16], 1);
|
|
||||||
|
|
||||||
A = H0;
|
|
||||||
B = H1;
|
|
||||||
C = H2;
|
|
||||||
D = H3;
|
|
||||||
E = H4;
|
|
||||||
|
|
||||||
for (i = 0; i <= 19; i++) {
|
|
||||||
temp = (rotate_left(A, 5) + ((B & C) | (~B & D)) + E + W[i] + 0x5A827999) & 0x0ffffffff;
|
|
||||||
E = D;
|
|
||||||
D = C;
|
|
||||||
C = rotate_left(B, 30);
|
|
||||||
B = A;
|
|
||||||
A = temp;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 20; i <= 39; i++) {
|
|
||||||
temp = (rotate_left(A, 5) + (B ^ C ^ D) + E + W[i] + 0x6ED9EBA1) & 0x0ffffffff;
|
|
||||||
E = D;
|
|
||||||
D = C;
|
|
||||||
C = rotate_left(B, 30);
|
|
||||||
B = A;
|
|
||||||
A = temp;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 40; i <= 59; i++) {
|
|
||||||
temp = (rotate_left(A, 5) + ((B & C) | (B & D) | (C & D)) + E + W[i] + 0x8F1BBCDC) & 0x0ffffffff;
|
|
||||||
E = D;
|
|
||||||
D = C;
|
|
||||||
C = rotate_left(B, 30);
|
|
||||||
B = A;
|
|
||||||
A = temp;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 60; i <= 79; i++) {
|
|
||||||
temp = (rotate_left(A, 5) + (B ^ C ^ D) + E + W[i] + 0xCA62C1D6) & 0x0ffffffff;
|
|
||||||
E = D;
|
|
||||||
D = C;
|
|
||||||
C = rotate_left(B, 30);
|
|
||||||
B = A;
|
|
||||||
A = temp;
|
|
||||||
}
|
|
||||||
|
|
||||||
H0 = (H0 + A) & 0x0ffffffff;
|
|
||||||
H1 = (H1 + B) & 0x0ffffffff;
|
|
||||||
H2 = (H2 + C) & 0x0ffffffff;
|
|
||||||
H3 = (H3 + D) & 0x0ffffffff;
|
|
||||||
H4 = (H4 + E) & 0x0ffffffff;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
var temp = cvt_hex(H0) + cvt_hex(H1) + cvt_hex(H2) + cvt_hex(H3) + cvt_hex(H4);
|
|
||||||
|
|
||||||
return temp.toLowerCase();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// jqm.page.params.js - version 0.1
|
|
||||||
// Copyright (c) 2011, Kin Blas
|
|
||||||
// All rights reserved.
|
|
||||||
//
|
|
||||||
// Redistribution and use in source and binary forms, with or without
|
|
||||||
// modification, are permitted provided that the following conditions are met:
|
|
||||||
// * Redistributions of source code must retain the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer.
|
|
||||||
// * Redistributions in binary form must reproduce the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer in the
|
|
||||||
// documentation and/or other materials provided with the distribution.
|
|
||||||
// * Neither the name of the <organization> nor the
|
|
||||||
// names of its contributors may be used to endorse or promote products
|
|
||||||
// derived from this software without specific prior written permission.
|
|
||||||
//
|
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
// DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
|
||||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
|
|
||||||
(function ($, window, undefined) {
|
|
||||||
|
|
||||||
// Given a query string, convert all the name/value pairs
|
|
||||||
// into a property/value object. If a name appears more than
|
|
||||||
// once in a query string, the value is automatically turned
|
|
||||||
// into an array.
|
|
||||||
function queryStringToObject(qstr) {
|
|
||||||
var result = {}, nvPairs = ((qstr || "").replace(/^\?/, "").split(/&/)), i, pair, n, v;
|
|
||||||
|
|
||||||
for (i = 0; i < nvPairs.length; i++) {
|
|
||||||
var pstr = nvPairs[i];
|
|
||||||
if (pstr) {
|
|
||||||
pair = pstr.split(/=/);
|
|
||||||
n = pair[0];
|
|
||||||
v = pair[1];
|
|
||||||
if (result[n] === undefined) {
|
|
||||||
result[n] = v;
|
|
||||||
} else {
|
|
||||||
if (typeof result[n] !== "object") {
|
|
||||||
result[n] = [result[n]];
|
|
||||||
}
|
|
||||||
result[n].push(v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// The idea here is to listen for any pagebeforechange notifications from
|
|
||||||
// jQuery Mobile, and then muck with the toPage and options so that query
|
|
||||||
// params can be passed to embedded/internal pages. So for example, if a
|
|
||||||
// changePage() request for a URL like:
|
|
||||||
//
|
|
||||||
// http://mycompany.com/myapp/#page-1?foo=1&bar=2
|
|
||||||
//
|
|
||||||
// is made, the page that will actually get shown is:
|
|
||||||
//
|
|
||||||
// http://mycompany.com/myapp/#page-1
|
|
||||||
//
|
|
||||||
// The browser's location will still be updated to show the original URL.
|
|
||||||
// The query params for the embedded page are also added as a property/value
|
|
||||||
// object on the options object. You can access it from your page notifications
|
|
||||||
// via data.options.pageData.
|
|
||||||
$(document).bind("pagebeforechange", function (e, data) {
|
|
||||||
|
|
||||||
// We only want to handle the case where we are being asked
|
|
||||||
// to go to a page by URL, and only if that URL is referring
|
|
||||||
// to an internal page by id.
|
|
||||||
|
|
||||||
if (typeof data.toPage === "string") {
|
|
||||||
var u = $.mobile.path.parseUrl(data.toPage);
|
|
||||||
if ($.mobile.path.isEmbeddedPage(u)) {
|
|
||||||
|
|
||||||
// The request is for an internal page, if the hash
|
|
||||||
// contains query (search) params, strip them off the
|
|
||||||
// toPage URL and then set options.dataUrl appropriately
|
|
||||||
// so the location.hash shows the originally requested URL
|
|
||||||
// that hash the query params in the hash.
|
|
||||||
|
|
||||||
var u2 = $.mobile.path.parseUrl(u.hash.replace(/^#/, ""));
|
|
||||||
if (u2.search) {
|
|
||||||
if (!data.options.dataUrl) {
|
|
||||||
data.options.dataUrl = data.toPage;
|
|
||||||
}
|
|
||||||
data.options.pageData = queryStringToObject(u2.search);
|
|
||||||
data.toPage = u.hrefNoHash + "#" + u2.pathname;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
})(jQuery, window);
|
|
|
@ -1,106 +0,0 @@
|
||||||
var IndexPage = {
|
|
||||||
|
|
||||||
onPageShow: function () {
|
|
||||||
IndexPage.loadLibrary(Dashboard.getCurrentUserId(), this);
|
|
||||||
},
|
|
||||||
|
|
||||||
loadLibrary: function (userId, page) {
|
|
||||||
|
|
||||||
if (!userId) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
page = $(page);
|
|
||||||
|
|
||||||
var options = {
|
|
||||||
|
|
||||||
limit: 5,
|
|
||||||
sortBy: "DateCreated",
|
|
||||||
sortOrder: "Descending",
|
|
||||||
filters: "IsRecentlyAdded,IsNotFolder",
|
|
||||||
ImageTypes: "Primary,Backdrop,Thumb",
|
|
||||||
recursive: true
|
|
||||||
};
|
|
||||||
|
|
||||||
ApiClient.getItems(userId, options).done(function (result) {
|
|
||||||
|
|
||||||
$('#divWhatsNew', page).html(Dashboard.getPosterViewHtml({
|
|
||||||
items: result.Items,
|
|
||||||
preferBackdrop: true,
|
|
||||||
showTitle: true
|
|
||||||
}));
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
options = {
|
|
||||||
|
|
||||||
limit: 5,
|
|
||||||
sortBy: "DatePlayed",
|
|
||||||
sortOrder: "Descending",
|
|
||||||
filters: "IsResumable",
|
|
||||||
recursive: true
|
|
||||||
};
|
|
||||||
|
|
||||||
ApiClient.getItems(userId, options).done(function (result) {
|
|
||||||
|
|
||||||
$('#divResumableItems', page).html(Dashboard.getPosterViewHtml({
|
|
||||||
items: result.Items,
|
|
||||||
preferBackdrop: true,
|
|
||||||
showTitle: true
|
|
||||||
}));
|
|
||||||
|
|
||||||
if (result.Items.length) {
|
|
||||||
$('#divResumable', page).show();
|
|
||||||
} else {
|
|
||||||
$('#divResumable', page).hide();
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
options = {
|
|
||||||
|
|
||||||
sortBy: "SortName"
|
|
||||||
};
|
|
||||||
|
|
||||||
ApiClient.getItems(userId, options).done(function (result) {
|
|
||||||
|
|
||||||
$('#divCollections', page).html(Dashboard.getPosterViewHtml({
|
|
||||||
items: result.Items,
|
|
||||||
showTitle: true
|
|
||||||
}));
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
IndexPage.loadMyLibrary(userId, page);
|
|
||||||
},
|
|
||||||
|
|
||||||
loadMyLibrary: function (userId, page) {
|
|
||||||
|
|
||||||
var items = [{
|
|
||||||
Name: "Recently Played",
|
|
||||||
IsFolder: true
|
|
||||||
}, {
|
|
||||||
Name: "Favorites",
|
|
||||||
IsFolder: true
|
|
||||||
}, {
|
|
||||||
Name: "Genres",
|
|
||||||
IsFolder: true
|
|
||||||
}, {
|
|
||||||
Name: "Studios",
|
|
||||||
IsFolder: true
|
|
||||||
}, {
|
|
||||||
Name: "Performers",
|
|
||||||
IsFolder: true
|
|
||||||
}, {
|
|
||||||
Name: "Directors",
|
|
||||||
IsFolder: true
|
|
||||||
}];
|
|
||||||
|
|
||||||
$('#divMyLibrary', page).html(Dashboard.getPosterViewHtml({
|
|
||||||
items: items,
|
|
||||||
showTitle: true
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
$(document).on('pageshow', "#indexPage", IndexPage.onPageShow);
|
|
|
@ -1,376 +0,0 @@
|
||||||
var ItemDetailPage = {
|
|
||||||
|
|
||||||
onPageShow: function () {
|
|
||||||
|
|
||||||
ItemDetailPage.reload();
|
|
||||||
|
|
||||||
$('#galleryCollapsible', this).on('expand', ItemDetailPage.onGalleryExpand);
|
|
||||||
},
|
|
||||||
|
|
||||||
onPageHide: function () {
|
|
||||||
|
|
||||||
$('#galleryCollapsible', this).off('expand', ItemDetailPage.onGalleryExpand);
|
|
||||||
|
|
||||||
ItemDetailPage.item = null;
|
|
||||||
},
|
|
||||||
|
|
||||||
reload: function () {
|
|
||||||
var id = getParameterByName('id');
|
|
||||||
|
|
||||||
Dashboard.showLoadingMsg();
|
|
||||||
|
|
||||||
ApiClient.getItem(Dashboard.getCurrentUserId(), id).done(ItemDetailPage.renderItem);
|
|
||||||
},
|
|
||||||
|
|
||||||
renderItem: function (item) {
|
|
||||||
|
|
||||||
ItemDetailPage.item = item;
|
|
||||||
|
|
||||||
var page = $.mobile.activePage;
|
|
||||||
|
|
||||||
ItemDetailPage.item = item;
|
|
||||||
|
|
||||||
var name = item.Name;
|
|
||||||
|
|
||||||
if (item.IndexNumber != null) {
|
|
||||||
name = item.IndexNumber + " - " + name;
|
|
||||||
}
|
|
||||||
|
|
||||||
Dashboard.setPageTitle(name);
|
|
||||||
|
|
||||||
ItemDetailPage.renderImage(item);
|
|
||||||
ItemDetailPage.renderOverviewBlock(item);
|
|
||||||
ItemDetailPage.renderScenes(item);
|
|
||||||
ItemDetailPage.renderMediaInfo(item);
|
|
||||||
|
|
||||||
$('#itemName', page).html(name);
|
|
||||||
|
|
||||||
Dashboard.hideLoadingMsg();
|
|
||||||
},
|
|
||||||
|
|
||||||
renderImage: function (item) {
|
|
||||||
|
|
||||||
var page = $.mobile.activePage;
|
|
||||||
|
|
||||||
var imageTags = item.ImageTags || {};
|
|
||||||
|
|
||||||
var html = '';
|
|
||||||
|
|
||||||
var url;
|
|
||||||
var useBackgroundColor;
|
|
||||||
|
|
||||||
if (imageTags.Primary) {
|
|
||||||
|
|
||||||
url = ApiClient.getImageUrl(item.Id, {
|
|
||||||
type: "Primary",
|
|
||||||
width: 800,
|
|
||||||
tag: item.ImageTags.Primary
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else if (item.BackdropImageTags && item.BackdropImageTags.length) {
|
|
||||||
|
|
||||||
url = ApiClient.getImageUrl(item.Id, {
|
|
||||||
type: "Backdrop",
|
|
||||||
width: 800,
|
|
||||||
tag: item.BackdropImageTags[0]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else if (imageTags.Thumb) {
|
|
||||||
|
|
||||||
url = ApiClient.getImageUrl(item.Id, {
|
|
||||||
type: "Thumb",
|
|
||||||
width: 800,
|
|
||||||
tag: item.ImageTags.Thumb
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else if (imageTags.Disc) {
|
|
||||||
|
|
||||||
url = ApiClient.getImageUrl(item.Id, {
|
|
||||||
type: "Disc",
|
|
||||||
width: 800,
|
|
||||||
tag: item.ImageTags.Disc
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else if (item.MediaType == "Audio") {
|
|
||||||
url = "css/images/itemDetails/audioDefault.png";
|
|
||||||
useBackgroundColor = true;
|
|
||||||
}
|
|
||||||
else if (item.MediaType == "Game") {
|
|
||||||
url = "css/images/itemDetails/gameDefault.png";
|
|
||||||
useBackgroundColor = true;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
url = "css/images/itemDetails/videoDefault.png";
|
|
||||||
useBackgroundColor = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (url) {
|
|
||||||
|
|
||||||
var style = useBackgroundColor ? "background-color:" + Dashboard.getRandomMetroColor() + ";" : "";
|
|
||||||
|
|
||||||
html += "<img class='itemDetailImage' src='" + url + "' style='" + style + "' />";
|
|
||||||
}
|
|
||||||
|
|
||||||
$('#itemImage', page).html(html);
|
|
||||||
},
|
|
||||||
|
|
||||||
renderOverviewBlock: function (item) {
|
|
||||||
|
|
||||||
var page = $.mobile.activePage;
|
|
||||||
|
|
||||||
if (item.Taglines && item.Taglines.length) {
|
|
||||||
$('#itemTagline', page).html(item.Taglines[0]).show();
|
|
||||||
} else {
|
|
||||||
$('#itemTagline', page).hide();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (item.Overview) {
|
|
||||||
$('#itemOverview', page).html(item.Overview).show();
|
|
||||||
} else {
|
|
||||||
$('#itemOverview', page).hide();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (item.CommunityRating) {
|
|
||||||
$('#itemCommunityRating', page).html(ItemDetailPage.getStarRating(item)).show().attr('title', item.CommunityRating);
|
|
||||||
} else {
|
|
||||||
$('#itemCommunityRating', page).hide();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (MediaPlayer.canPlay(item)) {
|
|
||||||
$('#btnPlay', page).show();
|
|
||||||
$('#playButtonShadow', page).show();
|
|
||||||
} else {
|
|
||||||
$('#btnPlay', page).hide();
|
|
||||||
$('#playButtonShadow', page).hide();
|
|
||||||
}
|
|
||||||
|
|
||||||
var miscInfo = [];
|
|
||||||
|
|
||||||
if (item.ProductionYear) {
|
|
||||||
miscInfo.push(item.ProductionYear);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (item.OfficialRating) {
|
|
||||||
miscInfo.push(item.OfficialRating);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (item.RunTimeTicks) {
|
|
||||||
|
|
||||||
var minutes = item.RunTimeTicks / 600000000;
|
|
||||||
|
|
||||||
minutes = minutes || 1;
|
|
||||||
|
|
||||||
miscInfo.push(parseInt(minutes) + "min");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (item.DisplayMediaType) {
|
|
||||||
miscInfo.push(item.DisplayMediaType);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (item.VideoFormat && item.VideoFormat !== 'Standard') {
|
|
||||||
miscInfo.push(item.VideoFormat);
|
|
||||||
}
|
|
||||||
|
|
||||||
$('#itemMiscInfo', page).html(miscInfo.join(' '));
|
|
||||||
|
|
||||||
ItemDetailPage.renderGenres(item);
|
|
||||||
ItemDetailPage.renderStudios(item);
|
|
||||||
},
|
|
||||||
|
|
||||||
renderGenres: function (item) {
|
|
||||||
|
|
||||||
var page = $.mobile.activePage;
|
|
||||||
|
|
||||||
if (item.Genres && item.Genres.length) {
|
|
||||||
var elem = $('#itemGenres', page).show();
|
|
||||||
|
|
||||||
var html = 'Genres: ';
|
|
||||||
|
|
||||||
for (var i = 0, length = item.Genres.length; i < length; i++) {
|
|
||||||
|
|
||||||
if (i > 0) {
|
|
||||||
html += ' / ';
|
|
||||||
}
|
|
||||||
|
|
||||||
html += '<a class="interiorLink" href="#">' + item.Genres[i] + '</a>';
|
|
||||||
}
|
|
||||||
|
|
||||||
elem.html(html);
|
|
||||||
|
|
||||||
|
|
||||||
} else {
|
|
||||||
$('#itemGenres', page).hide();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
renderStudios: function (item) {
|
|
||||||
|
|
||||||
var page = $.mobile.activePage;
|
|
||||||
|
|
||||||
if (item.Studios && item.Studios.length) {
|
|
||||||
var elem = $('#itemStudios', page).show();
|
|
||||||
|
|
||||||
var html = 'Studios: ';
|
|
||||||
|
|
||||||
for (var i = 0, length = item.Studios.length; i < length; i++) {
|
|
||||||
|
|
||||||
if (i > 0) {
|
|
||||||
html += ' / ';
|
|
||||||
}
|
|
||||||
|
|
||||||
html += '<a class="interiorLink" href="#">' + item.Studios[i] + '</a>';
|
|
||||||
}
|
|
||||||
|
|
||||||
elem.html(html);
|
|
||||||
|
|
||||||
|
|
||||||
} else {
|
|
||||||
$('#itemStudios', page).hide();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
getStarRating: function (item) {
|
|
||||||
var rating = item.CommunityRating;
|
|
||||||
|
|
||||||
var html = "";
|
|
||||||
for (var i = 1; i <= 10; i++) {
|
|
||||||
if (rating < i - 1) {
|
|
||||||
html += "<div class='starRating emptyStarRating'></div>";
|
|
||||||
}
|
|
||||||
else if (rating < i) {
|
|
||||||
html += "<div class='starRating halfStarRating'></div>";
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
html += "<div class='starRating'></div>";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return html;
|
|
||||||
},
|
|
||||||
|
|
||||||
renderScenes: function (item) {
|
|
||||||
|
|
||||||
var html = '';
|
|
||||||
|
|
||||||
var page = $.mobile.activePage;
|
|
||||||
|
|
||||||
if (!item.Chapters || !item.Chapters.length) {
|
|
||||||
$('#scenesCollapsible', page).hide();
|
|
||||||
$('#scenesContent', page).html(html);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (var i = 0, length = item.Chapters.length; i < length; i++) {
|
|
||||||
|
|
||||||
var chapter = item.Chapters[i];
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
$('#scenesCollapsible', page).show();
|
|
||||||
$('#scenesContent', page).html(html);
|
|
||||||
},
|
|
||||||
|
|
||||||
play: function () {
|
|
||||||
MediaPlayer.play([ItemDetailPage.item]);
|
|
||||||
},
|
|
||||||
|
|
||||||
onGalleryExpand: function() {
|
|
||||||
|
|
||||||
if (ItemDetailPage.item) {
|
|
||||||
|
|
||||||
ItemDetailPage.renderGallery(ItemDetailPage.item);
|
|
||||||
|
|
||||||
$(this).off('expand', ItemDetailPage.onGalleryExpand);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
renderGallery: function (item) {
|
|
||||||
|
|
||||||
var page = $.mobile.activePage;
|
|
||||||
|
|
||||||
var imageTags = item.ImageTags || {};
|
|
||||||
|
|
||||||
var html = '';
|
|
||||||
|
|
||||||
var downloadWidth = 400;
|
|
||||||
|
|
||||||
if (imageTags.Logo) {
|
|
||||||
|
|
||||||
html += '<img class="galleryImage" src="' + ApiClient.getImageUrl(item.Id, {
|
|
||||||
type: "Logo",
|
|
||||||
width: downloadWidth,
|
|
||||||
tag: item.ImageTags.Logo
|
|
||||||
}) + '" />';
|
|
||||||
}
|
|
||||||
if (imageTags.Thumb) {
|
|
||||||
|
|
||||||
html += '<img class="galleryImage" src="' + ApiClient.getImageUrl(item.Id, {
|
|
||||||
type: "Thumb",
|
|
||||||
width: downloadWidth,
|
|
||||||
tag: item.ImageTags.Thumb
|
|
||||||
}) + '" />';
|
|
||||||
}
|
|
||||||
if (imageTags.Art) {
|
|
||||||
|
|
||||||
html += '<img class="galleryImage" src="' + ApiClient.getImageUrl(item.Id, {
|
|
||||||
type: "Art",
|
|
||||||
width: downloadWidth,
|
|
||||||
tag: item.ImageTags.Art
|
|
||||||
}) + '" />';
|
|
||||||
}
|
|
||||||
if (imageTags.Menu) {
|
|
||||||
|
|
||||||
html += '<img class="galleryImage" src="' + ApiClient.getImageUrl(item.Id, {
|
|
||||||
type: "Menu",
|
|
||||||
width: downloadWidth,
|
|
||||||
tag: item.ImageTags.Menu
|
|
||||||
}) + '" />';
|
|
||||||
}
|
|
||||||
if (imageTags.Disc) {
|
|
||||||
|
|
||||||
html += '<img class="galleryImage" src="' + ApiClient.getImageUrl(item.Id, {
|
|
||||||
type: "Disc",
|
|
||||||
width: downloadWidth,
|
|
||||||
tag: item.ImageTags.Disc
|
|
||||||
}) + '" />';
|
|
||||||
}
|
|
||||||
if (imageTags.Box) {
|
|
||||||
|
|
||||||
html += '<img class="galleryImage" src="' + ApiClient.getImageUrl(item.Id, {
|
|
||||||
type: "Box",
|
|
||||||
width: downloadWidth,
|
|
||||||
tag: item.ImageTags.Box
|
|
||||||
}) + '" />';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (item.BackdropImageTags) {
|
|
||||||
|
|
||||||
for (var i = 0, length = item.BackdropImageTags.length; i < length; i++) {
|
|
||||||
html += '<img class="galleryImage" src="' + ApiClient.getImageUrl(item.Id, {
|
|
||||||
type: "Backdrop",
|
|
||||||
width: downloadWidth,
|
|
||||||
tag: item.BackdropImageTags[0],
|
|
||||||
index: i
|
|
||||||
}) + '" />';
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
$('#galleryContent', page).html(html);
|
|
||||||
},
|
|
||||||
|
|
||||||
renderMediaInfo: function(item) {
|
|
||||||
|
|
||||||
var page = $.mobile.activePage;
|
|
||||||
|
|
||||||
if (!item.MediaStreams || !item.MediaStreams.length) {
|
|
||||||
$('#mediaInfoCollapsible', page).hide();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$('#mediaInfoCollapsible', page).show();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
$(document).on('pageshow', "#itemDetailPage", ItemDetailPage.onPageShow).on('pagehide', "#itemDetailPage", ItemDetailPage.onPageHide);
|
|
|
@ -1,46 +0,0 @@
|
||||||
var ItemListPage = {
|
|
||||||
|
|
||||||
onPageShow: function () {
|
|
||||||
|
|
||||||
ItemListPage.reload();
|
|
||||||
},
|
|
||||||
|
|
||||||
reload: function () {
|
|
||||||
|
|
||||||
var userId = Dashboard.getCurrentUserId();
|
|
||||||
|
|
||||||
var parentId = getParameterByName('parentId');
|
|
||||||
|
|
||||||
var query = {};
|
|
||||||
|
|
||||||
if (parentId) {
|
|
||||||
query.parentId = parentId;
|
|
||||||
|
|
||||||
ApiClient.getItem(userId, parentId).done(ItemListPage.renderTitle);
|
|
||||||
}
|
|
||||||
|
|
||||||
ApiClient.getItems(userId, query).done(ItemListPage.renderItems);
|
|
||||||
},
|
|
||||||
|
|
||||||
renderItems: function(result) {
|
|
||||||
|
|
||||||
var items = result.Items;
|
|
||||||
|
|
||||||
var renderOptions = {
|
|
||||||
|
|
||||||
items: items
|
|
||||||
};
|
|
||||||
|
|
||||||
var html = Dashboard.getPosterViewHtml(renderOptions);
|
|
||||||
|
|
||||||
$('#listItems', $.mobile.activePage).html(html);
|
|
||||||
},
|
|
||||||
|
|
||||||
renderTitle: function (item) {
|
|
||||||
|
|
||||||
|
|
||||||
$('#itemName', $.mobile.activePage).html(item.Name);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
$(document).on('pageshow', "#itemListPage", ItemListPage.onPageShow);
|
|