From 605878700dc10792b267d5f7ac2d834e904d565e Mon Sep 17 00:00:00 2001 From: tidusjar Date: Wed, 25 May 2016 16:38:51 +0100 Subject: [PATCH 01/26] Fixed an issue where if you have only 1 plex friend it would not show in the list --- PlexRequests.UI/Views/Admin/Authentication.cshtml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PlexRequests.UI/Views/Admin/Authentication.cshtml b/PlexRequests.UI/Views/Admin/Authentication.cshtml index db3fc8819..8e2d89a5a 100644 --- a/PlexRequests.UI/Views/Admin/Authentication.cshtml +++ b/PlexRequests.UI/Views/Admin/Authentication.cshtml @@ -161,7 +161,7 @@ $('#users').append(""); return; } - if (response.users.length > 1) { + if (response.users.length > 0) { $(response.users).each(function () { $('#users').append(""); }); From c43e3a93d2b879ad837239936f69bcf498829827 Mon Sep 17 00:00:00 2001 From: tidusjar Date: Thu, 26 May 2016 08:56:36 +0100 Subject: [PATCH 02/26] Fixed #270 --- PlexRequests.UI/Modules/RequestsModule.cs | 2 +- PlexRequests.UI/Modules/SearchModule.cs | 3 ++- PlexRequests.UI/Views/Requests/Index.cshtml | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/PlexRequests.UI/Modules/RequestsModule.cs b/PlexRequests.UI/Modules/RequestsModule.cs index f813c038d..64e150f58 100644 --- a/PlexRequests.UI/Modules/RequestsModule.cs +++ b/PlexRequests.UI/Modules/RequestsModule.cs @@ -196,7 +196,7 @@ private Response GetTvShows() // TODO: async await the API calls { dbTv = t.Result.ToList(); - if (settings.UsersCanViewOnlyOwnRequests && !IsAdmin) + if (settings.UsersCanViewOnlyOwnRequests && !IsAdmin) { dbTv = dbTv.Where(x => x.UserHasRequested(Username)).ToList(); } diff --git a/PlexRequests.UI/Modules/SearchModule.cs b/PlexRequests.UI/Modules/SearchModule.cs index efae9678a..97c9ada30 100644 --- a/PlexRequests.UI/Modules/SearchModule.cs +++ b/PlexRequests.UI/Modules/SearchModule.cs @@ -627,7 +627,7 @@ private Response RequestTvShow(int showId, string seasons) RequestedUsers = new List { Username }, Issues = IssueState.None, ImdbId = showInfo.externals?.imdb ?? string.Empty, - SeasonCount = showInfo.seasonCount + SeasonCount = showInfo.seasonCount, }; var seasonsList = new List(); @@ -645,6 +645,7 @@ private Response RequestTvShow(int showId, string seasons) model.SeasonsRequested = "All"; break; default: + model.SeasonsRequested = seasons; var split = seasons.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); var seasonsCount = new int[split.Length]; for (var i = 0; i < split.Length; i++) diff --git a/PlexRequests.UI/Views/Requests/Index.cshtml b/PlexRequests.UI/Views/Requests/Index.cshtml index cdf45b288..d61f8b070 100644 --- a/PlexRequests.UI/Views/Requests/Index.cshtml +++ b/PlexRequests.UI/Views/Requests/Index.cshtml @@ -169,7 +169,7 @@ {{/if_eq}} {{#if_eq type "tv"}} -
Series Requested: {{seriesRequested}}
+
Seasons Requested: {{seriesRequested}}
{{/if_eq}} {{#if requestedUsers}}
Requested By: {{requestedUsers}}
From 573ad84fd81c4252ba30883933c9b8ebf48ab6a1 Mon Sep 17 00:00:00 2001 From: tidusjar Date: Thu, 26 May 2016 09:01:47 +0100 Subject: [PATCH 03/26] Fixed #240 --- .../Notification/EmailMessageNotification.cs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/PlexRequests.Services/Notification/EmailMessageNotification.cs b/PlexRequests.Services/Notification/EmailMessageNotification.cs index f2217dc7e..20ef3f612 100644 --- a/PlexRequests.Services/Notification/EmailMessageNotification.cs +++ b/PlexRequests.Services/Notification/EmailMessageNotification.cs @@ -62,7 +62,10 @@ public async Task NotifyAsync(NotificationModel model, Settings settings) var emailSettings = (EmailNotificationSettings)settings; - if (!ValidateConfiguration(emailSettings)) return; + if (!ValidateConfiguration(emailSettings)) + { + return; + } switch (model.NotificationType) { @@ -96,13 +99,17 @@ private EmailNotificationSettings GetConfiguration() private bool ValidateConfiguration(EmailNotificationSettings settings) { - if (!settings.Enabled) + if (string.IsNullOrEmpty(settings.EmailHost) || string.IsNullOrEmpty(settings.EmailUsername) || string.IsNullOrEmpty(settings.EmailPassword) || string.IsNullOrEmpty(settings.RecipientEmail) || string.IsNullOrEmpty(settings.EmailPort.ToString())) { return false; } - if (string.IsNullOrEmpty(settings.EmailHost) || string.IsNullOrEmpty(settings.EmailUsername) || string.IsNullOrEmpty(settings.EmailPassword) || string.IsNullOrEmpty(settings.RecipientEmail) || string.IsNullOrEmpty(settings.EmailPort.ToString())) + + if (!settings.EnableUserEmailNotifications) { - return false; + if (!settings.Enabled) + { + return false; + } } return true; From 25714f03f7ef778c45f1ef98fa21b62c90260467 Mon Sep 17 00:00:00 2001 From: tidusjar Date: Thu, 26 May 2016 13:40:44 +0100 Subject: [PATCH 04/26] Fixed #244 --- PlexRequests.UI/Modules/ApprovalModule.cs | 53 ++++++++++++++--------- PlexRequests.UI/Modules/SearchModule.cs | 21 ++++++++- 2 files changed, 53 insertions(+), 21 deletions(-) diff --git a/PlexRequests.UI/Modules/ApprovalModule.cs b/PlexRequests.UI/Modules/ApprovalModule.cs index c7e95dbd3..2f83e8757 100644 --- a/PlexRequests.UI/Modules/ApprovalModule.cs +++ b/PlexRequests.UI/Modules/ApprovalModule.cs @@ -50,7 +50,7 @@ public ApprovalModule(IRequestService service, ISettingsService sonarrSettings, ISickRageApi srApi, ISettingsService srSettings, ISettingsService hpSettings, IHeadphonesApi hpApi, ISettingsService pr) : base("approval", pr) { - this.RequiresClaims(UserClaims.Admin); + this.RequiresClaims(UserClaims.Admin); Service = service; CpService = cpService; @@ -130,7 +130,7 @@ private Response RequestTvAndUpdateStatus(RequestedModel request, string quality Log.Trace("Approval result: {0}", requestResult); if (requestResult) { - return Response.AsJson(new JsonResponseModel {Result = true}); + return Response.AsJson(new JsonResponseModel { Result = true }); } return Response.AsJson(new JsonResponseModel @@ -156,11 +156,9 @@ private Response RequestTvAndUpdateStatus(RequestedModel request, string quality request.Approved = true; var requestResult = Service.UpdateRequest(request); Log.Trace("Approval result: {0}", requestResult); - if (requestResult) - { - return Response.AsJson(new JsonResponseModel { Result = true }); - } - return Response.AsJson(new JsonResponseModel { Result = false, Message = "Updated SickRage but could not approve it in PlexRequests :(" }); + return Response.AsJson(requestResult + ? new JsonResponseModel { Result = true } + : new JsonResponseModel { Result = false, Message = "Updated SickRage but could not approve it in PlexRequests :(" }); } return Response.AsJson(new JsonResponseModel { @@ -168,11 +166,13 @@ private Response RequestTvAndUpdateStatus(RequestedModel request, string quality Message = result?.message != null ? "Message From SickRage: " + result.message : "Could not add the series to SickRage" }); } - return Response.AsJson(new JsonResponseModel - { - Result = false, - Message = "SickRage or Sonarr are not set up!" - }); + + + request.Approved = true; + var res = Service.UpdateRequest(request); + return Response.AsJson(res + ? new JsonResponseModel { Result = true, Message = "This has been approved, but It has not been sent to Sonarr/SickRage because it has not been configured" } + : new JsonResponseModel { Result = false, Message = "Updated SickRage but could not approve it in PlexRequests :(" }); } private Response RequestMovieAndUpdateStatus(RequestedModel request, string qualityId) @@ -248,9 +248,9 @@ private Response RequestAlbumAndUpdateStatus(RequestedModel request) var sender = new HeadphonesSender(HeadphoneApi, hpSettings, Service); var result = sender.AddAlbum(request); - - return Response.AsJson( new JsonResponseModel { Result = true, Message = "We have sent the approval to Headphones for processing, This can take a few minutes."} ); + + return Response.AsJson(new JsonResponseModel { Result = true, Message = "We have sent the approval to Headphones for processing, This can take a few minutes." }); } private Response ApproveAllMovies() @@ -327,15 +327,23 @@ private Response UpdateRequests(RequestedModel[] requestedModels) { if (r.Type == RequestType.Movie) { - var res = SendMovie(cpSettings, r, CpApi); - if (res) + if (cpSettings.Enabled) { - r.Approved = true; - updatedRequests.Add(r); + var res = SendMovie(cpSettings, r, CpApi); + if (res) + { + r.Approved = true; + updatedRequests.Add(r); + } + else + { + Log.Error("Could not approve and send the movie {0} to couch potato!", r.Title); + } } else { - Log.Error("Could not approve and send the movie {0} to couch potato!", r.Title); + r.Approved = true; + updatedRequests.Add(r); } } if (r.Type == RequestType.TvShow) @@ -358,7 +366,7 @@ private Response UpdateRequests(RequestedModel[] requestedModels) } } - if (sonarr.Enabled) + else if (sonarr.Enabled) { var res = sender.SendToSonarr(sonarr, r); if (!string.IsNullOrEmpty(res?.title)) @@ -372,6 +380,11 @@ private Response UpdateRequests(RequestedModel[] requestedModels) res?.ErrorMessages.ForEach(x => Log.Error("Error messages: {0}", x)); } } + else + { + r.Approved = true; + updatedRequests.Add(r); + } } } try diff --git a/PlexRequests.UI/Modules/SearchModule.cs b/PlexRequests.UI/Modules/SearchModule.cs index 97c9ada30..d84447477 100644 --- a/PlexRequests.UI/Modules/SearchModule.cs +++ b/PlexRequests.UI/Modules/SearchModule.cs @@ -606,7 +606,7 @@ private Response RequestTvShow(int showId, string seasons) return Response.AsJson(new JsonResponseModel { Result = false, Message = $"{fullShowName} is already in Plex!" }); } } - catch (ApplicationSettingsException) + catch (Exception) { return Response.AsJson(new JsonResponseModel { Result = false, Message = $"We could not check if {fullShowName} is in Plex, are you sure it's correctly setup?" }); } @@ -718,6 +718,25 @@ private Response RequestTvShow(int showId, string seasons) return Response.AsJson(new JsonResponseModel { Result = false, Message = result?.message != null ? "Message From SickRage: " + result.message : "Something went wrong adding the movie to SickRage! Please check your settings." }); } + if (!srSettings.Enabled && !sonarrSettings.Enabled) + { + model.Approved = true; + Log.Debug("Adding tv to database requests (No approval required) and Sonarr/Sickrage not setup"); + RequestService.AddRequest(model); + if (ShouldSendNotification()) + { + var notify2 = new NotificationModel + { + Title = model.Title, + User = Username, + DateTime = DateTime.Now, + NotificationType = NotificationType.NewRequest + }; + NotificationService.Publish(notify2); + } + return Response.AsJson(new JsonResponseModel { Result = true, Message = $"{fullShowName} was successfully added!" }); + } + return Response.AsJson(new JsonResponseModel { Result = false, Message = "The request of TV Shows is not correctly set up. Please contact your admin." }); } From a679f1a6a17108fdd5692d91f49990350f252c84 Mon Sep 17 00:00:00 2001 From: Drewster727 Date: Thu, 26 May 2016 10:57:30 -0500 Subject: [PATCH 05/26] fix null exception possibility in cp/sickrage cacher classes --- PlexRequests.Services/Jobs/CouchPotatoCacher.cs | 2 +- PlexRequests.Services/Jobs/SickRageCacher.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/PlexRequests.Services/Jobs/CouchPotatoCacher.cs b/PlexRequests.Services/Jobs/CouchPotatoCacher.cs index 6b905a9b3..3fb831b12 100644 --- a/PlexRequests.Services/Jobs/CouchPotatoCacher.cs +++ b/PlexRequests.Services/Jobs/CouchPotatoCacher.cs @@ -87,7 +87,7 @@ public void Queued() public int[] QueuedIds() { var movies = Cache.Get(CacheKeys.CouchPotatoQueued); - return movies?.movies.Select(x => x.info.tmdb_id).ToArray() ?? new int[] { }; + return movies?.movies?.Select(x => x.info.tmdb_id).ToArray() ?? new int[] { }; } public void Execute(IJobExecutionContext context) diff --git a/PlexRequests.Services/Jobs/SickRageCacher.cs b/PlexRequests.Services/Jobs/SickRageCacher.cs index 69b50b358..cece5100d 100644 --- a/PlexRequests.Services/Jobs/SickRageCacher.cs +++ b/PlexRequests.Services/Jobs/SickRageCacher.cs @@ -87,7 +87,7 @@ public void Queued() public int[] QueuedIds() { var tv = Cache.Get(CacheKeys.SickRageQueued); - return tv?.data.Values.Select(x => x.tvdbid).ToArray() ?? new int[] { }; + return tv?.data?.Values.Select(x => x.tvdbid).ToArray() ?? new int[] { }; } public void Execute(IJobExecutionContext context) From 16bd4f5b71ffc3c7e7cd6b5015ace2daabe0c356 Mon Sep 17 00:00:00 2001 From: tidusjar Date: Thu, 26 May 2016 17:31:01 +0100 Subject: [PATCH 06/26] Set the admin to have all claims --- PlexRequests.Core/Setup.cs | 31 +++++++++++++++ PlexRequests.Core/UserMapper.cs | 39 ++++++++++++++++++- PlexRequests.UI/Modules/LoginModule.cs | 3 +- .../Modules/UserManagementModule.cs | 34 ++++++++-------- 4 files changed, 87 insertions(+), 20 deletions(-) diff --git a/PlexRequests.Core/Setup.cs b/PlexRequests.Core/Setup.cs index 8bdf2faa6..740bc3df1 100644 --- a/PlexRequests.Core/Setup.cs +++ b/PlexRequests.Core/Setup.cs @@ -61,6 +61,10 @@ public string SetupDb(string urlBase) { MigrateToVersion1700(); } + if (version > 1800 && version <= 1899) + { + MigrateToVersion1800(); + } } return Db.DbConnection().ConnectionString; @@ -173,5 +177,32 @@ public void MigrateToVersion1700() TableCreation.DropTable(Db.DbConnection(), "User"); TableCreation.DropTable(Db.DbConnection(), "Log"); } + + /// + /// Migrates to version 1.8. + /// This includes updating the admin account to have all roles. + /// + private void MigrateToVersion1800() + { + try + { + var userMapper = new UserMapper(new UserRepository(Db)); + var users = userMapper.GetUsers(); + + foreach (var u in users) + { + var claims = new[] { UserClaims.User, UserClaims.Admin, UserClaims.PowerUser }; + u.Claims = ByteConverterHelper.ReturnBytes(claims); + + userMapper.EditUser(u); + } + } + catch (Exception e) + { + Log.Error(e); + throw; + } + + } } } diff --git a/PlexRequests.Core/UserMapper.cs b/PlexRequests.Core/UserMapper.cs index eb66cbea3..909c3a34c 100644 --- a/PlexRequests.Core/UserMapper.cs +++ b/PlexRequests.Core/UserMapper.cs @@ -81,6 +81,16 @@ public IUserIdentity GetUserFromIdentifier(Guid identifier, NancyContext context return null; } + public UsersModel EditUser(UsersModel user) + { + var existingUser = Repo.Get(user.UserGuid); + + user.Id = existingUser.Id; + user.UserGuid = existingUser.UserGuid; + Repo.Update(user); + return user; + } + public bool DoUsersExist() { var users = Repo.GetAll(); @@ -88,7 +98,7 @@ public bool DoUsersExist() return users.Any(); } - public Guid? CreateUser(string username, string password, string[] claims = default(string[])) + private Guid? CreateUser(string username, string password, string[] claims = default(string[])) { var salt = PasswordHasher.GenerateSalt(); @@ -108,6 +118,21 @@ public bool DoUsersExist() return new Guid(userRecord.UserGuid); } + public Guid? CreateAdmin(string username, string password) + { + return CreateUser(username, password, new[] { UserClaims.User, UserClaims.PowerUser, UserClaims.Admin }); + } + + public Guid? CreatePowerUser(string username, string password) + { + return CreateUser(username, password, new[] { UserClaims.User, UserClaims.PowerUser }); + } + + public Guid? CreateRegularUser(string username, string password) + { + return CreateUser(username, password, new[] { UserClaims.User }); + } + public bool UpdatePassword(string username, string oldPassword, string newPassword) { var users = Repo.GetAll(); @@ -134,15 +159,25 @@ public IEnumerable GetUsers() { return Repo.GetAll(); } + + public UsersModel GetUser(Guid userId) + { + var user = Repo.Get(userId.ToString()); + return user; + } } public interface ICustomUserMapper { IEnumerable GetUsers(); - Guid? CreateUser(string username, string password, string[] claims = default(string[])); + UsersModel GetUser(Guid userId); + UsersModel EditUser(UsersModel user); bool DoUsersExist(); Guid? ValidateUser(string username, string password); bool UpdatePassword(string username, string oldPassword, string newPassword); + Guid? CreateAdmin(string username, string password); + Guid? CreatePowerUser(string username, string password); + Guid? CreateRegularUser(string username, string password); } } diff --git a/PlexRequests.UI/Modules/LoginModule.cs b/PlexRequests.UI/Modules/LoginModule.cs index 326b7ec13..8e6a9d39c 100644 --- a/PlexRequests.UI/Modules/LoginModule.cs +++ b/PlexRequests.UI/Modules/LoginModule.cs @@ -35,6 +35,7 @@ using PlexRequests.Core; using PlexRequests.Core.SettingModels; +using PlexRequests.Helpers; using PlexRequests.UI.Models; namespace PlexRequests.UI.Modules @@ -103,7 +104,7 @@ public LoginModule(ISettingsService pr, ICustomUserMapper m { return Context.GetRedirect(!string.IsNullOrEmpty(BaseUrl) ? $"~/{BaseUrl}/register?error=true" : "~/register?error=true"); } - var userId = UserMapper.CreateUser(username, Request.Form.Password, new[] { "Admin" }); + var userId = UserMapper.CreateAdmin(username, Request.Form.Password); Session[SessionKeys.UsernameKey] = username; return this.LoginAndRedirect((Guid)userId); }; diff --git a/PlexRequests.UI/Modules/UserManagementModule.cs b/PlexRequests.UI/Modules/UserManagementModule.cs index c93977cd7..0d6dee073 100644 --- a/PlexRequests.UI/Modules/UserManagementModule.cs +++ b/PlexRequests.UI/Modules/UserManagementModule.cs @@ -46,24 +46,24 @@ private Response LoadUsers() return Response.AsJson(users); } - private Response CreateUser(string username, string password, string claims) - { - if (string.IsNullOrWhiteSpace(username) || string.IsNullOrWhiteSpace(password)) - { - return Response.AsJson(new JsonResponseModel - { - Result = true, - Message = "Please enter in a valid Username and Password" - }); - } - var user = UserMapper.CreateUser(username, password, new string[] {claims}); - if (user.HasValue) - { - return Response.AsJson(new JsonResponseModel {Result = true}); - } + //private Response CreateUser(string username, string password, string claims) + //{ + // if (string.IsNullOrWhiteSpace(username) || string.IsNullOrWhiteSpace(password)) + // { + // return Response.AsJson(new JsonResponseModel + // { + // Result = true, + // Message = "Please enter in a valid Username and Password" + // }); + // } + // var user = UserMapper.CreateUser(username, password, new string[] {claims}); + // if (user.HasValue) + // { + // return Response.AsJson(new JsonResponseModel {Result = true}); + // } - return Response.AsJson(new JsonResponseModel {Result = false, Message = "Could not save user"}); - } + // return Response.AsJson(new JsonResponseModel {Result = false, Message = "Could not save user"}); + //} } } From 96352e14ee6fac66cd3302551c584f7d9fe99c9f Mon Sep 17 00:00:00 2001 From: Drewster727 Date: Fri, 27 May 2016 01:30:49 -0500 Subject: [PATCH 07/26] #256 #237 UI Improvements and consolidation --- .../Themes/OriginalBootstrapCustom.min.css | 1 - .../Content/Themes/PlexBootstrap.css | 7007 ----------------- .../Content/Themes/PlexBootstrapCustom.css | 295 - .../Themes/PlexBootstrapCustom.min.css | 1 - .../Content/Themes/PlexBootstrapCustom.scss | 365 - PlexRequests.UI/Content/Themes/original.scss | 2 + PlexRequests.UI/Content/Themes/plex.css | 146 + PlexRequests.UI/Content/Themes/plex.min.css | 1 + PlexRequests.UI/Content/Themes/plex.scss | 183 + .../OriginalBootstrapCustom.css => base.css} | 2 +- PlexRequests.UI/Content/base.min.css | 1 + ...OriginalBootstrapCustom.scss => base.scss} | 5 +- .../OriginalBootstrap.css => bootstrap.css} | 0 PlexRequests.UI/Helpers/BaseUrlHelper.cs | 9 +- PlexRequests.UI/Helpers/Themes.cs | 4 +- PlexRequests.UI/PlexRequests.UI.csproj | 36 +- PlexRequests.UI/compilerconfig.json | 12 +- 17 files changed, 370 insertions(+), 7700 deletions(-) delete mode 100644 PlexRequests.UI/Content/Themes/OriginalBootstrapCustom.min.css delete mode 100644 PlexRequests.UI/Content/Themes/PlexBootstrap.css delete mode 100644 PlexRequests.UI/Content/Themes/PlexBootstrapCustom.css delete mode 100644 PlexRequests.UI/Content/Themes/PlexBootstrapCustom.min.css delete mode 100644 PlexRequests.UI/Content/Themes/PlexBootstrapCustom.scss create mode 100644 PlexRequests.UI/Content/Themes/original.scss create mode 100644 PlexRequests.UI/Content/Themes/plex.css create mode 100644 PlexRequests.UI/Content/Themes/plex.min.css create mode 100644 PlexRequests.UI/Content/Themes/plex.scss rename PlexRequests.UI/Content/{Themes/OriginalBootstrapCustom.css => base.css} (99%) create mode 100644 PlexRequests.UI/Content/base.min.css rename PlexRequests.UI/Content/{Themes/OriginalBootstrapCustom.scss => base.scss} (99%) rename PlexRequests.UI/Content/{Themes/OriginalBootstrap.css => bootstrap.css} (100%) diff --git a/PlexRequests.UI/Content/Themes/OriginalBootstrapCustom.min.css b/PlexRequests.UI/Content/Themes/OriginalBootstrapCustom.min.css deleted file mode 100644 index f2f72839a..000000000 --- a/PlexRequests.UI/Content/Themes/OriginalBootstrapCustom.min.css +++ /dev/null @@ -1 +0,0 @@ -@media(min-width:768px){.row{position:relative;}.bottom-align-text{position:absolute;bottom:0;right:0;}}@media(max-width:48em){.home{padding-top:1rem;}}@media(min-width:48em){.home{padding-top:4rem;}}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.active>a:hover,.navbar-default .navbar-nav>.active>a:focus{color:#fff;}hr{border-color:#777;}.btn{border-radius:.25rem !important;}.multiSelect{background-color:#4e5d6c;}.form-control-custom{background-color:#4e5d6c !important;color:#fff !important;border-radius:0;box-shadow:0 0 0 !important;}h1{font-size:3.5rem !important;font-weight:600 !important;}.request-title{margin-top:0 !important;font-size:1.9rem !important;}p{font-size:1.1rem !important;}label{display:inline-block !important;margin-bottom:.5rem !important;font-size:16px !important;}.nav-tabs>li{font-size:13px;line-height:21px;}.nav-tabs>li.active>a,.nav-tabs>li.active>a:hover,.nav-tabs>li.active>a:focus{background:#4e5d6c;}.nav-tabs>li>a>.fa{padding:3px 5px 3px 3px;}.nav-tabs>li.nav-tab-right{float:right;}.nav-tabs>li.nav-tab-right a{margin-right:0;margin-left:2px;}.nav-tabs>li.nav-tab-icononly .fa{padding:3px;}.navbar .nav a .fa,.dropdown-menu a .fa{font-size:130%;top:1px;position:relative;display:inline-block;margin-right:5px;}.dropdown-menu a .fa{top:2px;}.btn-danger-outline{color:#d9534f !important;background-color:transparent;background-image:none;border-color:#d9534f !important;}.btn-danger-outline:focus,.btn-danger-outline.focus,.btn-danger-outline:active,.btn-danger-outline.active,.btn-danger-outline:hover,.open>.btn-danger-outline.dropdown-toggle{color:#fff !important;background-color:#d9534f !important;border-color:#d9534f !important;}.btn-primary-outline{color:#ff761b !important;background-color:transparent;background-image:none;border-color:#ff761b !important;}.btn-primary-outline:focus,.btn-primary-outline.focus,.btn-primary-outline:active,.btn-primary-outline.active,.btn-primary-outline:hover,.open>.btn-primary-outline.dropdown-toggle{color:#fff !important;background-color:#df691a !important;border-color:#df691a !important;}.btn-info-outline{color:#5bc0de !important;background-color:transparent;background-image:none;border-color:#5bc0de !important;}.btn-info-outline:focus,.btn-info-outline.focus,.btn-info-outline:active,.btn-info-outline.active,.btn-info-outline:hover,.open>.btn-info-outline.dropdown-toggle{color:#fff !important;background-color:#5bc0de !important;border-color:#5bc0de !important;}.btn-warning-outline{color:#f0ad4e !important;background-color:transparent;background-image:none;border-color:#f0ad4e !important;}.btn-warning-outline:focus,.btn-warning-outline.focus,.btn-warning-outline:active,.btn-warning-outline.active,.btn-warning-outline:hover,.open>.btn-warning-outline.dropdown-toggle{color:#fff !important;background-color:#f0ad4e !important;border-color:#f0ad4e !important;}.btn-success-outline{color:#5cb85c !important;background-color:transparent;background-image:none;border-color:#5cb85c !important;}.btn-success-outline:focus,.btn-success-outline.focus,.btn-success-outline:active,.btn-success-outline.active,.btn-success-outline:hover,.open>.btn-success-outline.dropdown-toggle{color:#fff !important;background-color:#5cb85c !important;border-color:#5cb85c !important;}#movieList .mix{display:none;}#tvList .mix{display:none;}.scroll-top-wrapper{position:fixed;opacity:0;visibility:hidden;overflow:hidden;text-align:center;z-index:99999999;background-color:#4e5d6c;color:#eee;width:50px;height:48px;line-height:48px;right:30px;bottom:30px;padding-top:2px;border-top-left-radius:10px;border-top-right-radius:10px;border-bottom-right-radius:10px;border-bottom-left-radius:10px;-webkit-transition:all .5s ease-in-out;-moz-transition:all .5s ease-in-out;-ms-transition:all .5s ease-in-out;-o-transition:all .5s ease-in-out;transition:all .5s ease-in-out;}.scroll-top-wrapper:hover{background-color:#637689;}.scroll-top-wrapper.show{visibility:visible;cursor:pointer;opacity:1;}.scroll-top-wrapper i.fa{line-height:inherit;}.no-search-results{text-align:center;}.no-search-results .no-search-results-icon{font-size:10em;color:#4e5d6c;}.no-search-results .no-search-results-text{margin:20px 0;color:#ccc;}.form-control-search{padding:13px 105px 13px 16px;height:100%;}.form-control-withbuttons{padding-right:105px;}.input-group-addon .btn-group{position:absolute;right:45px;z-index:3;top:10px;box-shadow:0 0 0;}.input-group-addon .btn-group .btn{border:1px solid rgba(255,255,255,.7) !important;padding:3px 12px;color:rgba(255,255,255,.7) !important;}.btn-split .btn{border-radius:0 !important;}.btn-split .btn:not(.dropdown-toggle){border-radius:.25rem 0 0 .25rem !important;}.btn-split .btn.dropdown-toggle{border-radius:0 .25rem .25rem 0 !important;padding:12px 8px;}#updateAvailable{background-color:#df691a;text-align:center;font-size:15px;padding:3px 0;}.checkbox label{display:inline-block;cursor:pointer;position:relative;padding-left:25px;margin-right:15px;font-size:13px;margin-bottom:10px;}.checkbox label:before{content:"";display:inline-block;width:18px;height:18px;margin-right:10px;position:absolute;left:0;bottom:1px;border:2px solid #eee;border-radius:3px;}.checkbox input[type=checkbox]{display:none;}.checkbox input[type=checkbox]:checked+label:before{content:"✓";font-size:13px;color:#fafafa;text-align:center;line-height:13px;}.input-group-sm{padding-top:2px;padding-bottom:2px;}.tab-pane .form-horizontal .form-group{margin-right:15px;margin-left:15px;} \ No newline at end of file diff --git a/PlexRequests.UI/Content/Themes/PlexBootstrap.css b/PlexRequests.UI/Content/Themes/PlexBootstrap.css deleted file mode 100644 index 9d88eaa83..000000000 --- a/PlexRequests.UI/Content/Themes/PlexBootstrap.css +++ /dev/null @@ -1,7007 +0,0 @@ -@import url("https://fonts.googleapis.com/css?family=Lato:300,400,700"); -/*! - * bootswatch v3.3.6 - * Homepage: http://bootswatch.com - * Copyright 2012-2016 Thomas Park - * Licensed under MIT - * Based on Bootstrap -*/ -/*! - * Bootstrap v3.3.6 (http://getbootstrap.com) - * Copyright 2011-2015 Twitter, Inc. - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) - */ -/*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */ -html { - font-family: sans-serif; - -ms-text-size-adjust: 100%; - -webkit-text-size-adjust: 100%; -} -body { - margin: 60; -} -article, -aside, -details, -figcaption, -figure, -footer, -header, -hgroup, -main, -menu, -nav, -section, -summary { - display: block; -} -audio, -canvas, -progress, -video { - display: inline-block; - vertical-align: baseline; -} -audio:not([controls]) { - display: none; - height: 0; -} -[hidden], -template { - display: none; -} -a { - background-color: transparent; -} -a:active, -a:hover { - outline: 0; -} -abbr[title] { - border-bottom: 1px dotted; -} -b, -strong { - font-weight: bold; -} -dfn { - font-style: italic; -} -h1 { - font-size: 2em; - margin: 0.67em 0; -} -mark { - background: #ff0; - color: #000; -} -small { - font-size: 80%; -} -sub, -sup { - font-size: 75%; - line-height: 0; - position: relative; - vertical-align: baseline; -} -sup { - top: -0.5em; -} -sub { - bottom: -0.25em; -} -img { - border: 0; -} -svg:not(:root) { - overflow: hidden; -} -figure { - margin: 1em 40px; -} -hr { - -webkit-box-sizing: content-box; - -moz-box-sizing: content-box; - box-sizing: content-box; - height: 0; -} -pre { - overflow: auto; -} -code, -kbd, -pre, -samp { - font-family: monospace, monospace; - font-size: 1em; -} -button, -input, -optgroup, -select, -textarea { - color: inherit; - font: inherit; - margin: 0; -} -button { - overflow: visible; -} -button, -select { - text-transform: none; -} -button, -html input[type="button"], -input[type="reset"], -input[type="submit"] { - -webkit-appearance: button; - cursor: pointer; -} -button[disabled], -html input[disabled] { - cursor: default; -} -button::-moz-focus-inner, -input::-moz-focus-inner { - border: 0; - padding: 0; -} -input { - line-height: normal; -} -input[type="checkbox"], -input[type="radio"] { - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; - padding: 0; -} -input[type="number"]::-webkit-inner-spin-button, -input[type="number"]::-webkit-outer-spin-button { - height: auto; -} -input[type="search"] { - -webkit-appearance: textfield; - -webkit-box-sizing: content-box; - -moz-box-sizing: content-box; - box-sizing: content-box; -} -input[type="search"]::-webkit-search-cancel-button, -input[type="search"]::-webkit-search-decoration { - -webkit-appearance: none; -} -fieldset { - border: 1px solid #c0c0c0; - margin: 0 2px; - padding: 0.35em 0.625em 0.75em; -} -legend { - border: 0; - padding: 0; -} -textarea { - overflow: auto; -} -optgroup { - font-weight: bold; -} -table { - border-collapse: collapse; - border-spacing: 0; -} -td, -th { - padding: 0; -} -/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */ -@media print { - *, - *:before, - *:after { - background: transparent !important; - color: #000 !important; - -webkit-box-shadow: none !important; - box-shadow: none !important; - text-shadow: none !important; - } - a, - a:visited { - text-decoration: underline; - } - a[href]:after { - content: " (" attr(href) ")"; - } - abbr[title]:after { - content: " (" attr(title) ")"; - } - a[href^="#"]:after, - a[href^="javascript:"]:after { - content: ""; - } - pre, - blockquote { - border: 1px solid #999; - page-break-inside: avoid; - } - thead { - display: table-header-group; - } - tr, - img { - page-break-inside: avoid; - } - img { - max-width: 100% !important; - } - p, - h2, - h3 { - orphans: 3; - widows: 3; - } - h2, - h3 { - page-break-after: avoid; - } - .navbar { - display: none; - } - .btn > .caret, - .dropup > .btn > .caret { - border-top-color: #000 !important; - } - .label { - border: 1px solid #000; - } - .table { - border-collapse: collapse !important; - } - .table td, - .table th { - background-color: #fff !important; - } - .table-bordered th, - .table-bordered td { - border: 1px solid #ddd !important; - } -} -@font-face { - font-family: 'Glyphicons Halflings'; - src: url('../Content/fonts/glyphicons-halflings-regular.eot'); - src: url('../Content/fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'), url('../Content/fonts/glyphicons-halflings-regular.woff2') format('woff2'), url('../Content/fonts/glyphicons-halflings-regular.woff') format('woff'), url('../Content/fonts/glyphicons-halflings-regular.ttf') format('truetype'), url('../Content/fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular') format('svg'); -} -.glyphicon { - position: relative; - top: 1px; - display: inline-block; - font-family: 'Glyphicons Halflings'; - font-style: normal; - font-weight: normal; - line-height: 1; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} -.glyphicon-asterisk:before { - content: "\002a"; -} -.glyphicon-plus:before { - content: "\002b"; -} -.glyphicon-euro:before, -.glyphicon-eur:before { - content: "\20ac"; -} -.glyphicon-minus:before { - content: "\2212"; -} -.glyphicon-cloud:before { - content: "\2601"; -} -.glyphicon-envelope:before { - content: "\2709"; -} -.glyphicon-pencil:before { - content: "\270f"; -} -.glyphicon-glass:before { - content: "\e001"; -} -.glyphicon-music:before { - content: "\e002"; -} -.glyphicon-search:before { - content: "\e003"; -} -.glyphicon-heart:before { - content: "\e005"; -} -.glyphicon-star:before { - content: "\e006"; -} -.glyphicon-star-empty:before { - content: "\e007"; -} -.glyphicon-user:before { - content: "\e008"; -} -.glyphicon-film:before { - content: "\e009"; -} -.glyphicon-th-large:before { - content: "\e010"; -} -.glyphicon-th:before { - content: "\e011"; -} -.glyphicon-th-list:before { - content: "\e012"; -} -.glyphicon-ok:before { - content: "\e013"; -} -.glyphicon-remove:before { - content: "\e014"; -} -.glyphicon-zoom-in:before { - content: "\e015"; -} -.glyphicon-zoom-out:before { - content: "\e016"; -} -.glyphicon-off:before { - content: "\e017"; -} -.glyphicon-signal:before { - content: "\e018"; -} -.glyphicon-cog:before { - content: "\e019"; -} -.glyphicon-trash:before { - content: "\e020"; -} -.glyphicon-home:before { - content: "\e021"; -} -.glyphicon-file:before { - content: "\e022"; -} -.glyphicon-time:before { - content: "\e023"; -} -.glyphicon-road:before { - content: "\e024"; -} -.glyphicon-download-alt:before { - content: "\e025"; -} -.glyphicon-download:before { - content: "\e026"; -} -.glyphicon-upload:before { - content: "\e027"; -} -.glyphicon-inbox:before { - content: "\e028"; -} -.glyphicon-play-circle:before { - content: "\e029"; -} -.glyphicon-repeat:before { - content: "\e030"; -} -.glyphicon-refresh:before { - content: "\e031"; -} -.glyphicon-list-alt:before { - content: "\e032"; -} -.glyphicon-lock:before { - content: "\e033"; -} -.glyphicon-flag:before { - content: "\e034"; -} -.glyphicon-headphones:before { - content: "\e035"; -} -.glyphicon-volume-off:before { - content: "\e036"; -} -.glyphicon-volume-down:before { - content: "\e037"; -} -.glyphicon-volume-up:before { - content: "\e038"; -} -.glyphicon-qrcode:before { - content: "\e039"; -} -.glyphicon-barcode:before { - content: "\e040"; -} -.glyphicon-tag:before { - content: "\e041"; -} -.glyphicon-tags:before { - content: "\e042"; -} -.glyphicon-book:before { - content: "\e043"; -} -.glyphicon-bookmark:before { - content: "\e044"; -} -.glyphicon-print:before { - content: "\e045"; -} -.glyphicon-camera:before { - content: "\e046"; -} -.glyphicon-font:before { - content: "\e047"; -} -.glyphicon-bold:before { - content: "\e048"; -} -.glyphicon-italic:before { - content: "\e049"; -} -.glyphicon-text-height:before { - content: "\e050"; -} -.glyphicon-text-width:before { - content: "\e051"; -} -.glyphicon-align-left:before { - content: "\e052"; -} -.glyphicon-align-center:before { - content: "\e053"; -} -.glyphicon-align-right:before { - content: "\e054"; -} -.glyphicon-align-justify:before { - content: "\e055"; -} -.glyphicon-list:before { - content: "\e056"; -} -.glyphicon-indent-left:before { - content: "\e057"; -} -.glyphicon-indent-right:before { - content: "\e058"; -} -.glyphicon-facetime-video:before { - content: "\e059"; -} -.glyphicon-picture:before { - content: "\e060"; -} -.glyphicon-map-marker:before { - content: "\e062"; -} -.glyphicon-adjust:before { - content: "\e063"; -} -.glyphicon-tint:before { - content: "\e064"; -} -.glyphicon-edit:before { - content: "\e065"; -} -.glyphicon-share:before { - content: "\e066"; -} -.glyphicon-check:before { - content: "\e067"; -} -.glyphicon-move:before { - content: "\e068"; -} -.glyphicon-step-backward:before { - content: "\e069"; -} -.glyphicon-fast-backward:before { - content: "\e070"; -} -.glyphicon-backward:before { - content: "\e071"; -} -.glyphicon-play:before { - content: "\e072"; -} -.glyphicon-pause:before { - content: "\e073"; -} -.glyphicon-stop:before { - content: "\e074"; -} -.glyphicon-forward:before { - content: "\e075"; -} -.glyphicon-fast-forward:before { - content: "\e076"; -} -.glyphicon-step-forward:before { - content: "\e077"; -} -.glyphicon-eject:before { - content: "\e078"; -} -.glyphicon-chevron-left:before { - content: "\e079"; -} -.glyphicon-chevron-right:before { - content: "\e080"; -} -.glyphicon-plus-sign:before { - content: "\e081"; -} -.glyphicon-minus-sign:before { - content: "\e082"; -} -.glyphicon-remove-sign:before { - content: "\e083"; -} -.glyphicon-ok-sign:before { - content: "\e084"; -} -.glyphicon-question-sign:before { - content: "\e085"; -} -.glyphicon-info-sign:before { - content: "\e086"; -} -.glyphicon-screenshot:before { - content: "\e087"; -} -.glyphicon-remove-circle:before { - content: "\e088"; -} -.glyphicon-ok-circle:before { - content: "\e089"; -} -.glyphicon-ban-circle:before { - content: "\e090"; -} -.glyphicon-arrow-left:before { - content: "\e091"; -} -.glyphicon-arrow-right:before { - content: "\e092"; -} -.glyphicon-arrow-up:before { - content: "\e093"; -} -.glyphicon-arrow-down:before { - content: "\e094"; -} -.glyphicon-share-alt:before { - content: "\e095"; -} -.glyphicon-resize-full:before { - content: "\e096"; -} -.glyphicon-resize-small:before { - content: "\e097"; -} -.glyphicon-exclamation-sign:before { - content: "\e101"; -} -.glyphicon-gift:before { - content: "\e102"; -} -.glyphicon-leaf:before { - content: "\e103"; -} -.glyphicon-fire:before { - content: "\e104"; -} -.glyphicon-eye-open:before { - content: "\e105"; -} -.glyphicon-eye-close:before { - content: "\e106"; -} -.glyphicon-warning-sign:before { - content: "\e107"; -} -.glyphicon-plane:before { - content: "\e108"; -} -.glyphicon-calendar:before { - content: "\e109"; -} -.glyphicon-random:before { - content: "\e110"; -} -.glyphicon-comment:before { - content: "\e111"; -} -.glyphicon-magnet:before { - content: "\e112"; -} -.glyphicon-chevron-up:before { - content: "\e113"; -} -.glyphicon-chevron-down:before { - content: "\e114"; -} -.glyphicon-retweet:before { - content: "\e115"; -} -.glyphicon-shopping-cart:before { - content: "\e116"; -} -.glyphicon-folder-close:before { - content: "\e117"; -} -.glyphicon-folder-open:before { - content: "\e118"; -} -.glyphicon-resize-vertical:before { - content: "\e119"; -} -.glyphicon-resize-horizontal:before { - content: "\e120"; -} -.glyphicon-hdd:before { - content: "\e121"; -} -.glyphicon-bullhorn:before { - content: "\e122"; -} -.glyphicon-bell:before { - content: "\e123"; -} -.glyphicon-certificate:before { - content: "\e124"; -} -.glyphicon-thumbs-up:before { - content: "\e125"; -} -.glyphicon-thumbs-down:before { - content: "\e126"; -} -.glyphicon-hand-right:before { - content: "\e127"; -} -.glyphicon-hand-left:before { - content: "\e128"; -} -.glyphicon-hand-up:before { - content: "\e129"; -} -.glyphicon-hand-down:before { - content: "\e130"; -} -.glyphicon-circle-arrow-right:before { - content: "\e131"; -} -.glyphicon-circle-arrow-left:before { - content: "\e132"; -} -.glyphicon-circle-arrow-up:before { - content: "\e133"; -} -.glyphicon-circle-arrow-down:before { - content: "\e134"; -} -.glyphicon-globe:before { - content: "\e135"; -} -.glyphicon-wrench:before { - content: "\e136"; -} -.glyphicon-tasks:before { - content: "\e137"; -} -.glyphicon-filter:before { - content: "\e138"; -} -.glyphicon-briefcase:before { - content: "\e139"; -} -.glyphicon-fullscreen:before { - content: "\e140"; -} -.glyphicon-dashboard:before { - content: "\e141"; -} -.glyphicon-paperclip:before { - content: "\e142"; -} -.glyphicon-heart-empty:before { - content: "\e143"; -} -.glyphicon-link:before { - content: "\e144"; -} -.glyphicon-phone:before { - content: "\e145"; -} -.glyphicon-pushpin:before { - content: "\e146"; -} -.glyphicon-usd:before { - content: "\e148"; -} -.glyphicon-gbp:before { - content: "\e149"; -} -.glyphicon-sort:before { - content: "\e150"; -} -.glyphicon-sort-by-alphabet:before { - content: "\e151"; -} -.glyphicon-sort-by-alphabet-alt:before { - content: "\e152"; -} -.glyphicon-sort-by-order:before { - content: "\e153"; -} -.glyphicon-sort-by-order-alt:before { - content: "\e154"; -} -.glyphicon-sort-by-attributes:before { - content: "\e155"; -} -.glyphicon-sort-by-attributes-alt:before { - content: "\e156"; -} -.glyphicon-unchecked:before { - content: "\e157"; -} -.glyphicon-expand:before { - content: "\e158"; -} -.glyphicon-collapse-down:before { - content: "\e159"; -} -.glyphicon-collapse-up:before { - content: "\e160"; -} -.glyphicon-log-in:before { - content: "\e161"; -} -.glyphicon-flash:before { - content: "\e162"; -} -.glyphicon-log-out:before { - content: "\e163"; -} -.glyphicon-new-window:before { - content: "\e164"; -} -.glyphicon-record:before { - content: "\e165"; -} -.glyphicon-save:before { - content: "\e166"; -} -.glyphicon-open:before { - content: "\e167"; -} -.glyphicon-saved:before { - content: "\e168"; -} -.glyphicon-import:before { - content: "\e169"; -} -.glyphicon-export:before { - content: "\e170"; -} -.glyphicon-send:before { - content: "\e171"; -} -.glyphicon-floppy-disk:before { - content: "\e172"; -} -.glyphicon-floppy-saved:before { - content: "\e173"; -} -.glyphicon-floppy-remove:before { - content: "\e174"; -} -.glyphicon-floppy-save:before { - content: "\e175"; -} -.glyphicon-floppy-open:before { - content: "\e176"; -} -.glyphicon-credit-card:before { - content: "\e177"; -} -.glyphicon-transfer:before { - content: "\e178"; -} -.glyphicon-cutlery:before { - content: "\e179"; -} -.glyphicon-header:before { - content: "\e180"; -} -.glyphicon-compressed:before { - content: "\e181"; -} -.glyphicon-earphone:before { - content: "\e182"; -} -.glyphicon-phone-alt:before { - content: "\e183"; -} -.glyphicon-tower:before { - content: "\e184"; -} -.glyphicon-stats:before { - content: "\e185"; -} -.glyphicon-sd-video:before { - content: "\e186"; -} -.glyphicon-hd-video:before { - content: "\e187"; -} -.glyphicon-subtitles:before { - content: "\e188"; -} -.glyphicon-sound-stereo:before { - content: "\e189"; -} -.glyphicon-sound-dolby:before { - content: "\e190"; -} -.glyphicon-sound-5-1:before { - content: "\e191"; -} -.glyphicon-sound-6-1:before { - content: "\e192"; -} -.glyphicon-sound-7-1:before { - content: "\e193"; -} -.glyphicon-copyright-mark:before { - content: "\e194"; -} -.glyphicon-registration-mark:before { - content: "\e195"; -} -.glyphicon-cloud-download:before { - content: "\e197"; -} -.glyphicon-cloud-upload:before { - content: "\e198"; -} -.glyphicon-tree-conifer:before { - content: "\e199"; -} -.glyphicon-tree-deciduous:before { - content: "\e200"; -} -.glyphicon-cd:before { - content: "\e201"; -} -.glyphicon-save-file:before { - content: "\e202"; -} -.glyphicon-open-file:before { - content: "\e203"; -} -.glyphicon-level-up:before { - content: "\e204"; -} -.glyphicon-copy:before { - content: "\e205"; -} -.glyphicon-paste:before { - content: "\e206"; -} -.glyphicon-alert:before { - content: "\e209"; -} -.glyphicon-equalizer:before { - content: "\e210"; -} -.glyphicon-king:before { - content: "\e211"; -} -.glyphicon-queen:before { - content: "\e212"; -} -.glyphicon-pawn:before { - content: "\e213"; -} -.glyphicon-bishop:before { - content: "\e214"; -} -.glyphicon-knight:before { - content: "\e215"; -} -.glyphicon-baby-formula:before { - content: "\e216"; -} -.glyphicon-tent:before { - content: "\26fa"; -} -.glyphicon-blackboard:before { - content: "\e218"; -} -.glyphicon-bed:before { - content: "\e219"; -} -.glyphicon-apple:before { - content: "\f8ff"; -} -.glyphicon-erase:before { - content: "\e221"; -} -.glyphicon-hourglass:before { - content: "\231b"; -} -.glyphicon-lamp:before { - content: "\e223"; -} -.glyphicon-duplicate:before { - content: "\e224"; -} -.glyphicon-piggy-bank:before { - content: "\e225"; -} -.glyphicon-scissors:before { - content: "\e226"; -} -.glyphicon-bitcoin:before { - content: "\e227"; -} -.glyphicon-btc:before { - content: "\e227"; -} -.glyphicon-xbt:before { - content: "\e227"; -} -.glyphicon-yen:before { - content: "\00a5"; -} -.glyphicon-jpy:before { - content: "\00a5"; -} -.glyphicon-ruble:before { - content: "\20bd"; -} -.glyphicon-rub:before { - content: "\20bd"; -} -.glyphicon-scale:before { - content: "\e230"; -} -.glyphicon-ice-lolly:before { - content: "\e231"; -} -.glyphicon-ice-lolly-tasted:before { - content: "\e232"; -} -.glyphicon-education:before { - content: "\e233"; -} -.glyphicon-option-horizontal:before { - content: "\e234"; -} -.glyphicon-option-vertical:before { - content: "\e235"; -} -.glyphicon-menu-hamburger:before { - content: "\e236"; -} -.glyphicon-modal-window:before { - content: "\e237"; -} -.glyphicon-oil:before { - content: "\e238"; -} -.glyphicon-grain:before { - content: "\e239"; -} -.glyphicon-sunglasses:before { - content: "\e240"; -} -.glyphicon-text-size:before { - content: "\e241"; -} -.glyphicon-text-color:before { - content: "\e242"; -} -.glyphicon-text-background:before { - content: "\e243"; -} -.glyphicon-object-align-top:before { - content: "\e244"; -} -.glyphicon-object-align-bottom:before { - content: "\e245"; -} -.glyphicon-object-align-horizontal:before { - content: "\e246"; -} -.glyphicon-object-align-left:before { - content: "\e247"; -} -.glyphicon-object-align-vertical:before { - content: "\e248"; -} -.glyphicon-object-align-right:before { - content: "\e249"; -} -.glyphicon-triangle-right:before { - content: "\e250"; -} -.glyphicon-triangle-left:before { - content: "\e251"; -} -.glyphicon-triangle-bottom:before { - content: "\e252"; -} -.glyphicon-triangle-top:before { - content: "\e253"; -} -.glyphicon-console:before { - content: "\e254"; -} -.glyphicon-superscript:before { - content: "\e255"; -} -.glyphicon-subscript:before { - content: "\e256"; -} -.glyphicon-menu-left:before { - content: "\e257"; -} -.glyphicon-menu-right:before { - content: "\e258"; -} -.glyphicon-menu-down:before { - content: "\e259"; -} -.glyphicon-menu-up:before { - content: "\e260"; -} -* { - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; -} -*:before, -*:after { - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; -} -html { - font-size: 16px; - -webkit-tap-highlight-color: rgba(0, 0, 0, 0); -} -body { - font-family:Open Sans Regular,Helvetica Neue,Helvetica,Arial,sans-serif; - font-size: 15px; - line-height: 1.42857143; - color: #eee; - background-color: #1f1f1f; -} -input, -button, -select, -textarea { - font-family: inherit; - font-size: inherit; - line-height: inherit; -} -a { - color: #df691a; - text-decoration: none; -} -a:hover, -a:focus { - color: #df691a; - text-decoration: underline; -} -a:focus { - outline: thin dotted; - outline: 5px auto -webkit-focus-ring-color; - outline-offset: -2px; -} -figure { - margin: 0; -} -img { - vertical-align: middle; -} -.img-responsive, -.thumbnail > img, -.thumbnail a > img, -.carousel-inner > .item > img, -.carousel-inner > .item > a > img { - display: block; - max-width: 100%; - height: auto; -} -.img-rounded { - border-radius: 0; -} -.img-thumbnail { - padding: 4px; - line-height: 1.42857143; - background-color: #2b3e50; - border: 1px solid #dddddd; - border-radius: 0; - -webkit-transition: all 0.2s ease-in-out; - -o-transition: all 0.2s ease-in-out; - transition: all 0.2s ease-in-out; - display: inline-block; - max-width: 100%; - height: auto; -} -.img-circle { - border-radius: 50%; -} -hr { - margin-top: 21px; - margin-bottom: 21px; - border: 0; - border-top: 1px dashed #5cb85c; -} -.sr-only { - position: absolute; - width: 1px; - height: 1px; - margin: -1px; - padding: 0; - overflow: hidden; - clip: rect(0, 0, 0, 0); - border: 0; -} -.sr-only-focusable:active, -.sr-only-focusable:focus { - position: static; - width: auto; - height: auto; - margin: 0; - overflow: visible; - clip: auto; -} -[role="button"] { - cursor: pointer; -} -h1, -h2, -h3, -h4, -h5, -h6, -.h1, -.h2, -.h3, -.h4, -.h5, -.h6 { - font-family: inherit; - font-weight: 400; - line-height: 1.1; - color: inherit; -} -h1 small, -h2 small, -h3 small, -h4 small, -h5 small, -h6 small, -.h1 small, -.h2 small, -.h3 small, -.h4 small, -.h5 small, -.h6 small, -h1 .small, -h2 .small, -h3 .small, -h4 .small, -h5 .small, -h6 .small, -.h1 .small, -.h2 .small, -.h3 .small, -.h4 .small, -.h5 .small, -.h6 .small { - font-weight: normal; - line-height: 1; - color: #ebebeb; -} -h1, -.h1, -h2, -.h2, -h3, -.h3 { - margin-top: 21px; - margin-bottom: 10.5px; -} -h1 small, -.h1 small, -h2 small, -.h2 small, -h3 small, -.h3 small, -h1 .small, -.h1 .small, -h2 .small, -.h2 .small, -h3 .small, -.h3 .small { - font-size: 65%; -} -h4, -.h4, -h5, -.h5, -h6, -.h6 { - margin-top: 10.5px; - margin-bottom: 10.5px; -} -h4 small, -.h4 small, -h5 small, -.h5 small, -h6 small, -.h6 small, -h4 .small, -.h4 .small, -h5 .small, -.h5 .small, -h6 .small, -.h6 .small { - font-size: 75%; -} -h1, -.h1 { - font-size: 39px; -} -h2, -.h2 { - font-size: 32px; -} -h3, -.h3 { - font-size: 26px; -} -h4, -.h4 { - font-size: 19px; -} -h5, -.h5 { - font-size: 15px; -} -h6, -.h6 { - font-size: 13px; -} -p { - margin: 0 0 10.5px; -} -.lead { - margin-bottom: 21px; - font-size: 17px; - font-weight: 300; - line-height: 1.4; -} -@media (min-width: 768px) { - .lead { - font-size: 22.5px; - } -} -small, -.small { - font-size: 80%; -} -mark, -.mark { - background-color: #f0ad4e; - padding: .2em; -} -.text-left { - text-align: left; -} -.text-right { - text-align: right; -} -.text-center { - text-align: center; -} -.text-justify { - text-align: justify; -} -.text-nowrap { - white-space: nowrap; -} -.text-lowercase { - text-transform: lowercase; -} -.text-uppercase { - text-transform: uppercase; -} -.text-capitalize { - text-transform: capitalize; -} -.text-muted { - color: #4e5d6c; -} -.text-primary { - color: #df691a; -} -a.text-primary:hover, -a.text-primary:focus { - color: #b15315; -} -.text-success { - color: #ebebeb; -} -a.text-success:hover, -a.text-success:focus { - color: #d2d2d2; -} -.text-info { - color: #ebebeb; -} -a.text-info:hover, -a.text-info:focus { - color: #d2d2d2; -} -.text-warning { - color: #ebebeb; -} -a.text-warning:hover, -a.text-warning:focus { - color: #d2d2d2; -} -.text-danger { - color: #ebebeb; -} -a.text-danger:hover, -a.text-danger:focus { - color: #d2d2d2; -} -.bg-primary { - color: #fff; - background-color: #df691a; -} -a.bg-primary:hover, -a.bg-primary:focus { - background-color: #b15315; -} -.bg-success { - background-color: #5cb85c; -} -a.bg-success:hover, -a.bg-success:focus { - background-color: #449d44; -} -.bg-info { - background-color: #5bc0de; -} -a.bg-info:hover, -a.bg-info:focus { - background-color: #31b0d5; -} -.bg-warning { - background-color: #f0ad4e; -} -a.bg-warning:hover, -a.bg-warning:focus { - background-color: #ec971f; -} -.bg-danger { - background-color: #d9534f; -} -a.bg-danger:hover, -a.bg-danger:focus { - background-color: #c9302c; -} -.page-header { - padding-bottom: 9.5px; - margin: 42px 0 21px; - border-bottom: 1px solid #ebebeb; -} -ul, -ol { - margin-top: 0; - margin-bottom: 10.5px; -} -ul ul, -ol ul, -ul ol, -ol ol { - margin-bottom: 0; -} -.list-unstyled { - padding-left: 0; - list-style: none; -} -.list-inline { - padding-left: 0; - list-style: none; - margin-left: -5px; -} -.list-inline > li { - display: inline-block; - padding-left: 5px; - padding-right: 5px; -} -dl { - margin-top: 0; - margin-bottom: 21px; -} -dt, -dd { - line-height: 1.42857143; -} -dt { - font-weight: bold; -} -dd { - margin-left: 0; -} -@media (min-width: 768px) { - .dl-horizontal dt { - float: left; - width: 160px; - clear: left; - text-align: right; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - } - .dl-horizontal dd { - margin-left: 180px; - } -} -abbr[title], -abbr[data-original-title] { - cursor: help; - border-bottom: 1px dotted #4e5d6c; -} -.initialism { - font-size: 90%; - text-transform: uppercase; -} -blockquote { - padding: 10.5px 21px; - margin: 0 0 21px; - font-size: 18.75px; - border-left: 5px solid #4e5d6c; -} -blockquote p:last-child, -blockquote ul:last-child, -blockquote ol:last-child { - margin-bottom: 0; -} -blockquote footer, -blockquote small, -blockquote .small { - display: block; - font-size: 80%; - line-height: 1.42857143; - color: #ebebeb; -} -blockquote footer:before, -blockquote small:before, -blockquote .small:before { - content: '\2014 \00A0'; -} -.blockquote-reverse, -blockquote.pull-right { - padding-right: 15px; - padding-left: 0; - border-right: 5px solid #4e5d6c; - border-left: 0; - text-align: right; -} -.blockquote-reverse footer:before, -blockquote.pull-right footer:before, -.blockquote-reverse small:before, -blockquote.pull-right small:before, -.blockquote-reverse .small:before, -blockquote.pull-right .small:before { - content: ''; -} -.blockquote-reverse footer:after, -blockquote.pull-right footer:after, -.blockquote-reverse small:after, -blockquote.pull-right small:after, -.blockquote-reverse .small:after, -blockquote.pull-right .small:after { - content: '\00A0 \2014'; -} -address { - margin-bottom: 21px; - font-style: normal; - line-height: 1.42857143; -} -code, -kbd, -pre, -samp { - font-family: Menlo, Monaco, Consolas, "Courier New", monospace; -} -code { - padding: 2px 4px; - font-size: 90%; - color: #c7254e; - background-color: #f9f2f4; - border-radius: 0; -} -kbd { - padding: 2px 4px; - font-size: 90%; - color: #ffffff; - background-color: #333333; - border-radius: 0; - -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.25); - box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.25); -} -kbd kbd { - padding: 0; - font-size: 100%; - font-weight: bold; - -webkit-box-shadow: none; - box-shadow: none; -} -pre { - display: block; - padding: 10px; - margin: 0 0 10.5px; - font-size: 14px; - line-height: 1.42857143; - word-break: break-all; - word-wrap: break-word; - color: #333333; - background-color: #f5f5f5; - border: 1px solid #cccccc; - border-radius: 0; -} -pre code { - padding: 0; - font-size: inherit; - color: inherit; - white-space: pre-wrap; - background-color: transparent; - border-radius: 0; -} -.pre-scrollable { - max-height: 340px; - overflow-y: scroll; -} -.container { - margin-right: auto; - margin-left: auto; - padding-left: .9375rem; - padding-right: .9375rem; -} -@media (min-width: 768px) { - .container { - width: 750px; - } -} -@media (min-width: 992px) { - .container { - width: 970px; - } -} -@media (min-width: 1200px) { - .container { - width: 1170px; - } -} -.container-fluid { - margin-right: auto; - margin-left: auto; - padding-left: 15px; - padding-right: 15px; -} -.row { - margin-left: -15px; - margin-right: -15px; -} -.col-xs-1, .col-sm-1, .col-md-1, .col-lg-1, .col-xs-2, .col-sm-2, .col-md-2, .col-lg-2, .col-xs-3, .col-sm-3, .col-md-3, .col-lg-3, .col-xs-4, .col-sm-4, .col-md-4, .col-lg-4, .col-xs-5, .col-sm-5, .col-md-5, .col-lg-5, .col-xs-6, .col-sm-6, .col-md-6, .col-lg-6, .col-xs-7, .col-sm-7, .col-md-7, .col-lg-7, .col-xs-8, .col-sm-8, .col-md-8, .col-lg-8, .col-xs-9, .col-sm-9, .col-md-9, .col-lg-9, .col-xs-10, .col-sm-10, .col-md-10, .col-lg-10, .col-xs-11, .col-sm-11, .col-md-11, .col-lg-11, .col-xs-12, .col-sm-12, .col-md-12, .col-lg-12 { - position: relative; - min-height: 1px; - padding-left: 15px; - padding-right: 15px; -} -.col-xs-1, .col-xs-2, .col-xs-3, .col-xs-4, .col-xs-5, .col-xs-6, .col-xs-7, .col-xs-8, .col-xs-9, .col-xs-10, .col-xs-11, .col-xs-12 { - float: left; -} -.col-xs-12 { - width: 100%; -} -.col-xs-11 { - width: 91.66666667%; -} -.col-xs-10 { - width: 83.33333333%; -} -.col-xs-9 { - width: 75%; -} -.col-xs-8 { - width: 66.66666667%; -} -.col-xs-7 { - width: 58.33333333%; -} -.col-xs-6 { - width: 50%; -} -.col-xs-5 { - width: 41.66666667%; -} -.col-xs-4 { - width: 33.33333333%; -} -.col-xs-3 { - width: 25%; -} -.col-xs-2 { - width: 16.66666667%; -} -.col-xs-1 { - width: 8.33333333%; -} -.col-xs-pull-12 { - right: 100%; -} -.col-xs-pull-11 { - right: 91.66666667%; -} -.col-xs-pull-10 { - right: 83.33333333%; -} -.col-xs-pull-9 { - right: 75%; -} -.col-xs-pull-8 { - right: 66.66666667%; -} -.col-xs-pull-7 { - right: 58.33333333%; -} -.col-xs-pull-6 { - right: 50%; -} -.col-xs-pull-5 { - right: 41.66666667%; -} -.col-xs-pull-4 { - right: 33.33333333%; -} -.col-xs-pull-3 { - right: 25%; -} -.col-xs-pull-2 { - right: 16.66666667%; -} -.col-xs-pull-1 { - right: 8.33333333%; -} -.col-xs-pull-0 { - right: auto; -} -.col-xs-push-12 { - left: 100%; -} -.col-xs-push-11 { - left: 91.66666667%; -} -.col-xs-push-10 { - left: 83.33333333%; -} -.col-xs-push-9 { - left: 75%; -} -.col-xs-push-8 { - left: 66.66666667%; -} -.col-xs-push-7 { - left: 58.33333333%; -} -.col-xs-push-6 { - left: 50%; -} -.col-xs-push-5 { - left: 41.66666667%; -} -.col-xs-push-4 { - left: 33.33333333%; -} -.col-xs-push-3 { - left: 25%; -} -.col-xs-push-2 { - left: 16.66666667%; -} -.col-xs-push-1 { - left: 8.33333333%; -} -.col-xs-push-0 { - left: auto; -} -.col-xs-offset-12 { - margin-left: 100%; -} -.col-xs-offset-11 { - margin-left: 91.66666667%; -} -.col-xs-offset-10 { - margin-left: 83.33333333%; -} -.col-xs-offset-9 { - margin-left: 75%; -} -.col-xs-offset-8 { - margin-left: 66.66666667%; -} -.col-xs-offset-7 { - margin-left: 58.33333333%; -} -.col-xs-offset-6 { - margin-left: 50%; -} -.col-xs-offset-5 { - margin-left: 41.66666667%; -} -.col-xs-offset-4 { - margin-left: 33.33333333%; -} -.col-xs-offset-3 { - margin-left: 25%; -} -.col-xs-offset-2 { - margin-left: 16.66666667%; -} -.col-xs-offset-1 { - margin-left: 8.33333333%; -} -.col-xs-offset-0 { - margin-left: 0%; -} -@media (min-width: 768px) { - .col-sm-1, .col-sm-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9, .col-sm-10, .col-sm-11, .col-sm-12 { - float: left; - } - .col-sm-12 { - width: 100%; - } - .col-sm-11 { - width: 91.66666667%; - } - .col-sm-10 { - width: 83.33333333%; - } - .col-sm-9 { - width: 75%; - } - .col-sm-8 { - width: 66.66666667%; - } - .col-sm-7 { - width: 58.33333333%; - } - .col-sm-6 { - width: 50%; - } - .col-sm-5 { - width: 41.66666667%; - } - .col-sm-4 { - width: 33.33333333%; - } - .col-sm-3 { - width: 25%; - } - .col-sm-2 { - width: 16.66666667%; - } - .col-sm-1 { - width: 8.33333333%; - } - .col-sm-pull-12 { - right: 100%; - } - .col-sm-pull-11 { - right: 91.66666667%; - } - .col-sm-pull-10 { - right: 83.33333333%; - } - .col-sm-pull-9 { - right: 75%; - } - .col-sm-pull-8 { - right: 66.66666667%; - } - .col-sm-pull-7 { - right: 58.33333333%; - } - .col-sm-pull-6 { - right: 50%; - } - .col-sm-pull-5 { - right: 41.66666667%; - } - .col-sm-pull-4 { - right: 33.33333333%; - } - .col-sm-pull-3 { - right: 25%; - } - .col-sm-pull-2 { - right: 16.66666667%; - } - .col-sm-pull-1 { - right: 8.33333333%; - } - .col-sm-pull-0 { - right: auto; - } - .col-sm-push-12 { - left: 100%; - } - .col-sm-push-11 { - left: 91.66666667%; - } - .col-sm-push-10 { - left: 83.33333333%; - } - .col-sm-push-9 { - left: 75%; - } - .col-sm-push-8 { - left: 66.66666667%; - } - .col-sm-push-7 { - left: 58.33333333%; - } - .col-sm-push-6 { - left: 50%; - } - .col-sm-push-5 { - left: 41.66666667%; - } - .col-sm-push-4 { - left: 33.33333333%; - } - .col-sm-push-3 { - left: 25%; - } - .col-sm-push-2 { - left: 16.66666667%; - } - .col-sm-push-1 { - left: 8.33333333%; - } - .col-sm-push-0 { - left: auto; - } - .col-sm-offset-12 { - margin-left: 100%; - } - .col-sm-offset-11 { - margin-left: 91.66666667%; - } - .col-sm-offset-10 { - margin-left: 83.33333333%; - } - .col-sm-offset-9 { - margin-left: 75%; - } - .col-sm-offset-8 { - margin-left: 66.66666667%; - } - .col-sm-offset-7 { - margin-left: 58.33333333%; - } - .col-sm-offset-6 { - margin-left: 50%; - } - .col-sm-offset-5 { - margin-left: 41.66666667%; - } - .col-sm-offset-4 { - margin-left: 33.33333333%; - } - .col-sm-offset-3 { - margin-left: 25%; - } - .col-sm-offset-2 { - margin-left: 16.66666667%; - } - .col-sm-offset-1 { - margin-left: 8.33333333%; - } - .col-sm-offset-0 { - margin-left: 0%; - } -} -@media (min-width: 992px) { - .col-md-1, .col-md-2, .col-md-3, .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9, .col-md-10, .col-md-11, .col-md-12 { - float: left; - } - .col-md-12 { - width: 100%; - } - .col-md-11 { - width: 91.66666667%; - } - .col-md-10 { - width: 83.33333333%; - } - .col-md-9 { - width: 75%; - } - .col-md-8 { - width: 66.66666667%; - } - .col-md-7 { - width: 58.33333333%; - } - .col-md-6 { - width: 50%; - } - .col-md-5 { - width: 41.66666667%; - } - .col-md-4 { - width: 33.33333333%; - } - .col-md-3 { - width: 25%; - } - .col-md-2 { - width: 16.66666667%; - } - .col-md-1 { - width: 8.33333333%; - } - .col-md-pull-12 { - right: 100%; - } - .col-md-pull-11 { - right: 91.66666667%; - } - .col-md-pull-10 { - right: 83.33333333%; - } - .col-md-pull-9 { - right: 75%; - } - .col-md-pull-8 { - right: 66.66666667%; - } - .col-md-pull-7 { - right: 58.33333333%; - } - .col-md-pull-6 { - right: 50%; - } - .col-md-pull-5 { - right: 41.66666667%; - } - .col-md-pull-4 { - right: 33.33333333%; - } - .col-md-pull-3 { - right: 25%; - } - .col-md-pull-2 { - right: 16.66666667%; - } - .col-md-pull-1 { - right: 8.33333333%; - } - .col-md-pull-0 { - right: auto; - } - .col-md-push-12 { - left: 100%; - } - .col-md-push-11 { - left: 91.66666667%; - } - .col-md-push-10 { - left: 83.33333333%; - } - .col-md-push-9 { - left: 75%; - } - .col-md-push-8 { - left: 66.66666667%; - } - .col-md-push-7 { - left: 58.33333333%; - } - .col-md-push-6 { - left: 50%; - } - .col-md-push-5 { - left: 41.66666667%; - } - .col-md-push-4 { - left: 33.33333333%; - } - .col-md-push-3 { - left: 25%; - } - .col-md-push-2 { - left: 16.66666667%; - } - .col-md-push-1 { - left: 8.33333333%; - } - .col-md-push-0 { - left: auto; - } - .col-md-offset-12 { - margin-left: 100%; - } - .col-md-offset-11 { - margin-left: 91.66666667%; - } - .col-md-offset-10 { - margin-left: 83.33333333%; - } - .col-md-offset-9 { - margin-left: 75%; - } - .col-md-offset-8 { - margin-left: 66.66666667%; - } - .col-md-offset-7 { - margin-left: 58.33333333%; - } - .col-md-offset-6 { - margin-left: 50%; - } - .col-md-offset-5 { - margin-left: 41.66666667%; - } - .col-md-offset-4 { - margin-left: 33.33333333%; - } - .col-md-offset-3 { - margin-left: 25%; - } - .col-md-offset-2 { - margin-left: 16.66666667%; - } - .col-md-offset-1 { - margin-left: 8.33333333%; - } - .col-md-offset-0 { - margin-left: 0%; - } -} -@media (min-width: 1200px) { - .col-lg-1, .col-lg-2, .col-lg-3, .col-lg-4, .col-lg-5, .col-lg-6, .col-lg-7, .col-lg-8, .col-lg-9, .col-lg-10, .col-lg-11, .col-lg-12 { - float: left; - } - .col-lg-12 { - width: 100%; - } - .col-lg-11 { - width: 91.66666667%; - } - .col-lg-10 { - width: 83.33333333%; - } - .col-lg-9 { - width: 75%; - } - .col-lg-8 { - width: 66.66666667%; - } - .col-lg-7 { - width: 58.33333333%; - } - .col-lg-6 { - width: 50%; - } - .col-lg-5 { - width: 41.66666667%; - } - .col-lg-4 { - width: 33.33333333%; - } - .col-lg-3 { - width: 25%; - } - .col-lg-2 { - width: 16.66666667%; - } - .col-lg-1 { - width: 8.33333333%; - } - .col-lg-pull-12 { - right: 100%; - } - .col-lg-pull-11 { - right: 91.66666667%; - } - .col-lg-pull-10 { - right: 83.33333333%; - } - .col-lg-pull-9 { - right: 75%; - } - .col-lg-pull-8 { - right: 66.66666667%; - } - .col-lg-pull-7 { - right: 58.33333333%; - } - .col-lg-pull-6 { - right: 50%; - } - .col-lg-pull-5 { - right: 41.66666667%; - } - .col-lg-pull-4 { - right: 33.33333333%; - } - .col-lg-pull-3 { - right: 25%; - } - .col-lg-pull-2 { - right: 16.66666667%; - } - .col-lg-pull-1 { - right: 8.33333333%; - } - .col-lg-pull-0 { - right: auto; - } - .col-lg-push-12 { - left: 100%; - } - .col-lg-push-11 { - left: 91.66666667%; - } - .col-lg-push-10 { - left: 83.33333333%; - } - .col-lg-push-9 { - left: 75%; - } - .col-lg-push-8 { - left: 66.66666667%; - } - .col-lg-push-7 { - left: 58.33333333%; - } - .col-lg-push-6 { - left: 50%; - } - .col-lg-push-5 { - left: 41.66666667%; - } - .col-lg-push-4 { - left: 33.33333333%; - } - .col-lg-push-3 { - left: 25%; - } - .col-lg-push-2 { - left: 16.66666667%; - } - .col-lg-push-1 { - left: 8.33333333%; - } - .col-lg-push-0 { - left: auto; - } - .col-lg-offset-12 { - margin-left: 100%; - } - .col-lg-offset-11 { - margin-left: 91.66666667%; - } - .col-lg-offset-10 { - margin-left: 83.33333333%; - } - .col-lg-offset-9 { - margin-left: 75%; - } - .col-lg-offset-8 { - margin-left: 66.66666667%; - } - .col-lg-offset-7 { - margin-left: 58.33333333%; - } - .col-lg-offset-6 { - margin-left: 50%; - } - .col-lg-offset-5 { - margin-left: 41.66666667%; - } - .col-lg-offset-4 { - margin-left: 33.33333333%; - } - .col-lg-offset-3 { - margin-left: 25%; - } - .col-lg-offset-2 { - margin-left: 16.66666667%; - } - .col-lg-offset-1 { - margin-left: 8.33333333%; - } - .col-lg-offset-0 { - margin-left: 0%; - } -} -table { - background-color: transparent; -} -caption { - padding-top: 6px; - padding-bottom: 6px; - color: #4e5d6c; - text-align: left; -} -th { - text-align: left; -} -.table { - width: 100%; - max-width: 100%; - margin-bottom: 21px; -} -.table > thead > tr > th, -.table > tbody > tr > th, -.table > tfoot > tr > th, -.table > thead > tr > td, -.table > tbody > tr > td, -.table > tfoot > tr > td { - padding: 6px; - line-height: 1.42857143; - vertical-align: top; - border-top: 1px solid #4e5d6c; -} -.table > thead > tr > th { - vertical-align: bottom; - border-bottom: 2px solid #4e5d6c; -} -.table > caption + thead > tr:first-child > th, -.table > colgroup + thead > tr:first-child > th, -.table > thead:first-child > tr:first-child > th, -.table > caption + thead > tr:first-child > td, -.table > colgroup + thead > tr:first-child > td, -.table > thead:first-child > tr:first-child > td { - border-top: 0; -} -.table > tbody + tbody { - border-top: 2px solid #4e5d6c; -} -.table .table { - background-color: #2b3e50; -} -.table-condensed > thead > tr > th, -.table-condensed > tbody > tr > th, -.table-condensed > tfoot > tr > th, -.table-condensed > thead > tr > td, -.table-condensed > tbody > tr > td, -.table-condensed > tfoot > tr > td { - padding: 3px; -} -.table-bordered { - border: 1px solid #4e5d6c; -} -.table-bordered > thead > tr > th, -.table-bordered > tbody > tr > th, -.table-bordered > tfoot > tr > th, -.table-bordered > thead > tr > td, -.table-bordered > tbody > tr > td, -.table-bordered > tfoot > tr > td { - border: 1px solid #4e5d6c; -} -.table-bordered > thead > tr > th, -.table-bordered > thead > tr > td { - border-bottom-width: 2px; -} -.table-striped > tbody > tr:nth-of-type(odd) { - background-color: #333333; -} -.table-hover > tbody > tr:hover { - background-color: #282828; -} -table col[class*="col-"] { - position: static; - float: none; - display: table-column; -} -table td[class*="col-"], -table th[class*="col-"] { - position: static; - float: none; - display: table-cell; -} -.table > thead > tr > td.active, -.table > tbody > tr > td.active, -.table > tfoot > tr > td.active, -.table > thead > tr > th.active, -.table > tbody > tr > th.active, -.table > tfoot > tr > th.active, -.table > thead > tr.active > td, -.table > tbody > tr.active > td, -.table > tfoot > tr.active > td, -.table > thead > tr.active > th, -.table > tbody > tr.active > th, -.table > tfoot > tr.active > th { - background-color: #485563; -} -.table-hover > tbody > tr > td.active:hover, -.table-hover > tbody > tr > th.active:hover, -.table-hover > tbody > tr.active:hover > td, -.table-hover > tbody > tr:hover > .active, -.table-hover > tbody > tr.active:hover > th { - background-color: #3d4954; -} -.table > thead > tr > td.success, -.table > tbody > tr > td.success, -.table > tfoot > tr > td.success, -.table > thead > tr > th.success, -.table > tbody > tr > th.success, -.table > tfoot > tr > th.success, -.table > thead > tr.success > td, -.table > tbody > tr.success > td, -.table > tfoot > tr.success > td, -.table > thead > tr.success > th, -.table > tbody > tr.success > th, -.table > tfoot > tr.success > th { - background-color: #5cb85c; -} -.table-hover > tbody > tr > td.success:hover, -.table-hover > tbody > tr > th.success:hover, -.table-hover > tbody > tr.success:hover > td, -.table-hover > tbody > tr:hover > .success, -.table-hover > tbody > tr.success:hover > th { - background-color: #4cae4c; -} -.table > thead > tr > td.info, -.table > tbody > tr > td.info, -.table > tfoot > tr > td.info, -.table > thead > tr > th.info, -.table > tbody > tr > th.info, -.table > tfoot > tr > th.info, -.table > thead > tr.info > td, -.table > tbody > tr.info > td, -.table > tfoot > tr.info > td, -.table > thead > tr.info > th, -.table > tbody > tr.info > th, -.table > tfoot > tr.info > th { - background-color: #5bc0de; -} -.table-hover > tbody > tr > td.info:hover, -.table-hover > tbody > tr > th.info:hover, -.table-hover > tbody > tr.info:hover > td, -.table-hover > tbody > tr:hover > .info, -.table-hover > tbody > tr.info:hover > th { - background-color: #46b8da; -} -.table > thead > tr > td.warning, -.table > tbody > tr > td.warning, -.table > tfoot > tr > td.warning, -.table > thead > tr > th.warning, -.table > tbody > tr > th.warning, -.table > tfoot > tr > th.warning, -.table > thead > tr.warning > td, -.table > tbody > tr.warning > td, -.table > tfoot > tr.warning > td, -.table > thead > tr.warning > th, -.table > tbody > tr.warning > th, -.table > tfoot > tr.warning > th { - background-color: #f0ad4e; -} -.table-hover > tbody > tr > td.warning:hover, -.table-hover > tbody > tr > th.warning:hover, -.table-hover > tbody > tr.warning:hover > td, -.table-hover > tbody > tr:hover > .warning, -.table-hover > tbody > tr.warning:hover > th { - background-color: #eea236; -} -.table > thead > tr > td.danger, -.table > tbody > tr > td.danger, -.table > tfoot > tr > td.danger, -.table > thead > tr > th.danger, -.table > tbody > tr > th.danger, -.table > tfoot > tr > th.danger, -.table > thead > tr.danger > td, -.table > tbody > tr.danger > td, -.table > tfoot > tr.danger > td, -.table > thead > tr.danger > th, -.table > tbody > tr.danger > th, -.table > tfoot > tr.danger > th { - background-color: #d9534f; -} -.table-hover > tbody > tr > td.danger:hover, -.table-hover > tbody > tr > th.danger:hover, -.table-hover > tbody > tr.danger:hover > td, -.table-hover > tbody > tr:hover > .danger, -.table-hover > tbody > tr.danger:hover > th { - background-color: #d43f3a; -} -.table-responsive { - overflow-x: auto; - min-height: 0.01%; -} -@media screen and (max-width: 767px) { - .table-responsive { - width: 100%; - margin-bottom: 15.75px; - overflow-y: hidden; - -ms-overflow-style: -ms-autohiding-scrollbar; - border: 1px solid #4e5d6c; - } - .table-responsive > .table { - margin-bottom: 0; - } - .table-responsive > .table > thead > tr > th, - .table-responsive > .table > tbody > tr > th, - .table-responsive > .table > tfoot > tr > th, - .table-responsive > .table > thead > tr > td, - .table-responsive > .table > tbody > tr > td, - .table-responsive > .table > tfoot > tr > td { - white-space: nowrap; - } - .table-responsive > .table-bordered { - border: 0; - } - .table-responsive > .table-bordered > thead > tr > th:first-child, - .table-responsive > .table-bordered > tbody > tr > th:first-child, - .table-responsive > .table-bordered > tfoot > tr > th:first-child, - .table-responsive > .table-bordered > thead > tr > td:first-child, - .table-responsive > .table-bordered > tbody > tr > td:first-child, - .table-responsive > .table-bordered > tfoot > tr > td:first-child { - border-left: 0; - } - .table-responsive > .table-bordered > thead > tr > th:last-child, - .table-responsive > .table-bordered > tbody > tr > th:last-child, - .table-responsive > .table-bordered > tfoot > tr > th:last-child, - .table-responsive > .table-bordered > thead > tr > td:last-child, - .table-responsive > .table-bordered > tbody > tr > td:last-child, - .table-responsive > .table-bordered > tfoot > tr > td:last-child { - border-right: 0; - } - .table-responsive > .table-bordered > tbody > tr:last-child > th, - .table-responsive > .table-bordered > tfoot > tr:last-child > th, - .table-responsive > .table-bordered > tbody > tr:last-child > td, - .table-responsive > .table-bordered > tfoot > tr:last-child > td { - border-bottom: 0; - } -} -fieldset { - padding: 15px; - margin: 0; - border: 0; - min-width: 0; -} -legend { - display: block; - width: 100%; - padding: 0; - margin-bottom: 21px; - font-size: 22.5px; - line-height: inherit; - color: #ebebeb; - border: 0; - border-bottom: 1px solid #333333; -} -label { - display: inline-block; - max-width: 100%; - margin-bottom: 5px; - font-weight: bold; -} -input[type="search"] { - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; -} -input[type="radio"], -input[type="checkbox"] { - margin: 4px 0 0; - margin-top: 1px \9; - line-height: normal; -} -input[type="file"] { - display: block; -} -input[type="range"] { - display: block; - width: 100%; -} -select[multiple], -select[size] { - height: auto; -} -input[type="file"]:focus, -input[type="radio"]:focus, -input[type="checkbox"]:focus { - outline: thin dotted; - outline: 5px auto -webkit-focus-ring-color; - outline-offset: -2px; -} -output { - display: block; - padding-top: 9px; - font-size: 15px; - line-height: 1.42857143; - color: #2b3e50; -} -.form-control { - display: block; - width: 100%; - height: 39px; - padding: 8px 16px; - font-size: 15px; - line-height: 1.42857143; - color: #fefefe; - background-color: #333333; - background-image: none; - border: 1px solid transparent; - border-radius: .25rem; - -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); - box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); - -webkit-transition: border-color ease-in-out .15s, -webkit-box-shadow ease-in-out .15s; - -o-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s; - transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s; -} -.form-control:focus { - border-color: transparent; - outline: 0; - -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(0, 0, 0, 0.6); - box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(0, 0, 0, 0.6); -} -.form-control::-moz-placeholder { - color: #cccccc; - opacity: 1; -} -.form-control:-ms-input-placeholder { - color: #cccccc; -} -.form-control::-webkit-input-placeholder { - color: #cccccc; -} -.form-control::-ms-expand { - border: 0; - background-color: transparent; -} -.form-control[disabled], -.form-control[readonly], -fieldset[disabled] .form-control { - background-color: #ebebeb; - opacity: 1; -} -.form-control[disabled], -fieldset[disabled] .form-control { - cursor: not-allowed; -} -textarea.form-control { - height: auto; -} -input[type="search"] { - -webkit-appearance: none; -} -@media screen and (-webkit-min-device-pixel-ratio: 0) { - input[type="date"].form-control, - input[type="time"].form-control, - input[type="datetime-local"].form-control, - input[type="month"].form-control { - line-height: 39px; - } - input[type="date"].input-sm, - input[type="time"].input-sm, - input[type="datetime-local"].input-sm, - input[type="month"].input-sm, - .input-group-sm input[type="date"], - .input-group-sm input[type="time"], - .input-group-sm input[type="datetime-local"], - .input-group-sm input[type="month"] { - line-height: 30px; - } - input[type="date"].input-lg, - input[type="time"].input-lg, - input[type="datetime-local"].input-lg, - input[type="month"].input-lg, - .input-group-lg input[type="date"], - .input-group-lg input[type="time"], - .input-group-lg input[type="datetime-local"], - .input-group-lg input[type="month"] { - line-height: 52px; - } -} -.form-group { - margin-bottom: 15px; -} -.radio, -.checkbox { - position: relative; - display: block; - margin-top: 10px; - margin-bottom: 10px; -} -.radio label, -.checkbox label { - min-height: 21px; - padding-left: 20px; - margin-bottom: 0; - font-weight: normal; - cursor: pointer; -} -.radio input[type="radio"], -.radio-inline input[type="radio"], -.checkbox input[type="checkbox"], -.checkbox-inline input[type="checkbox"] { - position: absolute; - margin-left: -0px; - margin-top: 4px \9; -} -.radio + .radio, -.checkbox + .checkbox { - margin-top: -5px; -} -.radio-inline, -.checkbox-inline { - position: relative; - display: inline-block; - padding-left: 20px; - margin-bottom: 0; - vertical-align: middle; - font-weight: normal; - cursor: pointer; -} -.radio-inline + .radio-inline, -.checkbox-inline + .checkbox-inline { - margin-top: 0; - margin-left: 10px; -} -input[type="radio"][disabled], -input[type="checkbox"][disabled], -input[type="radio"].disabled, -input[type="checkbox"].disabled, -fieldset[disabled] input[type="radio"], -fieldset[disabled] input[type="checkbox"] { - cursor: not-allowed; -} -.radio-inline.disabled, -.checkbox-inline.disabled, -fieldset[disabled] .radio-inline, -fieldset[disabled] .checkbox-inline { - cursor: not-allowed; -} -.radio.disabled label, -.checkbox.disabled label, -fieldset[disabled] .radio label, -fieldset[disabled] .checkbox label { - cursor: not-allowed; -} -.form-control-static { - padding-top: 9px; - padding-bottom: 9px; - margin-bottom: 0; - min-height: 36px; -} -.form-control-static.input-lg, -.form-control-static.input-sm { - padding-left: 0; - padding-right: 0; -} -.input-sm { - height: 30px; - padding: 5px 10px; - font-size: 12px; - line-height: 1.5; - border-radius: 0; -} -select.input-sm { - height: 30px; - line-height: 30px; -} -textarea.input-sm, -select[multiple].input-sm { - height: auto; -} -.form-group-sm .form-control { - height: 30px; - padding: 5px 10px; - font-size: 12px; - line-height: 1.5; - border-radius: 0; -} -.form-group-sm select.form-control { - height: 30px; - line-height: 30px; -} -.form-group-sm textarea.form-control, -.form-group-sm select[multiple].form-control { - height: auto; -} -.form-group-sm .form-control-static { - height: 30px; - min-height: 33px; - padding: 6px 10px; - font-size: 12px; - line-height: 1.5; -} -.input-lg { - height: 52px; - padding: 12px 24px; - font-size: 19px; - line-height: 1.3333333; - border-radius: 0; -} -select.input-lg { - height: 52px; - line-height: 52px; -} -textarea.input-lg, -select[multiple].input-lg { - height: auto; -} -.form-group-lg .form-control { - height: 52px; - padding: 12px 24px; - font-size: 19px; - line-height: 1.3333333; - border-radius: 0; -} -.form-group-lg select.form-control { - height: 52px; - line-height: 52px; -} -.form-group-lg textarea.form-control, -.form-group-lg select[multiple].form-control { - height: auto; -} -.form-group-lg .form-control-static { - height: 52px; - min-height: 40px; - padding: 13px 24px; - font-size: 19px; - line-height: 1.3333333; -} -.has-feedback { - position: relative; -} -.has-feedback .form-control { - padding-right: 48.75px; -} -.form-control-feedback { - position: absolute; - top: 0; - right: 0; - z-index: 2; - display: block; - width: 39px; - height: 39px; - line-height: 39px; - text-align: center; - pointer-events: none; -} -.input-lg + .form-control-feedback, -.input-group-lg + .form-control-feedback, -.form-group-lg .form-control + .form-control-feedback { - width: 52px; - height: 52px; - line-height: 52px; -} -.input-sm + .form-control-feedback, -.input-group-sm + .form-control-feedback, -.form-group-sm .form-control + .form-control-feedback { - width: 30px; - height: 30px; - line-height: 30px; -} -.has-success .help-block, -.has-success .control-label, -.has-success .radio, -.has-success .checkbox, -.has-success .radio-inline, -.has-success .checkbox-inline, -.has-success.radio label, -.has-success.checkbox label, -.has-success.radio-inline label, -.has-success.checkbox-inline label { - color: #ebebeb; -} -.has-success .form-control { - border-color: #ebebeb; - -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); - box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); -} -.has-success .form-control:focus { - border-color: #d2d2d2; - -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ffffff; - box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ffffff; -} -.has-success .input-group-addon { - color: #ebebeb; - border-color: #ebebeb; - background-color: #5cb85c; -} -.has-success .form-control-feedback { - color: #ebebeb; -} -.has-warning .help-block, -.has-warning .control-label, -.has-warning .radio, -.has-warning .checkbox, -.has-warning .radio-inline, -.has-warning .checkbox-inline, -.has-warning.radio label, -.has-warning.checkbox label, -.has-warning.radio-inline label, -.has-warning.checkbox-inline label { - color: #ebebeb; -} -.has-warning .form-control { - border-color: #ebebeb; - -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); - box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); -} -.has-warning .form-control:focus { - border-color: #d2d2d2; - -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ffffff; - box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ffffff; -} -.has-warning .input-group-addon { - color: #ebebeb; - border-color: #ebebeb; - background-color: #f0ad4e; -} -.has-warning .form-control-feedback { - color: #ebebeb; -} -.has-error .help-block, -.has-error .control-label, -.has-error .radio, -.has-error .checkbox, -.has-error .radio-inline, -.has-error .checkbox-inline, -.has-error.radio label, -.has-error.checkbox label, -.has-error.radio-inline label, -.has-error.checkbox-inline label { - color: #ebebeb; -} -.has-error .form-control { - border-color: #ebebeb; - -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); - box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); -} -.has-error .form-control:focus { - border-color: #d2d2d2; - -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ffffff; - box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ffffff; -} -.has-error .input-group-addon { - color: #ebebeb; - border-color: #ebebeb; - background-color: #d9534f; -} -.has-error .form-control-feedback { - color: #ebebeb; -} -.has-feedback label ~ .form-control-feedback { - top: 26px; -} -.has-feedback label.sr-only ~ .form-control-feedback { - top: 0; -} -.help-block { - display: block; - margin-top: 5px; - margin-bottom: 10px; - color: #ffffff; -} -@media (min-width: 768px) { - .form-inline .form-group { - display: inline-block; - margin-bottom: 0; - vertical-align: middle; - } - .form-inline .form-control { - display: inline-block; - width: auto; - vertical-align: middle; - } - .form-inline .form-control-static { - display: inline-block; - } - .form-inline .input-group { - display: inline-table; - vertical-align: middle; - } - .form-inline .input-group .input-group-addon, - .form-inline .input-group .input-group-btn, - .form-inline .input-group .form-control { - width: auto; - } - .form-inline .input-group > .form-control { - width: 100%; - } - .form-inline .control-label { - margin-bottom: 0; - vertical-align: middle; - } - .form-inline .radio, - .form-inline .checkbox { - display: inline-block; - margin-top: 0; - margin-bottom: 0; - vertical-align: middle; - } - .form-inline .radio label, - .form-inline .checkbox label { - padding-left: 0; - } - .form-inline .radio input[type="radio"], - .form-inline .checkbox input[type="checkbox"] { - position: relative; - margin-left: 0; - } - .form-inline .has-feedback .form-control-feedback { - top: 0; - } -} -.form-horizontal .radio, -.form-horizontal .checkbox, -.form-horizontal .radio-inline, -.form-horizontal .checkbox-inline { - margin-top: -15px; - margin-bottom: 0; - padding-top: 9px; -} -.form-horizontal .radio, -.form-horizontal .checkbox { - min-height: 30px; -} -.form-horizontal .form-group { - margin-left: -15px; - margin-right: -15px; -} -@media (min-width: 768px) { - .form-horizontal .control-label { - text-align: right; - margin-bottom: 0; - padding-top: 9px; - } -} -.form-horizontal .has-feedback .form-control-feedback { - right: 15px; -} -@media (min-width: 768px) { - .form-horizontal .form-group-lg .control-label { - padding-top: 13px; - font-size: 19px; - } -} -@media (min-width: 768px) { - .form-horizontal .form-group-sm .control-label { - padding-top: 6px; - font-size: 12px; - } -} -.btn { - display: inline-block; - margin-bottom: 0; - font-weight: normal; - text-align: center; - vertical-align: middle; - -ms-touch-action: manipulation; - touch-action: manipulation; - cursor: pointer; - background-image: none; - border: 1px solid transparent; - white-space: nowrap; - padding: 8px 16px; - font-size: 15px; - line-height: 1.42857143; - border-radius: 0; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; -} -.btn:focus, -.btn:active:focus, -.btn.active:focus, -.btn.focus, -.btn:active.focus, -.btn.active.focus { - outline: thin dotted; - outline: 5px auto -webkit-focus-ring-color; - outline-offset: -2px; -} -.btn:hover, -.btn:focus, -.btn.focus { - color: #ffffff; - text-decoration: none; -} -.btn:active, -.btn.active { - outline: 0; - background-image: none; - -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); - box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); -} -.btn.disabled, -.btn[disabled], -fieldset[disabled] .btn { - cursor: not-allowed; - opacity: 0.65; - filter: alpha(opacity=65); - -webkit-box-shadow: none; - box-shadow: none; -} -a.btn.disabled, -fieldset[disabled] a.btn { - pointer-events: none; -} -.btn-default { - color: #ffffff; - background-color: #4e5d6c; - border-color: transparent; -} -.btn-default:focus, -.btn-default.focus { - color: #ffffff; - background-color: #39444e; - border-color: rgba(0, 0, 0, 0); -} -.btn-default:hover { - color: #ffffff; - background-color: #39444e; - border-color: rgba(0, 0, 0, 0); -} -.btn-default:active, -.btn-default.active, -.open > .dropdown-toggle.btn-default { - color: #ffffff; - background-color: #39444e; - border-color: rgba(0, 0, 0, 0); -} -.btn-default:active:hover, -.btn-default.active:hover, -.open > .dropdown-toggle.btn-default:hover, -.btn-default:active:focus, -.btn-default.active:focus, -.open > .dropdown-toggle.btn-default:focus, -.btn-default:active.focus, -.btn-default.active.focus, -.open > .dropdown-toggle.btn-default.focus { - color: #ffffff; - background-color: #2a323a; - border-color: rgba(0, 0, 0, 0); -} -.btn-default:active, -.btn-default.active, -.open > .dropdown-toggle.btn-default { - background-image: none; -} -.btn-default.disabled:hover, -.btn-default[disabled]:hover, -fieldset[disabled] .btn-default:hover, -.btn-default.disabled:focus, -.btn-default[disabled]:focus, -fieldset[disabled] .btn-default:focus, -.btn-default.disabled.focus, -.btn-default[disabled].focus, -fieldset[disabled] .btn-default.focus { - background-color: #4e5d6c; - border-color: transparent; -} -.btn-default .badge { - color: #4e5d6c; - background-color: #ffffff; -} -.btn-primary { - color: #ffffff; - background-color: #df691a; - border-color: transparent; -} -.btn-primary:focus, -.btn-primary.focus { - color: #ffffff; - background-color: #b15315; - border-color: rgba(0, 0, 0, 0); -} -.btn-primary:hover { - color: #ffffff; - background-color: #b15315; - border-color: rgba(0, 0, 0, 0); -} -.btn-primary:active, -.btn-primary.active, -.open > .dropdown-toggle.btn-primary { - color: #ffffff; - background-color: #b15315; - border-color: rgba(0, 0, 0, 0); -} -.btn-primary:active:hover, -.btn-primary.active:hover, -.open > .dropdown-toggle.btn-primary:hover, -.btn-primary:active:focus, -.btn-primary.active:focus, -.open > .dropdown-toggle.btn-primary:focus, -.btn-primary:active.focus, -.btn-primary.active.focus, -.open > .dropdown-toggle.btn-primary.focus { - color: #ffffff; - background-color: #914411; - border-color: rgba(0, 0, 0, 0); -} -.btn-primary:active, -.btn-primary.active, -.open > .dropdown-toggle.btn-primary { - background-image: none; -} -.btn-primary.disabled:hover, -.btn-primary[disabled]:hover, -fieldset[disabled] .btn-primary:hover, -.btn-primary.disabled:focus, -.btn-primary[disabled]:focus, -fieldset[disabled] .btn-primary:focus, -.btn-primary.disabled.focus, -.btn-primary[disabled].focus, -fieldset[disabled] .btn-primary.focus { - background-color: #df691a; - border-color: transparent; -} -.btn-primary .badge { - color: #df691a; - background-color: #ffffff; -} -.btn-success { - color: #ffffff; - background-color: #5cb85c; - border-color: transparent; -} -.btn-success:focus, -.btn-success.focus { - color: #ffffff; - background-color: #449d44; - border-color: rgba(0, 0, 0, 0); -} -.btn-success:hover { - color: #ffffff; - background-color: #449d44; - border-color: rgba(0, 0, 0, 0); -} -.btn-success:active, -.btn-success.active, -.open > .dropdown-toggle.btn-success { - color: #ffffff; - background-color: #449d44; - border-color: rgba(0, 0, 0, 0); -} -.btn-success:active:hover, -.btn-success.active:hover, -.open > .dropdown-toggle.btn-success:hover, -.btn-success:active:focus, -.btn-success.active:focus, -.open > .dropdown-toggle.btn-success:focus, -.btn-success:active.focus, -.btn-success.active.focus, -.open > .dropdown-toggle.btn-success.focus { - color: #ffffff; - background-color: #398439; - border-color: rgba(0, 0, 0, 0); -} -.btn-success:active, -.btn-success.active, -.open > .dropdown-toggle.btn-success { - background-image: none; -} -.btn-success.disabled:hover, -.btn-success[disabled]:hover, -fieldset[disabled] .btn-success:hover, -.btn-success.disabled:focus, -.btn-success[disabled]:focus, -fieldset[disabled] .btn-success:focus, -.btn-success.disabled.focus, -.btn-success[disabled].focus, -fieldset[disabled] .btn-success.focus { - background-color: #5cb85c; - border-color: transparent; -} -.btn-success .badge { - color: #5cb85c; - background-color: #ffffff; -} -.btn-info { - color: #ffffff; - background-color: #5bc0de; - border-color: transparent; -} -.btn-info:focus, -.btn-info.focus { - color: #ffffff; - background-color: #31b0d5; - border-color: rgba(0, 0, 0, 0); -} -.btn-info:hover { - color: #ffffff; - background-color: #31b0d5; - border-color: rgba(0, 0, 0, 0); -} -.btn-info:active, -.btn-info.active, -.open > .dropdown-toggle.btn-info { - color: #ffffff; - background-color: #31b0d5; - border-color: rgba(0, 0, 0, 0); -} -.btn-info:active:hover, -.btn-info.active:hover, -.open > .dropdown-toggle.btn-info:hover, -.btn-info:active:focus, -.btn-info.active:focus, -.open > .dropdown-toggle.btn-info:focus, -.btn-info:active.focus, -.btn-info.active.focus, -.open > .dropdown-toggle.btn-info.focus { - color: #ffffff; - background-color: #269abc; - border-color: rgba(0, 0, 0, 0); -} -.btn-info:active, -.btn-info.active, -.open > .dropdown-toggle.btn-info { - background-image: none; -} -.btn-info.disabled:hover, -.btn-info[disabled]:hover, -fieldset[disabled] .btn-info:hover, -.btn-info.disabled:focus, -.btn-info[disabled]:focus, -fieldset[disabled] .btn-info:focus, -.btn-info.disabled.focus, -.btn-info[disabled].focus, -fieldset[disabled] .btn-info.focus { - background-color: #5bc0de; - border-color: transparent; -} -.btn-info .badge { - color: #5bc0de; - background-color: #ffffff; -} -.btn-warning { - color: #ffffff; - background-color: #f0ad4e; - border-color: transparent; -} -.btn-warning:focus, -.btn-warning.focus { - color: #ffffff; - background-color: #ec971f; - border-color: rgba(0, 0, 0, 0); -} -.btn-warning:hover { - color: #ffffff; - background-color: #ec971f; - border-color: rgba(0, 0, 0, 0); -} -.btn-warning:active, -.btn-warning.active, -.open > .dropdown-toggle.btn-warning { - color: #ffffff; - background-color: #ec971f; - border-color: rgba(0, 0, 0, 0); -} -.btn-warning:active:hover, -.btn-warning.active:hover, -.open > .dropdown-toggle.btn-warning:hover, -.btn-warning:active:focus, -.btn-warning.active:focus, -.open > .dropdown-toggle.btn-warning:focus, -.btn-warning:active.focus, -.btn-warning.active.focus, -.open > .dropdown-toggle.btn-warning.focus { - color: #ffffff; - background-color: #d58512; - border-color: rgba(0, 0, 0, 0); -} -.btn-warning:active, -.btn-warning.active, -.open > .dropdown-toggle.btn-warning { - background-image: none; -} -.btn-warning.disabled:hover, -.btn-warning[disabled]:hover, -fieldset[disabled] .btn-warning:hover, -.btn-warning.disabled:focus, -.btn-warning[disabled]:focus, -fieldset[disabled] .btn-warning:focus, -.btn-warning.disabled.focus, -.btn-warning[disabled].focus, -fieldset[disabled] .btn-warning.focus { - background-color: #f0ad4e; - border-color: transparent; -} -.btn-warning .badge { - color: #f0ad4e; - background-color: #ffffff; -} -.btn-danger { - color: #ffffff; - background-color: #d9534f; - border-color: transparent; -} -.btn-danger:focus, -.btn-danger.focus { - color: #ffffff; - background-color: #c9302c; - border-color: rgba(0, 0, 0, 0); -} -.btn-danger:hover { - color: #ffffff; - background-color: #c9302c; - border-color: rgba(0, 0, 0, 0); -} -.btn-danger:active, -.btn-danger.active, -.open > .dropdown-toggle.btn-danger { - color: #ffffff; - background-color: #c9302c; - border-color: rgba(0, 0, 0, 0); -} -.btn-danger:active:hover, -.btn-danger.active:hover, -.open > .dropdown-toggle.btn-danger:hover, -.btn-danger:active:focus, -.btn-danger.active:focus, -.open > .dropdown-toggle.btn-danger:focus, -.btn-danger:active.focus, -.btn-danger.active.focus, -.open > .dropdown-toggle.btn-danger.focus { - color: #ffffff; - background-color: #ac2925; - border-color: rgba(0, 0, 0, 0); -} -.btn-danger:active, -.btn-danger.active, -.open > .dropdown-toggle.btn-danger { - background-image: none; -} -.btn-danger.disabled:hover, -.btn-danger[disabled]:hover, -fieldset[disabled] .btn-danger:hover, -.btn-danger.disabled:focus, -.btn-danger[disabled]:focus, -fieldset[disabled] .btn-danger:focus, -.btn-danger.disabled.focus, -.btn-danger[disabled].focus, -fieldset[disabled] .btn-danger.focus { - background-color: #d9534f; - border-color: transparent; -} -.btn-danger .badge { - color: #d9534f; - background-color: #ffffff; -} -.btn-link { - color: #df691a; - font-weight: normal; - border-radius: 0; -} -.btn-link, -.btn-link:active, -.btn-link.active, -.btn-link[disabled], -fieldset[disabled] .btn-link { - background-color: transparent; - -webkit-box-shadow: none; - box-shadow: none; -} -.btn-link, -.btn-link:hover, -.btn-link:focus, -.btn-link:active { - border-color: transparent; -} -.btn-link:hover, -.btn-link:focus { - color: #df691a; - text-decoration: underline; - background-color: transparent; -} -.btn-link[disabled]:hover, -fieldset[disabled] .btn-link:hover, -.btn-link[disabled]:focus, -fieldset[disabled] .btn-link:focus { - color: #4e5d6c; - text-decoration: none; -} -.btn-lg, -.btn-group-lg > .btn { - padding: 12px 24px; - font-size: 19px; - line-height: 1.3333333; - border-radius: 0; -} -.btn-sm, -.btn-group-sm > .btn { - padding: 5px 10px; - font-size: 12px; - line-height: 1.5; - border-radius: 0; -} -.btn-xs, -.btn-group-xs > .btn { - padding: 1px 5px; - font-size: 12px; - line-height: 1.5; - border-radius: 0; -} -.btn-block { - display: block; - width: 100%; -} -.btn-block + .btn-block { - margin-top: 5px; -} -input[type="submit"].btn-block, -input[type="reset"].btn-block, -input[type="button"].btn-block { - width: 100%; -} -.fade { - opacity: 0; - -webkit-transition: opacity 0.15s linear; - -o-transition: opacity 0.15s linear; - transition: opacity 0.15s linear; -} -.fade.in { - opacity: 1; -} -.collapse { - display: none; -} -.collapse.in { - display: block; -} -tr.collapse.in { - display: table-row; -} -tbody.collapse.in { - display: table-row-group; -} -.collapsing { - position: relative; - height: 0; - overflow: hidden; - -webkit-transition-property: height, visibility; - -o-transition-property: height, visibility; - transition-property: height, visibility; - -webkit-transition-duration: 0.35s; - -o-transition-duration: 0.35s; - transition-duration: 0.35s; - -webkit-transition-timing-function: ease; - -o-transition-timing-function: ease; - transition-timing-function: ease; -} -.caret { - display: inline-block; - width: 0; - height: 0; - margin-left: 2px; - vertical-align: middle; - border-top: 4px dashed; - border-top: 4px solid \9; - border-right: 4px solid transparent; - border-left: 4px solid transparent; -} -.dropup, -.dropdown { - position: relative; -} -.dropdown-toggle:focus { - outline: 0; -} -.dropdown-menu { - position: absolute; - top: 100%; - left: 0; - z-index: 1000; - display: none; - float: left; - min-width: 160px; - padding: 5px 0; - margin: 2px 0 0; - list-style: none; - font-size: 15px; - text-align: left; - background-color: #282828; - border: 1px solid transparent; - border-radius: 0; - -webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175); - box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175); - -webkit-background-clip: padding-box; - background-clip: padding-box; -} -.dropdown-menu.pull-right { - right: 0; - left: auto; -} -.dropdown-menu .divider { - height: 1px; - margin: 9.5px 0; - overflow: hidden; - background-color: #333333; -} -.dropdown-menu > li > a { - display: block; - padding: 3px 20px; - clear: both; - font-weight: normal; - line-height: 1.42857143; - color: #ebebeb; - white-space: nowrap; -} -.dropdown-menu > li > a:hover, -.dropdown-menu > li > a:focus { - text-decoration: none; - color: #ebebeb; - background-color: #333333; -} -.dropdown-menu > .active > a, -.dropdown-menu > .active > a:hover, -.dropdown-menu > .active > a:focus { - color: #ffffff; - text-decoration: none; - outline: 0; - background-color: #df691a; -} -.dropdown-menu > .disabled > a, -.dropdown-menu > .disabled > a:hover, -.dropdown-menu > .disabled > a:focus { - color: #2b3e50; -} -.dropdown-menu > .disabled > a:hover, -.dropdown-menu > .disabled > a:focus { - text-decoration: none; - background-color: transparent; - background-image: none; - filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); - cursor: not-allowed; -} -.open > .dropdown-menu { - display: block; -} -.open > a { - outline: 0; -} -.dropdown-menu-right { - left: auto; - right: 0; -} -.dropdown-menu-left { - left: 0; - right: auto; -} -.dropdown-header { - display: block; - padding: 3px 20px; - font-size: 12px; - line-height: 1.42857143; - color: #2b3e50; - white-space: nowrap; -} -.dropdown-backdrop { - position: fixed; - left: 0; - right: 0; - bottom: 0; - top: 0; - z-index: 990; -} -.pull-right > .dropdown-menu { - right: 0; - left: auto; -} -.dropup .caret, -.navbar-fixed-bottom .dropdown .caret { - border-top: 0; - border-bottom: 4px dashed; - border-bottom: 4px solid \9; - content: ""; -} -.dropup .dropdown-menu, -.navbar-fixed-bottom .dropdown .dropdown-menu { - top: auto; - bottom: 100%; - margin-bottom: 2px; -} -@media (min-width: 768px) { - .navbar-right .dropdown-menu { - left: auto; - right: 0; - } - .navbar-right .dropdown-menu-left { - left: 0; - right: auto; - } -} -.btn-group, -.btn-group-vertical { - position: relative; - display: inline-block; - vertical-align: middle; -} -.btn-group > .btn, -.btn-group-vertical > .btn { - position: relative; - float: left; -} -.btn-group > .btn:hover, -.btn-group-vertical > .btn:hover, -.btn-group > .btn:focus, -.btn-group-vertical > .btn:focus, -.btn-group > .btn:active, -.btn-group-vertical > .btn:active, -.btn-group > .btn.active, -.btn-group-vertical > .btn.active { - z-index: 2; -} -.btn-group .btn + .btn, -.btn-group .btn + .btn-group, -.btn-group .btn-group + .btn, -.btn-group .btn-group + .btn-group { - margin-left: -1px; -} -.btn-toolbar { - margin-left: -5px; -} -.btn-toolbar .btn, -.btn-toolbar .btn-group, -.btn-toolbar .input-group { - float: left; -} -.btn-toolbar > .btn, -.btn-toolbar > .btn-group, -.btn-toolbar > .input-group { - margin-left: 5px; -} -.btn-group > .btn:not(:first-child):not(:last-child):not(.dropdown-toggle) { - border-radius: 0; -} -.btn-group > .btn:first-child { - margin-left: 0; -} -.btn-group > .btn:first-child:not(:last-child):not(.dropdown-toggle) { - border-bottom-right-radius: 0; - border-top-right-radius: 0; -} -.btn-group > .btn:last-child:not(:first-child), -.btn-group > .dropdown-toggle:not(:first-child) { - border-bottom-left-radius: 0; - border-top-left-radius: 0; -} -.btn-group > .btn-group { - float: left; -} -.btn-group > .btn-group:not(:first-child):not(:last-child) > .btn { - border-radius: 0; -} -.btn-group > .btn-group:first-child:not(:last-child) > .btn:last-child, -.btn-group > .btn-group:first-child:not(:last-child) > .dropdown-toggle { - border-bottom-right-radius: 0; - border-top-right-radius: 0; -} -.btn-group > .btn-group:last-child:not(:first-child) > .btn:first-child { - border-bottom-left-radius: 0; - border-top-left-radius: 0; -} -.btn-group .dropdown-toggle:active, -.btn-group.open .dropdown-toggle { - outline: 0; -} -.btn-group > .btn + .dropdown-toggle { - padding-left: 8px; - padding-right: 8px; -} -.btn-group > .btn-lg + .dropdown-toggle { - padding-left: 12px; - padding-right: 12px; -} -.btn-group.open .dropdown-toggle { - -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); - box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); -} -.btn-group.open .dropdown-toggle.btn-link { - -webkit-box-shadow: none; - box-shadow: none; -} -.btn .caret { - margin-left: 0; -} -.btn-lg .caret { - border-width: 5px 5px 0; - border-bottom-width: 0; -} -.dropup .btn-lg .caret { - border-width: 0 5px 5px; -} -.btn-group-vertical > .btn, -.btn-group-vertical > .btn-group, -.btn-group-vertical > .btn-group > .btn { - display: block; - float: none; - width: 100%; - max-width: 100%; -} -.btn-group-vertical > .btn-group > .btn { - float: none; -} -.btn-group-vertical > .btn + .btn, -.btn-group-vertical > .btn + .btn-group, -.btn-group-vertical > .btn-group + .btn, -.btn-group-vertical > .btn-group + .btn-group { - margin-top: -1px; - margin-left: 0; -} -.btn-group-vertical > .btn:not(:first-child):not(:last-child) { - border-radius: 0; -} -.btn-group-vertical > .btn:first-child:not(:last-child) { - border-top-right-radius: 0; - border-top-left-radius: 0; - border-bottom-right-radius: 0; - border-bottom-left-radius: 0; -} -.btn-group-vertical > .btn:last-child:not(:first-child) { - border-top-right-radius: 0; - border-top-left-radius: 0; - border-bottom-right-radius: 0; - border-bottom-left-radius: 0; -} -.btn-group-vertical > .btn-group:not(:first-child):not(:last-child) > .btn { - border-radius: 0; -} -.btn-group-vertical > .btn-group:first-child:not(:last-child) > .btn:last-child, -.btn-group-vertical > .btn-group:first-child:not(:last-child) > .dropdown-toggle { - border-bottom-right-radius: 0; - border-bottom-left-radius: 0; -} -.btn-group-vertical > .btn-group:last-child:not(:first-child) > .btn:first-child { - border-top-right-radius: 0; - border-top-left-radius: 0; -} -.btn-group-justified { - display: table; - width: 100%; - table-layout: fixed; - border-collapse: separate; -} -.btn-group-justified > .btn, -.btn-group-justified > .btn-group { - float: none; - display: table-cell; - width: 1%; -} -.btn-group-justified > .btn-group .btn { - width: 100%; -} -.btn-group-justified > .btn-group .dropdown-menu { - left: auto; -} -[data-toggle="buttons"] > .btn input[type="radio"], -[data-toggle="buttons"] > .btn-group > .btn input[type="radio"], -[data-toggle="buttons"] > .btn input[type="checkbox"], -[data-toggle="buttons"] > .btn-group > .btn input[type="checkbox"] { - position: absolute; - clip: rect(0, 0, 0, 0); - pointer-events: none; -} -.input-group { - position: relative; - display: table; - border-collapse: separate; -} -.input-group[class*="col-"] { - float: none; - padding-left: 0; - padding-right: 0; -} -.input-group .form-control { - position: relative; - z-index: 2; - float: left; - width: 100%; - margin-bottom: 0; -} -.input-group .form-control:focus { - z-index: 3; -} -.input-group-lg > .form-control, -.input-group-lg > .input-group-addon, -.input-group-lg > .input-group-btn > .btn { - height: 52px; - padding: 12px 24px; - font-size: 19px; - line-height: 1.3333333; - border-radius: 0; -} -select.input-group-lg > .form-control, -select.input-group-lg > .input-group-addon, -select.input-group-lg > .input-group-btn > .btn { - height: 52px; - line-height: 52px; -} -textarea.input-group-lg > .form-control, -textarea.input-group-lg > .input-group-addon, -textarea.input-group-lg > .input-group-btn > .btn, -select[multiple].input-group-lg > .form-control, -select[multiple].input-group-lg > .input-group-addon, -select[multiple].input-group-lg > .input-group-btn > .btn { - height: auto; -} -.input-group-sm > .form-control, -.input-group-sm > .input-group-addon, -.input-group-sm > .input-group-btn > .btn { - height: 30px; - padding: 5px 10px; - font-size: 12px; - line-height: 1.5; - border-radius: 0; -} -select.input-group-sm > .form-control, -select.input-group-sm > .input-group-addon, -select.input-group-sm > .input-group-btn > .btn { - height: 30px; - line-height: 30px; -} -textarea.input-group-sm > .form-control, -textarea.input-group-sm > .input-group-addon, -textarea.input-group-sm > .input-group-btn > .btn, -select[multiple].input-group-sm > .form-control, -select[multiple].input-group-sm > .input-group-addon, -select[multiple].input-group-sm > .input-group-btn > .btn { - height: auto; -} -.input-group-addon, -.input-group-btn, -.input-group .form-control { - display: table-cell; -} -.input-group-addon:not(:first-child):not(:last-child), -.input-group-btn:not(:first-child):not(:last-child), -.input-group .form-control:not(:first-child):not(:last-child) { - border-radius: 0; -} -.input-group-addon, -.input-group-btn { - width: 1%; - white-space: nowrap; - vertical-align: middle; -} -.input-group-addon { - padding: 8px 16px; - font-size: 15px; - font-weight: normal; - line-height: 1; - color: #2b3e50; - text-align: center; - background-color: #333333; - border: 1px solid transparent; - border-radius: 0; -} -.input-group-addon.input-sm { - padding: 5px 10px; - font-size: 12px; - border-radius: 0; -} -.input-group-addon.input-lg { - padding: 12px 24px; - font-size: 19px; - border-radius: 0; -} -.input-group-addon input[type="radio"], -.input-group-addon input[type="checkbox"] { - margin-top: 0; -} -.input-group .form-control:first-child, -.input-group-addon:first-child, -.input-group-btn:first-child > .btn, -.input-group-btn:first-child > .btn-group > .btn, -.input-group-btn:first-child > .dropdown-toggle, -.input-group-btn:last-child > .btn:not(:last-child):not(.dropdown-toggle), -.input-group-btn:last-child > .btn-group:not(:last-child) > .btn { - border-bottom-right-radius: 0; - border-top-right-radius: 0; -} -.input-group-addon:first-child { - border-right: 0; -} -.input-group .form-control:last-child, -.input-group-addon:last-child, -.input-group-btn:last-child > .btn, -.input-group-btn:last-child > .btn-group > .btn, -.input-group-btn:last-child > .dropdown-toggle, -.input-group-btn:first-child > .btn:not(:first-child), -.input-group-btn:first-child > .btn-group:not(:first-child) > .btn { - border-bottom-left-radius: 0; - border-top-left-radius: 0; -} -.input-group-addon:last-child { - border-left: 0; -} -.input-group-btn { - position: relative; - font-size: 0; - white-space: nowrap; -} -.input-group-btn > .btn { - position: relative; -} -.input-group-btn > .btn + .btn { - margin-left: -1px; -} -.input-group-btn > .btn:hover, -.input-group-btn > .btn:focus, -.input-group-btn > .btn:active { - z-index: 2; -} -.input-group-btn:first-child > .btn, -.input-group-btn:first-child > .btn-group { - margin-right: -1px; -} -.input-group-btn:last-child > .btn, -.input-group-btn:last-child > .btn-group { - z-index: 2; - margin-left: -1px; -} -.nav { - margin-bottom: 0; - padding-left: 0; - list-style: none; -} -.nav > li { - position: relative; - display: block; -} -.nav > li > a { - position: relative; - display: block; - padding: 10px 15px; -} -.nav > li > a:hover, -.nav > li > a:focus { - text-decoration: none; - background-color: #df691a; -} -.nav > li.disabled > a { - color: #4e5d6c; -} -.nav > li.disabled > a:hover, -.nav > li.disabled > a:focus { - color: #4e5d6c; - text-decoration: none; - background-color: transparent; - cursor: not-allowed; -} -.nav .open > a, -.nav .open > a:hover, -.nav .open > a:focus { - background-color: #4e5d6c; - border-color: #df691a; -} -.nav .nav-divider { - height: 1px; - margin: 9.5px 0; - overflow: hidden; - background-color: #e5e5e5; -} -.nav > li > a > img { - max-width: none; -} -.nav-tabs { - border-bottom: 1px solid transparent; -} -.nav-tabs > li { - float: left; - margin-bottom: -1px; -} -.nav-tabs > li > a { - margin-right: 2px; - line-height: 1.42857143; - border: 1px solid transparent; - border-radius: 0 0 0 0; -} -.nav-tabs > li > a:hover { - border-color: #df691a #df691a transparent; - - -} -.nav-tabs > li.active > a, -.nav-tabs > li.active > a:hover, -.nav-tabs > li.active > a:focus { - color: #ebebeb; - background-color: #df691a; - border: 1px solid #df691a; - border-bottom-color: transparent; - cursor: default; -} -.nav-tabs.nav-justified { - width: 100%; - border-bottom: 0; -} -.nav-tabs.nav-justified > li { - float: none; -} -.nav-tabs.nav-justified > li > a { - text-align: center; - margin-bottom: 5px; -} -.nav-tabs.nav-justified > .dropdown .dropdown-menu { - top: auto; - left: auto; -} -@media (min-width: 768px) { - .nav-tabs.nav-justified > li { - display: table-cell; - width: 1%; - } - .nav-tabs.nav-justified > li > a { - margin-bottom: 0; - } -} -.nav-tabs.nav-justified > li > a { - margin-right: 0; - border-radius: 0; -} -.nav-tabs.nav-justified > .active > a, -.nav-tabs.nav-justified > .active > a:hover, -.nav-tabs.nav-justified > .active > a:focus { - border: 1px solid #df691a; -} -@media (min-width: 768px) { - .nav-tabs.nav-justified > li > a { - border-bottom: 1px solid #4e5d6c; - border-radius: 0 0 0 0; - } - .nav-tabs.nav-justified > .active > a, - .nav-tabs.nav-justified > .active > a:hover, - .nav-tabs.nav-justified > .active > a:focus { - border-bottom-color: #4e5d6c; - } -} -.nav-pills > li { - float: left; -} -.nav-pills > li > a { - border-radius: 0; -} -.nav-pills > li + li { - margin-left: 2px; -} -.nav-pills > li.active > a, -.nav-pills > li.active > a:hover, -.nav-pills > li.active > a:focus { - color: #ffffff; - background-color: #df691a; -} -.nav-stacked > li { - float: none; -} -.nav-stacked > li + li { - margin-top: 2px; - margin-left: 0; -} -.nav-justified { - width: 100%; -} -.nav-justified > li { - float: none; -} -.nav-justified > li > a { - text-align: center; - margin-bottom: 5px; -} -.nav-justified > .dropdown .dropdown-menu { - top: auto; - left: auto; -} -@media (min-width: 768px) { - .nav-justified > li { - display: table-cell; - width: 1%; - } - .nav-justified > li > a { - margin-bottom: 0; - } -} -.nav-tabs-justified { - border-bottom: 0; -} -.nav-tabs-justified > li > a { - margin-right: 0; - border-radius: 0; -} -.nav-tabs-justified > .active > a, -.nav-tabs-justified > .active > a:hover, -.nav-tabs-justified > .active > a:focus { - border: 1px solid #4e5d6c; -} -@media (min-width: 768px) { - .nav-tabs-justified > li > a { - border-bottom: 1px solid #4e5d6c; - border-radius: 0 0 0 0; - } - .nav-tabs-justified > .active > a, - .nav-tabs-justified > .active > a:hover, - .nav-tabs-justified > .active > a:focus { - border-bottom-color: #4e5d6c; - } -} -.tab-content > .tab-pane { - display: none; -} -.tab-content > .active { - display: block; -} -.nav-tabs .dropdown-menu { - margin-top: -1px; - border-top-right-radius: 0; - border-top-left-radius: 0; -} -.navbar { - position: fixed; - top: 0px; - right: 0px; - left: 0px; - z-index: 1000; - padding: 0px 3px; - font-size: 24px; - background-color: #000; - box-shadow: 0px 0px 0px 3px rgba(0, 0, 0, 0.2); -} - - -@media (min-width: 768px) { - .navbar { - border-radius: 0; - } -} -@media (min-width: 768px) { - .navbar-header { - float: left; - } -} -.navbar-collapse { - overflow-x: visible; - padding-right: 15px; - padding-left: 15px; - border-top: 1px solid transparent; - -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1); - box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1); - -webkit-overflow-scrolling: touch; -} -.navbar-collapse.in { - overflow-y: auto; -} -@media (min-width: 768px) { - .navbar-collapse { - width: auto; - border-top: 0; - -webkit-box-shadow: none; - box-shadow: none; - } - .navbar-collapse.collapse { - display: block !important; - height: auto !important; - padding-bottom: 0; - overflow: visible !important; - } - .navbar-collapse.in { - overflow-y: visible; - } - .navbar-fixed-top .navbar-collapse, - .navbar-static-top .navbar-collapse, - .navbar-fixed-bottom .navbar-collapse { - padding-left: 0; - padding-right: 0; - } -} -.navbar-fixed-top .navbar-collapse, -.navbar-fixed-bottom .navbar-collapse { - max-height: 340px; -} -@media (max-device-width: 480px) and (orientation: landscape) { - .navbar-fixed-top .navbar-collapse, - .navbar-fixed-bottom .navbar-collapse { - max-height: 200px; - } -} -.container > .navbar-header, -.container-fluid > .navbar-header, -.container > .navbar-collapse, -.container-fluid > .navbar-collapse { - margin-right: -15px; - margin-left: -15px; -} -@media (min-width: 768px) { - .container > .navbar-header, - .container-fluid > .navbar-header, - .container > .navbar-collapse, - .container-fluid > .navbar-collapse { - margin-right: 0; - margin-left: 0; - } -} -.navbar-static-top { - z-index: 1000; - border-width: 0 0 1px; -} -@media (min-width: 768px) { - .navbar-static-top { - border-radius: 0; - } -} -.navbar-fixed-top, -.navbar-fixed-bottom { - position: fixed; - right: 0; - left: 0; - z-index: 1030; -} -@media (min-width: 768px) { - .navbar-fixed-top, - .navbar-fixed-bottom { - border-radius: 0; - } -} -.navbar-fixed-top { - top: 0; - border-width: 0 0 1px; -} -.navbar-fixed-bottom { - bottom: 0; - margin-bottom: 0; - border-width: 1px 0 0; -} -.navbar-brand { - float: left; - padding: 9.5px 15px; - font-size: 19px; - line-height: 21px; - height: 40px; -} -.navbar-brand:hover, -.navbar-brand:focus { - text-decoration: none; -} -.navbar-brand > img { - display: block; -} -@media (min-width: 768px) { - .navbar > .container .navbar-brand, - .navbar > .container-fluid .navbar-brand { - margin-left: -15px; - } -} -.navbar-toggle { - position: relative; - float: right; - margin-right: 15px; - padding: 9px 10px; - margin-top: 3px; - margin-bottom: 3px; - background-color: transparent; - background-image: none; - border: 1px solid transparent; - border-radius: 0; -} -.navbar-toggle:focus { - outline: 0; -} -.navbar-toggle .icon-bar { - display: block; - width: 22px; - height: 2px; - border-radius: 1px; -} -.navbar-toggle .icon-bar + .icon-bar { - margin-top: 4px; -} -@media (min-width: 768px) { - .navbar-toggle { - display: none; - } -} -.navbar-nav { - margin: 4.75px -15px; -} -.navbar-nav > li > a { - padding-top: 10px; - padding-bottom: 10px; - line-height: 21px; -} -@media (max-width: 767px) { - .navbar-nav .open .dropdown-menu { - position: static; - float: none; - width: auto; - margin-top: 0; - background-color: transparent; - border: 0; - -webkit-box-shadow: none; - box-shadow: none; - } - .navbar-nav .open .dropdown-menu > li > a, - .navbar-nav .open .dropdown-menu .dropdown-header { - padding: 5px 15px 5px 25px; - } - .navbar-nav .open .dropdown-menu > li > a { - line-height: 21px; - } - .navbar-nav .open .dropdown-menu > li > a:hover, - .navbar-nav .open .dropdown-menu > li > a:focus { - background-image: none; - } -} -@media (min-width: 768px) { - .navbar-nav { - float: left; - margin: 0; - } - .navbar-nav > li { - float: left; - } - .navbar-nav > li > a { - padding-top: 9.5px; - padding-bottom: 9.5px; - } -} -.navbar-form { - margin-left: -15px; - margin-right: -15px; - padding: 10px 15px; - border-top: 1px solid transparent; - border-bottom: 1px solid transparent; - -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); - box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); - margin-top: 0.5px; - margin-bottom: 0.5px; -} -@media (min-width: 768px) { - .navbar-form .form-group { - display: inline-block; - margin-bottom: 0; - vertical-align: middle; - } - .navbar-form .form-control { - display: inline-block; - width: auto; - vertical-align: middle; - } - .navbar-form .form-control-static { - display: inline-block; - } - .navbar-form .input-group { - display: inline-table; - vertical-align: middle; - } - .navbar-form .input-group .input-group-addon, - .navbar-form .input-group .input-group-btn, - .navbar-form .input-group .form-control { - width: auto; - } - .navbar-form .input-group > .form-control { - width: 100%; - } - .navbar-form .control-label { - margin-bottom: 0; - vertical-align: middle; - } - .navbar-form .radio, - .navbar-form .checkbox { - display: inline-block; - margin-top: 0; - margin-bottom: 0; - vertical-align: middle; - } - .navbar-form .radio label, - .navbar-form .checkbox label { - padding-left: 0; - } - .navbar-form .radio input[type="radio"], - .navbar-form .checkbox input[type="checkbox"] { - position: relative; - margin-left: 0; - } - .navbar-form .has-feedback .form-control-feedback { - top: 0; - } -} -@media (max-width: 767px) { - .navbar-form .form-group { - margin-bottom: 5px; - } - .navbar-form .form-group:last-child { - margin-bottom: 0; - } -} -@media (min-width: 768px) { - .navbar-form { - width: auto; - border: 0; - margin-left: 0; - margin-right: 0; - padding-top: 0; - padding-bottom: 0; - -webkit-box-shadow: none; - box-shadow: none; - } -} -.navbar-nav > li > .dropdown-menu { - margin-top: 0; - border-top-right-radius: 0; - border-top-left-radius: 0; -} -.navbar-fixed-bottom .navbar-nav > li > .dropdown-menu { - margin-bottom: 0; - border-top-right-radius: 0; - border-top-left-radius: 0; - border-bottom-right-radius: 0; - border-bottom-left-radius: 0; -} -.navbar-btn { - margin-top: 0.5px; - margin-bottom: 0.5px; -} -.navbar-btn.btn-sm { - margin-top: 5px; - margin-bottom: 5px; -} -.navbar-btn.btn-xs { - margin-top: 9px; - margin-bottom: 9px; -} -.navbar-text { - margin-top: 9.5px; - margin-bottom: 9.5px; -} -@media (min-width: 768px) { - .navbar-text { - float: left; - margin-left: 15px; - margin-right: 15px; - } -} -@media (min-width: 768px) { - .navbar-left { - float: left !important; - } - .navbar-right { - float: right !important; - margin-right: -15px; - } - .navbar-right ~ .navbar-right { - margin-right: 0; - } -} -.navbar-default { - background-color: #0a0a0a; - border-color: transparent; -} -.navbar-default .navbar-brand { - color: #DF691A; -} -.navbar-default .navbar-brand:hover, -.navbar-default .navbar-brand:focus { - color: #ebebeb; - background-color: transparent; -} -.navbar-default .navbar-text { - color: #ebebeb; -} -.navbar-default .navbar-nav > li > a { - color: #ebebeb; -} -.navbar-default .navbar-nav > li > a:hover, -.navbar-default .navbar-nav > li > a:focus { - color: #F0ad4e; - background-color: #282828; -} -.navbar-default .navbar-nav > .active > a, -.navbar-default .navbar-nav > .active > a:hover, -.navbar-default .navbar-nav > .active > a:focus { - color: #009688; - background-color: #282828; -} -.navbar-default .navbar-nav > .disabled > a, -.navbar-default .navbar-nav > .disabled > a:hover, -.navbar-default .navbar-nav > .disabled > a:focus { - color: #cccccc; - background-color: transparent; -} -.navbar-default .navbar-toggle { - border-color: transparent; -} -.navbar-default .navbar-toggle:hover, -.navbar-default .navbar-toggle:focus { - background-color: #485563; -} -.navbar-default .navbar-toggle .icon-bar { - background-color: #ebebeb; -} -.navbar-default .navbar-collapse, -.navbar-default .navbar-form { - border-color: transparent; -} -.navbar-default .navbar-nav > .open > a, -.navbar-default .navbar-nav > .open > a:hover, -.navbar-default .navbar-nav > .open > a:focus { - background-color: #f9be03; - color: #282828; -} -@media (max-width: 767px) { - .navbar-default .navbar-nav .open .dropdown-menu > li > a { - color: #ebebeb; - } - .navbar-default .navbar-nav .open .dropdown-menu > li > a:hover, - .navbar-default .navbar-nav .open .dropdown-menu > li > a:focus { - color: #ebebeb; - background-color: #485563; - } - .navbar-default .navbar-nav .open .dropdown-menu > .active > a, - .navbar-default .navbar-nav .open .dropdown-menu > .active > a:hover, - .navbar-default .navbar-nav .open .dropdown-menu > .active > a:focus { - color: #ebebeb; - background-color: #485563; - } - .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a, - .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:hover, - .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:focus { - color: #cccccc; - background-color: transparent; - } -} -.navbar-default .navbar-link { - color: #ebebeb; -} -.navbar-default .navbar-link:hover { - color: #ebebeb; -} -.navbar-default .btn-link { - color: #ebebeb; -} -.navbar-default .btn-link:hover, -.navbar-default .btn-link:focus { - color: #ebebeb; -} -.navbar-default .btn-link[disabled]:hover, -fieldset[disabled] .navbar-default .btn-link:hover, -.navbar-default .btn-link[disabled]:focus, -fieldset[disabled] .navbar-default .btn-link:focus { - color: #cccccc; -} -.navbar-inverse { - background-color: #df691a; - border-color: transparent; -} -.navbar-inverse .navbar-brand { - color: #ebebeb; -} -.navbar-inverse .navbar-brand:hover, -.navbar-inverse .navbar-brand:focus { - color: #ebebeb; - background-color: transparent; -} -.navbar-inverse .navbar-text { - color: #ebebeb; -} -.navbar-inverse .navbar-nav > li > a { - color: #ebebeb; -} -.navbar-inverse .navbar-nav > li > a:hover, -.navbar-inverse .navbar-nav > li > a:focus { - color: #ebebeb; - background-color: #c85e17; -} -.navbar-inverse .navbar-nav > .active > a, -.navbar-inverse .navbar-nav > .active > a:hover, -.navbar-inverse .navbar-nav > .active > a:focus { - color: #ebebeb; - background-color: #c85e17; -} -.navbar-inverse .navbar-nav > .disabled > a, -.navbar-inverse .navbar-nav > .disabled > a:hover, -.navbar-inverse .navbar-nav > .disabled > a:focus { - color: #444444; - background-color: transparent; -} -.navbar-inverse .navbar-toggle { - border-color: transparent; -} -.navbar-inverse .navbar-toggle:hover, -.navbar-inverse .navbar-toggle:focus { - background-color: #c85e17; -} -.navbar-inverse .navbar-toggle .icon-bar { - background-color: #ebebeb; -} -.navbar-inverse .navbar-collapse, -.navbar-inverse .navbar-form { - border-color: #bf5a16; -} -.navbar-inverse .navbar-nav > .open > a, -.navbar-inverse .navbar-nav > .open > a:hover, -.navbar-inverse .navbar-nav > .open > a:focus { - background-color: #c85e17; - color: #ebebeb; -} -@media (max-width: 767px) { - .navbar-inverse .navbar-nav .open .dropdown-menu > .dropdown-header { - border-color: transparent; - } - .navbar-inverse .navbar-nav .open .dropdown-menu .divider { - background-color: transparent; - } - .navbar-inverse .navbar-nav .open .dropdown-menu > li > a { - color: #ebebeb; - } - .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:hover, - .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:focus { - color: #ebebeb; - background-color: #c85e17; - } - .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a, - .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:hover, - .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:focus { - color: #ebebeb; - background-color: #c85e17; - } - .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a, - .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:hover, - .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:focus { - color: #444444; - background-color: transparent; - } -} -.navbar-inverse .navbar-link { - color: #ebebeb; -} -.navbar-inverse .navbar-link:hover { - color: #ebebeb; -} -.navbar-inverse .btn-link { - color: #ebebeb; -} -.navbar-inverse .btn-link:hover, -.navbar-inverse .btn-link:focus { - color: #ebebeb; -} -.navbar-inverse .btn-link[disabled]:hover, -fieldset[disabled] .navbar-inverse .btn-link:hover, -.navbar-inverse .btn-link[disabled]:focus, -fieldset[disabled] .navbar-inverse .btn-link:focus { - color: #444444; -} -.breadcrumb { - padding: 8px 15px; - margin-bottom: 21px; - list-style: none; - background-color: #4e5d6c; - border-radius: 0; -} -.breadcrumb > li { - display: inline-block; -} -.breadcrumb > li + li:before { - content: "/\00a0"; - padding: 0 5px; - color: #ebebeb; -} -.breadcrumb > .active { - color: #ebebeb; -} -.pagination { - display: inline-block; - padding-left: 0; - margin: 21px 0; - border-radius: 0; -} -.pagination > li { - display: inline; -} -.pagination > li > a, -.pagination > li > span { - position: relative; - float: left; - padding: 8px 16px; - line-height: 1.42857143; - text-decoration: none; - color: #ebebeb; - background-color: #282828; - border: 1px solid transparent; - margin-left: -1px; -} -.pagination > li:first-child > a, -.pagination > li:first-child > span { - margin-left: 0; - border-bottom-left-radius: 0; - border-top-left-radius: 0; -} -.pagination > li:last-child > a, -.pagination > li:last-child > span { - border-bottom-right-radius: 0; - border-top-right-radius: 0; -} -.pagination > li > a:hover, -.pagination > li > span:hover, -.pagination > li > a:focus, -.pagination > li > span:focus { - z-index: 2; - color: #ebebeb; - background-color: #333333; - border-color: transparent; -} -.pagination > .active > a, -.pagination > .active > span, -.pagination > .active > a:hover, -.pagination > .active > span:hover, -.pagination > .active > a:focus, -.pagination > .active > span:focus { - z-index: 3; - color: #ebebeb; - background-color: #df691a; - border-color: transparent; - cursor: default; -} -.pagination > .disabled > span, -.pagination > .disabled > span:hover, -.pagination > .disabled > span:focus, -.pagination > .disabled > a, -.pagination > .disabled > a:hover, -.pagination > .disabled > a:focus { - color: #fefefe; - background-color: #333333; - border-color: transparent; - cursor: not-allowed; -} -.pagination-lg > li > a, -.pagination-lg > li > span { - padding: 12px 24px; - font-size: 19px; - line-height: 1.3333333; -} -.pagination-lg > li:first-child > a, -.pagination-lg > li:first-child > span { - border-bottom-left-radius: 0; - border-top-left-radius: 0; -} -.pagination-lg > li:last-child > a, -.pagination-lg > li:last-child > span { - border-bottom-right-radius: 0; - border-top-right-radius: 0; -} -.pagination-sm > li > a, -.pagination-sm > li > span { - padding: 5px 10px; - font-size: 12px; - line-height: 1.5; -} -.pagination-sm > li:first-child > a, -.pagination-sm > li:first-child > span { - border-bottom-left-radius: 0; - border-top-left-radius: 0; -} -.pagination-sm > li:last-child > a, -.pagination-sm > li:last-child > span { - border-bottom-right-radius: 0; - border-top-right-radius: 0; -} -.pager { - padding-left: 0; - margin: 21px 0; - list-style: none; - text-align: center; -} -.pager li { - display: inline; -} -.pager li > a, -.pager li > span { - display: inline-block; - padding: 5px 14px; - background-color: #4e5d6c; - border: 1px solid transparent; - border-radius: 15px; -} -.pager li > a:hover, -.pager li > a:focus { - text-decoration: none; - background-color: #485563; -} -.pager .next > a, -.pager .next > span { - float: right; -} -.pager .previous > a, -.pager .previous > span { - float: left; -} -.pager .disabled > a, -.pager .disabled > a:hover, -.pager .disabled > a:focus, -.pager .disabled > span { - color: #323c46; - background-color: #4e5d6c; - cursor: not-allowed; -} -.label { - display: inline; - padding: .2em .6em .3em; - font-size: 75%; - font-weight: bold; - line-height: 1; - color: #ffffff; - text-align: center; - white-space: nowrap; - vertical-align: baseline; - border-radius: .25em; -} -a.label:hover, -a.label:focus { - color: #ffffff; - text-decoration: none; - cursor: pointer; -} -.label:empty { - display: none; -} -.btn .label { - position: relative; - top: -1px; -} -.label-default { - background-color: #4e5d6c; -} -.label-default[href]:hover, -.label-default[href]:focus { - background-color: #39444e; -} -.label-primary { - background-color: #df691a; -} -.label-primary[href]:hover, -.label-primary[href]:focus { - background-color: #b15315; -} -.label-success { - background-color: #5cb85c; -} -.label-success[href]:hover, -.label-success[href]:focus { - background-color: #449d44; -} -.label-info { - background-color: #5bc0de; -} -.label-info[href]:hover, -.label-info[href]:focus { - background-color: #31b0d5; -} -.label-warning { - background-color: #f0ad4e; -} -.label-warning[href]:hover, -.label-warning[href]:focus { - background-color: #ec971f; -} -.label-danger { - background-color: #d9534f; -} -.label-danger[href]:hover, -.label-danger[href]:focus { - background-color: #c9302c; -} -.badge { - display: inline-block; - min-width: 10px; - padding: 3px 7px; - font-size: 12px; - font-weight: 300; - color: #ebebeb; - line-height: 1; - vertical-align: middle; - white-space: nowrap; - text-align: center; - background-color: #4e5d6c; - border-radius: 10px; -} -.badge:empty { - display: none; -} -.btn .badge { - position: relative; - top: -1px; -} -.btn-xs .badge, -.btn-group-xs > .btn .badge { - top: 0; - padding: 1px 5px; -} -a.badge:hover, -a.badge:focus { - color: #ffffff; - text-decoration: none; - cursor: pointer; -} -.list-group-item.active > .badge, -.nav-pills > .active > a > .badge { - color: #df691a; - background-color: #ffffff; -} -.list-group-item > .badge { - float: right; -} -.list-group-item > .badge + .badge { - margin-right: 5px; -} -.nav-pills > li > a > .badge { - margin-left: 3px; -} -.jumbotron { - padding-top: 30px; - padding-bottom: 30px; - margin-bottom: 30px; - color: inherit; - background-color: #4e5d6c; -} -.jumbotron h1, -.jumbotron .h1 { - color: inherit; -} -.jumbotron p { - margin-bottom: 15px; - font-size: 23px; - font-weight: 200; -} -.jumbotron > hr { - border-top-color: #39444e; -} -.container .jumbotron, -.container-fluid .jumbotron { - border-radius: 0; - padding-left: 15px; - padding-right: 15px; -} -.jumbotron .container { - max-width: 100%; -} -@media screen and (min-width: 768px) { - .jumbotron { - padding-top: 48px; - padding-bottom: 48px; - } - .container .jumbotron, - .container-fluid .jumbotron { - padding-left: 60px; - padding-right: 60px; - } - .jumbotron h1, - .jumbotron .h1 { - font-size: 68px; - } -} -.thumbnail { - display: block; - padding: 4px; - margin-bottom: 21px; - line-height: 1.42857143; - background-color: #2b3e50; - border: 1px solid #dddddd; - border-radius: 0; - -webkit-transition: border 0.2s ease-in-out; - -o-transition: border 0.2s ease-in-out; - transition: border 0.2s ease-in-out; -} -.thumbnail > img, -.thumbnail a > img { - margin-left: auto; - margin-right: auto; -} -a.thumbnail:hover, -a.thumbnail:focus, -a.thumbnail.active { - border-color: #df691a; -} -.thumbnail .caption { - padding: 9px; - color: #ebebeb; -} -.alert { - padding: 15px; - margin-bottom: 21px; - border: 1px solid transparent; - border-radius: 0; -} -.alert h4 { - margin-top: 0; - color: inherit; -} -.alert .alert-link { - font-weight: bold; -} -.alert > p, -.alert > ul { - margin-bottom: 0; -} -.alert > p + p { - margin-top: 5px; -} -.alert-dismissable, -.alert-dismissible { - padding-right: 35px; -} -.alert-dismissable .close, -.alert-dismissible .close { - position: relative; - top: -2px; - right: -21px; - color: inherit; -} -.alert-success { - background-color: #5cb85c; - border-color: transparent; - color: #ebebeb; -} -.alert-success hr { - border-top-color: rgba(0, 0, 0, 0); -} -.alert-success .alert-link { - color: #d2d2d2; -} -.alert-info { - background-color: #5bc0de; - border-color: transparent; - color: #ebebeb; -} -.alert-info hr { - border-top-color: rgba(0, 0, 0, 0); -} -.alert-info .alert-link { - color: #d2d2d2; -} -.alert-warning { - background-color: #f0ad4e; - border-color: transparent; - color: #ebebeb; -} -.alert-warning hr { - border-top-color: rgba(0, 0, 0, 0); -} -.alert-warning .alert-link { - color: #d2d2d2; -} -.alert-danger { - background-color: #d9534f; - border-color: transparent; - color: #ebebeb; -} -.alert-danger hr { - border-top-color: rgba(0, 0, 0, 0); -} -.alert-danger .alert-link { - color: #d2d2d2; -} -@-webkit-keyframes progress-bar-stripes { - from { - background-position: 40px 0; - } - to { - background-position: 0 0; - } -} -@-o-keyframes progress-bar-stripes { - from { - background-position: 40px 0; - } - to { - background-position: 0 0; - } -} -@keyframes progress-bar-stripes { - from { - background-position: 40px 0; - } - to { - background-position: 0 0; - } -} -.progress { - overflow: hidden; - height: 21px; - margin-bottom: 21px; - background-color: #4e5d6c; - border-radius: 0; - -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); - box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); -} -.progress-bar { - float: left; - width: 0%; - height: 100%; - font-size: 12px; - line-height: 21px; - color: #ffffff; - text-align: center; - background-color: #df691a; - -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); - box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); - -webkit-transition: width 0.6s ease; - -o-transition: width 0.6s ease; - transition: width 0.6s ease; -} -.progress-striped .progress-bar, -.progress-bar-striped { - background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); - background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); - background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); - -webkit-background-size: 40px 40px; - background-size: 40px 40px; -} -.progress.active .progress-bar, -.progress-bar.active { - -webkit-animation: progress-bar-stripes 2s linear infinite; - -o-animation: progress-bar-stripes 2s linear infinite; - animation: progress-bar-stripes 2s linear infinite; -} -.progress-bar-success { - background-color: #5cb85c; -} -.progress-striped .progress-bar-success { - background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); - background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); - background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); -} -.progress-bar-info { - background-color: #5bc0de; -} -.progress-striped .progress-bar-info { - background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); - background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); - background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); -} -.progress-bar-warning { - background-color: #f0ad4e; -} -.progress-striped .progress-bar-warning { - background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); - background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); - background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); -} -.progress-bar-danger { - background-color: #d9534f; -} -.progress-striped .progress-bar-danger { - background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); - background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); - background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); -} -.media { - margin-top: 15px; -} -.media:first-child { - margin-top: 0; -} -.media, -.media-body { - zoom: 1; - overflow: hidden; -} -.media-body { - width: 10000px; -} -.media-object { - display: block; -} -.media-object.img-thumbnail { - max-width: none; -} -.media-right, -.media > .pull-right { - padding-left: 10px; -} -.media-left, -.media > .pull-left { - padding-right: 10px; -} -.media-left, -.media-right, -.media-body { - display: table-cell; - vertical-align: top; -} -.media-middle { - vertical-align: middle; -} -.media-bottom { - vertical-align: bottom; -} -.media-heading { - margin-top: 0; - margin-bottom: 5px; -} -.media-list { - padding-left: 0; - list-style: none; -} -.list-group { - margin-bottom: 20px; - padding-left: 0; -} -.list-group-item { - position: relative; - display: block; - padding: 10px 15px; - margin-bottom: -1px; - background-color: #282828; - border: 1px solid transparent; -} -.list-group-item:first-child { - border-top-right-radius: 0; - border-top-left-radius: 0; -} -.list-group-item:last-child { - margin-bottom: 0; - border-bottom-right-radius: 0; - border-bottom-left-radius: 0; -} -a.list-group-item, -button.list-group-item { - color: #ebebeb; -} -a.list-group-item .list-group-item-heading, -button.list-group-item .list-group-item-heading { - color: #ebebeb; -} -a.list-group-item:hover, -button.list-group-item:hover, -a.list-group-item:focus, -button.list-group-item:focus { - text-decoration: none; - color: #ebebeb; - background-color: #333333; -} -button.list-group-item { - width: 100%; - text-align: left; -} -.list-group-item.disabled, -.list-group-item.disabled:hover, -.list-group-item.disabled:focus { - background-color: #ebebeb; - color: #4e5d6c; - cursor: not-allowed; -} -.list-group-item.disabled .list-group-item-heading, -.list-group-item.disabled:hover .list-group-item-heading, -.list-group-item.disabled:focus .list-group-item-heading { - color: inherit; -} -.list-group-item.disabled .list-group-item-text, -.list-group-item.disabled:hover .list-group-item-text, -.list-group-item.disabled:focus .list-group-item-text { - color: #4e5d6c; -} -.list-group-item.active, -.list-group-item.active:hover, -.list-group-item.active:focus { - z-index: 2; - color: #ffffff; - background-color: #df691a; - border-color: #df691a; -} -.list-group-item.active .list-group-item-heading, -.list-group-item.active:hover .list-group-item-heading, -.list-group-item.active:focus .list-group-item-heading, -.list-group-item.active .list-group-item-heading > small, -.list-group-item.active:hover .list-group-item-heading > small, -.list-group-item.active:focus .list-group-item-heading > small, -.list-group-item.active .list-group-item-heading > .small, -.list-group-item.active:hover .list-group-item-heading > .small, -.list-group-item.active:focus .list-group-item-heading > .small { - color: inherit; -} -.list-group-item.active .list-group-item-text, -.list-group-item.active:hover .list-group-item-text, -.list-group-item.active:focus .list-group-item-text { - color: #f9decc; -} -.list-group-item-success { - color: #ebebeb; - background-color: #5cb85c; -} -a.list-group-item-success, -button.list-group-item-success { - color: #ebebeb; -} -a.list-group-item-success .list-group-item-heading, -button.list-group-item-success .list-group-item-heading { - color: inherit; -} -a.list-group-item-success:hover, -button.list-group-item-success:hover, -a.list-group-item-success:focus, -button.list-group-item-success:focus { - color: #ebebeb; - background-color: #4cae4c; -} -a.list-group-item-success.active, -button.list-group-item-success.active, -a.list-group-item-success.active:hover, -button.list-group-item-success.active:hover, -a.list-group-item-success.active:focus, -button.list-group-item-success.active:focus { - color: #fff; - background-color: #ebebeb; - border-color: #ebebeb; -} -.list-group-item-info { - color: #ebebeb; - background-color: #5bc0de; -} -a.list-group-item-info, -button.list-group-item-info { - color: #ebebeb; -} -a.list-group-item-info .list-group-item-heading, -button.list-group-item-info .list-group-item-heading { - color: inherit; -} -a.list-group-item-info:hover, -button.list-group-item-info:hover, -a.list-group-item-info:focus, -button.list-group-item-info:focus { - color: #ebebeb; - background-color: #46b8da; -} -a.list-group-item-info.active, -button.list-group-item-info.active, -a.list-group-item-info.active:hover, -button.list-group-item-info.active:hover, -a.list-group-item-info.active:focus, -button.list-group-item-info.active:focus { - color: #fff; - background-color: #ebebeb; - border-color: #ebebeb; -} -.list-group-item-warning { - color: #ebebeb; - background-color: #f0ad4e; -} -a.list-group-item-warning, -button.list-group-item-warning { - color: #ebebeb; -} -a.list-group-item-warning .list-group-item-heading, -button.list-group-item-warning .list-group-item-heading { - color: inherit; -} -a.list-group-item-warning:hover, -button.list-group-item-warning:hover, -a.list-group-item-warning:focus, -button.list-group-item-warning:focus { - color: #ebebeb; - background-color: #eea236; -} -a.list-group-item-warning.active, -button.list-group-item-warning.active, -a.list-group-item-warning.active:hover, -button.list-group-item-warning.active:hover, -a.list-group-item-warning.active:focus, -button.list-group-item-warning.active:focus { - color: #fff; - background-color: #ebebeb; - border-color: #ebebeb; -} -.list-group-item-danger { - color: #ebebeb; - background-color: #d9534f; -} -a.list-group-item-danger, -button.list-group-item-danger { - color: #ebebeb; -} -a.list-group-item-danger .list-group-item-heading, -button.list-group-item-danger .list-group-item-heading { - color: inherit; -} -a.list-group-item-danger:hover, -button.list-group-item-danger:hover, -a.list-group-item-danger:focus, -button.list-group-item-danger:focus { - color: #ebebeb; - background-color: #d43f3a; -} -a.list-group-item-danger.active, -button.list-group-item-danger.active, -a.list-group-item-danger.active:hover, -button.list-group-item-danger.active:hover, -a.list-group-item-danger.active:focus, -button.list-group-item-danger.active:focus { - color: #fff; - background-color: #ebebeb; - border-color: #ebebeb; -} -.list-group-item-heading { - margin-top: 0; - margin-bottom: 5px; -} -.list-group-item-text { - margin-bottom: 0; - line-height: 1.3; -} -.panel { - margin-bottom: 21px; - background-color: #4e5d6c; - border: 1px solid transparent; - border-radius: 0; - -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05); - box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05); -} -.panel-body { - padding: 15px; -} -.panel-heading { - padding: 10px 15px; - border-bottom: 1px solid transparent; - border-top-right-radius: -1; - border-top-left-radius: -1; -} -.panel-heading > .dropdown .dropdown-toggle { - color: inherit; -} -.panel-title { - margin-top: 0; - margin-bottom: 0; - font-size: 17px; - color: inherit; -} -.panel-title > a, -.panel-title > small, -.panel-title > .small, -.panel-title > small > a, -.panel-title > .small > a { - color: inherit; -} -.panel-footer { - padding: 10px 15px; - background-color: #485563; - border-top: 1px solid transparent; - border-bottom-right-radius: -1; - border-bottom-left-radius: -1; -} -.panel > .list-group, -.panel > .panel-collapse > .list-group { - margin-bottom: 0; -} -.panel > .list-group .list-group-item, -.panel > .panel-collapse > .list-group .list-group-item { - border-width: 1px 0; - border-radius: 0; -} -.panel > .list-group:first-child .list-group-item:first-child, -.panel > .panel-collapse > .list-group:first-child .list-group-item:first-child { - border-top: 0; - border-top-right-radius: -1; - border-top-left-radius: -1; -} -.panel > .list-group:last-child .list-group-item:last-child, -.panel > .panel-collapse > .list-group:last-child .list-group-item:last-child { - border-bottom: 0; - border-bottom-right-radius: -1; - border-bottom-left-radius: -1; -} -.panel > .panel-heading + .panel-collapse > .list-group .list-group-item:first-child { - border-top-right-radius: 0; - border-top-left-radius: 0; -} -.panel-heading + .list-group .list-group-item:first-child { - border-top-width: 0; -} -.list-group + .panel-footer { - border-top-width: 0; -} -.panel > .table, -.panel > .table-responsive > .table, -.panel > .panel-collapse > .table { - margin-bottom: 0; -} -.panel > .table caption, -.panel > .table-responsive > .table caption, -.panel > .panel-collapse > .table caption { - padding-left: 15px; - padding-right: 15px; -} -.panel > .table:first-child, -.panel > .table-responsive:first-child > .table:first-child { - border-top-right-radius: -1; - border-top-left-radius: -1; -} -.panel > .table:first-child > thead:first-child > tr:first-child, -.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child, -.panel > .table:first-child > tbody:first-child > tr:first-child, -.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child { - border-top-left-radius: -1; - border-top-right-radius: -1; -} -.panel > .table:first-child > thead:first-child > tr:first-child td:first-child, -.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:first-child, -.panel > .table:first-child > tbody:first-child > tr:first-child td:first-child, -.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:first-child, -.panel > .table:first-child > thead:first-child > tr:first-child th:first-child, -.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:first-child, -.panel > .table:first-child > tbody:first-child > tr:first-child th:first-child, -.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:first-child { - border-top-left-radius: -1; -} -.panel > .table:first-child > thead:first-child > tr:first-child td:last-child, -.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:last-child, -.panel > .table:first-child > tbody:first-child > tr:first-child td:last-child, -.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:last-child, -.panel > .table:first-child > thead:first-child > tr:first-child th:last-child, -.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:last-child, -.panel > .table:first-child > tbody:first-child > tr:first-child th:last-child, -.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:last-child { - border-top-right-radius: -1; -} -.panel > .table:last-child, -.panel > .table-responsive:last-child > .table:last-child { - border-bottom-right-radius: -1; - border-bottom-left-radius: -1; -} -.panel > .table:last-child > tbody:last-child > tr:last-child, -.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child, -.panel > .table:last-child > tfoot:last-child > tr:last-child, -.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child { - border-bottom-left-radius: -1; - border-bottom-right-radius: -1; -} -.panel > .table:last-child > tbody:last-child > tr:last-child td:first-child, -.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:first-child, -.panel > .table:last-child > tfoot:last-child > tr:last-child td:first-child, -.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:first-child, -.panel > .table:last-child > tbody:last-child > tr:last-child th:first-child, -.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:first-child, -.panel > .table:last-child > tfoot:last-child > tr:last-child th:first-child, -.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:first-child { - border-bottom-left-radius: -1; -} -.panel > .table:last-child > tbody:last-child > tr:last-child td:last-child, -.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:last-child, -.panel > .table:last-child > tfoot:last-child > tr:last-child td:last-child, -.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:last-child, -.panel > .table:last-child > tbody:last-child > tr:last-child th:last-child, -.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:last-child, -.panel > .table:last-child > tfoot:last-child > tr:last-child th:last-child, -.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:last-child { - border-bottom-right-radius: -1; -} -.panel > .panel-body + .table, -.panel > .panel-body + .table-responsive, -.panel > .table + .panel-body, -.panel > .table-responsive + .panel-body { - border-top: 1px solid #4e5d6c; -} -.panel > .table > tbody:first-child > tr:first-child th, -.panel > .table > tbody:first-child > tr:first-child td { - border-top: 0; -} -.panel > .table-bordered, -.panel > .table-responsive > .table-bordered { - border: 0; -} -.panel > .table-bordered > thead > tr > th:first-child, -.panel > .table-responsive > .table-bordered > thead > tr > th:first-child, -.panel > .table-bordered > tbody > tr > th:first-child, -.panel > .table-responsive > .table-bordered > tbody > tr > th:first-child, -.panel > .table-bordered > tfoot > tr > th:first-child, -.panel > .table-responsive > .table-bordered > tfoot > tr > th:first-child, -.panel > .table-bordered > thead > tr > td:first-child, -.panel > .table-responsive > .table-bordered > thead > tr > td:first-child, -.panel > .table-bordered > tbody > tr > td:first-child, -.panel > .table-responsive > .table-bordered > tbody > tr > td:first-child, -.panel > .table-bordered > tfoot > tr > td:first-child, -.panel > .table-responsive > .table-bordered > tfoot > tr > td:first-child { - border-left: 0; -} -.panel > .table-bordered > thead > tr > th:last-child, -.panel > .table-responsive > .table-bordered > thead > tr > th:last-child, -.panel > .table-bordered > tbody > tr > th:last-child, -.panel > .table-responsive > .table-bordered > tbody > tr > th:last-child, -.panel > .table-bordered > tfoot > tr > th:last-child, -.panel > .table-responsive > .table-bordered > tfoot > tr > th:last-child, -.panel > .table-bordered > thead > tr > td:last-child, -.panel > .table-responsive > .table-bordered > thead > tr > td:last-child, -.panel > .table-bordered > tbody > tr > td:last-child, -.panel > .table-responsive > .table-bordered > tbody > tr > td:last-child, -.panel > .table-bordered > tfoot > tr > td:last-child, -.panel > .table-responsive > .table-bordered > tfoot > tr > td:last-child { - border-right: 0; -} -.panel > .table-bordered > thead > tr:first-child > td, -.panel > .table-responsive > .table-bordered > thead > tr:first-child > td, -.panel > .table-bordered > tbody > tr:first-child > td, -.panel > .table-responsive > .table-bordered > tbody > tr:first-child > td, -.panel > .table-bordered > thead > tr:first-child > th, -.panel > .table-responsive > .table-bordered > thead > tr:first-child > th, -.panel > .table-bordered > tbody > tr:first-child > th, -.panel > .table-responsive > .table-bordered > tbody > tr:first-child > th { - border-bottom: 0; -} -.panel > .table-bordered > tbody > tr:last-child > td, -.panel > .table-responsive > .table-bordered > tbody > tr:last-child > td, -.panel > .table-bordered > tfoot > tr:last-child > td, -.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > td, -.panel > .table-bordered > tbody > tr:last-child > th, -.panel > .table-responsive > .table-bordered > tbody > tr:last-child > th, -.panel > .table-bordered > tfoot > tr:last-child > th, -.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > th { - border-bottom: 0; -} -.panel > .table-responsive { - border: 0; - margin-bottom: 0; -} -.panel-group { - margin-bottom: 21px; -} -.panel-group .panel { - margin-bottom: 0; - border-radius: 0; -} -.panel-group .panel + .panel { - margin-top: 5px; -} -.panel-group .panel-heading { - border-bottom: 0; -} -.panel-group .panel-heading + .panel-collapse > .panel-body, -.panel-group .panel-heading + .panel-collapse > .list-group { - border-top: 1px solid transparent; -} -.panel-group .panel-footer { - border-top: 0; -} -.panel-group .panel-footer + .panel-collapse .panel-body { - border-bottom: 1px solid transparent; -} -.panel-default { - border-color: transparent; -} -.panel-default > .panel-heading { - color: #333333; - background-color: #f5f5f5; - border-color: transparent; -} -.panel-default > .panel-heading + .panel-collapse > .panel-body { - border-top-color: transparent; -} -.panel-default > .panel-heading .badge { - color: #f5f5f5; - background-color: #333333; -} -.panel-default > .panel-footer + .panel-collapse > .panel-body { - border-bottom-color: transparent; -} -.panel-primary { - border-color: transparent; -} -.panel-primary > .panel-heading { - color: #ffffff; - background-color: #df691a; - border-color: transparent; -} -.panel-primary > .panel-heading + .panel-collapse > .panel-body { - border-top-color: transparent; -} -.panel-primary > .panel-heading .badge { - color: #df691a; - background-color: #ffffff; -} -.panel-primary > .panel-footer + .panel-collapse > .panel-body { - border-bottom-color: transparent; -} -.panel-success { - border-color: transparent; -} -.panel-success > .panel-heading { - color: #ebebeb; - background-color: #5cb85c; - border-color: transparent; -} -.panel-success > .panel-heading + .panel-collapse > .panel-body { - border-top-color: transparent; -} -.panel-success > .panel-heading .badge { - color: #5cb85c; - background-color: #ebebeb; -} -.panel-success > .panel-footer + .panel-collapse > .panel-body { - border-bottom-color: transparent; -} -.panel-info { - border-color: transparent; -} -.panel-info > .panel-heading { - color: #ebebeb; - background-color: #5bc0de; - border-color: transparent; -} -.panel-info > .panel-heading + .panel-collapse > .panel-body { - border-top-color: transparent; -} -.panel-info > .panel-heading .badge { - color: #5bc0de; - background-color: #ebebeb; -} -.panel-info > .panel-footer + .panel-collapse > .panel-body { - border-bottom-color: transparent; -} -.panel-warning { - border-color: transparent; -} -.panel-warning > .panel-heading { - color: #ebebeb; - background-color: #f0ad4e; - border-color: transparent; -} -.panel-warning > .panel-heading + .panel-collapse > .panel-body { - border-top-color: transparent; -} -.panel-warning > .panel-heading .badge { - color: #f0ad4e; - background-color: #ebebeb; -} -.panel-warning > .panel-footer + .panel-collapse > .panel-body { - border-bottom-color: transparent; -} -.panel-danger { - border-color: transparent; -} -.panel-danger > .panel-heading { - color: #ebebeb; - background-color: #d9534f; - border-color: transparent; -} -.panel-danger > .panel-heading + .panel-collapse > .panel-body { - border-top-color: transparent; -} -.panel-danger > .panel-heading .badge { - color: #d9534f; - background-color: #ebebeb; -} -.panel-danger > .panel-footer + .panel-collapse > .panel-body { - border-bottom-color: transparent; -} -.embed-responsive { - position: relative; - display: block; - height: 0; - padding: 0; - overflow: hidden; -} -.embed-responsive .embed-responsive-item, -.embed-responsive iframe, -.embed-responsive embed, -.embed-responsive object, -.embed-responsive video { - position: absolute; - top: 0; - left: 0; - bottom: 0; - height: 100%; - width: 100%; - border: 0; -} -.embed-responsive-16by9 { - padding-bottom: 56.25%; -} -.embed-responsive-4by3 { - padding-bottom: 75%; -} -.well { - min-height: 20px; - padding: 19px; - margin-bottom: 20px; - background-color: #4e5d6c; - border: 1px solid transparent; - border-radius: 0; - -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); - box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); -} -.well blockquote { - border-color: #ddd; - border-color: rgba(0, 0, 0, 0.15); -} -.well-lg { - padding: 24px; - border-radius: 0; -} -.well-sm { - padding: 9px; - border-radius: 0; -} -.close { - float: right; - font-size: 22.5px; - font-weight: bold; - line-height: 1; - color: #ebebeb; - text-shadow: none; - opacity: 0.2; - filter: alpha(opacity=20); -} -.close:hover, -.close:focus { - color: #ebebeb; - text-decoration: none; - cursor: pointer; - opacity: 0.5; - filter: alpha(opacity=50); -} -button.close { - padding: 0; - cursor: pointer; - background: transparent; - border: 0; - -webkit-appearance: none; -} -.modal-open { - overflow: hidden; -} -.modal { - display: none; - overflow: hidden; - position: fixed; - top: 0; - right: 0; - bottom: 0; - left: 0; - z-index: 1050; - -webkit-overflow-scrolling: touch; - outline: 0; -} -.modal.fade .modal-dialog { - -webkit-transform: translate(0, -25%); - -ms-transform: translate(0, -25%); - -o-transform: translate(0, -25%); - transform: translate(0, -25%); - -webkit-transition: -webkit-transform 0.3s ease-out; - -o-transition: -o-transform 0.3s ease-out; - transition: transform 0.3s ease-out; -} -.modal.in .modal-dialog { - -webkit-transform: translate(0, 0); - -ms-transform: translate(0, 0); - -o-transform: translate(0, 0); - transform: translate(0, 0); -} -.modal-open .modal { - overflow-x: hidden; - overflow-y: auto; -} -.modal-dialog { - position: relative; - width: auto; - margin: 10px; -} -.modal-content { - position: relative; - background-color: #282828; - border: 1px solid transparent; - border-radius: 0; - -webkit-box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5); - box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5); - -webkit-background-clip: padding-box; - background-clip: padding-box; - outline: 0; -} -.modal-backdrop { - position: fixed; - top: 0; - right: 0; - bottom: 0; - left: 0; - z-index: 1040; - background-color: #000000; -} -.modal-backdrop.fade { - opacity: 0; - filter: alpha(opacity=0); -} -.modal-backdrop.in { - opacity: 0.5; - filter: alpha(opacity=50); -} -.modal-header { - padding: 15px; - border-bottom: 1px solid #2b3e50; -} -.modal-header .close { - margin-top: -2px; -} -.modal-title { - margin: 0; - line-height: 1.42857143; -} -.modal-body { - position: relative; - padding: 20px; -} -.modal-footer { - padding: 20px; - text-align: right; - border-top: 1px solid #2b3e50; -} -.modal-footer .btn + .btn { - margin-left: 5px; - margin-bottom: 0; -} -.modal-footer .btn-group .btn + .btn { - margin-left: -1px; -} -.modal-footer .btn-block + .btn-block { - margin-left: 0; -} -.modal-scrollbar-measure { - position: absolute; - top: -9999px; - width: 50px; - height: 50px; - overflow: scroll; -} -@media (min-width: 768px) { - .modal-dialog { - width: 600px; - margin: 30px auto; - } - .modal-content { - -webkit-box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5); - box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5); - } - .modal-sm { - width: 300px; - } -} -@media (min-width: 992px) { - .modal-lg { - width: 900px; - } -} -.tooltip { - position: absolute; - z-index: 1070; - display: block; - font-family: "Lato", "Helvetica Neue", Helvetica, Arial, sans-serif; - font-style: normal; - font-weight: normal; - letter-spacing: normal; - line-break: auto; - line-height: 1.42857143; - text-align: left; - text-align: start; - text-decoration: none; - text-shadow: none; - text-transform: none; - white-space: normal; - word-break: normal; - word-spacing: normal; - word-wrap: normal; - font-size: 12px; - opacity: 0; - filter: alpha(opacity=0); -} -.tooltip.in { - opacity: 0.9; - filter: alpha(opacity=90); -} -.tooltip.top { - margin-top: -3px; - padding: 5px 0; -} -.tooltip.right { - margin-left: 3px; - padding: 0 5px; -} -.tooltip.bottom { - margin-top: 3px; - padding: 5px 0; -} -.tooltip.left { - margin-left: -3px; - padding: 0 5px; -} -.tooltip-inner { - max-width: 200px; - padding: 3px 8px; - color: #ffffff; - text-align: center; - background-color: #000000; - border-radius: 0; -} -.tooltip-arrow { - position: absolute; - width: 0; - height: 0; - border-color: transparent; - border-style: solid; -} -.tooltip.top .tooltip-arrow { - bottom: 0; - left: 50%; - margin-left: -5px; - border-width: 5px 5px 0; - border-top-color: #000000; -} -.tooltip.top-left .tooltip-arrow { - bottom: 0; - right: 5px; - margin-bottom: -5px; - border-width: 5px 5px 0; - border-top-color: #000000; -} -.tooltip.top-right .tooltip-arrow { - bottom: 0; - left: 5px; - margin-bottom: -5px; - border-width: 5px 5px 0; - border-top-color: #000000; -} -.tooltip.right .tooltip-arrow { - top: 50%; - left: 0; - margin-top: -5px; - border-width: 5px 5px 5px 0; - border-right-color: #000000; -} -.tooltip.left .tooltip-arrow { - top: 50%; - right: 0; - margin-top: -5px; - border-width: 5px 0 5px 5px; - border-left-color: #000000; -} -.tooltip.bottom .tooltip-arrow { - top: 0; - left: 50%; - margin-left: -5px; - border-width: 0 5px 5px; - border-bottom-color: #000000; -} -.tooltip.bottom-left .tooltip-arrow { - top: 0; - right: 5px; - margin-top: -5px; - border-width: 0 5px 5px; - border-bottom-color: #000000; -} -.tooltip.bottom-right .tooltip-arrow { - top: 0; - left: 5px; - margin-top: -5px; - border-width: 0 5px 5px; - border-bottom-color: #000000; -} -.popover { - position: absolute; - top: 0; - left: 0; - z-index: 1060; - display: none; - max-width: 276px; - padding: 1px; - font-family: "Lato", "Helvetica Neue", Helvetica, Arial, sans-serif; - font-style: normal; - font-weight: normal; - letter-spacing: normal; - line-break: auto; - line-height: 1.42857143; - text-align: left; - text-align: start; - text-decoration: none; - text-shadow: none; - text-transform: none; - white-space: normal; - word-break: normal; - word-spacing: normal; - word-wrap: normal; - font-size: 15px; - background-color: #4e5d6c; - -webkit-background-clip: padding-box; - background-clip: padding-box; - border: 1px solid transparent; - border-radius: 0; - -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); - box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); -} -.popover.top { - margin-top: -10px; -} -.popover.right { - margin-left: 10px; -} -.popover.bottom { - margin-top: 10px; -} -.popover.left { - margin-left: -10px; -} -.popover-title { - margin: 0; - padding: 8px 14px; - font-size: 15px; - background-color: #485563; - border-bottom: 1px solid #3d4954; - border-radius: -1 -1 0 0; -} -.popover-content { - padding: 9px 14px; -} -.popover > .arrow, -.popover > .arrow:after { - position: absolute; - display: block; - width: 0; - height: 0; - border-color: transparent; - border-style: solid; -} -.popover > .arrow { - border-width: 11px; -} -.popover > .arrow:after { - border-width: 10px; - content: ""; -} -.popover.top > .arrow { - left: 50%; - margin-left: -11px; - border-bottom-width: 0; - border-top-color: transparent; - bottom: -11px; -} -.popover.top > .arrow:after { - content: " "; - bottom: 1px; - margin-left: -10px; - border-bottom-width: 0; - border-top-color: #4e5d6c; -} -.popover.right > .arrow { - top: 50%; - left: -11px; - margin-top: -11px; - border-left-width: 0; - border-right-color: transparent; -} -.popover.right > .arrow:after { - content: " "; - left: 1px; - bottom: -10px; - border-left-width: 0; - border-right-color: #4e5d6c; -} -.popover.bottom > .arrow { - left: 50%; - margin-left: -11px; - border-top-width: 0; - border-bottom-color: transparent; - top: -11px; -} -.popover.bottom > .arrow:after { - content: " "; - top: 1px; - margin-left: -10px; - border-top-width: 0; - border-bottom-color: #4e5d6c; -} -.popover.left > .arrow { - top: 50%; - right: -11px; - margin-top: -11px; - border-right-width: 0; - border-left-color: transparent; -} -.popover.left > .arrow:after { - content: " "; - right: 1px; - border-right-width: 0; - border-left-color: #4e5d6c; - bottom: -10px; -} -.carousel { - position: relative; -} -.carousel-inner { - position: relative; - overflow: hidden; - width: 100%; -} -.carousel-inner > .item { - display: none; - position: relative; - -webkit-transition: 0.6s ease-in-out left; - -o-transition: 0.6s ease-in-out left; - transition: 0.6s ease-in-out left; -} -.carousel-inner > .item > img, -.carousel-inner > .item > a > img { - line-height: 1; -} -@media all and (transform-3d), (-webkit-transform-3d) { - .carousel-inner > .item { - -webkit-transition: -webkit-transform 0.6s ease-in-out; - -o-transition: -o-transform 0.6s ease-in-out; - transition: transform 0.6s ease-in-out; - -webkit-backface-visibility: hidden; - backface-visibility: hidden; - -webkit-perspective: 1000px; - perspective: 1000px; - } - .carousel-inner > .item.next, - .carousel-inner > .item.active.right { - -webkit-transform: translate3d(100%, 0, 0); - transform: translate3d(100%, 0, 0); - left: 0; - } - .carousel-inner > .item.prev, - .carousel-inner > .item.active.left { - -webkit-transform: translate3d(-100%, 0, 0); - transform: translate3d(-100%, 0, 0); - left: 0; - } - .carousel-inner > .item.next.left, - .carousel-inner > .item.prev.right, - .carousel-inner > .item.active { - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - left: 0; - } -} -.carousel-inner > .active, -.carousel-inner > .next, -.carousel-inner > .prev { - display: block; -} -.carousel-inner > .active { - left: 0; -} -.carousel-inner > .next, -.carousel-inner > .prev { - position: absolute; - top: 0; - width: 100%; -} -.carousel-inner > .next { - left: 100%; -} -.carousel-inner > .prev { - left: -100%; -} -.carousel-inner > .next.left, -.carousel-inner > .prev.right { - left: 0; -} -.carousel-inner > .active.left { - left: -100%; -} -.carousel-inner > .active.right { - left: 100%; -} -.carousel-control { - position: absolute; - top: 0; - left: 0; - bottom: 0; - width: 15%; - opacity: 0.5; - filter: alpha(opacity=50); - font-size: 20px; - color: #ffffff; - text-align: center; - text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6); - background-color: rgba(0, 0, 0, 0); -} -.carousel-control.left { - background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.0001) 100%); - background-image: -o-linear-gradient(left, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.0001) 100%); - background-image: -webkit-gradient(linear, left top, right top, from(rgba(0, 0, 0, 0.5)), to(rgba(0, 0, 0, 0.0001))); - background-image: linear-gradient(to right, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.0001) 100%); - background-repeat: repeat-x; - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1); -} -.carousel-control.right { - left: auto; - right: 0; - background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, 0.0001) 0%, rgba(0, 0, 0, 0.5) 100%); - background-image: -o-linear-gradient(left, rgba(0, 0, 0, 0.0001) 0%, rgba(0, 0, 0, 0.5) 100%); - background-image: -webkit-gradient(linear, left top, right top, from(rgba(0, 0, 0, 0.0001)), to(rgba(0, 0, 0, 0.5))); - background-image: linear-gradient(to right, rgba(0, 0, 0, 0.0001) 0%, rgba(0, 0, 0, 0.5) 100%); - background-repeat: repeat-x; - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1); -} -.carousel-control:hover, -.carousel-control:focus { - outline: 0; - color: #ffffff; - text-decoration: none; - opacity: 0.9; - filter: alpha(opacity=90); -} -.carousel-control .icon-prev, -.carousel-control .icon-next, -.carousel-control .glyphicon-chevron-left, -.carousel-control .glyphicon-chevron-right { - position: absolute; - top: 50%; - margin-top: -10px; - z-index: 5; - display: inline-block; -} -.carousel-control .icon-prev, -.carousel-control .glyphicon-chevron-left { - left: 50%; - margin-left: -10px; -} -.carousel-control .icon-next, -.carousel-control .glyphicon-chevron-right { - right: 50%; - margin-right: -10px; -} -.carousel-control .icon-prev, -.carousel-control .icon-next { - width: 20px; - height: 20px; - line-height: 1; - font-family: serif; -} -.carousel-control .icon-prev:before { - content: '\2039'; -} -.carousel-control .icon-next:before { - content: '\203a'; -} -.carousel-indicators { - position: absolute; - bottom: 10px; - left: 50%; - z-index: 15; - width: 60%; - margin-left: -30%; - padding-left: 0; - list-style: none; - text-align: center; -} -.carousel-indicators li { - display: inline-block; - width: 10px; - height: 10px; - margin: 1px; - text-indent: -999px; - border: 1px solid #ffffff; - border-radius: 10px; - cursor: pointer; - background-color: #000 \9; - background-color: rgba(0, 0, 0, 0); -} -.carousel-indicators .active { - margin: 0; - width: 12px; - height: 12px; - background-color: #ffffff; -} -.carousel-caption { - position: absolute; - left: 15%; - right: 15%; - bottom: 20px; - z-index: 10; - padding-top: 20px; - padding-bottom: 20px; - color: #ffffff; - text-align: center; - text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6); -} -.carousel-caption .btn { - text-shadow: none; -} -@media screen and (min-width: 768px) { - .carousel-control .glyphicon-chevron-left, - .carousel-control .glyphicon-chevron-right, - .carousel-control .icon-prev, - .carousel-control .icon-next { - width: 30px; - height: 30px; - margin-top: -10px; - font-size: 30px; - } - .carousel-control .glyphicon-chevron-left, - .carousel-control .icon-prev { - margin-left: -10px; - } - .carousel-control .glyphicon-chevron-right, - .carousel-control .icon-next { - margin-right: -10px; - } - .carousel-caption { - left: 20%; - right: 20%; - padding-bottom: 30px; - } - .carousel-indicators { - bottom: 20px; - } -} -.clearfix:before, -.clearfix:after, -.dl-horizontal dd:before, -.dl-horizontal dd:after, -.container:before, -.container:after, -.container-fluid:before, -.container-fluid:after, -.row:before, -.row:after, -.form-horizontal .form-group:before, -.form-horizontal .form-group:after, -.btn-toolbar:before, -.btn-toolbar:after, -.btn-group-vertical > .btn-group:before, -.btn-group-vertical > .btn-group:after, -.nav:before, -.nav:after, -.navbar:before, -.navbar:after, -.navbar-header:before, -.navbar-header:after, -.navbar-collapse:before, -.navbar-collapse:after, -.pager:before, -.pager:after, -.panel-body:before, -.panel-body:after, -.modal-header:before, -.modal-header:after, -.modal-footer:before, -.modal-footer:after { - content: " "; - display: table; -} -.clearfix:after, -.dl-horizontal dd:after, -.container:after, -.container-fluid:after, -.row:after, -.form-horizontal .form-group:after, -.btn-toolbar:after, -.btn-group-vertical > .btn-group:after, -.nav:after, -.navbar:after, -.navbar-header:after, -.navbar-collapse:after, -.pager:after, -.panel-body:after, -.modal-header:after, -.modal-footer:after { - clear: both; -} -.center-block { - display: block; - margin-left: auto; - margin-right: auto; -} -.pull-right { - float: right !important; -} -.pull-left { - float: left !important; -} -.hide { - display: none !important; -} -.show { - display: block !important; -} -.invisible { - visibility: hidden; -} -.text-hide { - font: 0/0 a; - color: transparent; - text-shadow: none; - background-color: transparent; - border: 0; -} -.hidden { - display: none !important; -} -.affix { - position: fixed; -} -@-ms-viewport { - width: device-width; -} -.visible-xs, -.visible-sm, -.visible-md, -.visible-lg { - display: none !important; -} -.visible-xs-block, -.visible-xs-inline, -.visible-xs-inline-block, -.visible-sm-block, -.visible-sm-inline, -.visible-sm-inline-block, -.visible-md-block, -.visible-md-inline, -.visible-md-inline-block, -.visible-lg-block, -.visible-lg-inline, -.visible-lg-inline-block { - display: none !important; -} -@media (max-width: 767px) { - .visible-xs { - display: block !important; - } - table.visible-xs { - display: table !important; - } - tr.visible-xs { - display: table-row !important; - } - th.visible-xs, - td.visible-xs { - display: table-cell !important; - } -} -@media (max-width: 767px) { - .visible-xs-block { - display: block !important; - } -} -@media (max-width: 767px) { - .visible-xs-inline { - display: inline !important; - } -} -@media (max-width: 767px) { - .visible-xs-inline-block { - display: inline-block !important; - } -} -@media (min-width: 768px) and (max-width: 991px) { - .visible-sm { - display: block !important; - } - table.visible-sm { - display: table !important; - } - tr.visible-sm { - display: table-row !important; - } - th.visible-sm, - td.visible-sm { - display: table-cell !important; - } -} -@media (min-width: 768px) and (max-width: 991px) { - .visible-sm-block { - display: block !important; - } -} -@media (min-width: 768px) and (max-width: 991px) { - .visible-sm-inline { - display: inline !important; - } -} -@media (min-width: 768px) and (max-width: 991px) { - .visible-sm-inline-block { - display: inline-block !important; - } -} -@media (min-width: 992px) and (max-width: 1199px) { - .visible-md { - display: block !important; - } - table.visible-md { - display: table !important; - } - tr.visible-md { - display: table-row !important; - } - th.visible-md, - td.visible-md { - display: table-cell !important; - } -} -@media (min-width: 992px) and (max-width: 1199px) { - .visible-md-block { - display: block !important; - } -} -@media (min-width: 992px) and (max-width: 1199px) { - .visible-md-inline { - display: inline !important; - } -} -@media (min-width: 992px) and (max-width: 1199px) { - .visible-md-inline-block { - display: inline-block !important; - } -} -@media (min-width: 1200px) { - .visible-lg { - display: block !important; - } - table.visible-lg { - display: table !important; - } - tr.visible-lg { - display: table-row !important; - } - th.visible-lg, - td.visible-lg { - display: table-cell !important; - } -} -@media (min-width: 1200px) { - .visible-lg-block { - display: block !important; - } -} -@media (min-width: 1200px) { - .visible-lg-inline { - display: inline !important; - } -} -@media (min-width: 1200px) { - .visible-lg-inline-block { - display: inline-block !important; - } -} -@media (max-width: 767px) { - .hidden-xs { - display: none !important; - } -} -@media (min-width: 768px) and (max-width: 991px) { - .hidden-sm { - display: none !important; - } -} -@media (min-width: 992px) and (max-width: 1199px) { - .hidden-md { - display: none !important; - } -} -@media (min-width: 1200px) { - .hidden-lg { - display: none !important; - } -} -.visible-print { - display: none !important; -} -@media print { - .visible-print { - display: block !important; - } - table.visible-print { - display: table !important; - } - tr.visible-print { - display: table-row !important; - } - th.visible-print, - td.visible-print { - display: table-cell !important; - } -} -.visible-print-block { - display: none !important; -} -@media print { - .visible-print-block { - display: block !important; - } -} -.visible-print-inline { - display: none !important; -} -@media print { - .visible-print-inline { - display: inline !important; - } -} -.visible-print-inline-block { - display: none !important; -} -@media print { - .visible-print-inline-block { - display: inline-block !important; - } -} -@media print { - .hidden-print { - display: none !important; - } -} -.navbar { - -webkit-box-shadow: none; - box-shadow: none; - border: none; - font-size: 12px; -} -.navbar-default .badge { - background-color: #fff; - color: #4e5d6c; -} -.navbar-inverse .badge { - background-color: #fff; - color: #df691a; -} -.btn-default:hover { - background-color: #485563; -} -.btn-sm, -.btn-xs { - font-size: 12px; -} -.text-primary, -.text-primary:hover { - color: #df691a; -} -.text-success, -.text-success:hover { - color: #5cb85c; -} -.text-danger, -.text-danger:hover { - color: #d9534f; -} -.text-warning, -.text-warning:hover { - color: #f0ad4e; -} -.text-info, -.text-info:hover { - color: #5bc0de; -} -.page-header { - border-bottom-color: #4e5d6c; -} -.dropdown-menu { - border: none; - margin: 0; - -webkit-box-shadow: none; - box-shadow: none; -} -.dropdown-menu > li > a { - font-size: 12px; -} -.btn-group.open .dropdown-toggle { - -webkit-box-shadow: none; - box-shadow: none; -} -.dropdown-header { - font-size: 12px; -} -table, -.table { - font-size: 12px; -} -table a:not(.btn), -.table a:not(.btn) { - color: #fff; - text-decoration: underline; -} -table .dropdown-menu a, -.table .dropdown-menu a { - text-decoration: none; -} -table .text-muted, -.table .text-muted { - color: #4e5d6c; -} -table > thead > tr > th, -.table > thead > tr > th, -table > tbody > tr > th, -.table > tbody > tr > th, -table > tfoot > tr > th, -.table > tfoot > tr > th, -table > thead > tr > td, -.table > thead > tr > td, -table > tbody > tr > td, -.table > tbody > tr > td, -table > tfoot > tr > td, -.table > tfoot > tr > td { - border-color: transparent; -} -input, -textarea { - color: #2b3e50; -} -label, -.radio label, -.checkbox label, -.help-block { - font-size: 12px; -} -.input-addon, -.input-group-addon { - color: #df691a; -} -.has-warning .help-block, -.has-warning .control-label, -.has-warning .radio, -.has-warning .checkbox, -.has-warning .radio-inline, -.has-warning .checkbox-inline, -.has-warning.radio label, -.has-warning.checkbox label, -.has-warning.radio-inline label, -.has-warning.checkbox-inline label, -.has-warning .form-control-feedback { - color: #f0ad4e; -} -.has-warning .input-group-addon { - border: none; -} -.has-error .help-block, -.has-error .control-label, -.has-error .radio, -.has-error .checkbox, -.has-error .radio-inline, -.has-error .checkbox-inline, -.has-error.radio label, -.has-error.checkbox label, -.has-error.radio-inline label, -.has-error.checkbox-inline label, -.has-error .form-control-feedback { - color: #d9534f; -} -.has-error .input-group-addon { - border: none; -} -.has-success .help-block, -.has-success .control-label, -.has-success .radio, -.has-success .checkbox, -.has-success .radio-inline, -.has-success .checkbox-inline, -.has-success.radio label, -.has-success.checkbox label, -.has-success.radio-inline label, -.has-success.checkbox-inline label, -.has-success .form-control-feedback { - color: #5cb85c; -} -.has-success .input-group-addon { - border: none; -} -.form-control:focus { - -webkit-box-shadow: none; - box-shadow: none; -} -.has-warning .form-control:focus, -.has-error .form-control:focus, -.has-success .form-control:focus { - -webkit-box-shadow: none; - box-shadow: none; -} -.nav .open > a, -.nav .open > a:hover, -.nav .open > a:focus { - border-color: transparent; -} -.nav-tabs > li > a { - color: #ebebeb; -} -.nav-pills > li > a { - color: #ebebeb; -} -.pager a { - color: #ebebeb; -} -.alert { - color: #fff; -} -.alert a, -.alert .alert-link { - color: #fff; -} -.close { - opacity: 0.4; -} -.close:hover, -.close:focus { - opacity: 1; -} -.well { - -webkit-box-shadow: none; - box-shadow: none; -} -a.list-group-item.active, -a.list-group-item.active:hover, -a.list-group-item.active:focus { - border: none; -} -a.list-group-item-success.active { - background-color: #5cb85c; -} -a.list-group-item-success.active:hover, -a.list-group-item-success.active:focus { - background-color: #4cae4c; -} -a.list-group-item-warning.active { - background-color: #f0ad4e; -} -a.list-group-item-warning.active:hover, -a.list-group-item-warning.active:focus { - background-color: #eea236; -} -a.list-group-item-danger.active { - background-color: #d9534f; -} -a.list-group-item-danger.active:hover, -a.list-group-item-danger.active:focus { - background-color: #d43f3a; -} -.panel { - border: none; -} -.panel-default > .panel-heading { - background-color: #485563; - color: #ebebeb; -} -.thumbnail { - background-color: #4e5d6c; - border: none; -} -.modal { - padding: 0; -} -.modal-header, -.modal-footer { - background-color: #282828; - border: none; - border-radius: 0; -} -.popover-title { - border: none; -} - diff --git a/PlexRequests.UI/Content/Themes/PlexBootstrapCustom.css b/PlexRequests.UI/Content/Themes/PlexBootstrapCustom.css deleted file mode 100644 index 5cc85cf8a..000000000 --- a/PlexRequests.UI/Content/Themes/PlexBootstrapCustom.css +++ /dev/null @@ -1,295 +0,0 @@ -@media (min-width: 768px) { - .row { - position: relative; } - .bottom-align-text { - position: absolute; - bottom: 0; - right: 0; } } - -@media (max-width: 48em) { - .home { - padding-top: 1rem; } } - -@media (min-width: 48em) { - .home { - padding-top: 4rem; } } - -.navbar-default .navbar-nav > .active > a, -.navbar-default .navbar-nav > .active > a:hover, -.navbar-default .navbar-nav > .active > a:focus { - color: #fff; } - -hr { - border-color: #777; } - -body.update-available { - margin-top: 80px; } - -.btn { - border-radius: 0.25rem !important; } - -.multiSelect { - background-color: #4e5d6c; } - -.form-control-custom { - background-color: #333333 !important; - color: white !important; - border-radius: 0; - box-shadow: 0 0 0 !important; } - -h1 { - font-size: 3.5rem !important; - font-weight: 600 !important; } - -.request-title { - margin-top: 0 !important; - font-size: 1.9rem !important; } - -p { - font-size: 1.1rem !important; } - -label { - display: inline-block !important; - margin-bottom: 0.5rem !important; - font-size: 16px !important; } - -.nav-tabs > li { - font-size: 13px; - line-height: 21px; } - -.nav-tabs > li.active > a, -.nav-tabs > li.active > a:hover, -.nav-tabs > li.active > a:focus { - background: #df691a; } - -.nav-tabs > li > a > .fa { - padding: 3px 5px 3px 3px; } - -.nav-tabs > li.nav-tab-right { - float: right; } - -.nav-tabs > li.nav-tab-right a { - margin-right: 0; - margin-left: 2px; } - -.nav-tabs > li.nav-tab-icononly .fa { - padding: 3px; } - -.navbar .nav a .fa, -.dropdown-menu a .fa { - font-size: 130%; - top: 1px; - position: relative; - display: inline-block; - margin-right: 5px; } - -.dropdown-menu a .fa { - top: 2px; } - -.btn-danger-outline { - color: #d9534f !important; - background-color: transparent; - background-image: none; - border-color: #d9534f !important; } - -.btn-danger-outline:focus, -.btn-danger-outline.focus, -.btn-danger-outline:active, -.btn-danger-outline.active, -.btn-danger-outline:hover, -.open > .btn-danger-outline.dropdown-toggle { - color: #fff !important; - background-color: #d9534f !important; - border-color: #d9534f !important; } - -.btn-primary-outline { - color: #ff761b !important; - background-color: transparent; - background-image: none; - border-color: #ff761b !important; } - -.btn-primary-outline:focus, -.btn-primary-outline.focus, -.btn-primary-outline:active, -.btn-primary-outline.active, -.btn-primary-outline:hover, -.open > .btn-primary-outline.dropdown-toggle { - color: #fff !important; - background-color: #df691a !important; - border-color: #df691a !important; } - -.btn-info-outline { - color: #5bc0de !important; - background-color: transparent; - background-image: none; - border-color: #5bc0de !important; } - -.btn-info-outline:focus, -.btn-info-outline.focus, -.btn-info-outline:active, -.btn-info-outline.active, -.btn-info-outline:hover, -.open > .btn-info-outline.dropdown-toggle { - color: #fff !important; - background-color: #5bc0de !important; - border-color: #5bc0de !important; } - -.btn-warning-outline { - color: #f0ad4e !important; - background-color: transparent; - background-image: none; - border-color: #f0ad4e !important; } - -.btn-warning-outline:focus, -.btn-warning-outline.focus, -.btn-warning-outline:active, -.btn-warning-outline.active, -.btn-warning-outline:hover, -.open > .btn-warning-outline.dropdown-toggle { - color: #fff !important; - background-color: #f0ad4e !important; - border-color: #f0ad4e !important; } - -.btn-success-outline { - color: #5cb85c !important; - background-color: transparent; - background-image: none; - border-color: #5cb85c !important; } - -.btn-success-outline:focus, -.btn-success-outline.focus, -.btn-success-outline:active, -.btn-success-outline.active, -.btn-success-outline:hover, -.open > .btn-success-outline.dropdown-toggle { - color: #fff !important; - background-color: #5cb85c !important; - border-color: #5cb85c !important; } - -#movieList .mix { - display: none; } - -#tvList .mix { - display: none; } - -.scroll-top-wrapper { - position: fixed; - opacity: 0; - visibility: hidden; - overflow: hidden; - text-align: center; - z-index: 99999999; - background-color: #333333; - color: #eeeeee; - width: 50px; - height: 48px; - line-height: 48px; - right: 30px; - bottom: 30px; - padding-top: 2px; - border-top-left-radius: 10px; - border-top-right-radius: 10px; - border-bottom-right-radius: 10px; - border-bottom-left-radius: 10px; - -webkit-transition: all 0.5s ease-in-out; - -moz-transition: all 0.5s ease-in-out; - -ms-transition: all 0.5s ease-in-out; - -o-transition: all 0.5s ease-in-out; - transition: all 0.5s ease-in-out; } - -.scroll-top-wrapper:hover { - background-color: #df691a; } - -.scroll-top-wrapper.show { - visibility: visible; - cursor: pointer; - opacity: 1.0; } - -.scroll-top-wrapper i.fa { - line-height: inherit; } - -.no-search-results { - text-align: center; } - -.no-search-results .no-search-results-icon { - font-size: 10em; - color: #4e5d6c; } - -.no-search-results .no-search-results-text { - margin: 20px 0; - color: #ccc; } - -.form-control-search { - padding: 13px 105px 13px 16px; - height: 100%; } - -.form-control-withbuttons { - padding-right: 105px; } - -.input-group-addon .btn-group { - position: absolute; - right: 45px; - z-index: 3; - top: 10px; - box-shadow: 0 0 0; } - -.input-group-addon .btn-group .btn { - border: 1px solid rgba(255, 255, 255, 0.7) !important; - padding: 3px 12px; - color: rgba(255, 255, 255, 0.7) !important; } - -.btn-split .btn { - border-radius: 0 !important; } - -.btn-split .btn:not(.dropdown-toggle) { - border-radius: 0.25rem 0 0 0.25rem !important; } - -.btn-split .btn.dropdown-toggle { - border-radius: 0 0.25rem 0.25rem 0 !important; - padding: 12px 8px; } - -#updateAvailable { - background-color: #df691a; - text-align: center; - font-size: 15px; - padding: 3px 0; } - -.checkbox label { - display: inline-block; - cursor: pointer; - position: relative; - padding-left: 25px; - margin-right: 15px; - font-size: 13px; - margin-bottom: 10px; } - -.checkbox label:before { - content: ""; - display: inline-block; - width: 18px; - height: 18px; - margin-right: 10px; - position: absolute; - left: 0; - bottom: 1px; - border: 2px solid #eee; - border-radius: 3px; } - -.checkbox input[type=checkbox] { - display: none; } - -.checkbox input[type=checkbox]:checked + label:before { - content: "\2713"; - font-size: 13px; - color: #fafafa; - text-align: center; - line-height: 13px; } - -.input-group-sm { - padding-top: 2px; - padding-bottom: 2px; } - -.tab-pane .form-horizontal .form-group { - margin-right: 15px; - margin-left: 15px; } - diff --git a/PlexRequests.UI/Content/Themes/PlexBootstrapCustom.min.css b/PlexRequests.UI/Content/Themes/PlexBootstrapCustom.min.css deleted file mode 100644 index 5c3bef0cd..000000000 --- a/PlexRequests.UI/Content/Themes/PlexBootstrapCustom.min.css +++ /dev/null @@ -1 +0,0 @@ -@media(min-width:768px){.row{position:relative;}.bottom-align-text{position:absolute;bottom:0;right:0;}}@media(max-width:48em){.home{padding-top:1rem;}}@media(min-width:48em){.home{padding-top:4rem;}}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.active>a:hover,.navbar-default .navbar-nav>.active>a:focus{color:#fff;}hr{border-color:#777;}body.update-available{margin-top:80px;}.btn{border-radius:.25rem !important;}.multiSelect{background-color:#4e5d6c;}.form-control-custom{background-color:#333 !important;color:#fff !important;border-radius:0;box-shadow:0 0 0 !important;}h1{font-size:3.5rem !important;font-weight:600 !important;}.request-title{margin-top:0 !important;font-size:1.9rem !important;}p{font-size:1.1rem !important;}label{display:inline-block !important;margin-bottom:.5rem !important;font-size:16px !important;}.nav-tabs>li{font-size:13px;line-height:21px;}.nav-tabs>li.active>a,.nav-tabs>li.active>a:hover,.nav-tabs>li.active>a:focus{background:#df691a;}.nav-tabs>li>a>.fa{padding:3px 5px 3px 3px;}.nav-tabs>li.nav-tab-right{float:right;}.nav-tabs>li.nav-tab-right a{margin-right:0;margin-left:2px;}.nav-tabs>li.nav-tab-icononly .fa{padding:3px;}.navbar .nav a .fa,.dropdown-menu a .fa{font-size:130%;top:1px;position:relative;display:inline-block;margin-right:5px;}.dropdown-menu a .fa{top:2px;}.btn-danger-outline{color:#d9534f !important;background-color:transparent;background-image:none;border-color:#d9534f !important;}.btn-danger-outline:focus,.btn-danger-outline.focus,.btn-danger-outline:active,.btn-danger-outline.active,.btn-danger-outline:hover,.open>.btn-danger-outline.dropdown-toggle{color:#fff !important;background-color:#d9534f !important;border-color:#d9534f !important;}.btn-primary-outline{color:#ff761b !important;background-color:transparent;background-image:none;border-color:#ff761b !important;}.btn-primary-outline:focus,.btn-primary-outline.focus,.btn-primary-outline:active,.btn-primary-outline.active,.btn-primary-outline:hover,.open>.btn-primary-outline.dropdown-toggle{color:#fff !important;background-color:#df691a !important;border-color:#df691a !important;}.btn-info-outline{color:#5bc0de !important;background-color:transparent;background-image:none;border-color:#5bc0de !important;}.btn-info-outline:focus,.btn-info-outline.focus,.btn-info-outline:active,.btn-info-outline.active,.btn-info-outline:hover,.open>.btn-info-outline.dropdown-toggle{color:#fff !important;background-color:#5bc0de !important;border-color:#5bc0de !important;}.btn-warning-outline{color:#f0ad4e !important;background-color:transparent;background-image:none;border-color:#f0ad4e !important;}.btn-warning-outline:focus,.btn-warning-outline.focus,.btn-warning-outline:active,.btn-warning-outline.active,.btn-warning-outline:hover,.open>.btn-warning-outline.dropdown-toggle{color:#fff !important;background-color:#f0ad4e !important;border-color:#f0ad4e !important;}.btn-success-outline{color:#5cb85c !important;background-color:transparent;background-image:none;border-color:#5cb85c !important;}.btn-success-outline:focus,.btn-success-outline.focus,.btn-success-outline:active,.btn-success-outline.active,.btn-success-outline:hover,.open>.btn-success-outline.dropdown-toggle{color:#fff !important;background-color:#5cb85c !important;border-color:#5cb85c !important;}#movieList .mix{display:none;}#tvList .mix{display:none;}.scroll-top-wrapper{position:fixed;opacity:0;visibility:hidden;overflow:hidden;text-align:center;z-index:99999999;background-color:#333;color:#eee;width:50px;height:48px;line-height:48px;right:30px;bottom:30px;padding-top:2px;border-top-left-radius:10px;border-top-right-radius:10px;border-bottom-right-radius:10px;border-bottom-left-radius:10px;-webkit-transition:all .5s ease-in-out;-moz-transition:all .5s ease-in-out;-ms-transition:all .5s ease-in-out;-o-transition:all .5s ease-in-out;transition:all .5s ease-in-out;}.scroll-top-wrapper:hover{background-color:#df691a;}.scroll-top-wrapper.show{visibility:visible;cursor:pointer;opacity:1;}.scroll-top-wrapper i.fa{line-height:inherit;}.no-search-results{text-align:center;}.no-search-results .no-search-results-icon{font-size:10em;color:#4e5d6c;}.no-search-results .no-search-results-text{margin:20px 0;color:#ccc;}.form-control-search{padding:13px 105px 13px 16px;height:100%;}.form-control-withbuttons{padding-right:105px;}.input-group-addon .btn-group{position:absolute;right:45px;z-index:3;top:10px;box-shadow:0 0 0;}.input-group-addon .btn-group .btn{border:1px solid rgba(255,255,255,.7) !important;padding:3px 12px;color:rgba(255,255,255,.7) !important;}.btn-split .btn{border-radius:0 !important;}.btn-split .btn:not(.dropdown-toggle){border-radius:.25rem 0 0 .25rem !important;}.btn-split .btn.dropdown-toggle{border-radius:0 .25rem .25rem 0 !important;padding:12px 8px;}#updateAvailable{background-color:#df691a;text-align:center;font-size:15px;padding:3px 0;}.checkbox label{display:inline-block;cursor:pointer;position:relative;padding-left:25px;margin-right:15px;font-size:13px;margin-bottom:10px;}.checkbox label:before{content:"";display:inline-block;width:18px;height:18px;margin-right:10px;position:absolute;left:0;bottom:1px;border:2px solid #eee;border-radius:3px;}.checkbox input[type=checkbox]{display:none;}.checkbox input[type=checkbox]:checked+label:before{content:"✓";font-size:13px;color:#fafafa;text-align:center;line-height:13px;}.input-group-sm{padding-top:2px;padding-bottom:2px;}.tab-pane .form-horizontal .form-group{margin-right:15px;margin-left:15px;} \ No newline at end of file diff --git a/PlexRequests.UI/Content/Themes/PlexBootstrapCustom.scss b/PlexRequests.UI/Content/Themes/PlexBootstrapCustom.scss deleted file mode 100644 index cf72d924c..000000000 --- a/PlexRequests.UI/Content/Themes/PlexBootstrapCustom.scss +++ /dev/null @@ -1,365 +0,0 @@ -$form-color: #4e5d6c; -$form-color-lighter: #637689; -$primary-colour: #df691a; -$primary-colour-outline: #ff761b; -$info-colour: #5bc0de; -$warning-colour: #f0ad4e; -$danger-colour: #d9534f; -$success-colour: #5cb85c; -$bg-colour: #333333; -$i: -!important; - -@media (min-width: 768px ) { - .row { - position: relative; - } - - .bottom-align-text { - position: absolute; - bottom: 0; - right: 0; - } -} - -@media (max-width: 48em) { - .home { - padding-top: 1rem; - } -} - -@media (min-width: 48em) { - .home { - padding-top: 4rem; - } -} - -.navbar-default .navbar-nav > .active > a, -.navbar-default .navbar-nav > .active > a:hover, -.navbar-default .navbar-nav > .active > a:focus { - color: #fff; -} - -hr { - border-color: #777; -} - -body.update-available { - margin-top: 80px; -} - -.btn { - border-radius: .25rem $i; -} - -.multiSelect { - background-color: $form-color; -} - -.form-control-custom { - background-color: $bg-colour $i; - color: white $i; - border-radius: 0; - box-shadow: 0 0 0 !important; -} - - -h1 { - font-size: 3.5rem $i; - font-weight: 600 $i; -} - -.request-title { - margin-top: 0 $i; - font-size: 1.9rem $i; -} - -p { - font-size: 1.1rem $i; -} - -label { - display: inline-block $i; - margin-bottom: .5rem $i; - font-size: 16px $i; -} - -.nav-tabs > li { - font-size: 13px; - line-height: 21px; -} - -.nav-tabs > li.active > a, -.nav-tabs > li.active > a:hover, -.nav-tabs > li.active > a:focus { - background: $primary-colour; -} - -.nav-tabs > li > a > .fa { - padding: 3px 5px 3px 3px; -} - -.nav-tabs > li.nav-tab-right { - float: right; -} - -.nav-tabs > li.nav-tab-right a { - margin-right: 0; - margin-left: 2px; -} - -.nav-tabs > li.nav-tab-icononly .fa { - padding: 3px; -} - -.navbar .nav a .fa, -.dropdown-menu a .fa { - font-size: 130%; - top: 1px; - position: relative; - display: inline-block; - margin-right: 5px; -} - -.dropdown-menu a .fa { - top: 2px; -} - -.btn-danger-outline { - color: $danger-colour $i; - background-color: transparent; - background-image: none; - border-color: $danger-colour $i; -} - -.btn-danger-outline:focus, -.btn-danger-outline.focus, -.btn-danger-outline:active, -.btn-danger-outline.active, -.btn-danger-outline:hover, -.open > .btn-danger-outline.dropdown-toggle { - color: #fff $i; - background-color: $danger-colour $i; - border-color: $danger-colour $i; -} - - -.btn-primary-outline { - color: $primary-colour-outline $i; - background-color: transparent; - background-image: none; - border-color: $primary-colour-outline $i; -} - -.btn-primary-outline:focus, -.btn-primary-outline.focus, -.btn-primary-outline:active, -.btn-primary-outline.active, -.btn-primary-outline:hover, -.open > .btn-primary-outline.dropdown-toggle { - color: #fff $i; - background-color: $primary-colour $i; - border-color: $primary-colour $i; -} - -.btn-info-outline { - color: $info-colour $i; - background-color: transparent; - background-image: none; - border-color: $info-colour $i; -} - -.btn-info-outline:focus, -.btn-info-outline.focus, -.btn-info-outline:active, -.btn-info-outline.active, -.btn-info-outline:hover, -.open > .btn-info-outline.dropdown-toggle { - color: #fff $i; - background-color: $info-colour $i; - border-color: $info-colour $i; -} - -.btn-warning-outline { - color: $warning-colour $i; - background-color: transparent; - background-image: none; - border-color: $warning-colour $i; -} - -.btn-warning-outline:focus, -.btn-warning-outline.focus, -.btn-warning-outline:active, -.btn-warning-outline.active, -.btn-warning-outline:hover, -.open > .btn-warning-outline.dropdown-toggle { - color: #fff $i; - background-color: $warning-colour $i; - border-color: $warning-colour $i; -} - -.btn-success-outline { - color: $success-colour $i; - background-color: transparent; - background-image: none; - border-color: $success-colour $i; -} - -.btn-success-outline:focus, -.btn-success-outline.focus, -.btn-success-outline:active, -.btn-success-outline.active, -.btn-success-outline:hover, -.open > .btn-success-outline.dropdown-toggle { - color: #fff $i; - background-color: $success-colour $i; - border-color: $success-colour $i; -} - -#movieList .mix { - display: none; -} - -#tvList .mix { - display: none; -} - -$border-radius: 10px; - -.scroll-top-wrapper { - position: fixed; - opacity: 0; - visibility: hidden; - overflow: hidden; - text-align: center; - z-index: 99999999; - background-color: $bg-colour; - color: #eeeeee; - width: 50px; - height: 48px; - line-height: 48px; - right: 30px; - bottom: 30px; - padding-top: 2px; - border-top-left-radius: $border-radius; - border-top-right-radius: $border-radius; - border-bottom-right-radius: $border-radius; - border-bottom-left-radius: $border-radius; - -webkit-transition: all 0.5s ease-in-out; - -moz-transition: all 0.5s ease-in-out; - -ms-transition: all 0.5s ease-in-out; - -o-transition: all 0.5s ease-in-out; - transition: all 0.5s ease-in-out; -} - -.scroll-top-wrapper:hover { - background-color: $primary-colour; -} - -.scroll-top-wrapper.show { - visibility: visible; - cursor: pointer; - opacity: 1.0; -} - -.scroll-top-wrapper i.fa { - line-height: inherit; -} - - -.no-search-results { - text-align: center; -} - -.no-search-results .no-search-results-icon { - font-size: 10em; - color: $form-color; -} - -.no-search-results .no-search-results-text { - margin: 20px 0; - color: #ccc; -} - -.form-control-search { - padding: 13px 105px 13px 16px; - height: 100%; -} - -.form-control-withbuttons { - padding-right: 105px; -} - -.input-group-addon .btn-group { - position: absolute; - right: 45px; - z-index: 3; - top: 10px; - box-shadow: 0 0 0; -} - -.input-group-addon .btn-group .btn { - border: 1px solid rgba(255,255,255,.7) !important; - padding: 3px 12px; - color: rgba(255,255,255,.7) !important; -} - -.btn-split .btn { - border-radius: 0 !important; -} - -.btn-split .btn:not(.dropdown-toggle) { - border-radius: .25rem 0 0 .25rem $i; -} - -.btn-split .btn.dropdown-toggle { - border-radius: 0 .25rem .25rem 0 $i; - padding: 12px 8px; -} - -#updateAvailable { - background-color: #df691a; - text-align: center; - font-size: 15px; - padding: 3px 0; -} - -.checkbox label { - display: inline-block; - cursor: pointer; - position: relative; - padding-left: 25px; - margin-right: 15px; - font-size: 13px; - margin-bottom: 10px; } - - .checkbox label:before { - content: ""; - display: inline-block; - width: 18px; - height: 18px; - margin-right: 10px; - position: absolute; - left: 0; - bottom: 1px; - border: 2px solid #eee; - border-radius: 3px; } - - .checkbox input[type=checkbox] { - display: none; } - - .checkbox input[type=checkbox]:checked + label:before { - content: "\2713"; - font-size: 13px; - color: #fafafa; - text-align: center; - line-height: 13px; } - -.input-group-sm{ - padding-top: 2px; - padding-bottom: 2px; -} - -.tab-pane .form-horizontal .form-group { - margin-right: 15px; - margin-left: 15px; } \ No newline at end of file diff --git a/PlexRequests.UI/Content/Themes/original.scss b/PlexRequests.UI/Content/Themes/original.scss new file mode 100644 index 000000000..46800d16a --- /dev/null +++ b/PlexRequests.UI/Content/Themes/original.scss @@ -0,0 +1,2 @@ +body { +} diff --git a/PlexRequests.UI/Content/Themes/plex.css b/PlexRequests.UI/Content/Themes/plex.css new file mode 100644 index 000000000..783cf6d76 --- /dev/null +++ b/PlexRequests.UI/Content/Themes/plex.css @@ -0,0 +1,146 @@ +.form-control-custom { + background-color: #333333 !important; } + +.nav-tabs > li.active > a, +.nav-tabs > li.active > a:hover, +.nav-tabs > li.active > a:focus { + background: #df691a; } + +scroll-top-wrapper { + background-color: #333333; } + +.scroll-top-wrapper:hover { + background-color: #df691a; } + +body { + font-family: Open Sans Regular,Helvetica Neue,Helvetica,Arial,sans-serif; + color: #eee; + background-color: #1f1f1f; } + +.table-striped > tbody > tr:nth-of-type(odd) { + background-color: #333; } + +.table-hover > tbody > tr:hover { + background-color: #282828; } + +fieldset { + padding: 15px; } + +legend { + border-bottom: 1px solid #333333; } + +.form-control { + color: #fefefe; + background-color: #333; } + +.radio input[type="radio"], +.radio-inline input[type="radio"], +.checkbox input[type="checkbox"], +.checkbox-inline input[type="checkbox"] { + margin-left: -0px; } + +.form-horizontal .radio, +.form-horizontal .checkbox, +.form-horizontal .radio-inline, +.form-horizontal .checkbox-inline { + margin-top: -15px; } + +.dropdown-menu { + background-color: #282828; } + +.dropdown-menu .divider { + background-color: #333333; } + +.dropdown-menu > li > a:hover, +.dropdown-menu > li > a:focus { + background-color: #333; } + +.input-group-addon { + background-color: #333333; } + +.nav > li > a:hover, +.nav > li > a:focus { + background-color: #df691a; } + +.nav-tabs > li > a:hover { + border-color: #df691a #df691a transparent; } + +.nav-tabs > li.active > a, +.nav-tabs > li.active > a:hover, +.nav-tabs > li.active > a:focus { + background-color: #df691a; + border: 1px solid #df691a; } + +.nav-tabs.nav-justified > .active > a, +.nav-tabs.nav-justified > .active > a:hover, +.nav-tabs.nav-justified > .active > a:focus { + border: 1px solid #df691a; } + +/*.navbar { + position: relative; + min-height: 40px; + margin-bottom: 21px; + z-index: 1000; + padding: 0px 3px; + font-size: 24px; + background-color: #000; + box-shadow: 0px 0px 0px 3px rgba(0, 0, 0, 0.2); +}*/ +.navbar-default { + background-color: #0a0a0a; } + +.navbar-default .navbar-brand { + color: #DF691A; } + +.navbar-default .navbar-nav > li > a:hover, +.navbar-default .navbar-nav > li > a:focus { + color: #F0ad4e; + background-color: #282828; } + +.navbar-default .navbar-nav > .active > a, +.navbar-default .navbar-nav > .active > a:hover, +.navbar-default .navbar-nav > .active > a:focus { + background-color: #282828; } + +.navbar-default .navbar-nav > .open > a, +.navbar-default .navbar-nav > .open > a:hover, +.navbar-default .navbar-nav > .open > a:focus { + background-color: #df691a; + color: #fff; } + +.pagination > li > a, +.pagination > li > span { + background-color: #282828; } + +.pagination > li > a:hover, +.pagination > li > span:hover, +.pagination > li > a:focus, +.pagination > li > span:focus { + background-color: #333; } + +.pagination > .disabled > span, +.pagination > .disabled > span:hover, +.pagination > .disabled > span:focus, +.pagination > .disabled > a, +.pagination > .disabled > a:hover, +.pagination > .disabled > a:focus { + color: #fefefe; + background-color: #333333; } + +.list-group-item { + background-color: #282828; } + +a.list-group-item:hover, +button.list-group-item:hover, +a.list-group-item:focus, +button.list-group-item:focus { + background-color: #333333; } + +.input-addon, +.input-group-addon { + color: #df691a; } + +.modal-header, +.modal-footer { + background-color: #282828; } + diff --git a/PlexRequests.UI/Content/Themes/plex.min.css b/PlexRequests.UI/Content/Themes/plex.min.css new file mode 100644 index 000000000..5bfca0787 --- /dev/null +++ b/PlexRequests.UI/Content/Themes/plex.min.css @@ -0,0 +1 @@ +.form-control-custom{background-color:#333 !important;}.nav-tabs>li.active>a,.nav-tabs>li.active>a:hover,.nav-tabs>li.active>a:focus{background:#df691a;}scroll-top-wrapper{background-color:#333;}.scroll-top-wrapper:hover{background-color:#df691a;}body{font-family:Open Sans Regular,Helvetica Neue,Helvetica,Arial,sans-serif;color:#eee;background-color:#1f1f1f;}.table-striped>tbody>tr:nth-of-type(odd){background-color:#333;}.table-hover>tbody>tr:hover{background-color:#282828;}fieldset{padding:15px;}legend{border-bottom:1px solid #333;}.form-control{color:#fefefe;background-color:#333;}.radio input[type="radio"],.radio-inline input[type="radio"],.checkbox input[type="checkbox"],.checkbox-inline input[type="checkbox"]{margin-left:-0;}.form-horizontal .radio,.form-horizontal .checkbox,.form-horizontal .radio-inline,.form-horizontal .checkbox-inline{margin-top:-15px;}.dropdown-menu{background-color:#282828;}.dropdown-menu .divider{background-color:#333;}.dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus{background-color:#333;}.input-group-addon{background-color:#333;}.nav>li>a:hover,.nav>li>a:focus{background-color:#df691a;}.nav-tabs>li>a:hover{border-color:#df691a #df691a transparent;}.nav-tabs>li.active>a,.nav-tabs>li.active>a:hover,.nav-tabs>li.active>a:focus{background-color:#df691a;border:1px solid #df691a;}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:hover,.nav-tabs.nav-justified>.active>a:focus{border:1px solid #df691a;}.navbar-default{background-color:#0a0a0a;}.navbar-default .navbar-brand{color:#df691a;}.navbar-default .navbar-nav>li>a:hover,.navbar-default .navbar-nav>li>a:focus{color:#f0ad4e;background-color:#282828;}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.active>a:hover,.navbar-default .navbar-nav>.active>a:focus{background-color:#282828;}.navbar-default .navbar-nav>.open>a,.navbar-default .navbar-nav>.open>a:hover,.navbar-default .navbar-nav>.open>a:focus{background-color:#df691a;color:#fff;}.pagination>li>a,.pagination>li>span{background-color:#282828;}.pagination>li>a:hover,.pagination>li>span:hover,.pagination>li>a:focus,.pagination>li>span:focus{background-color:#333;}.pagination>.disabled>span,.pagination>.disabled>span:hover,.pagination>.disabled>span:focus,.pagination>.disabled>a,.pagination>.disabled>a:hover,.pagination>.disabled>a:focus{color:#fefefe;background-color:#333;}.list-group-item{background-color:#282828;}a.list-group-item:hover,button.list-group-item:hover,a.list-group-item:focus,button.list-group-item:focus{background-color:#333;}.input-addon,.input-group-addon{color:#df691a;}.modal-header,.modal-footer{background-color:#282828;} \ No newline at end of file diff --git a/PlexRequests.UI/Content/Themes/plex.scss b/PlexRequests.UI/Content/Themes/plex.scss new file mode 100644 index 000000000..8e8a8aee3 --- /dev/null +++ b/PlexRequests.UI/Content/Themes/plex.scss @@ -0,0 +1,183 @@ +$primary-colour: #df691a; +$primary-colour-outline: #ff761b; +$bg-colour: #333333; +$i: !important; + +.form-control-custom { + background-color: $bg-colour $i; +} + +.nav-tabs > li.active > a, +.nav-tabs > li.active > a:hover, +.nav-tabs > li.active > a:focus { + background: $primary-colour; +} + +scroll-top-wrapper { + background-color: $bg-colour; +} + +.scroll-top-wrapper:hover { + background-color: $primary-colour; +} + +body { + font-family: Open Sans Regular,Helvetica Neue,Helvetica,Arial,sans-serif; + color: #eee; + background-color: #1f1f1f; +} + +.table-striped > tbody > tr:nth-of-type(odd) { + background-color: #333; +} + +.table-hover > tbody > tr:hover { + background-color: #282828; +} + +fieldset { + padding: 15px; +} + +legend { + border-bottom: 1px solid #333333; +} + +.form-control { + color: #fefefe; + background-color: #333; +} + +.radio input[type="radio"], +.radio-inline input[type="radio"], +.checkbox input[type="checkbox"], +.checkbox-inline input[type="checkbox"] { + margin-left: -0px; +} + +.form-horizontal .radio, +.form-horizontal .checkbox, +.form-horizontal .radio-inline, +.form-horizontal .checkbox-inline { + margin-top: -15px; +} + +.dropdown-menu { + background-color: #282828; +} + +.dropdown-menu .divider { + background-color: #333333; +} + +.dropdown-menu > li > a:hover, +.dropdown-menu > li > a:focus { + background-color: #333; +} + +.input-group-addon { + background-color: #333333; +} + +.nav > li > a:hover, +.nav > li > a:focus { + background-color: #df691a; +} + +.nav-tabs > li > a:hover { + border-color: #df691a #df691a transparent; +} + +.nav-tabs > li.active > a, +.nav-tabs > li.active > a:hover, +.nav-tabs > li.active > a:focus { + background-color: #df691a; + border: 1px solid #df691a; +} + +.nav-tabs.nav-justified > .active > a, +.nav-tabs.nav-justified > .active > a:hover, +.nav-tabs.nav-justified > .active > a:focus { + border: 1px solid #df691a; +} + +/*.navbar { + position: relative; + min-height: 40px; + margin-bottom: 21px; + z-index: 1000; + padding: 0px 3px; + font-size: 24px; + background-color: #000; + box-shadow: 0px 0px 0px 3px rgba(0, 0, 0, 0.2); +}*/ + +.navbar-default { + background-color: #0a0a0a; +} + +.navbar-default .navbar-brand { + color: #DF691A; +} + +.navbar-default .navbar-nav > li > a:hover, +.navbar-default .navbar-nav > li > a:focus { + color: #F0ad4e; + background-color: #282828; +} + +.navbar-default .navbar-nav > .active > a, +.navbar-default .navbar-nav > .active > a:hover, +.navbar-default .navbar-nav > .active > a:focus { + background-color: #282828; +} + +.navbar-default .navbar-nav > .open > a, +.navbar-default .navbar-nav > .open > a:hover, +.navbar-default .navbar-nav > .open > a:focus { + background-color: #df691a; + color: #fff; +} + +.pagination > li > a, +.pagination > li > span { + background-color: #282828; +} + +.pagination > li > a:hover, +.pagination > li > span:hover, +.pagination > li > a:focus, +.pagination > li > span:focus { + background-color: #333; +} + +.pagination > .disabled > span, +.pagination > .disabled > span:hover, +.pagination > .disabled > span:focus, +.pagination > .disabled > a, +.pagination > .disabled > a:hover, +.pagination > .disabled > a:focus { + color: #fefefe; + background-color: #333333; +} + +.list-group-item { + background-color: #282828; +} + +a.list-group-item:hover, +button.list-group-item:hover, +a.list-group-item:focus, +button.list-group-item:focus { + background-color: #333333; +} + +.input-addon, +.input-group-addon { + color: #df691a; +} + +.modal-header, +.modal-footer { + background-color: #282828; +} diff --git a/PlexRequests.UI/Content/Themes/OriginalBootstrapCustom.css b/PlexRequests.UI/Content/base.css similarity index 99% rename from PlexRequests.UI/Content/Themes/OriginalBootstrapCustom.css rename to PlexRequests.UI/Content/base.css index 6c1f89cc6..1ad9a6bc7 100644 --- a/PlexRequests.UI/Content/Themes/OriginalBootstrapCustom.css +++ b/PlexRequests.UI/Content/base.css @@ -20,7 +20,7 @@ color: #fff; } hr { - border-color: #777; } + border: 1px dashed #777; } .btn { border-radius: 0.25rem !important; } diff --git a/PlexRequests.UI/Content/base.min.css b/PlexRequests.UI/Content/base.min.css new file mode 100644 index 000000000..b165bae88 --- /dev/null +++ b/PlexRequests.UI/Content/base.min.css @@ -0,0 +1 @@ +@media(min-width:768px){.row{position:relative;}.bottom-align-text{position:absolute;bottom:0;right:0;}}@media(max-width:48em){.home{padding-top:1rem;}}@media(min-width:48em){.home{padding-top:4rem;}}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.active>a:hover,.navbar-default .navbar-nav>.active>a:focus{color:#fff;}hr{border:1px dashed #777;}.btn{border-radius:.25rem !important;}.multiSelect{background-color:#4e5d6c;}.form-control-custom{background-color:#4e5d6c !important;color:#fff !important;border-radius:0;box-shadow:0 0 0 !important;}h1{font-size:3.5rem !important;font-weight:600 !important;}.request-title{margin-top:0 !important;font-size:1.9rem !important;}p{font-size:1.1rem !important;}label{display:inline-block !important;margin-bottom:.5rem !important;font-size:16px !important;}.nav-tabs>li{font-size:13px;line-height:21px;}.nav-tabs>li.active>a,.nav-tabs>li.active>a:hover,.nav-tabs>li.active>a:focus{background:#4e5d6c;}.nav-tabs>li>a>.fa{padding:3px 5px 3px 3px;}.nav-tabs>li.nav-tab-right{float:right;}.nav-tabs>li.nav-tab-right a{margin-right:0;margin-left:2px;}.nav-tabs>li.nav-tab-icononly .fa{padding:3px;}.navbar .nav a .fa,.dropdown-menu a .fa{font-size:130%;top:1px;position:relative;display:inline-block;margin-right:5px;}.dropdown-menu a .fa{top:2px;}.btn-danger-outline{color:#d9534f !important;background-color:transparent;background-image:none;border-color:#d9534f !important;}.btn-danger-outline:focus,.btn-danger-outline.focus,.btn-danger-outline:active,.btn-danger-outline.active,.btn-danger-outline:hover,.open>.btn-danger-outline.dropdown-toggle{color:#fff !important;background-color:#d9534f !important;border-color:#d9534f !important;}.btn-primary-outline{color:#ff761b !important;background-color:transparent;background-image:none;border-color:#ff761b !important;}.btn-primary-outline:focus,.btn-primary-outline.focus,.btn-primary-outline:active,.btn-primary-outline.active,.btn-primary-outline:hover,.open>.btn-primary-outline.dropdown-toggle{color:#fff !important;background-color:#df691a !important;border-color:#df691a !important;}.btn-info-outline{color:#5bc0de !important;background-color:transparent;background-image:none;border-color:#5bc0de !important;}.btn-info-outline:focus,.btn-info-outline.focus,.btn-info-outline:active,.btn-info-outline.active,.btn-info-outline:hover,.open>.btn-info-outline.dropdown-toggle{color:#fff !important;background-color:#5bc0de !important;border-color:#5bc0de !important;}.btn-warning-outline{color:#f0ad4e !important;background-color:transparent;background-image:none;border-color:#f0ad4e !important;}.btn-warning-outline:focus,.btn-warning-outline.focus,.btn-warning-outline:active,.btn-warning-outline.active,.btn-warning-outline:hover,.open>.btn-warning-outline.dropdown-toggle{color:#fff !important;background-color:#f0ad4e !important;border-color:#f0ad4e !important;}.btn-success-outline{color:#5cb85c !important;background-color:transparent;background-image:none;border-color:#5cb85c !important;}.btn-success-outline:focus,.btn-success-outline.focus,.btn-success-outline:active,.btn-success-outline.active,.btn-success-outline:hover,.open>.btn-success-outline.dropdown-toggle{color:#fff !important;background-color:#5cb85c !important;border-color:#5cb85c !important;}#movieList .mix{display:none;}#tvList .mix{display:none;}.scroll-top-wrapper{position:fixed;opacity:0;visibility:hidden;overflow:hidden;text-align:center;z-index:99999999;background-color:#4e5d6c;color:#eee;width:50px;height:48px;line-height:48px;right:30px;bottom:30px;padding-top:2px;border-top-left-radius:10px;border-top-right-radius:10px;border-bottom-right-radius:10px;border-bottom-left-radius:10px;-webkit-transition:all .5s ease-in-out;-moz-transition:all .5s ease-in-out;-ms-transition:all .5s ease-in-out;-o-transition:all .5s ease-in-out;transition:all .5s ease-in-out;}.scroll-top-wrapper:hover{background-color:#637689;}.scroll-top-wrapper.show{visibility:visible;cursor:pointer;opacity:1;}.scroll-top-wrapper i.fa{line-height:inherit;}.no-search-results{text-align:center;}.no-search-results .no-search-results-icon{font-size:10em;color:#4e5d6c;}.no-search-results .no-search-results-text{margin:20px 0;color:#ccc;}.form-control-search{padding:13px 105px 13px 16px;height:100%;}.form-control-withbuttons{padding-right:105px;}.input-group-addon .btn-group{position:absolute;right:45px;z-index:3;top:10px;box-shadow:0 0 0;}.input-group-addon .btn-group .btn{border:1px solid rgba(255,255,255,.7) !important;padding:3px 12px;color:rgba(255,255,255,.7) !important;}.btn-split .btn{border-radius:0 !important;}.btn-split .btn:not(.dropdown-toggle){border-radius:.25rem 0 0 .25rem !important;}.btn-split .btn.dropdown-toggle{border-radius:0 .25rem .25rem 0 !important;padding:12px 8px;}#updateAvailable{background-color:#df691a;text-align:center;font-size:15px;padding:3px 0;}.checkbox label{display:inline-block;cursor:pointer;position:relative;padding-left:25px;margin-right:15px;font-size:13px;margin-bottom:10px;}.checkbox label:before{content:"";display:inline-block;width:18px;height:18px;margin-right:10px;position:absolute;left:0;bottom:1px;border:2px solid #eee;border-radius:3px;}.checkbox input[type=checkbox]{display:none;}.checkbox input[type=checkbox]:checked+label:before{content:"✓";font-size:13px;color:#fafafa;text-align:center;line-height:13px;}.input-group-sm{padding-top:2px;padding-bottom:2px;}.tab-pane .form-horizontal .form-group{margin-right:15px;margin-left:15px;} \ No newline at end of file diff --git a/PlexRequests.UI/Content/Themes/OriginalBootstrapCustom.scss b/PlexRequests.UI/Content/base.scss similarity index 99% rename from PlexRequests.UI/Content/Themes/OriginalBootstrapCustom.scss rename to PlexRequests.UI/Content/base.scss index 85fcc1a73..2839c225b 100644 --- a/PlexRequests.UI/Content/Themes/OriginalBootstrapCustom.scss +++ b/PlexRequests.UI/Content/base.scss @@ -6,8 +6,7 @@ $info-colour: #5bc0de; $warning-colour: #f0ad4e; $danger-colour: #d9534f; $success-colour: #5cb85c; -$i: -!important; +$i: !important; @media (min-width: 768px ) { .row { @@ -40,7 +39,7 @@ $i: } hr { - border-color: #777; + border: 1px dashed #777; } .btn { diff --git a/PlexRequests.UI/Content/Themes/OriginalBootstrap.css b/PlexRequests.UI/Content/bootstrap.css similarity index 100% rename from PlexRequests.UI/Content/Themes/OriginalBootstrap.css rename to PlexRequests.UI/Content/bootstrap.css diff --git a/PlexRequests.UI/Helpers/BaseUrlHelper.cs b/PlexRequests.UI/Helpers/BaseUrlHelper.cs index 2732714ed..f186054b9 100644 --- a/PlexRequests.UI/Helpers/BaseUrlHelper.cs +++ b/PlexRequests.UI/Helpers/BaseUrlHelper.cs @@ -57,12 +57,15 @@ public static IHtmlString LoadAssets(this HtmlHelpers helper) { settings.ThemeName = Themes.PlexTheme; } - - sb.AppendLine($""); - sb.AppendLine($""); + if (settings.ThemeName == "PlexBootstrap.css") settings.ThemeName = Themes.PlexTheme; + if (settings.ThemeName == "OriginalBootstrap.css") settings.ThemeName = Themes.OriginalTheme; + + sb.AppendLine($""); sb.AppendLine($""); sb.AppendLine($""); sb.AppendLine($""); + sb.AppendLine($""); + sb.AppendLine($""); sb.AppendLine($""); sb.AppendLine($""); diff --git a/PlexRequests.UI/Helpers/Themes.cs b/PlexRequests.UI/Helpers/Themes.cs index 2e7e54fa1..a5e3af613 100644 --- a/PlexRequests.UI/Helpers/Themes.cs +++ b/PlexRequests.UI/Helpers/Themes.cs @@ -28,7 +28,7 @@ namespace PlexRequests.UI.Helpers { public static class Themes { - public const string OriginalTheme = "OriginalBootstrap.css"; - public const string PlexTheme = "PlexBootstrap.css"; + public const string OriginalTheme = "original.css"; + public const string PlexTheme = "plex.css"; } } \ No newline at end of file diff --git a/PlexRequests.UI/PlexRequests.UI.csproj b/PlexRequests.UI/PlexRequests.UI.csproj index 0029e9ed6..e7d79575e 100644 --- a/PlexRequests.UI/PlexRequests.UI.csproj +++ b/PlexRequests.UI/PlexRequests.UI.csproj @@ -210,7 +210,15 @@ PreserveNewest - + + base.scss + PreserveNewest + + + base.css + PreserveNewest + + PreserveNewest @@ -286,22 +294,13 @@ PreserveNewest - - OriginalBootstrapCustom.scss - - - OriginalBootstrapCustom.css - Always - - - Always - - - PlexBootstrapCustom.scss + + plex.scss + PreserveNewest - - PlexBootstrapCustom.css - Always + + plex.css + PreserveNewest PreserveNewest @@ -387,8 +386,9 @@ PreserveNewest - - + + + Always diff --git a/PlexRequests.UI/compilerconfig.json b/PlexRequests.UI/compilerconfig.json index 0fbfabdd4..64b20cbb4 100644 --- a/PlexRequests.UI/compilerconfig.json +++ b/PlexRequests.UI/compilerconfig.json @@ -1,8 +1,4 @@ [ - { - "outputFile": "Content/custom.css", - "inputFile": "Content/custom.scss" - }, { "outputFile": "Content/pace.css", "inputFile": "Content/pace.scss" @@ -18,5 +14,13 @@ { "outputFile": "Content/Themes/PlexBootstrapCustom.css", "inputFile": "Content/Themes/PlexBootstrapCustom.scss" + }, + { + "outputFile": "Content/base.css", + "inputFile": "Content/base.scss" + }, + { + "outputFile": "Content/Themes/plex.css", + "inputFile": "Content/Themes/plex.scss" } ] \ No newline at end of file From 217ce391e01ead0258ace83be4af67663007cded Mon Sep 17 00:00:00 2001 From: Drewster727 Date: Fri, 27 May 2016 02:21:54 -0500 Subject: [PATCH 08/26] #221 delete requests per category --- PlexRequests.Core/IRequestService.cs | 1 + PlexRequests.Core/JsonRequestService.cs | 6 ++ .../Repository/IRequestRepository.cs | 2 + .../Repository/RequestJsonRepository.cs | 15 ++++ PlexRequests.UI/Content/base.css | 4 + PlexRequests.UI/Content/base.min.css | 2 +- PlexRequests.UI/Content/base.scss | 5 ++ PlexRequests.UI/Content/requests-1.7.js | 76 +++++++++++++++++-- PlexRequests.UI/Modules/ApprovalModule.cs | 61 ++++++++++++++- PlexRequests.UI/Views/Requests/Index.cshtml | 5 +- 10 files changed, 169 insertions(+), 8 deletions(-) diff --git a/PlexRequests.Core/IRequestService.cs b/PlexRequests.Core/IRequestService.cs index 342e83d05..cd8427ac5 100644 --- a/PlexRequests.Core/IRequestService.cs +++ b/PlexRequests.Core/IRequestService.cs @@ -41,5 +41,6 @@ public interface IRequestService RequestedModel Get(int id); IEnumerable GetAll(); bool BatchUpdate(List model); + bool BatchDelete(List model); } } \ No newline at end of file diff --git a/PlexRequests.Core/JsonRequestService.cs b/PlexRequests.Core/JsonRequestService.cs index deefdfccd..770b41444 100644 --- a/PlexRequests.Core/JsonRequestService.cs +++ b/PlexRequests.Core/JsonRequestService.cs @@ -107,5 +107,11 @@ public bool BatchUpdate(List model) var entities = model.Select(m => new RequestBlobs { Type = m.Type, Content = ByteConverterHelper.ReturnBytes(m), ProviderId = m.ProviderId, Id = m.Id }).ToList(); return Repo.UpdateAll(entities); } + + public bool BatchDelete(List model) + { + var entities = model.Select(m => new RequestBlobs { Type = m.Type, Content = ByteConverterHelper.ReturnBytes(m), ProviderId = m.ProviderId, Id = m.Id }).ToList(); + return Repo.DeleteAll(entities); + } } } \ No newline at end of file diff --git a/PlexRequests.Store/Repository/IRequestRepository.cs b/PlexRequests.Store/Repository/IRequestRepository.cs index 809628c51..650dc9b4b 100644 --- a/PlexRequests.Store/Repository/IRequestRepository.cs +++ b/PlexRequests.Store/Repository/IRequestRepository.cs @@ -53,6 +53,8 @@ public interface IRequestRepository /// bool Delete(RequestBlobs entity); + bool DeleteAll(IEnumerable entity); + /// /// Updates the specified entity. /// diff --git a/PlexRequests.Store/Repository/RequestJsonRepository.cs b/PlexRequests.Store/Repository/RequestJsonRepository.cs index 872e07745..bad8736da 100644 --- a/PlexRequests.Store/Repository/RequestJsonRepository.cs +++ b/PlexRequests.Store/Repository/RequestJsonRepository.cs @@ -122,5 +122,20 @@ public bool UpdateAll(IEnumerable entity) } return result.All(x => true); } + + public bool DeleteAll(IEnumerable entity) + { + ResetCache(); + var result = new HashSet(); + using (var db = Db.DbConnection()) + { + db.Open(); + foreach (var e in entity) + { + result.Add(db.Delete(e)); + } + } + return result.All(x => true); + } } } diff --git a/PlexRequests.UI/Content/base.css b/PlexRequests.UI/Content/base.css index 1ad9a6bc7..d0479a8d1 100644 --- a/PlexRequests.UI/Content/base.css +++ b/PlexRequests.UI/Content/base.css @@ -25,6 +25,10 @@ hr { .btn { border-radius: 0.25rem !important; } +.btn-group-separated .btn, +.btn-group-separated .btn + .btn { + margin-left: 3px; } + .multiSelect { background-color: #4e5d6c; } diff --git a/PlexRequests.UI/Content/base.min.css b/PlexRequests.UI/Content/base.min.css index b165bae88..a16d98f54 100644 --- a/PlexRequests.UI/Content/base.min.css +++ b/PlexRequests.UI/Content/base.min.css @@ -1 +1 @@ -@media(min-width:768px){.row{position:relative;}.bottom-align-text{position:absolute;bottom:0;right:0;}}@media(max-width:48em){.home{padding-top:1rem;}}@media(min-width:48em){.home{padding-top:4rem;}}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.active>a:hover,.navbar-default .navbar-nav>.active>a:focus{color:#fff;}hr{border:1px dashed #777;}.btn{border-radius:.25rem !important;}.multiSelect{background-color:#4e5d6c;}.form-control-custom{background-color:#4e5d6c !important;color:#fff !important;border-radius:0;box-shadow:0 0 0 !important;}h1{font-size:3.5rem !important;font-weight:600 !important;}.request-title{margin-top:0 !important;font-size:1.9rem !important;}p{font-size:1.1rem !important;}label{display:inline-block !important;margin-bottom:.5rem !important;font-size:16px !important;}.nav-tabs>li{font-size:13px;line-height:21px;}.nav-tabs>li.active>a,.nav-tabs>li.active>a:hover,.nav-tabs>li.active>a:focus{background:#4e5d6c;}.nav-tabs>li>a>.fa{padding:3px 5px 3px 3px;}.nav-tabs>li.nav-tab-right{float:right;}.nav-tabs>li.nav-tab-right a{margin-right:0;margin-left:2px;}.nav-tabs>li.nav-tab-icononly .fa{padding:3px;}.navbar .nav a .fa,.dropdown-menu a .fa{font-size:130%;top:1px;position:relative;display:inline-block;margin-right:5px;}.dropdown-menu a .fa{top:2px;}.btn-danger-outline{color:#d9534f !important;background-color:transparent;background-image:none;border-color:#d9534f !important;}.btn-danger-outline:focus,.btn-danger-outline.focus,.btn-danger-outline:active,.btn-danger-outline.active,.btn-danger-outline:hover,.open>.btn-danger-outline.dropdown-toggle{color:#fff !important;background-color:#d9534f !important;border-color:#d9534f !important;}.btn-primary-outline{color:#ff761b !important;background-color:transparent;background-image:none;border-color:#ff761b !important;}.btn-primary-outline:focus,.btn-primary-outline.focus,.btn-primary-outline:active,.btn-primary-outline.active,.btn-primary-outline:hover,.open>.btn-primary-outline.dropdown-toggle{color:#fff !important;background-color:#df691a !important;border-color:#df691a !important;}.btn-info-outline{color:#5bc0de !important;background-color:transparent;background-image:none;border-color:#5bc0de !important;}.btn-info-outline:focus,.btn-info-outline.focus,.btn-info-outline:active,.btn-info-outline.active,.btn-info-outline:hover,.open>.btn-info-outline.dropdown-toggle{color:#fff !important;background-color:#5bc0de !important;border-color:#5bc0de !important;}.btn-warning-outline{color:#f0ad4e !important;background-color:transparent;background-image:none;border-color:#f0ad4e !important;}.btn-warning-outline:focus,.btn-warning-outline.focus,.btn-warning-outline:active,.btn-warning-outline.active,.btn-warning-outline:hover,.open>.btn-warning-outline.dropdown-toggle{color:#fff !important;background-color:#f0ad4e !important;border-color:#f0ad4e !important;}.btn-success-outline{color:#5cb85c !important;background-color:transparent;background-image:none;border-color:#5cb85c !important;}.btn-success-outline:focus,.btn-success-outline.focus,.btn-success-outline:active,.btn-success-outline.active,.btn-success-outline:hover,.open>.btn-success-outline.dropdown-toggle{color:#fff !important;background-color:#5cb85c !important;border-color:#5cb85c !important;}#movieList .mix{display:none;}#tvList .mix{display:none;}.scroll-top-wrapper{position:fixed;opacity:0;visibility:hidden;overflow:hidden;text-align:center;z-index:99999999;background-color:#4e5d6c;color:#eee;width:50px;height:48px;line-height:48px;right:30px;bottom:30px;padding-top:2px;border-top-left-radius:10px;border-top-right-radius:10px;border-bottom-right-radius:10px;border-bottom-left-radius:10px;-webkit-transition:all .5s ease-in-out;-moz-transition:all .5s ease-in-out;-ms-transition:all .5s ease-in-out;-o-transition:all .5s ease-in-out;transition:all .5s ease-in-out;}.scroll-top-wrapper:hover{background-color:#637689;}.scroll-top-wrapper.show{visibility:visible;cursor:pointer;opacity:1;}.scroll-top-wrapper i.fa{line-height:inherit;}.no-search-results{text-align:center;}.no-search-results .no-search-results-icon{font-size:10em;color:#4e5d6c;}.no-search-results .no-search-results-text{margin:20px 0;color:#ccc;}.form-control-search{padding:13px 105px 13px 16px;height:100%;}.form-control-withbuttons{padding-right:105px;}.input-group-addon .btn-group{position:absolute;right:45px;z-index:3;top:10px;box-shadow:0 0 0;}.input-group-addon .btn-group .btn{border:1px solid rgba(255,255,255,.7) !important;padding:3px 12px;color:rgba(255,255,255,.7) !important;}.btn-split .btn{border-radius:0 !important;}.btn-split .btn:not(.dropdown-toggle){border-radius:.25rem 0 0 .25rem !important;}.btn-split .btn.dropdown-toggle{border-radius:0 .25rem .25rem 0 !important;padding:12px 8px;}#updateAvailable{background-color:#df691a;text-align:center;font-size:15px;padding:3px 0;}.checkbox label{display:inline-block;cursor:pointer;position:relative;padding-left:25px;margin-right:15px;font-size:13px;margin-bottom:10px;}.checkbox label:before{content:"";display:inline-block;width:18px;height:18px;margin-right:10px;position:absolute;left:0;bottom:1px;border:2px solid #eee;border-radius:3px;}.checkbox input[type=checkbox]{display:none;}.checkbox input[type=checkbox]:checked+label:before{content:"✓";font-size:13px;color:#fafafa;text-align:center;line-height:13px;}.input-group-sm{padding-top:2px;padding-bottom:2px;}.tab-pane .form-horizontal .form-group{margin-right:15px;margin-left:15px;} \ No newline at end of file +@media(min-width:768px){.row{position:relative;}.bottom-align-text{position:absolute;bottom:0;right:0;}}@media(max-width:48em){.home{padding-top:1rem;}}@media(min-width:48em){.home{padding-top:4rem;}}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.active>a:hover,.navbar-default .navbar-nav>.active>a:focus{color:#fff;}hr{border:1px dashed #777;}.btn{border-radius:.25rem !important;}.btn-group-separated .btn,.btn-group-separated .btn+.btn{margin-left:3px;}.multiSelect{background-color:#4e5d6c;}.form-control-custom{background-color:#4e5d6c !important;color:#fff !important;border-radius:0;box-shadow:0 0 0 !important;}h1{font-size:3.5rem !important;font-weight:600 !important;}.request-title{margin-top:0 !important;font-size:1.9rem !important;}p{font-size:1.1rem !important;}label{display:inline-block !important;margin-bottom:.5rem !important;font-size:16px !important;}.nav-tabs>li{font-size:13px;line-height:21px;}.nav-tabs>li.active>a,.nav-tabs>li.active>a:hover,.nav-tabs>li.active>a:focus{background:#4e5d6c;}.nav-tabs>li>a>.fa{padding:3px 5px 3px 3px;}.nav-tabs>li.nav-tab-right{float:right;}.nav-tabs>li.nav-tab-right a{margin-right:0;margin-left:2px;}.nav-tabs>li.nav-tab-icononly .fa{padding:3px;}.navbar .nav a .fa,.dropdown-menu a .fa{font-size:130%;top:1px;position:relative;display:inline-block;margin-right:5px;}.dropdown-menu a .fa{top:2px;}.btn-danger-outline{color:#d9534f !important;background-color:transparent;background-image:none;border-color:#d9534f !important;}.btn-danger-outline:focus,.btn-danger-outline.focus,.btn-danger-outline:active,.btn-danger-outline.active,.btn-danger-outline:hover,.open>.btn-danger-outline.dropdown-toggle{color:#fff !important;background-color:#d9534f !important;border-color:#d9534f !important;}.btn-primary-outline{color:#ff761b !important;background-color:transparent;background-image:none;border-color:#ff761b !important;}.btn-primary-outline:focus,.btn-primary-outline.focus,.btn-primary-outline:active,.btn-primary-outline.active,.btn-primary-outline:hover,.open>.btn-primary-outline.dropdown-toggle{color:#fff !important;background-color:#df691a !important;border-color:#df691a !important;}.btn-info-outline{color:#5bc0de !important;background-color:transparent;background-image:none;border-color:#5bc0de !important;}.btn-info-outline:focus,.btn-info-outline.focus,.btn-info-outline:active,.btn-info-outline.active,.btn-info-outline:hover,.open>.btn-info-outline.dropdown-toggle{color:#fff !important;background-color:#5bc0de !important;border-color:#5bc0de !important;}.btn-warning-outline{color:#f0ad4e !important;background-color:transparent;background-image:none;border-color:#f0ad4e !important;}.btn-warning-outline:focus,.btn-warning-outline.focus,.btn-warning-outline:active,.btn-warning-outline.active,.btn-warning-outline:hover,.open>.btn-warning-outline.dropdown-toggle{color:#fff !important;background-color:#f0ad4e !important;border-color:#f0ad4e !important;}.btn-success-outline{color:#5cb85c !important;background-color:transparent;background-image:none;border-color:#5cb85c !important;}.btn-success-outline:focus,.btn-success-outline.focus,.btn-success-outline:active,.btn-success-outline.active,.btn-success-outline:hover,.open>.btn-success-outline.dropdown-toggle{color:#fff !important;background-color:#5cb85c !important;border-color:#5cb85c !important;}#movieList .mix{display:none;}#tvList .mix{display:none;}.scroll-top-wrapper{position:fixed;opacity:0;visibility:hidden;overflow:hidden;text-align:center;z-index:99999999;background-color:#4e5d6c;color:#eee;width:50px;height:48px;line-height:48px;right:30px;bottom:30px;padding-top:2px;border-top-left-radius:10px;border-top-right-radius:10px;border-bottom-right-radius:10px;border-bottom-left-radius:10px;-webkit-transition:all .5s ease-in-out;-moz-transition:all .5s ease-in-out;-ms-transition:all .5s ease-in-out;-o-transition:all .5s ease-in-out;transition:all .5s ease-in-out;}.scroll-top-wrapper:hover{background-color:#637689;}.scroll-top-wrapper.show{visibility:visible;cursor:pointer;opacity:1;}.scroll-top-wrapper i.fa{line-height:inherit;}.no-search-results{text-align:center;}.no-search-results .no-search-results-icon{font-size:10em;color:#4e5d6c;}.no-search-results .no-search-results-text{margin:20px 0;color:#ccc;}.form-control-search{padding:13px 105px 13px 16px;height:100%;}.form-control-withbuttons{padding-right:105px;}.input-group-addon .btn-group{position:absolute;right:45px;z-index:3;top:10px;box-shadow:0 0 0;}.input-group-addon .btn-group .btn{border:1px solid rgba(255,255,255,.7) !important;padding:3px 12px;color:rgba(255,255,255,.7) !important;}.btn-split .btn{border-radius:0 !important;}.btn-split .btn:not(.dropdown-toggle){border-radius:.25rem 0 0 .25rem !important;}.btn-split .btn.dropdown-toggle{border-radius:0 .25rem .25rem 0 !important;padding:12px 8px;}#updateAvailable{background-color:#df691a;text-align:center;font-size:15px;padding:3px 0;}.checkbox label{display:inline-block;cursor:pointer;position:relative;padding-left:25px;margin-right:15px;font-size:13px;margin-bottom:10px;}.checkbox label:before{content:"";display:inline-block;width:18px;height:18px;margin-right:10px;position:absolute;left:0;bottom:1px;border:2px solid #eee;border-radius:3px;}.checkbox input[type=checkbox]{display:none;}.checkbox input[type=checkbox]:checked+label:before{content:"✓";font-size:13px;color:#fafafa;text-align:center;line-height:13px;}.input-group-sm{padding-top:2px;padding-bottom:2px;}.tab-pane .form-horizontal .form-group{margin-right:15px;margin-left:15px;} \ No newline at end of file diff --git a/PlexRequests.UI/Content/base.scss b/PlexRequests.UI/Content/base.scss index 2839c225b..7cb008433 100644 --- a/PlexRequests.UI/Content/base.scss +++ b/PlexRequests.UI/Content/base.scss @@ -46,6 +46,11 @@ hr { border-radius: .25rem $i; } +.btn-group-separated .btn, +.btn-group-separated .btn + .btn { + margin-left: 3px; +} + .multiSelect { background-color: $form-color; } diff --git a/PlexRequests.UI/Content/requests-1.7.js b/PlexRequests.UI/Content/requests-1.7.js index 96b7ae4da..5438310f1 100644 --- a/PlexRequests.UI/Content/requests-1.7.js +++ b/PlexRequests.UI/Content/requests-1.7.js @@ -40,9 +40,9 @@ $('a[data-toggle="tab"]').on('shown.bs.tab', function (e) { var $tvl = $('#tvList'); var $musicL = $('#musicList'); - $('.approve-category').hide(); + $('.approve-category,.delete-category').hide(); if (target === "#TvShowTab") { - $('#approveTVShows').show(); + $('#approveTVShows,#deleteTVShows').show(); if ($ml.mixItUp('isLoaded')) { activeState = $ml.mixItUp('getState'); $ml.mixItUp('destroy'); @@ -55,7 +55,7 @@ $('a[data-toggle="tab"]').on('shown.bs.tab', function (e) { $tvl.mixItUp(mixItUpConfig(activeState)); // init or reinit } if (target === "#MoviesTab") { - $('#approveMovies').show(); + $('#approveMovies,#deleteMovies').show(); if ($tvl.mixItUp('isLoaded')) { activeState = $tvl.mixItUp('getState'); $tvl.mixItUp('destroy'); @@ -69,7 +69,7 @@ $('a[data-toggle="tab"]').on('shown.bs.tab', function (e) { } if (target === "#MusicTab") { - $('#approveMusic').show(); + $('#approveMusic,#deleteMusic').show(); if ($tvl.mixItUp('isLoaded')) { activeState = $tvl.mixItUp('getState'); $tvl.mixItUp('destroy'); @@ -124,7 +124,7 @@ $('#approveTVShows').click(function (e) { return; } - loadingButton(buttonId, "success"); + loadingButton(buttonId, "warning"); var url = createBaseUrl(base, '/approval/approvealltvshows'); $.ajax({ type: 'post', @@ -140,6 +140,72 @@ $('#approveTVShows').click(function (e) { console.log(e); generateNotify("Something went wrong!", "danger"); }, + complete: function (e) { + finishLoading(buttonId, "warning", origHtml); + } + }); +}); + +$('#deleteMovies').click(function (e) { + e.preventDefault(); + if (!confirm("Are you sure you want to delete all TV show requests?")) return; + + var buttonId = e.target.id; + var origHtml = $(this).html(); + + if ($('#' + buttonId).text() === " Loading...") { + return; + } + + loadingButton(buttonId, "warning"); + + var url = createBaseUrl(base, '/approval/deleteallmovies'); + $.ajax({ + type: 'post', + url: url, + dataType: "json", + success: function (response) { + if (checkJsonResponse(response)) { + generateNotify("Success! All Movie requests deleted!", "success"); + movieLoad(); + } + }, + error: function (e) { + console.log(e); + generateNotify("Something went wrong!", "danger"); + }, + complete: function (e) { + finishLoading(buttonId, "warning", origHtml); + } + }); +}); +$('#deleteTVShows').click(function (e) { + e.preventDefault(); + if (!confirm("Are you sure you want to delete all TV show requests?")) return; + + var buttonId = e.target.id; + var origHtml = $(this).html(); + + if ($('#' + buttonId).text() === " Loading...") { + return; + } + + loadingButton(buttonId, "success"); + var url = createBaseUrl(base, '/approval/deletealltvshows'); + $.ajax({ + type: 'post', + url: url, + dataType: "json", + success: function (response) { + if (checkJsonResponse(response)) { + generateNotify("Success! All TV Show requests deleted!", "success"); + tvLoad(); + } + }, + error: function (e) { + console.log(e); + generateNotify("Something went wrong!", "danger"); + }, complete: function (e) { finishLoading(buttonId, "success", origHtml); } diff --git a/PlexRequests.UI/Modules/ApprovalModule.cs b/PlexRequests.UI/Modules/ApprovalModule.cs index 2f83e8757..33356ca02 100644 --- a/PlexRequests.UI/Modules/ApprovalModule.cs +++ b/PlexRequests.UI/Modules/ApprovalModule.cs @@ -66,6 +66,8 @@ public ApprovalModule(IRequestService service, ISettingsService ApproveAll(); Post["/approveallmovies"] = x => ApproveAllMovies(); Post["/approvealltvshows"] = x => ApproveAllTVShows(); + Post["/deleteallmovies"] = x => DeleteAllMovies(); + Post["/deletealltvshows"] = x => DeleteAllTVShows(); } private IRequestService Service { get; } @@ -274,6 +276,27 @@ private Response ApproveAllMovies() } } + private Response DeleteAllMovies() + { + + var requests = Service.GetAll().Where(x => x.Type == RequestType.Movie); + var requestedModels = requests as RequestedModel[] ?? requests.ToArray(); + if (!requestedModels.Any()) + { + return Response.AsJson(new JsonResponseModel { Result = false, Message = "There are no movie requests to delete. Please refresh." }); + } + + try + { + return DeleteRequests(requestedModels); + } + catch (Exception e) + { + Log.Fatal(e); + return Response.AsJson(new JsonResponseModel { Result = false, Message = "Something bad happened, please check the logs!" }); + } + } + private Response ApproveAllTVShows() { var requests = Service.GetAll().Where(x => x.CanApprove && x.Type == RequestType.TvShow); @@ -294,6 +317,27 @@ private Response ApproveAllTVShows() } } + private Response DeleteAllTVShows() + { + + var requests = Service.GetAll().Where(x => x.Type == RequestType.TvShow); + var requestedModels = requests as RequestedModel[] ?? requests.ToArray(); + if (!requestedModels.Any()) + { + return Response.AsJson(new JsonResponseModel { Result = false, Message = "There are no tv show requests to delete. Please refresh." }); + } + + try + { + return DeleteRequests(requestedModels); + } + catch (Exception e) + { + Log.Fatal(e); + return Response.AsJson(new JsonResponseModel { Result = false, Message = "Something bad happened, please check the logs!" }); + } + } + /// /// Approves all. /// @@ -319,6 +363,22 @@ private Response ApproveAll() } + private Response DeleteRequests(RequestedModel[] requestedModels) + { + try + { + var result = Service.BatchDelete(requestedModels.ToList()); + return Response.AsJson(result + ? new JsonResponseModel { Result = true } + : new JsonResponseModel { Result = false, Message = "We could not delete all of the requests. Please try again or check the logs." }); + } + catch (Exception e) + { + Log.Fatal(e); + return Response.AsJson(new JsonResponseModel { Result = false, Message = "Something bad happened, please check the logs!" }); + } + } + private Response UpdateRequests(RequestedModel[] requestedModels) { var cpSettings = CpService.GetSettings(); @@ -389,7 +449,6 @@ private Response UpdateRequests(RequestedModel[] requestedModels) } try { - var result = Service.BatchUpdate(updatedRequests); return Response.AsJson(result ? new JsonResponseModel { Result = true } diff --git a/PlexRequests.UI/Views/Requests/Index.cshtml b/PlexRequests.UI/Views/Requests/Index.cshtml index d61f8b070..15fcfe61b 100644 --- a/PlexRequests.UI/Views/Requests/Index.cshtml +++ b/PlexRequests.UI/Views/Requests/Index.cshtml @@ -35,19 +35,22 @@
-
+
@if (Context.CurrentUser.IsAuthenticated()) //TODO replace with IsAdmin { @if (Model.SearchForMovies) { + } @if (Model.SearchForTvShows) { + } @if (Model.SearchForMusic) { + } } From 9cf107524f4312bfd6287dd089973a0a87fb95f9 Mon Sep 17 00:00:00 2001 From: Drewster727 Date: Fri, 27 May 2016 02:47:06 -0500 Subject: [PATCH 09/26] #26q make the auth users list taller --- PlexRequests.UI/Views/Admin/Authentication.cshtml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PlexRequests.UI/Views/Admin/Authentication.cshtml b/PlexRequests.UI/Views/Admin/Authentication.cshtml index 8e2d89a5a..67e5e5db4 100644 --- a/PlexRequests.UI/Views/Admin/Authentication.cshtml +++ b/PlexRequests.UI/Views/Admin/Authentication.cshtml @@ -77,7 +77,7 @@

Current users that are allowed to authenticate:

- +
From 66602094272a5a6f86a8027a0718d028ff42c684 Mon Sep 17 00:00:00 2001 From: Drewster727 Date: Fri, 27 May 2016 02:47:06 -0500 Subject: [PATCH 10/26] #262 make the auth users list taller --- PlexRequests.UI/Views/Admin/Authentication.cshtml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PlexRequests.UI/Views/Admin/Authentication.cshtml b/PlexRequests.UI/Views/Admin/Authentication.cshtml index 8e2d89a5a..67e5e5db4 100644 --- a/PlexRequests.UI/Views/Admin/Authentication.cshtml +++ b/PlexRequests.UI/Views/Admin/Authentication.cshtml @@ -77,7 +77,7 @@

Current users that are allowed to authenticate:

- +
From 95d1a8320849572241e647c9470d3cd51eb2ae8c Mon Sep 17 00:00:00 2001 From: Drewster727 Date: Fri, 27 May 2016 03:10:50 -0500 Subject: [PATCH 11/26] fix 404 error --- PlexRequests.UI/Content/Themes/original.css | 1 + PlexRequests.UI/Content/Themes/original.min.css | 1 + PlexRequests.UI/PlexRequests.UI.csproj | 8 ++++++++ PlexRequests.UI/compilerconfig.json | 4 ++++ 4 files changed, 14 insertions(+) create mode 100644 PlexRequests.UI/Content/Themes/original.css create mode 100644 PlexRequests.UI/Content/Themes/original.min.css diff --git a/PlexRequests.UI/Content/Themes/original.css b/PlexRequests.UI/Content/Themes/original.css new file mode 100644 index 000000000..e02abfc9b --- /dev/null +++ b/PlexRequests.UI/Content/Themes/original.css @@ -0,0 +1 @@ + diff --git a/PlexRequests.UI/Content/Themes/original.min.css b/PlexRequests.UI/Content/Themes/original.min.css new file mode 100644 index 000000000..5f282702b --- /dev/null +++ b/PlexRequests.UI/Content/Themes/original.min.css @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/PlexRequests.UI/PlexRequests.UI.csproj b/PlexRequests.UI/PlexRequests.UI.csproj index e7d79575e..2e226b54f 100644 --- a/PlexRequests.UI/PlexRequests.UI.csproj +++ b/PlexRequests.UI/PlexRequests.UI.csproj @@ -294,6 +294,14 @@ PreserveNewest + + original.scss + PreserveNewest + + + original.css + PreserveNewest + plex.scss PreserveNewest diff --git a/PlexRequests.UI/compilerconfig.json b/PlexRequests.UI/compilerconfig.json index 64b20cbb4..1e826536c 100644 --- a/PlexRequests.UI/compilerconfig.json +++ b/PlexRequests.UI/compilerconfig.json @@ -22,5 +22,9 @@ { "outputFile": "Content/Themes/plex.css", "inputFile": "Content/Themes/plex.scss" + }, + { + "outputFile": "Content/Themes/original.css", + "inputFile": "Content/Themes/original.scss" } ] \ No newline at end of file From 31e5c073835365ac258af420ac6621dce4928c3c Mon Sep 17 00:00:00 2001 From: tidusjar Date: Fri, 27 May 2016 10:42:55 +0100 Subject: [PATCH 12/26] Fixed a bug in the user notification where if an admin wants to be notified they wouldn't be. Also added more diagnostic logging under Debug. Added logging under Info to see who notifications are being sent to. --- .../Jobs/PlexAvailabilityChecker.cs | 45 +++++++++++++------ 1 file changed, 31 insertions(+), 14 deletions(-) diff --git a/PlexRequests.Services/Jobs/PlexAvailabilityChecker.cs b/PlexRequests.Services/Jobs/PlexAvailabilityChecker.cs index d6bd244ca..b22961317 100644 --- a/PlexRequests.Services/Jobs/PlexAvailabilityChecker.cs +++ b/PlexRequests.Services/Jobs/PlexAvailabilityChecker.cs @@ -326,33 +326,36 @@ private void NotifyUsers(IEnumerable modelChanged, string apiKey try { var plexUser = PlexApi.GetUsers(apiKey); - if (plexUser?.User == null || plexUser.User.Length == 0) - { - return; - } + var userAccount = PlexApi.GetAccount(apiKey); + + var adminUsername = userAccount.Username ?? string.Empty; var users = UserNotifyRepo.GetAll().ToList(); + Log.Debug("Notifying Users Count {0}", users.Count); foreach (var model in modelChanged) { var selectedUsers = users.Select(x => x.Username).Intersect(model.RequestedUsers); + Log.Debug("Selected Users {0}", selectedUsers.DumpJson()); foreach (var user in selectedUsers) { + Log.Info("Notifying user {0}", user); + if (user == adminUsername) + { + Log.Info("This user is the Plex server owner"); + PublishUserNotification(userAccount.Username, userAccount.Email, model.Title); + return; + } + var email = plexUser.User.FirstOrDefault(x => x.Username == user); if (email == null) { + Log.Info("There is no email address for this Plex user, cannot send notification"); // We do not have a plex user that requested this! continue; } - var notificationModel = new NotificationModel - { - User = email.Username, - UserEmail = email.Email, - NotificationType = NotificationType.RequestAvailable, - Title = model.Title - }; - - // Send the notification to the user. - Notification.Publish(notificationModel); + + Log.Info("Sending notification to: {0} at: {1}, for title: {2}", email.Username, email.Email, model.Title); + PublishUserNotification(email.Username, email.Email, model.Title); } } } @@ -362,6 +365,20 @@ private void NotifyUsers(IEnumerable modelChanged, string apiKey } } + private void PublishUserNotification(string username, string email, string title) + { + var notificationModel = new NotificationModel + { + User = username, + UserEmail = email, + NotificationType = NotificationType.RequestAvailable, + Title = title + }; + + // Send the notification to the user. + Notification.Publish(notificationModel); + } + public void Execute(IJobExecutionContext context) { CheckAndUpdateAll(); From a1ae37eae4afe72486ff45bf24913fe5dc06c2c2 Mon Sep 17 00:00:00 2001 From: tidusjar Date: Fri, 27 May 2016 13:30:21 +0100 Subject: [PATCH 13/26] Reworked some tests --- .../PasswordHasherTests.cs | 3 +- .../PlexRequests.Helpers.Tests.csproj | 3 +- PlexRequests.Helpers.Tests/UriHelperTests.cs | 89 ++++++++++--------- PlexRequests.Helpers.Tests/app.config | 12 +-- PlexRequests.sln | 50 ++++++----- 5 files changed, 82 insertions(+), 75 deletions(-) diff --git a/PlexRequests.Helpers.Tests/PasswordHasherTests.cs b/PlexRequests.Helpers.Tests/PasswordHasherTests.cs index 500d07534..2ac54a547 100644 --- a/PlexRequests.Helpers.Tests/PasswordHasherTests.cs +++ b/PlexRequests.Helpers.Tests/PasswordHasherTests.cs @@ -24,7 +24,6 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // ************************************************************************/ #endregion -using System.Diagnostics; using NUnit.Framework; @@ -41,7 +40,7 @@ public void TestHash() var hash = PasswordHasher.ComputeHash(password, salt); Assert.That(hash, Is.Not.EqualTo(password)); - + var match = PasswordHasher.VerifyPassword(password, salt, hash); Assert.That(match, Is.True); diff --git a/PlexRequests.Helpers.Tests/PlexRequests.Helpers.Tests.csproj b/PlexRequests.Helpers.Tests/PlexRequests.Helpers.Tests.csproj index bb9e7143b..9f3adbd0d 100644 --- a/PlexRequests.Helpers.Tests/PlexRequests.Helpers.Tests.csproj +++ b/PlexRequests.Helpers.Tests/PlexRequests.Helpers.Tests.csproj @@ -8,7 +8,7 @@ Properties PlexRequests.Helpers.Tests PlexRequests.Helpers.Tests - v4.6 + v4.5 512 {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 10.0 @@ -16,6 +16,7 @@ $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages False UnitTest + true diff --git a/PlexRequests.Helpers.Tests/UriHelperTests.cs b/PlexRequests.Helpers.Tests/UriHelperTests.cs index 93fb32997..cc748f95c 100644 --- a/PlexRequests.Helpers.Tests/UriHelperTests.cs +++ b/PlexRequests.Helpers.Tests/UriHelperTests.cs @@ -26,7 +26,8 @@ #endregion using System; -using System.Linq.Expressions; +using System.Collections.Generic; + using NUnit.Framework; namespace PlexRequests.Helpers.Tests @@ -35,11 +36,9 @@ namespace PlexRequests.Helpers.Tests public class UriHelperTests { [TestCaseSource(nameof(UriData))] - public void CreateUri1(string uri, Uri expected) + public Uri CreateUri1(string uri) { - var result = uri.ReturnUri(); - - Assert.That(result, Is.EqualTo(expected)); + return uri.ReturnUri(); } [Test] @@ -52,54 +51,58 @@ public void CreateUriWithSsl() } [TestCaseSource(nameof(UriDataWithPort))] - public void CreateUri2(string uri, int port, Uri expected) + public Uri CreateUri2(string uri, int port) { - var result = uri.ReturnUri(port); - - Assert.That(result, Is.EqualTo(expected)); + return uri.ReturnUri(port); } [TestCaseSource(nameof(UriDataWithSubDir))] - public void CreateUriWithSubDir(string uri, int port, bool ssl, string subDir, Uri expected) + public Uri CreateUriWithSubDir(string uri, int port, bool ssl, string subDir) { - var result = uri.ReturnUriWithSubDir(port, ssl, subDir); - - Assert.That(result, Is.EqualTo(expected)); + return uri.ReturnUriWithSubDir(port, ssl, subDir); } - static readonly object[] UriData = + private static IEnumerable UriData { - new object[] { "google.com", new Uri("http://google.com/"), }, - new object[] { "http://google.com", new Uri("http://google.com/"), }, - new object[] { "https://google.com", new Uri("https://google.com/"), }, - new object[] { "192.168.1.1", new Uri("http://192.168.1.1")}, - new object[] { "0.0.0.0:5533", new Uri("http://0.0.0.0:5533")}, - new object[] {"www.google.com", new Uri("http://www.google.com/")}, - new object[] {"http://www.google.com/", new Uri("http://www.google.com/") }, - new object[] {"https://www.google.com", new Uri("https://www.google.com/") }, - new object[] {"www.google.com:443", new Uri("http://www.google.com:443/") }, - new object[] {"https://www.google.com:443", new Uri("https://www.google.com:443/") }, - new object[] {"http://www.google.com:443/id=2", new Uri("http://www.google.com:443/id=2") }, - new object[] {"www.google.com:4438/id=22", new Uri("http://www.google.com:4438/id=22") } - }; + get + { + yield return new TestCaseData("google.com").Returns(new Uri("http://google.com/")); + yield return new TestCaseData("http://google.com").Returns(new Uri("http://google.com/")); + yield return new TestCaseData("https://google.com").Returns(new Uri("https://google.com/")); + yield return new TestCaseData("192.168.1.1").Returns(new Uri("http://192.168.1.1")); + yield return new TestCaseData("0.0.0.0:5533").Returns(new Uri("http://0.0.0.0:5533")); + yield return new TestCaseData("www.google.com").Returns(new Uri("http://www.google.com/")); + yield return new TestCaseData("http://www.google.com/").Returns(new Uri("http://www.google.com/")); + yield return new TestCaseData("https://www.google.com").Returns(new Uri("https://www.google.com/")); + yield return new TestCaseData("www.google.com:443").Returns(new Uri("http://www.google.com:443/")); + yield return new TestCaseData("https://www.google.com:443").Returns(new Uri("https://www.google.com/")); + yield return new TestCaseData("http://www.google.com:443/id=2").Returns(new Uri("http://www.google.com:443/id=2")); + yield return new TestCaseData("www.google.com:4438/id=22").Returns(new Uri("http://www.google.com:4438/id=22")); + } + } - static readonly object[] UriDataWithPort = + private static IEnumerable UriDataWithPort { - new object[] {"www.google.com", 80, new Uri("http://www.google.com:80/"), }, - new object[] {"www.google.com", 443, new Uri("http://www.google.com:443/") }, - new object[] {"http://www.google.com", 443, new Uri("http://www.google.com:443/") }, - new object[] {"https://www.google.com", 443, new Uri("https://www.google.com:443/") }, - new object[] {"http://www.google.com/id=2", 443, new Uri("http://www.google.com:443/id=2") }, - new object[] {"http://www.google.com/id=2", 443, new Uri("http://www.google.com:443/id=2") }, - new object[] {"https://www.google.com/id=2", 443, new Uri("https://www.google.com:443/id=2") }, - }; + get + { + yield return new TestCaseData("www.google.com", 80).Returns(new Uri("http://www.google.com:80/")); + yield return new TestCaseData("www.google.com", 443).Returns(new Uri("http://www.google.com:443/")); + yield return new TestCaseData("http://www.google.com", 443).Returns(new Uri("http://www.google.com:443/")); + yield return new TestCaseData("https://www.google.com", 443).Returns(new Uri("https://www.google.com:443/")); + yield return new TestCaseData("http://www.google.com/id=2", 443).Returns(new Uri("http://www.google.com:443/id=2")); + yield return new TestCaseData("https://www.google.com/id=2", 443).Returns(new Uri("https://www.google.com:443/id=2")); + } + } - static readonly object[] UriDataWithSubDir = -{ - new object[] {"www.google.com", 80, false,"test", new Uri("http://www.google.com:80/test"), }, - new object[] {"www.google.com", 443, false,"test", new Uri("http://www.google.com:443/test") }, - new object[] {"http://www.google.com", 443, true,"test", new Uri("https://www.google.com:443/test") }, - new object[] {"https://www.google.com", 443,true,"test", new Uri("https://www.google.com:443/test") }, - }; + private static IEnumerable UriDataWithSubDir + { + get + { + yield return new TestCaseData("www.google.com", 80, false, "test").Returns(new Uri("http://www.google.com:80/test")); + yield return new TestCaseData("www.google.com", 443, false, "test").Returns(new Uri("http://www.google.com:443/test")); + yield return new TestCaseData("http://www.google.com", 443, true, "test").Returns(new Uri("https://www.google.com:443/test")); + yield return new TestCaseData("https://www.google.com", 443, true, "test").Returns(new Uri("https://www.google.com:443/test")); + } + } } } \ No newline at end of file diff --git a/PlexRequests.Helpers.Tests/app.config b/PlexRequests.Helpers.Tests/app.config index 6a9f5188b..1911601e2 100644 --- a/PlexRequests.Helpers.Tests/app.config +++ b/PlexRequests.Helpers.Tests/app.config @@ -1,15 +1,15 @@ - + - - + + - - + + - \ No newline at end of file + diff --git a/PlexRequests.sln b/PlexRequests.sln index 77eb7e978..93ac3b1f4 100644 --- a/PlexRequests.sln +++ b/PlexRequests.sln @@ -1,6 +1,6 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 2012 +# Visual Studio 14 VisualStudioVersion = 14.0.25123.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PlexRequests.UI", "PlexRequests.UI\PlexRequests.UI.csproj", "{68F5F5F3-B8BB-4911-875F-6F00AAE04EA6}" @@ -35,20 +35,14 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PlexRequests.Services.Tests EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PlexRequests.Updater", "PlexRequests.Updater\PlexRequests.Updater.csproj", "{EBE6FC1C-7B4B-47E9-AF54-0EE0604A2BE5}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PlexRequests.Helpers.Tests", "PlexRequests.Helpers.Tests\PlexRequests.Helpers.Tests.csproj", "{0E6395D3-B074-49E8-898D-0EB99E507E0E}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {1252336D-42A3-482A-804C-836E60173DFA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {1252336D-42A3-482A-804C-836E60173DFA}.Debug|Any CPU.Build.0 = Debug|Any CPU - {1252336D-42A3-482A-804C-836E60173DFA}.Release|Any CPU.ActiveCfg = Release|Any CPU - {1252336D-42A3-482A-804C-836E60173DFA}.Release|Any CPU.Build.0 = Release|Any CPU - {566EFA49-68F8-4716-9693-A6B3F2624DEA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {566EFA49-68F8-4716-9693-A6B3F2624DEA}.Debug|Any CPU.Build.0 = Debug|Any CPU - {566EFA49-68F8-4716-9693-A6B3F2624DEA}.Release|Any CPU.ActiveCfg = Release|Any CPU - {566EFA49-68F8-4716-9693-A6B3F2624DEA}.Release|Any CPU.Build.0 = Release|Any CPU {68F5F5F3-B8BB-4911-875F-6F00AAE04EA6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {68F5F5F3-B8BB-4911-875F-6F00AAE04EA6}.Debug|Any CPU.Build.0 = Debug|Any CPU {68F5F5F3-B8BB-4911-875F-6F00AAE04EA6}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -57,26 +51,38 @@ Global {8CB8D235-2674-442D-9C6A-35FCAEEB160D}.Debug|Any CPU.Build.0 = Debug|Any CPU {8CB8D235-2674-442D-9C6A-35FCAEEB160D}.Release|Any CPU.ActiveCfg = Release|Any CPU {8CB8D235-2674-442D-9C6A-35FCAEEB160D}.Release|Any CPU.Build.0 = Release|Any CPU - {92433867-2B7B-477B-A566-96C382427525}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {92433867-2B7B-477B-A566-96C382427525}.Debug|Any CPU.Build.0 = Debug|Any CPU - {92433867-2B7B-477B-A566-96C382427525}.Release|Any CPU.ActiveCfg = Release|Any CPU - {92433867-2B7B-477B-A566-96C382427525}.Release|Any CPU.Build.0 = Release|Any CPU {95834072-A675-415D-AA8F-877C91623810}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {95834072-A675-415D-AA8F-877C91623810}.Debug|Any CPU.Build.0 = Debug|Any CPU {95834072-A675-415D-AA8F-877C91623810}.Release|Any CPU.ActiveCfg = Release|Any CPU {95834072-A675-415D-AA8F-877C91623810}.Release|Any CPU.Build.0 = Release|Any CPU + {DD7DC444-D3BF-4027-8AB9-EFC71F5EC581}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DD7DC444-D3BF-4027-8AB9-EFC71F5EC581}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DD7DC444-D3BF-4027-8AB9-EFC71F5EC581}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DD7DC444-D3BF-4027-8AB9-EFC71F5EC581}.Release|Any CPU.Build.0 = Release|Any CPU + {92433867-2B7B-477B-A566-96C382427525}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {92433867-2B7B-477B-A566-96C382427525}.Debug|Any CPU.Build.0 = Debug|Any CPU + {92433867-2B7B-477B-A566-96C382427525}.Release|Any CPU.ActiveCfg = Release|Any CPU + {92433867-2B7B-477B-A566-96C382427525}.Release|Any CPU.Build.0 = Release|Any CPU + {1252336D-42A3-482A-804C-836E60173DFA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1252336D-42A3-482A-804C-836E60173DFA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1252336D-42A3-482A-804C-836E60173DFA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1252336D-42A3-482A-804C-836E60173DFA}.Release|Any CPU.Build.0 = Release|Any CPU {A930E2CF-79E2-45F9-B06A-9A719A254CE4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {A930E2CF-79E2-45F9-B06A-9A719A254CE4}.Debug|Any CPU.Build.0 = Debug|Any CPU {A930E2CF-79E2-45F9-B06A-9A719A254CE4}.Release|Any CPU.ActiveCfg = Release|Any CPU {A930E2CF-79E2-45F9-B06A-9A719A254CE4}.Release|Any CPU.Build.0 = Release|Any CPU + {FCFECD5D-47F6-454D-8692-E27A921BE655}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FCFECD5D-47F6-454D-8692-E27A921BE655}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FCFECD5D-47F6-454D-8692-E27A921BE655}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FCFECD5D-47F6-454D-8692-E27A921BE655}.Release|Any CPU.Build.0 = Release|Any CPU + {566EFA49-68F8-4716-9693-A6B3F2624DEA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {566EFA49-68F8-4716-9693-A6B3F2624DEA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {566EFA49-68F8-4716-9693-A6B3F2624DEA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {566EFA49-68F8-4716-9693-A6B3F2624DEA}.Release|Any CPU.Build.0 = Release|Any CPU {CB37A5F8-6DFC-4554-99D3-A42B502E4591}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {CB37A5F8-6DFC-4554-99D3-A42B502E4591}.Debug|Any CPU.Build.0 = Debug|Any CPU {CB37A5F8-6DFC-4554-99D3-A42B502E4591}.Release|Any CPU.ActiveCfg = Release|Any CPU {CB37A5F8-6DFC-4554-99D3-A42B502E4591}.Release|Any CPU.Build.0 = Release|Any CPU - {DD7DC444-D3BF-4027-8AB9-EFC71F5EC581}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {DD7DC444-D3BF-4027-8AB9-EFC71F5EC581}.Debug|Any CPU.Build.0 = Debug|Any CPU - {DD7DC444-D3BF-4027-8AB9-EFC71F5EC581}.Release|Any CPU.ActiveCfg = Release|Any CPU - {DD7DC444-D3BF-4027-8AB9-EFC71F5EC581}.Release|Any CPU.Build.0 = Release|Any CPU {EAADB4AC-064F-4D3A-AFF9-64A33131A9A7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {EAADB4AC-064F-4D3A-AFF9-64A33131A9A7}.Debug|Any CPU.Build.0 = Debug|Any CPU {EAADB4AC-064F-4D3A-AFF9-64A33131A9A7}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -85,12 +91,10 @@ Global {EBE6FC1C-7B4B-47E9-AF54-0EE0604A2BE5}.Debug|Any CPU.Build.0 = Debug|Any CPU {EBE6FC1C-7B4B-47E9-AF54-0EE0604A2BE5}.Release|Any CPU.ActiveCfg = Release|Any CPU {EBE6FC1C-7B4B-47E9-AF54-0EE0604A2BE5}.Release|Any CPU.Build.0 = Release|Any CPU - {FCFECD5D-47F6-454D-8692-E27A921BE655}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {FCFECD5D-47F6-454D-8692-E27A921BE655}.Debug|Any CPU.Build.0 = Debug|Any CPU - {FCFECD5D-47F6-454D-8692-E27A921BE655}.Release|Any CPU.ActiveCfg = Release|Any CPU - {FCFECD5D-47F6-454D-8692-E27A921BE655}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(NestedProjects) = preSolution + {0E6395D3-B074-49E8-898D-0EB99E507E0E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0E6395D3-B074-49E8-898D-0EB99E507E0E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0E6395D3-B074-49E8-898D-0EB99E507E0E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0E6395D3-B074-49E8-898D-0EB99E507E0E}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE From 34e74c74c1e72b0688ce794a3c7717f72088b7ff Mon Sep 17 00:00:00 2001 From: tidusjar Date: Fri, 27 May 2016 13:50:27 +0100 Subject: [PATCH 14/26] Fixed #277 --- PlexRequests.Core/Setup.cs | 22 +++- PlexRequests.Services/Jobs/JobNames.cs | 3 +- PlexRequests.Services/Jobs/StoreBackup.cs | 117 +++++++++--------- PlexRequests.Services/Jobs/StoreCleanup.cs | 82 ++++++++++++ .../PlexRequests.Services.csproj | 1 + PlexRequests.UI/Jobs/Scheduler.cs | 14 ++- 6 files changed, 176 insertions(+), 63 deletions(-) create mode 100644 PlexRequests.Services/Jobs/StoreCleanup.cs diff --git a/PlexRequests.Core/Setup.cs b/PlexRequests.Core/Setup.cs index 740bc3df1..4c6128259 100644 --- a/PlexRequests.Core/Setup.cs +++ b/PlexRequests.Core/Setup.cs @@ -53,7 +53,7 @@ public string SetupDb(string urlBase) { CreateDefaultSettingsPage(urlBase); } - + var version = CheckSchema(); if (version > 0) { @@ -77,7 +77,7 @@ private int CheckSchema() { var productVersion = AssemblyHelper.GetProductVersion(); var trimStatus = new Regex("[^0-9]", RegexOptions.Compiled).Replace(productVersion, string.Empty).PadRight(4, '0'); - var version = int.Parse(trimStatus); + var version = int.Parse(trimStatus); var connection = Db.DbConnection(); var schema = connection.GetSchemaVersion(); @@ -181,6 +181,7 @@ public void MigrateToVersion1700() /// /// Migrates to version 1.8. /// This includes updating the admin account to have all roles. + /// Set the log level to info /// private void MigrateToVersion1800() { @@ -203,6 +204,23 @@ private void MigrateToVersion1800() throw; } + try + { + var settingsService = new SettingsServiceV2(new SettingsJsonRepository(Db, new MemoryCacheProvider())); + var logSettings = settingsService.GetSettings(); + logSettings.Level = LogLevel.Info.Ordinal; + settingsService.SaveSettings(logSettings); + + LoggingHelper.ReconfigureLogLevel(LogLevel.FromOrdinal(logSettings.Level)); + + } + catch (Exception e) + { + Log.Error(e); + throw; + } + + } } } diff --git a/PlexRequests.Services/Jobs/JobNames.cs b/PlexRequests.Services/Jobs/JobNames.cs index d996ac01e..ff6791d92 100644 --- a/PlexRequests.Services/Jobs/JobNames.cs +++ b/PlexRequests.Services/Jobs/JobNames.cs @@ -24,7 +24,7 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // ************************************************************************/ #endregion -namespace PlexRequests.Services +namespace PlexRequests.Services.Jobs { public static class JobNames { @@ -33,5 +33,6 @@ public static class JobNames public const string SonarrCacher = "Sonarr Cacher"; public const string SrCacher = "SickRage Cacher"; public const string PlexChecker = "Plex Availability Cacher"; + public const string StoreCleanup = "Database Cleanup"; } } \ No newline at end of file diff --git a/PlexRequests.Services/Jobs/StoreBackup.cs b/PlexRequests.Services/Jobs/StoreBackup.cs index 1009e0daf..e36f73eb4 100644 --- a/PlexRequests.Services/Jobs/StoreBackup.cs +++ b/PlexRequests.Services/Jobs/StoreBackup.cs @@ -26,15 +26,11 @@ #endregion using System; using System.IO; -using System.Linq; -using System.Globalization; using NLog; using PlexRequests.Services.Interfaces; using PlexRequests.Store; -using PlexRequests.Store.Models; -using PlexRequests.Store.Repository; using Quartz; @@ -57,7 +53,7 @@ public StoreBackup(ISqliteConfiguration sql, IJobRecord rec) public void Execute(IJobExecutionContext context) { TakeBackup(); - Cleanup (); + Cleanup(); } private void TakeBackup() @@ -81,11 +77,11 @@ private void TakeBackup() try { - if(DoWeNeedToBackup(backupDir.FullName)) - { - File.Copy(dbPath, Path.Combine(backupDir.FullName, $"PlexRequests.sqlite_{DateTime.Now.ToString("yyyy-MM-dd hh.mm.ss")}.bak")); - } - } + if (DoWeNeedToBackup(backupDir.FullName)) + { + File.Copy(dbPath, Path.Combine(backupDir.FullName, $"PlexRequests.sqlite_{DateTime.Now.ToString("yyyy-MM-dd hh.mm.ss")}.bak")); + } + } catch (Exception e) { Log.Warn(e); @@ -98,53 +94,58 @@ private void TakeBackup() } - private void Cleanup() - { - Log.Trace("Starting DB Cleanup"); - var dbPath = Sql.CurrentPath; - var dir = Path.GetDirectoryName(dbPath); - if (dir == null) - { - Log.Warn("We couldn't find the DB path. We cannot backup."); - return; - } - var backupDir = Directory.CreateDirectory(Path.Combine(dir, "Backup")); - - var files = backupDir.GetFiles(); - - foreach (var file in files) { - var dt = ParseName(file.Name); - if(dt < DateTime.Now.AddDays(-7)){ - try { - - File.Delete(file.FullName); - } catch (Exception ex) { - Log.Error(ex); - } - } - } - - } - - private bool DoWeNeedToBackup(string backupPath) - { - var files = Directory.GetFiles(backupPath); - //TODO Get the latest file and if it's within an hour of DateTime.Now then don't bother backing up. - return true; - } - - private DateTime ParseName(string fileName) - { - var names = fileName.Split(new []{'_','.',' '}, StringSplitOptions.RemoveEmptyEntries); - if(names.Count() > 1) - { - DateTime parsed; - //DateTime.TryParseExcat(names[1], "yyyy-MM-dd hh.mm.ss",CultureInfo.CurrentUICulture, DateTimeStyles.None, out parsed); - DateTime.TryParse(names[2], out parsed); - return parsed; - - } - return DateTime.MinValue; - } + private void Cleanup() + { + Log.Trace("Starting DB Cleanup"); + var dbPath = Sql.CurrentPath; + var dir = Path.GetDirectoryName(dbPath); + if (dir == null) + { + Log.Warn("We couldn't find the DB path. We cannot backup."); + return; + } + var backupDir = Directory.CreateDirectory(Path.Combine(dir, "Backup")); + + var files = backupDir.GetFiles(); + + foreach (var file in files) + { + var dt = ParseName(file.Name); + if (dt < DateTime.Now.AddDays(-7)) + { + try + { + + File.Delete(file.FullName); + } + catch (Exception ex) + { + Log.Error(ex); + } + } + } + + } + + private bool DoWeNeedToBackup(string backupPath) + { + var files = Directory.GetFiles(backupPath); + //TODO Get the latest file and if it's within an hour of DateTime.Now then don't bother backing up. + return true; + } + + private DateTime ParseName(string fileName) + { + var names = fileName.Split(new[] { '_', '.', ' ' }, StringSplitOptions.RemoveEmptyEntries); + if (names.Length > 1) + { + DateTime parsed; + //DateTime.TryParseExcat(names[1], "yyyy-MM-dd hh.mm.ss",CultureInfo.CurrentUICulture, DateTimeStyles.None, out parsed); + DateTime.TryParse(names[2], out parsed); + return parsed; + + } + return DateTime.MinValue; + } } } \ No newline at end of file diff --git a/PlexRequests.Services/Jobs/StoreCleanup.cs b/PlexRequests.Services/Jobs/StoreCleanup.cs new file mode 100644 index 000000000..a394211f5 --- /dev/null +++ b/PlexRequests.Services/Jobs/StoreCleanup.cs @@ -0,0 +1,82 @@ +#region Copyright +// /************************************************************************ +// Copyright (c) 2016 Jamie Rees +// File: StoreCleanup.cs +// Created By: Jamie Rees +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// ************************************************************************/ +#endregion +using System; +using System.Linq; + +using NLog; + +using PlexRequests.Services.Interfaces; +using PlexRequests.Store.Models; +using PlexRequests.Store.Repository; + +using Quartz; + +namespace PlexRequests.Services.Jobs +{ + public class StoreCleanup : IJob + { + private static readonly Logger Log = LogManager.GetCurrentClassLogger(); + + public StoreCleanup(IRepository repo, IJobRecord rec) + { + Repo = repo; + JobRecord = rec; + } + + private IJobRecord JobRecord { get; } + + private IRepository Repo { get; } + + private void Cleanup() + { + try + { + var items = Repo.GetAll(); + var orderedItems = items.Where(x => x.Date < DateTime.Now.AddDays(-7)); + + foreach (var o in orderedItems) + { + Repo.Delete(o); + } + } + catch (Exception e) + { + Log.Error(e); + } + finally + { + JobRecord.Record(JobNames.StoreCleanup); + } + + } + + public void Execute(IJobExecutionContext context) + { + Cleanup(); + } + } +} \ No newline at end of file diff --git a/PlexRequests.Services/PlexRequests.Services.csproj b/PlexRequests.Services/PlexRequests.Services.csproj index 257fc5b7e..caafe8d77 100644 --- a/PlexRequests.Services/PlexRequests.Services.csproj +++ b/PlexRequests.Services/PlexRequests.Services.csproj @@ -73,6 +73,7 @@ + diff --git a/PlexRequests.UI/Jobs/Scheduler.cs b/PlexRequests.UI/Jobs/Scheduler.cs index 0ccae710b..63ffe8b64 100644 --- a/PlexRequests.UI/Jobs/Scheduler.cs +++ b/PlexRequests.UI/Jobs/Scheduler.cs @@ -56,13 +56,15 @@ private IEnumerable CreateJobs() var sickrage = JobBuilder.Create().WithIdentity("SickRageCacher", "Cache").Build(); var sonarr = JobBuilder.Create().WithIdentity("SonarrCacher", "Cache").Build(); var cp = JobBuilder.Create().WithIdentity("CouchPotatoCacher", "Cache").Build(); - var store = JobBuilder.Create().WithIdentity("StoreBackup", "Backup").Build(); + var store = JobBuilder.Create().WithIdentity("StoreBackup", "Database").Build(); + var storeClean = JobBuilder.Create().WithIdentity("StoreCleanup", "Database").Build(); jobs.Add(plex); jobs.Add(sickrage); jobs.Add(sonarr); jobs.Add(cp); jobs.Add(store); + jobs.Add(storeClean); return jobs; } @@ -129,17 +131,25 @@ private IEnumerable CreateTriggers() var storeBackup = TriggerBuilder.Create() - .WithIdentity("StoreBackup", "Backup") + .WithIdentity("StoreBackup", "Database") .StartNow() .WithSimpleSchedule(x => x.WithIntervalInHours(24).RepeatForever()) .Build(); + var storeCleanup = + TriggerBuilder.Create() + .WithIdentity("StoreCleanup", "Database") + .StartNow() + .WithSimpleSchedule(x => x.WithIntervalInHours(24).RepeatForever()) + .Build(); + triggers.Add(plexAvailabilityChecker); triggers.Add(srCacher); triggers.Add(sonarrCacher); triggers.Add(cpCacher); triggers.Add(storeBackup); + triggers.Add(storeCleanup); return triggers; } From e3cd016dc7bbca92f29b2bb61bb02d9ca1f7e6db Mon Sep 17 00:00:00 2001 From: tidusjar Date: Fri, 27 May 2016 14:04:40 +0100 Subject: [PATCH 15/26] Updater wouldn't work when running a reverse proxy #236 --- PlexRequests.UI/Content/requests-1.7.js | 2 +- PlexRequests.UI/Views/Admin/Status.cshtml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/PlexRequests.UI/Content/requests-1.7.js b/PlexRequests.UI/Content/requests-1.7.js index 5438310f1..453c6d7cb 100644 --- a/PlexRequests.UI/Content/requests-1.7.js +++ b/PlexRequests.UI/Content/requests-1.7.js @@ -190,7 +190,7 @@ $('#deleteTVShows').click(function (e) { return; } - loadingButton(buttonId, "success"); + loadingButton(buttonId, "warning"); var url = createBaseUrl(base, '/approval/deletealltvshows'); $.ajax({ type: 'post', diff --git a/PlexRequests.UI/Views/Admin/Status.cshtml b/PlexRequests.UI/Views/Admin/Status.cshtml index eb5f1b743..efea96a0f 100644 --- a/PlexRequests.UI/Views/Admin/Status.cshtml +++ b/PlexRequests.UI/Views/Admin/Status.cshtml @@ -54,10 +54,10 @@ var dots = new Array(count % 10).join('.'); document.getElementById('autoUpdate').innerHTML = "Updating" + dots; }, 1000); - var url = createBaseUrl(base, "autoupdate"); + $.ajax({ type: "Post", - url: url, + url: "autoupdate", data: { url: "@Model.DownloadUri" }, dataType: "json", error: function () { From 8550cc4c5ef6a467505dede7861c54bdf8c17dc9 Mon Sep 17 00:00:00 2001 From: tidusjar Date: Fri, 27 May 2016 14:31:47 +0100 Subject: [PATCH 16/26] Made some of the searching async #278 --- PlexRequests.UI/Modules/SearchModule.cs | 165 +++++++++++------------- 1 file changed, 78 insertions(+), 87 deletions(-) diff --git a/PlexRequests.UI/Modules/SearchModule.cs b/PlexRequests.UI/Modules/SearchModule.cs index d84447477..f517a1387 100644 --- a/PlexRequests.UI/Modules/SearchModule.cs +++ b/PlexRequests.UI/Modules/SearchModule.cs @@ -47,7 +47,7 @@ using PlexRequests.UI.Helpers; using PlexRequests.UI.Models; using System.Threading.Tasks; -using System.Windows.Forms; + using Nancy.Extensions; using PlexRequests.Api.Models.Tv; using PlexRequests.Store.Models; @@ -94,13 +94,13 @@ public SearchModule(ICacheProvider cache, ISettingsService Get["/"] = parameters => RequestLoad(); - Get["movie/{searchTerm}"] = parameters => SearchMovie((string)parameters.searchTerm); - Get["tv/{searchTerm}"] = parameters => SearchTvShow((string)parameters.searchTerm); - Get["music/{searchTerm}"] = parameters => SearchMusic((string)parameters.searchTerm); + Get["movie/{searchTerm}", true] = async (x, ct) => await SearchMovie((string)x.searchTerm); + Get["tv/{searchTerm}", true] = async (x, ct) => await SearchTvShow((string)x.searchTerm); + Get["music/{searchTerm}", true] = async (x, ct) => await SearchMusic((string)x.searchTerm); Get["music/coverArt/{id}"] = p => GetMusicBrainzCoverArt((string)p.id); - Get["movie/upcoming"] = parameters => UpcomingMovies(); - Get["movie/playing"] = parameters => CurrentlyPlayingMovies(); + Get["movie/upcoming", true] = async (x, ct) => await UpcomingMovies(); + Get["movie/playing", true] = async (x, ct) => await CurrentlyPlayingMovies(); Post["request/movie"] = parameters => RequestMovie((int)Request.Form.movieId); Post["request/tv"] = parameters => RequestTvShow((int)Request.Form.tvId, (string)Request.Form.seasons); @@ -144,75 +144,80 @@ private Negotiator RequestLoad() return View["Search/Index", settings]; } - private Response UpcomingMovies() + private async Task UpcomingMovies() { Log.Trace("Loading upcoming movies"); - return ProcessMovies(MovieSearchType.Upcoming, string.Empty); + return await ProcessMovies(MovieSearchType.Upcoming, string.Empty); } - private Response CurrentlyPlayingMovies() + private async Task CurrentlyPlayingMovies() { Log.Trace("Loading currently playing movies"); - return ProcessMovies(MovieSearchType.CurrentlyPlaying, string.Empty); + return await ProcessMovies(MovieSearchType.CurrentlyPlaying, string.Empty); } - private Response SearchMovie(string searchTerm) + private async Task SearchMovie(string searchTerm) { Log.Trace("Searching for Movie {0}", searchTerm); - return ProcessMovies(MovieSearchType.Search, searchTerm); + return await ProcessMovies(MovieSearchType.Search, searchTerm); } - private Response ProcessMovies(MovieSearchType searchType, string searchTerm) + private async Task ProcessMovies(MovieSearchType searchType, string searchTerm) { - var taskList = new List(); + var apiMovies = new List(); - taskList.Add(Task.Factory.StartNew(() => - { - switch (searchType) + await Task.Factory.StartNew( + () => { - case MovieSearchType.Search: - return MovieApi.SearchMovie(searchTerm).Result.Select(x => new MovieResult() - { - Adult = x.Adult, - BackdropPath = x.BackdropPath, - GenreIds = x.GenreIds, - Id = x.Id, - OriginalLanguage = x.OriginalLanguage, - OriginalTitle = x.OriginalTitle, - Overview = x.Overview, - Popularity = x.Popularity, - PosterPath = x.PosterPath, - ReleaseDate = x.ReleaseDate, - Title = x.Title, - Video = x.Video, - VoteAverage = x.VoteAverage, - VoteCount = x.VoteCount - }).ToList(); - case MovieSearchType.CurrentlyPlaying: - return MovieApi.GetCurrentPlayingMovies().Result.ToList(); - case MovieSearchType.Upcoming: - return MovieApi.GetUpcomingMovies().Result.ToList(); - default: - return new List(); - } - }).ContinueWith((t) => - { - apiMovies = t.Result; - })); + switch (searchType) + { + case MovieSearchType.Search: + return + MovieApi.SearchMovie(searchTerm) + .Result.Select( + x => + new MovieResult() + { + Adult = x.Adult, + BackdropPath = x.BackdropPath, + GenreIds = x.GenreIds, + Id = x.Id, + OriginalLanguage = x.OriginalLanguage, + OriginalTitle = x.OriginalTitle, + Overview = x.Overview, + Popularity = x.Popularity, + PosterPath = x.PosterPath, + ReleaseDate = x.ReleaseDate, + Title = x.Title, + Video = x.Video, + VoteAverage = x.VoteAverage, + VoteCount = x.VoteCount + }) + .ToList(); + case MovieSearchType.CurrentlyPlaying: + return MovieApi.GetCurrentPlayingMovies().Result.ToList(); + case MovieSearchType.Upcoming: + return MovieApi.GetUpcomingMovies().Result.ToList(); + default: + return new List(); + } + }).ContinueWith( + (t) => + { + apiMovies = t.Result; + }); Dictionary dbMovies = new Dictionary(); - taskList.Add(Task.Factory.StartNew(() => - { - return RequestService.GetAll().Where(x => x.Type == RequestType.Movie); + await Task.Factory.StartNew(() => + { + return RequestService.GetAll().Where(x => x.Type == RequestType.Movie); - }).ContinueWith((t) => - { - var distinctResults = t.Result.DistinctBy(x => x.ProviderId); - dbMovies = distinctResults.ToDictionary(x => x.ProviderId); - })); - - Task.WaitAll(taskList.ToArray()); + }).ContinueWith((t) => + { + var distinctResults = t.Result.DistinctBy(x => x.ProviderId); + dbMovies = distinctResults.ToDictionary(x => x.ProviderId); + }); var cpCached = CpCacher.QueuedIds(); var plexMovies = Checker.GetPlexMovies(); @@ -272,33 +277,25 @@ private bool CanUserSeeThisRequest(int movieId, bool usersCanViewOnlyOwnRequests return true; } - private Response SearchTvShow(string searchTerm) + private async Task SearchTvShow(string searchTerm) { Log.Trace("Searching for TV Show {0}", searchTerm); - var taskList = new List(); - var apiTv = new List(); - taskList.Add(Task.Factory.StartNew(() => - { - return new TvMazeApi().Search(searchTerm); - - }).ContinueWith((t) => + await Task.Factory.StartNew(() => new TvMazeApi().Search(searchTerm)).ContinueWith((t) => { apiTv = t.Result; - })); + }); var dbTv = new Dictionary(); - taskList.Add(Task.Factory.StartNew(() => + await Task.Factory.StartNew(() => { return RequestService.GetAll().Where(x => x.Type == RequestType.TvShow); }).ContinueWith((t) => { dbTv = t.Result.ToDictionary(x => x.ProviderId); - })); - - Task.WaitAll(taskList.ToArray()); + }); if (!apiTv.Any()) { @@ -361,31 +358,25 @@ private Response SearchTvShow(string searchTerm) return Response.AsJson(viewTv); } - private Response SearchMusic(string searchTerm) + private async Task SearchMusic(string searchTerm) { - var taskList = new List(); - var apiAlbums = new List(); - taskList.Add(Task.Factory.StartNew(() => - { - return MusicBrainzApi.SearchAlbum(searchTerm); - - }).ContinueWith((t) => + await Task.Factory.StartNew(() => MusicBrainzApi.SearchAlbum(searchTerm)).ContinueWith((t) => { apiAlbums = t.Result.releases ?? new List(); - })); + }); var dbAlbum = new Dictionary(); - taskList.Add(Task.Factory.StartNew(() => - { - return RequestService.GetAll().Where(x => x.Type == RequestType.Album); + await Task.Factory.StartNew(() => + { + return RequestService.GetAll().Where(x => x.Type == RequestType.Album); + + }).ContinueWith((t) => + { + dbAlbum = t.Result.ToDictionary(x => x.MusicBrainzId); + }); - }).ContinueWith((t) => - { - dbAlbum = t.Result.ToDictionary(x => x.MusicBrainzId); - })); - Task.WaitAll(taskList.ToArray()); var plexAlbums = Checker.GetPlexAlbums(); @@ -935,7 +926,7 @@ private Response NotifyUser(bool notify) var email = EmailNotificationSettings.GetSettings().EnableUserEmailNotifications; if (!auth) { - return Response.AsJson(new JsonResponseModel { Result = false, Message = "Sorry, but this functionality is currently only for users with Plex accounts"}); + return Response.AsJson(new JsonResponseModel { Result = false, Message = "Sorry, but this functionality is currently only for users with Plex accounts" }); } if (!email) { From 166e0f81cf2ab3f46f20999fc4ddd13a1d066d38 Mon Sep 17 00:00:00 2001 From: tidusjar Date: Fri, 27 May 2016 15:07:07 +0100 Subject: [PATCH 17/26] Made more async goodness --- PlexRequests.Core/IRequestService.cs | 7 ++ PlexRequests.Core/JsonRequestService.cs | 45 ++++++++++ PlexRequests.Helpers/ICacheProvider.cs | 2 + PlexRequests.Helpers/MemoryCacheProvider.cs | 18 ++++ .../Repository/IRequestRepository.cs | 10 +++ .../Repository/RequestJsonRepository.cs | 87 +++++++++++++++++++ PlexRequests.UI/Modules/SearchModule.cs | 42 +++------ 7 files changed, 181 insertions(+), 30 deletions(-) diff --git a/PlexRequests.Core/IRequestService.cs b/PlexRequests.Core/IRequestService.cs index cd8427ac5..dabade7ae 100644 --- a/PlexRequests.Core/IRequestService.cs +++ b/PlexRequests.Core/IRequestService.cs @@ -26,6 +26,8 @@ #endregion using System.Collections.Generic; +using System.Threading.Tasks; + using PlexRequests.Store; namespace PlexRequests.Core @@ -33,13 +35,18 @@ namespace PlexRequests.Core public interface IRequestService { long AddRequest(RequestedModel model); + Task AddRequestAsync(RequestedModel model); RequestedModel CheckRequest(int providerId); RequestedModel CheckRequest(string musicId); void DeleteRequest(RequestedModel request); + Task DeleteRequestAsync(RequestedModel request); bool UpdateRequest(RequestedModel model); + Task UpdateRequestAsync(RequestedModel model); RequestedModel Get(int id); + Task GetAsync(int id); IEnumerable GetAll(); + Task> GetAllAsync(); bool BatchUpdate(List model); bool BatchDelete(List model); } diff --git a/PlexRequests.Core/JsonRequestService.cs b/PlexRequests.Core/JsonRequestService.cs index 770b41444..5a5ec2e4f 100644 --- a/PlexRequests.Core/JsonRequestService.cs +++ b/PlexRequests.Core/JsonRequestService.cs @@ -27,6 +27,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; +using System.Threading.Tasks; using Newtonsoft.Json; @@ -57,6 +58,19 @@ public long AddRequest(RequestedModel model) return result ? id : -1; } + public async Task AddRequestAsync(RequestedModel model) + { + var entity = new RequestBlobs { Type = model.Type, Content = ByteConverterHelper.ReturnBytes(model), ProviderId = model.ProviderId }; + var id = await Repo.InsertAsync(entity); + + model.Id = id; + + entity = new RequestBlobs { Type = model.Type, Content = ByteConverterHelper.ReturnBytes(model), ProviderId = model.ProviderId, Id = id, MusicId = model.MusicBrainzId }; + var result = await Repo.UpdateAsync(entity); + + return result ? id : -1; + } + public RequestedModel CheckRequest(int providerId) { var blobs = Repo.GetAll(); @@ -77,12 +91,24 @@ public void DeleteRequest(RequestedModel request) Repo.Delete(blob); } + public async Task DeleteRequestAsync(RequestedModel request) + { + var blob = await Repo.GetAsync(request.Id); + await Repo.DeleteAsync(blob); + } + public bool UpdateRequest(RequestedModel model) { var entity = new RequestBlobs { Type = model.Type, Content = ByteConverterHelper.ReturnBytes(model), ProviderId = model.ProviderId, Id = model.Id }; return Repo.Update(entity); } + public async Task UpdateRequestAsync(RequestedModel model) + { + var entity = new RequestBlobs { Type = model.Type, Content = ByteConverterHelper.ReturnBytes(model), ProviderId = model.ProviderId, Id = model.Id }; + return await Repo.UpdateAsync(entity); + } + public RequestedModel Get(int id) { var blob = Repo.Get(id); @@ -94,6 +120,17 @@ public RequestedModel Get(int id) return model; } + public async Task GetAsync(int id) + { + var blob = await Repo.GetAsync(id); + if (blob == null) + { + return new RequestedModel(); + } + var model = ByteConverterHelper.ReturnObject(blob.Content); + return model; + } + public IEnumerable GetAll() { var blobs = Repo.GetAll(); @@ -102,6 +139,14 @@ public IEnumerable GetAll() .ToList(); } + public async Task> GetAllAsync() + { + var blobs = await Repo.GetAllAsync(); + return blobs.Select(b => Encoding.UTF8.GetString(b.Content)) + .Select(JsonConvert.DeserializeObject) + .ToList(); + } + public bool BatchUpdate(List model) { var entities = model.Select(m => new RequestBlobs { Type = m.Type, Content = ByteConverterHelper.ReturnBytes(m), ProviderId = m.ProviderId, Id = m.Id }).ToList(); diff --git a/PlexRequests.Helpers/ICacheProvider.cs b/PlexRequests.Helpers/ICacheProvider.cs index fa957315d..00fde411b 100644 --- a/PlexRequests.Helpers/ICacheProvider.cs +++ b/PlexRequests.Helpers/ICacheProvider.cs @@ -25,6 +25,7 @@ // ************************************************************************/ #endregion using System; +using System.Threading.Tasks; namespace PlexRequests.Helpers { @@ -40,6 +41,7 @@ public interface ICacheProvider /// The amount of time we want to cache the object /// T GetOrSet(string key, Func itemCallback, int cacheTime = 20) where T : class; + Task GetOrSetAsync(string key, Func> itemCallback, int cacheTime = 20) where T : class; /// /// Gets the specified item from the cache. diff --git a/PlexRequests.Helpers/MemoryCacheProvider.cs b/PlexRequests.Helpers/MemoryCacheProvider.cs index fdb78f291..c85ef40f0 100644 --- a/PlexRequests.Helpers/MemoryCacheProvider.cs +++ b/PlexRequests.Helpers/MemoryCacheProvider.cs @@ -27,6 +27,7 @@ using System; using System.Linq; using System.Runtime.Caching; +using System.Threading.Tasks; namespace PlexRequests.Helpers { @@ -65,6 +66,23 @@ public T GetOrSet(string key, Func itemCallback, int cacheTime = 20) where return item.CloneJson(); } + public async Task GetOrSetAsync(string key, Func> itemCallback, int cacheTime = 20) where T : class + { + var item = Get(key); + if (item == null) + { + item = await itemCallback(); + if (item != null) + { + Set(key, item, cacheTime); + } + } + + // Return a copy, not the stored cache reference + // The cached object will not change + return item.CloneJson(); + } + /// /// Gets the specified item from the cache. /// diff --git a/PlexRequests.Store/Repository/IRequestRepository.cs b/PlexRequests.Store/Repository/IRequestRepository.cs index 650dc9b4b..440fe715e 100644 --- a/PlexRequests.Store/Repository/IRequestRepository.cs +++ b/PlexRequests.Store/Repository/IRequestRepository.cs @@ -25,6 +25,7 @@ // ************************************************************************/ #endregion using System.Collections.Generic; +using System.Threading.Tasks; using PlexRequests.Store.Models; @@ -38,13 +39,18 @@ public interface IRequestRepository /// The entity. long Insert(RequestBlobs entity); + Task InsertAsync(RequestBlobs entity); + /// /// Gets all. /// /// IEnumerable GetAll(); + Task> GetAllAsync(); + RequestBlobs Get(int id); + Task GetAsync(int id); /// /// Deletes the specified entity. @@ -52,8 +58,10 @@ public interface IRequestRepository /// The entity. /// bool Delete(RequestBlobs entity); + Task DeleteAsync(RequestBlobs entity); bool DeleteAll(IEnumerable entity); + Task DeleteAllAsync(IEnumerable entity); /// /// Updates the specified entity. @@ -61,7 +69,9 @@ public interface IRequestRepository /// The entity. /// bool Update(RequestBlobs entity); + Task UpdateAsync(RequestBlobs entity); bool UpdateAll(IEnumerable entity); + Task UpdateAllAsync(IEnumerable entity); } } \ No newline at end of file diff --git a/PlexRequests.Store/Repository/RequestJsonRepository.cs b/PlexRequests.Store/Repository/RequestJsonRepository.cs index bad8736da..07ac3c0bd 100644 --- a/PlexRequests.Store/Repository/RequestJsonRepository.cs +++ b/PlexRequests.Store/Repository/RequestJsonRepository.cs @@ -26,6 +26,7 @@ #endregion using System.Collections.Generic; using System.Linq; +using System.Threading.Tasks; using Dapper.Contrib.Extensions; @@ -56,6 +57,16 @@ public long Insert(RequestBlobs entity) } } + public async Task InsertAsync(RequestBlobs entity) + { + ResetCache(); + using (var con = Db.DbConnection()) + { + var id = await con.InsertAsync(entity); + return id; + } + } + public IEnumerable GetAll() { var key = "GetAll"; @@ -70,6 +81,20 @@ public IEnumerable GetAll() return item; } + public async Task> GetAllAsync() + { + var key = "GetAll"; + var item = await Cache.GetOrSetAsync(key, async() => + { + using (var con = Db.DbConnection()) + { + var page = await con.GetAllAsync(); + return page; + } + }, 5); + return item; + } + public RequestBlobs Get(int id) { var key = "Get" + id; @@ -84,6 +109,20 @@ public RequestBlobs Get(int id) return item; } + public async Task GetAsync(int id) + { + var key = "Get" + id; + var item = await Cache.GetOrSetAsync(key, async () => + { + using (var con = Db.DbConnection()) + { + var page = await con.GetAsync(id); + return page; + } + }, 5); + return item; + } + public bool Delete(RequestBlobs entity) { ResetCache(); @@ -93,6 +132,30 @@ public bool Delete(RequestBlobs entity) } } + public async Task DeleteAsync(RequestBlobs entity) + { + ResetCache(); + using (var con = Db.DbConnection()) + { + return await con.DeleteAsync(entity); + } + } + + public async Task DeleteAllAsync(IEnumerable entity) + { + ResetCache(); + var result = new HashSet(); + using (var db = Db.DbConnection()) + { + db.Open(); + foreach (var e in entity) + { + result.Add(await db.DeleteAsync(e)); + } + } + return result.All(x => true); + } + public bool Update(RequestBlobs entity) { ResetCache(); @@ -102,6 +165,15 @@ public bool Update(RequestBlobs entity) } } + public async Task UpdateAsync(RequestBlobs entity) + { + ResetCache(); + using (var con = Db.DbConnection()) + { + return await con.UpdateAsync(entity); + } + } + private void ResetCache() { Cache.Remove("Get"); @@ -123,6 +195,21 @@ public bool UpdateAll(IEnumerable entity) return result.All(x => true); } + public async Task UpdateAllAsync(IEnumerable entity) + { + ResetCache(); + var result = new HashSet(); + using (var db = Db.DbConnection()) + { + db.Open(); + foreach (var e in entity) + { + result.Add(await db.UpdateAsync(e)); + } + } + return result.All(x => true); + } + public bool DeleteAll(IEnumerable entity) { ResetCache(); diff --git a/PlexRequests.UI/Modules/SearchModule.cs b/PlexRequests.UI/Modules/SearchModule.cs index f517a1387..0979c1c6a 100644 --- a/PlexRequests.UI/Modules/SearchModule.cs +++ b/PlexRequests.UI/Modules/SearchModule.cs @@ -164,8 +164,6 @@ private async Task SearchMovie(string searchTerm) private async Task ProcessMovies(MovieSearchType searchType, string searchTerm) { - - var apiMovies = new List(); await Task.Factory.StartNew( () => @@ -208,16 +206,12 @@ await Task.Factory.StartNew( apiMovies = t.Result; }); - Dictionary dbMovies = new Dictionary(); - await Task.Factory.StartNew(() => - { - return RequestService.GetAll().Where(x => x.Type == RequestType.Movie); + var allResults = await RequestService.GetAllAsync(); + allResults = allResults.Where(x => x.Type == RequestType.Movie); + + var distinctResults = allResults.DistinctBy(x => x.ProviderId); + var dbMovies = distinctResults.ToDictionary(x => x.ProviderId); - }).ContinueWith((t) => - { - var distinctResults = t.Result.DistinctBy(x => x.ProviderId); - dbMovies = distinctResults.ToDictionary(x => x.ProviderId); - }); var cpCached = CpCacher.QueuedIds(); var plexMovies = Checker.GetPlexMovies(); @@ -287,15 +281,10 @@ private async Task SearchTvShow(string searchTerm) apiTv = t.Result; }); - var dbTv = new Dictionary(); - await Task.Factory.StartNew(() => - { - return RequestService.GetAll().Where(x => x.Type == RequestType.TvShow); + var allResults = await RequestService.GetAllAsync(); + allResults = allResults.Where(x => x.Type == RequestType.TvShow); - }).ContinueWith((t) => - { - dbTv = t.Result.ToDictionary(x => x.ProviderId); - }); + var dbTv = allResults.ToDictionary(x => x.ProviderId); if (!apiTv.Any()) { @@ -366,18 +355,11 @@ await Task.Factory.StartNew(() => MusicBrainzApi.SearchAlbum(searchTerm)).Contin apiAlbums = t.Result.releases ?? new List(); }); - var dbAlbum = new Dictionary(); - await Task.Factory.StartNew(() => - { - return RequestService.GetAll().Where(x => x.Type == RequestType.Album); - - }).ContinueWith((t) => - { - dbAlbum = t.Result.ToDictionary(x => x.MusicBrainzId); - }); - - + var allResults = await RequestService.GetAllAsync(); + allResults = allResults.Where(x => x.Type == RequestType.Album); + var dbAlbum = allResults.ToDictionary(x => x.MusicBrainzId); + var plexAlbums = Checker.GetPlexAlbums(); var viewAlbum = new List(); From a728becc32f7c23b1ff5a7677d1348d3dd9e9494 Mon Sep 17 00:00:00 2001 From: tidusjar Date: Fri, 27 May 2016 15:18:27 +0100 Subject: [PATCH 18/26] Stop dumping out the settings to the log. --- PlexRequests.UI/Modules/AdminModule.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/PlexRequests.UI/Modules/AdminModule.cs b/PlexRequests.UI/Modules/AdminModule.cs index c62b7ff46..bdf0248a6 100644 --- a/PlexRequests.UI/Modules/AdminModule.cs +++ b/PlexRequests.UI/Modules/AdminModule.cs @@ -481,8 +481,7 @@ private Response SaveEmailNotifications() { return Response.AsJson(valid.SendJsonError()); } - Log.Trace(settings.DumpJson()); - + var result = EmailService.SaveSettings(settings); if (settings.Enabled) From e9d74a3d765ab7ac6cb87b7938763676ff434ec0 Mon Sep 17 00:00:00 2001 From: tidusjar Date: Fri, 27 May 2016 17:32:01 +0100 Subject: [PATCH 19/26] Started some dynamic scrolling. --- PlexRequests.UI/Content/requests-1.7.js | 50 ++++++- PlexRequests.UI/Modules/RequestsModule.cs | 174 ++++++++++++++-------- 2 files changed, 159 insertions(+), 65 deletions(-) diff --git a/PlexRequests.UI/Content/requests-1.7.js b/PlexRequests.UI/Content/requests-1.7.js index 453c6d7cb..84c0e5d49 100644 --- a/PlexRequests.UI/Content/requests-1.7.js +++ b/PlexRequests.UI/Content/requests-1.7.js @@ -514,8 +514,10 @@ function mixItUpConfig(activeState) { return conf; }; +var position = 0; function initLoad() { - movieLoad(); + //movieLoad(); + movieLoadWithPosition(0); tvLoad(); albumLoad(); } @@ -544,6 +546,52 @@ function movieLoad() { }); }; +function movieLoadWithPosition(pos) { + var $ml = $('#movieList'); + if ($ml.mixItUp('isLoaded')) { + activeState = $ml.mixItUp('getState'); + $ml.mixItUp('destroy'); + } + + var url = createBaseUrl(base, '/requests/movies/'+pos); + $.ajax(url).success(function (results) { + if (results.length > 0) { + position++; + results.forEach(function (result) { + var context = buildRequestContext(result, "movie"); + var html = searchTemplate(context); + $ml.append(html); + }); + } + else { + $ml.append(noResultsHtml.format("movie")); + } + $ml.mixItUp(mixItUpConfig()); + }); +}; + +var win = $(window); + +$(win).scroll(function () { + if ($(win).scrollTop() + $(win).height() >= $(document).height() - 100) { + // Debounce the scroll event + if (this.timeoutId) + win.clearTimeout(this.timeoutId); + this.timeoutId = win.setTimeout(function () { + movieLoadWithPosition(position); + }, 200); + } +}); +//// Each time the user scrolls +//win.scroll(function () { +// // End of the document reached? +// if ($(document).height() - win.height() == win.scrollTop()) { +// $('#loading').show(); + +// movieLoadWithPosition(position); +// } +//}); + function tvLoad() { var $tvl = $('#tvList'); if ($tvl.mixItUp('isLoaded')) { diff --git a/PlexRequests.UI/Modules/RequestsModule.cs b/PlexRequests.UI/Modules/RequestsModule.cs index 64e150f58..460ac964b 100644 --- a/PlexRequests.UI/Modules/RequestsModule.cs +++ b/PlexRequests.UI/Modules/RequestsModule.cs @@ -74,7 +74,8 @@ public RequestsModule( Cache = cache; Get["/"] = _ => LoadRequests(); - Get["/movies"] = _ => GetMovies(); + Get["/movies", true] = async (x, ct) => await GetMovies(); + Get["/movies/{position}", true] = async (x, ct) => await GetMovies(x.position); Get["/tvshows"] = _ => GetTvShows(); Get["/albums"] = _ => GetAlbumRequests(); Post["/delete"] = _ => DeleteRequest((int)Request.Form.id); @@ -105,77 +106,61 @@ private Negotiator LoadRequests() return View["Index", settings]; } - private Response GetMovies() // TODO: async await the API calls + private async Task GetMovies() { var settings = PrSettings.GetSettings(); - List taskList = new List(); + var allRequests = await Service.GetAllAsync(); + allRequests = allRequests.Where(x => x.Type == RequestType.Movie); - List dbMovies = new List(); - taskList.Add(Task.Factory.StartNew(() => - { - return Service.GetAll().Where(x => x.Type == RequestType.Movie); + var dbMovies = allRequests.ToList(); - }).ContinueWith((t) => + if (settings.UsersCanViewOnlyOwnRequests && !IsAdmin) { - dbMovies = t.Result.ToList(); - - if (settings.UsersCanViewOnlyOwnRequests && !IsAdmin) - { - dbMovies = dbMovies.Where(x => x.UserHasRequested(Username)).ToList(); - } - })); - + dbMovies = dbMovies.Where(x => x.UserHasRequested(Username)).ToList(); + } List qualities = new List(); - if (IsAdmin) + if (IsAdmin) { var cpSettings = CpSettings.GetSettings(); if (cpSettings.Enabled) { - taskList.Add(Task.Factory.StartNew(() => - { - return Cache.GetOrSet(CacheKeys.CouchPotatoQualityProfiles, () => - { - return CpApi.GetProfiles(cpSettings.FullUri, cpSettings.ApiKey); // TODO: cache this! - }); - }).ContinueWith((t) => + + var result = await Cache.GetOrSetAsync(CacheKeys.CouchPotatoQualityProfiles, async () => { - qualities = t.Result.list.Select(x => new QualityModel() { Id = x._id, Name = x.label }).ToList(); - })); + return await Task.Run(() => CpApi.GetProfiles(cpSettings.FullUri, cpSettings.ApiKey)).ConfigureAwait(false); + }); + + qualities = result.list.Select(x => new QualityModel() { Id = x._id, Name = x.label }).ToList(); } } - Task.WaitAll(taskList.ToArray()); - - var viewModel = dbMovies.Select(movie => + var viewModel = dbMovies.Select(movie => new RequestViewModel { - return new RequestViewModel - { - ProviderId = movie.ProviderId, - Type = movie.Type, - Status = movie.Status, - ImdbId = movie.ImdbId, - Id = movie.Id, - PosterPath = movie.PosterPath, - ReleaseDate = movie.ReleaseDate, - ReleaseDateTicks = movie.ReleaseDate.Ticks, - RequestedDate = movie.RequestedDate, - Released = DateTime.Now > movie.ReleaseDate, - RequestedDateTicks = DateTimeHelper.OffsetUTCDateTime(movie.RequestedDate, DateTimeOffset).Ticks, - Approved = movie.Available || movie.Approved, - Title = movie.Title, - Overview = movie.Overview, - RequestedUsers = IsAdmin ? movie.AllUsers.ToArray() : new string[] { }, - ReleaseYear = movie.ReleaseDate.Year.ToString(), - Available = movie.Available, - Admin = IsAdmin, - Issues = movie.Issues.ToString().CamelCaseToWords(), - OtherMessage = movie.OtherMessage, - AdminNotes = movie.AdminNote, - Qualities = qualities.ToArray() - }; + ProviderId = movie.ProviderId, + Type = movie.Type, + Status = movie.Status, + ImdbId = movie.ImdbId, + Id = movie.Id, + PosterPath = movie.PosterPath, + ReleaseDate = movie.ReleaseDate, + ReleaseDateTicks = movie.ReleaseDate.Ticks, + RequestedDate = movie.RequestedDate, + Released = DateTime.Now > movie.ReleaseDate, + RequestedDateTicks = DateTimeHelper.OffsetUTCDateTime(movie.RequestedDate, DateTimeOffset).Ticks, + Approved = movie.Available || movie.Approved, + Title = movie.Title, + Overview = movie.Overview, + RequestedUsers = IsAdmin ? movie.AllUsers.ToArray() : new string[] { }, + ReleaseYear = movie.ReleaseDate.Year.ToString(), + Available = movie.Available, + Admin = IsAdmin, + Issues = movie.Issues.ToString().CamelCaseToWords(), + OtherMessage = movie.OtherMessage, + AdminNotes = movie.AdminNote, + Qualities = qualities.ToArray() }).ToList(); return Response.AsJson(viewModel); @@ -196,7 +181,7 @@ private Response GetTvShows() // TODO: async await the API calls { dbTv = t.Result.ToList(); - if (settings.UsersCanViewOnlyOwnRequests && !IsAdmin) + if (settings.UsersCanViewOnlyOwnRequests && !IsAdmin) { dbTv = dbTv.Where(x => x.UserHasRequested(Username)).ToList(); } @@ -214,13 +199,14 @@ private Response GetTvShows() // TODO: async await the API calls { return SonarrApi.GetProfiles(sonarrSettings.ApiKey, sonarrSettings.FullUri); // TODO: cache this! - }); + }); }).ContinueWith((t) => { qualities = t.Result.Select(x => new QualityModel() { Id = x.id.ToString(), Name = x.name }).ToList(); })); } - else { + else + { var sickRageSettings = SickRageSettings.GetSettings(); if (sickRageSettings.Enabled) { @@ -309,8 +295,8 @@ private Response GetAlbumRequests() } private Response DeleteRequest(int requestid) - { - this.RequiresClaims (UserClaims.Admin); + { + this.RequiresClaims(UserClaims.Admin); var currentEntity = Service.Get(requestid); Service.DeleteRequest(currentEntity); @@ -357,7 +343,7 @@ private Response ReportIssue(int requestId, IssueState issue, string comment) private Response ClearIssue(int requestId) { - this.RequiresClaims ( UserClaims.Admin); + this.RequiresClaims(UserClaims.Admin); var originalRequest = Service.Get(requestId); if (originalRequest == null) @@ -374,8 +360,8 @@ private Response ClearIssue(int requestId) } private Response ChangeRequestAvailability(int requestId, bool available) - { - this.RequiresClaims (UserClaims.Admin); + { + this.RequiresClaims(UserClaims.Admin); var originalRequest = Service.Get(requestId); if (originalRequest == null) { @@ -391,8 +377,8 @@ private Response ChangeRequestAvailability(int requestId, bool available) } private Response AddNote(int requestId, string noteArea) - { - this.RequiresClaims (UserClaims.Admin); + { + this.RequiresClaims(UserClaims.Admin); var originalRequest = Service.Get(requestId); if (originalRequest == null) { @@ -406,5 +392,65 @@ private Response AddNote(int requestId, string noteArea) ? new JsonResponseModel { Result = true } : new JsonResponseModel { Result = false, Message = "Could not update the notes, please try again or check the logs" }); } + + private async Task GetMovies(int position) + { + var settings = PrSettings.GetSettings(); + + var allRequests = await Service.GetAllAsync(); + allRequests = allRequests.Where(x => x.Type == RequestType.Movie).OrderByDescending(x => x.RequestedDate).Skip(position == 0 ? 0 : position * 3).Take(3); + + var dbMovies = allRequests.ToList(); + + if (settings.UsersCanViewOnlyOwnRequests && !IsAdmin) + { + dbMovies = dbMovies.Where(x => x.UserHasRequested(Username)).ToList(); + } + + List qualities = new List(); + + if (IsAdmin) + { + var cpSettings = CpSettings.GetSettings(); + if (cpSettings.Enabled) + { + + var result = await Cache.GetOrSetAsync(CacheKeys.CouchPotatoQualityProfiles, async () => + { + return await Task.Run(() => CpApi.GetProfiles(cpSettings.FullUri, cpSettings.ApiKey)).ConfigureAwait(false); + }); + + qualities = result.list.Select(x => new QualityModel() { Id = x._id, Name = x.label }).ToList(); + } + } + + var viewModel = dbMovies.Select(movie => new RequestViewModel + { + ProviderId = movie.ProviderId, + Type = movie.Type, + Status = movie.Status, + ImdbId = movie.ImdbId, + Id = movie.Id, + PosterPath = movie.PosterPath, + ReleaseDate = movie.ReleaseDate, + ReleaseDateTicks = movie.ReleaseDate.Ticks, + RequestedDate = movie.RequestedDate, + Released = DateTime.Now > movie.ReleaseDate, + RequestedDateTicks = DateTimeHelper.OffsetUTCDateTime(movie.RequestedDate, DateTimeOffset).Ticks, + Approved = movie.Available || movie.Approved, + Title = movie.Title, + Overview = movie.Overview, + RequestedUsers = IsAdmin ? movie.AllUsers.ToArray() : new string[] { }, + ReleaseYear = movie.ReleaseDate.Year.ToString(), + Available = movie.Available, + Admin = IsAdmin, + Issues = movie.Issues.ToString().CamelCaseToWords(), + OtherMessage = movie.OtherMessage, + AdminNotes = movie.AdminNote, + Qualities = qualities.ToArray() + }).ToList(); + + return Response.AsJson(viewModel); + } } } From 05b219a351f156ab52d083ebe1b6f173f67da76d Mon Sep 17 00:00:00 2001 From: tidusjar Date: Fri, 27 May 2016 21:17:58 +0100 Subject: [PATCH 20/26] Made the request module async #278 --- PlexRequests.UI/Content/requests-1.7.js | 67 +++------- PlexRequests.UI/Modules/RequestsModule.cs | 153 ++++++---------------- 2 files changed, 54 insertions(+), 166 deletions(-) diff --git a/PlexRequests.UI/Content/requests-1.7.js b/PlexRequests.UI/Content/requests-1.7.js index 84c0e5d49..37538e97c 100644 --- a/PlexRequests.UI/Content/requests-1.7.js +++ b/PlexRequests.UI/Content/requests-1.7.js @@ -12,6 +12,8 @@ var albumTemplate = Handlebars.compile(albumSource); var movieTimer = 0; var tvimer = 0; var base = $('#baseUrl').text(); +var tvLoaded = false; +var albumLoaded = false; var mixItUpDefault = { animation: { enable: true }, @@ -42,6 +44,11 @@ $('a[data-toggle="tab"]').on('shown.bs.tab', function (e) { $('.approve-category,.delete-category').hide(); if (target === "#TvShowTab") { + if (!tvLoaded) { + tvLoaded = true; + tvLoad(); + } + $('#approveTVShows,#deleteTVShows').show(); if ($ml.mixItUp('isLoaded')) { activeState = $ml.mixItUp('getState'); @@ -51,8 +58,8 @@ $('a[data-toggle="tab"]').on('shown.bs.tab', function (e) { activeState = $musicL.mixItUp('getState'); $musicL.mixItUp('destroy'); } - if ($tvl.mixItUp('isLoaded')) $tvl.mixItUp('destroy'); - $tvl.mixItUp(mixItUpConfig(activeState)); // init or reinit + //if ($tvl.mixItUp('isLoaded')) $tvl.mixItUp('destroy'); + //$tvl.mixItUp(mixItUpConfig(activeState)); // init or reinit } if (target === "#MoviesTab") { $('#approveMovies,#deleteMovies').show(); @@ -69,6 +76,10 @@ $('a[data-toggle="tab"]').on('shown.bs.tab', function (e) { } if (target === "#MusicTab") { + if (!albumLoaded) { + albumLoaded = true; + albumLoad(); + } $('#approveMusic,#deleteMusic').show(); if ($tvl.mixItUp('isLoaded')) { activeState = $tvl.mixItUp('getState'); @@ -516,10 +527,8 @@ function mixItUpConfig(activeState) { var position = 0; function initLoad() { - //movieLoad(); - movieLoadWithPosition(0); - tvLoad(); - albumLoad(); + movieLoad(); + } function movieLoad() { @@ -546,52 +555,6 @@ function movieLoad() { }); }; -function movieLoadWithPosition(pos) { - var $ml = $('#movieList'); - if ($ml.mixItUp('isLoaded')) { - activeState = $ml.mixItUp('getState'); - $ml.mixItUp('destroy'); - } - - var url = createBaseUrl(base, '/requests/movies/'+pos); - $.ajax(url).success(function (results) { - if (results.length > 0) { - position++; - results.forEach(function (result) { - var context = buildRequestContext(result, "movie"); - var html = searchTemplate(context); - $ml.append(html); - }); - } - else { - $ml.append(noResultsHtml.format("movie")); - } - $ml.mixItUp(mixItUpConfig()); - }); -}; - -var win = $(window); - -$(win).scroll(function () { - if ($(win).scrollTop() + $(win).height() >= $(document).height() - 100) { - // Debounce the scroll event - if (this.timeoutId) - win.clearTimeout(this.timeoutId); - this.timeoutId = win.setTimeout(function () { - movieLoadWithPosition(position); - }, 200); - } -}); -//// Each time the user scrolls -//win.scroll(function () { -// // End of the document reached? -// if ($(document).height() - win.height() == win.scrollTop()) { -// $('#loading').show(); - -// movieLoadWithPosition(position); -// } -//}); - function tvLoad() { var $tvl = $('#tvList'); if ($tvl.mixItUp('isLoaded')) { diff --git a/PlexRequests.UI/Modules/RequestsModule.cs b/PlexRequests.UI/Modules/RequestsModule.cs index 460ac964b..16bbd1cb2 100644 --- a/PlexRequests.UI/Modules/RequestsModule.cs +++ b/PlexRequests.UI/Modules/RequestsModule.cs @@ -75,17 +75,16 @@ public RequestsModule( Get["/"] = _ => LoadRequests(); Get["/movies", true] = async (x, ct) => await GetMovies(); - Get["/movies/{position}", true] = async (x, ct) => await GetMovies(x.position); - Get["/tvshows"] = _ => GetTvShows(); - Get["/albums"] = _ => GetAlbumRequests(); - Post["/delete"] = _ => DeleteRequest((int)Request.Form.id); - Post["/reportissue"] = _ => ReportIssue((int)Request.Form.requestId, (IssueState)(int)Request.Form.issue, null); - Post["/reportissuecomment"] = _ => ReportIssue((int)Request.Form.requestId, IssueState.Other, (string)Request.Form.commentArea); + Get["/tvshows", true] = async (c, ct) => await GetTvShows(); + Get["/albums", true] = async (x,ct) => await GetAlbumRequests(); + Post["/delete", true] = async (x, ct) => await DeleteRequest((int)Request.Form.id); + Post["/reportissue", true] = async (x, ct) => await ReportIssue((int)Request.Form.requestId, (IssueState)(int)Request.Form.issue, null); + Post["/reportissuecomment", true] = async (x, ct) => await ReportIssue((int)Request.Form.requestId, IssueState.Other, (string)Request.Form.commentArea); - Post["/clearissues"] = _ => ClearIssue((int)Request.Form.Id); + Post["/clearissues", true] = async (x, ct) => await ClearIssue((int)Request.Form.Id); - Post["/changeavailability"] = _ => ChangeRequestAvailability((int)Request.Form.Id, (bool)Request.Form.Available); - Post["/addnote"] = _ => AddNote((int)Request.Form.requestId, (string)Request.Form.noteArea); + Post["/changeavailability", true] = async (x, ct) => await ChangeRequestAvailability((int)Request.Form.Id, (bool)Request.Form.Available); + Post["/addnote", true] = async (x, ct) => await AddNote((int)Request.Form.requestId, (string)Request.Form.noteArea); } private IRequestService Service { get; } @@ -166,44 +165,31 @@ private async Task GetMovies() return Response.AsJson(viewModel); } - private Response GetTvShows() // TODO: async await the API calls + private async Task GetTvShows() { var settings = PrSettings.GetSettings(); - List taskList = new List(); + var requests = await Service.GetAllAsync(); + requests = requests.Where(x => x.Type == RequestType.TvShow); - List dbTv = new List(); - taskList.Add(Task.Factory.StartNew(() => - { - return Service.GetAll().Where(x => x.Type == RequestType.TvShow); + var dbTv = requests; - }).ContinueWith((t) => + if (settings.UsersCanViewOnlyOwnRequests && !IsAdmin) { - dbTv = t.Result.ToList(); - - if (settings.UsersCanViewOnlyOwnRequests && !IsAdmin) - { - dbTv = dbTv.Where(x => x.UserHasRequested(Username)).ToList(); - } - })); + dbTv = dbTv.Where(x => x.UserHasRequested(Username)).ToList(); + } - List qualities = new List(); + IEnumerable qualities = new List(); if (IsAdmin) { var sonarrSettings = SonarrSettings.GetSettings(); if (sonarrSettings.Enabled) { - taskList.Add(Task.Factory.StartNew(() => - { - return Cache.GetOrSet(CacheKeys.SonarrQualityProfiles, () => - { - return SonarrApi.GetProfiles(sonarrSettings.ApiKey, sonarrSettings.FullUri); // TODO: cache this! - - }); - }).ContinueWith((t) => + var result = Cache.GetOrSetAsync(CacheKeys.SonarrQualityProfiles, async () => { - qualities = t.Result.Select(x => new QualityModel() { Id = x.id.ToString(), Name = x.name }).ToList(); - })); + return await Task.Run(() => SonarrApi.GetProfiles(sonarrSettings.ApiKey, sonarrSettings.FullUri)); + }); + qualities = result.Result.Select(x => new QualityModel() { Id = x.id.ToString(), Name = x.name }).ToList(); } else { @@ -215,8 +201,6 @@ private Response GetTvShows() // TODO: async await the API calls } } - Task.WaitAll(taskList.ToArray()); - var viewModel = dbTv.Select(tv => { return new RequestViewModel @@ -250,10 +234,11 @@ private Response GetTvShows() // TODO: async await the API calls return Response.AsJson(viewModel); } - private Response GetAlbumRequests() + private async Task GetAlbumRequests() { var settings = PrSettings.GetSettings(); - var dbAlbum = Service.GetAll().Where(x => x.Type == RequestType.Album); + var dbAlbum = await Service.GetAllAsync(); + dbAlbum = dbAlbum.Where(x => x.Type == RequestType.Album); if (settings.UsersCanViewOnlyOwnRequests && !IsAdmin) { dbAlbum = dbAlbum.Where(x => x.UserHasRequested(Username)); @@ -294,12 +279,12 @@ private Response GetAlbumRequests() return Response.AsJson(viewModel); } - private Response DeleteRequest(int requestid) + private async Task DeleteRequest(int requestid) { this.RequiresClaims(UserClaims.Admin); - var currentEntity = Service.Get(requestid); - Service.DeleteRequest(currentEntity); + var currentEntity = await Service.GetAsync(requestid); + await Service.DeleteRequestAsync(currentEntity); return Response.AsJson(new JsonResponseModel { Result = true }); } @@ -311,9 +296,9 @@ private Response DeleteRequest(int requestid) /// The issue. /// The comment. /// - private Response ReportIssue(int requestId, IssueState issue, string comment) + private async Task ReportIssue(int requestId, IssueState issue, string comment) { - var originalRequest = Service.Get(requestId); + var originalRequest = await Service.GetAsync(requestId); if (originalRequest == null) { return Response.AsJson(new JsonResponseModel { Result = false, Message = "Could not add issue, please try again or contact the administrator!" }); @@ -324,7 +309,7 @@ private Response ReportIssue(int requestId, IssueState issue, string comment) : string.Empty; - var result = Service.UpdateRequest(originalRequest); + var result = await Service.UpdateRequestAsync(originalRequest); var model = new NotificationModel { @@ -334,18 +319,18 @@ private Response ReportIssue(int requestId, IssueState issue, string comment) DateTime = DateTime.Now, Body = issue == IssueState.Other ? comment : issue.ToString().CamelCaseToWords() }; - NotificationService.Publish(model); + await NotificationService.Publish(model); return Response.AsJson(result ? new JsonResponseModel { Result = true } : new JsonResponseModel { Result = false, Message = "Could not add issue, please try again or contact the administrator!" }); } - private Response ClearIssue(int requestId) + private async Task ClearIssue(int requestId) { this.RequiresClaims(UserClaims.Admin); - var originalRequest = Service.Get(requestId); + var originalRequest = await Service.GetAsync(requestId); if (originalRequest == null) { return Response.AsJson(new JsonResponseModel { Result = false, Message = "Request does not exist to clear it!" }); @@ -353,16 +338,16 @@ private Response ClearIssue(int requestId) originalRequest.Issues = IssueState.None; originalRequest.OtherMessage = string.Empty; - var result = Service.UpdateRequest(originalRequest); + var result = await Service.UpdateRequestAsync(originalRequest); return Response.AsJson(result ? new JsonResponseModel { Result = true } : new JsonResponseModel { Result = false, Message = "Could not clear issue, please try again or check the logs" }); } - private Response ChangeRequestAvailability(int requestId, bool available) + private async Task ChangeRequestAvailability(int requestId, bool available) { this.RequiresClaims(UserClaims.Admin); - var originalRequest = Service.Get(requestId); + var originalRequest = await Service.GetAsync(requestId); if (originalRequest == null) { return Response.AsJson(new JsonResponseModel { Result = false, Message = "Request does not exist to change the availability!" }); @@ -370,16 +355,16 @@ private Response ChangeRequestAvailability(int requestId, bool available) originalRequest.Available = available; - var result = Service.UpdateRequest(originalRequest); + var result = await Service.UpdateRequestAsync(originalRequest); return Response.AsJson(result ? new { Result = true, Available = available, Message = string.Empty } : new { Result = false, Available = false, Message = "Could not update the availability, please try again or check the logs" }); } - private Response AddNote(int requestId, string noteArea) + private async Task AddNote(int requestId, string noteArea) { this.RequiresClaims(UserClaims.Admin); - var originalRequest = Service.Get(requestId); + var originalRequest = await Service.GetAsync(requestId); if (originalRequest == null) { return Response.AsJson(new JsonResponseModel { Result = false, Message = "Request does not exist to add a note!" }); @@ -387,70 +372,10 @@ private Response AddNote(int requestId, string noteArea) originalRequest.AdminNote = noteArea; - var result = Service.UpdateRequest(originalRequest); + var result = await Service.UpdateRequestAsync(originalRequest); return Response.AsJson(result ? new JsonResponseModel { Result = true } : new JsonResponseModel { Result = false, Message = "Could not update the notes, please try again or check the logs" }); } - - private async Task GetMovies(int position) - { - var settings = PrSettings.GetSettings(); - - var allRequests = await Service.GetAllAsync(); - allRequests = allRequests.Where(x => x.Type == RequestType.Movie).OrderByDescending(x => x.RequestedDate).Skip(position == 0 ? 0 : position * 3).Take(3); - - var dbMovies = allRequests.ToList(); - - if (settings.UsersCanViewOnlyOwnRequests && !IsAdmin) - { - dbMovies = dbMovies.Where(x => x.UserHasRequested(Username)).ToList(); - } - - List qualities = new List(); - - if (IsAdmin) - { - var cpSettings = CpSettings.GetSettings(); - if (cpSettings.Enabled) - { - - var result = await Cache.GetOrSetAsync(CacheKeys.CouchPotatoQualityProfiles, async () => - { - return await Task.Run(() => CpApi.GetProfiles(cpSettings.FullUri, cpSettings.ApiKey)).ConfigureAwait(false); - }); - - qualities = result.list.Select(x => new QualityModel() { Id = x._id, Name = x.label }).ToList(); - } - } - - var viewModel = dbMovies.Select(movie => new RequestViewModel - { - ProviderId = movie.ProviderId, - Type = movie.Type, - Status = movie.Status, - ImdbId = movie.ImdbId, - Id = movie.Id, - PosterPath = movie.PosterPath, - ReleaseDate = movie.ReleaseDate, - ReleaseDateTicks = movie.ReleaseDate.Ticks, - RequestedDate = movie.RequestedDate, - Released = DateTime.Now > movie.ReleaseDate, - RequestedDateTicks = DateTimeHelper.OffsetUTCDateTime(movie.RequestedDate, DateTimeOffset).Ticks, - Approved = movie.Available || movie.Approved, - Title = movie.Title, - Overview = movie.Overview, - RequestedUsers = IsAdmin ? movie.AllUsers.ToArray() : new string[] { }, - ReleaseYear = movie.ReleaseDate.Year.ToString(), - Available = movie.Available, - Admin = IsAdmin, - Issues = movie.Issues.ToString().CamelCaseToWords(), - OtherMessage = movie.OtherMessage, - AdminNotes = movie.AdminNote, - Qualities = qualities.ToArray() - }).ToList(); - - return Response.AsJson(viewModel); - } } } From 03ce3611839dc605a96f756ce3bb09c0f8e593f7 Mon Sep 17 00:00:00 2001 From: tidusjar Date: Fri, 27 May 2016 22:04:25 +0100 Subject: [PATCH 21/26] Made the search page all async goodness #278 --- PlexRequests.Core/IRequestService.cs | 2 + PlexRequests.Core/ISettingsService.cs | 6 + PlexRequests.Core/JsonRequestService.cs | 14 ++ PlexRequests.Core/SettingsServiceV2.cs | 53 ++++++ PlexRequests.Core/Setup.cs | 2 +- PlexRequests.Store/PlexRequests.Store.csproj | 1 + .../Repository/BaseGenericRepository.cs | 179 ++++++++++++++++++ .../Repository/GenericRepository.cs | 103 +++------- PlexRequests.Store/Repository/IRepository.cs | 9 + .../Repository/ISettingsRepository.cs | 7 +- .../Repository/SettingsJsonRepository.cs | 57 +++++- PlexRequests.Store/UserRepository.cs | 53 ++---- PlexRequests.UI/Modules/SearchModule.cs | 125 ++++++------ 13 files changed, 430 insertions(+), 181 deletions(-) create mode 100644 PlexRequests.Store/Repository/BaseGenericRepository.cs diff --git a/PlexRequests.Core/IRequestService.cs b/PlexRequests.Core/IRequestService.cs index dabade7ae..20fe5e071 100644 --- a/PlexRequests.Core/IRequestService.cs +++ b/PlexRequests.Core/IRequestService.cs @@ -37,7 +37,9 @@ public interface IRequestService long AddRequest(RequestedModel model); Task AddRequestAsync(RequestedModel model); RequestedModel CheckRequest(int providerId); + Task CheckRequestAsync(int providerId); RequestedModel CheckRequest(string musicId); + Task CheckRequestAsync(string musicId); void DeleteRequest(RequestedModel request); Task DeleteRequestAsync(RequestedModel request); diff --git a/PlexRequests.Core/ISettingsService.cs b/PlexRequests.Core/ISettingsService.cs index 9687d920e..a1ef1341e 100644 --- a/PlexRequests.Core/ISettingsService.cs +++ b/PlexRequests.Core/ISettingsService.cs @@ -24,12 +24,18 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // ************************************************************************/ #endregion + +using System.Threading.Tasks; + namespace PlexRequests.Core { public interface ISettingsService { T GetSettings(); + Task GetSettingsAsync(); bool SaveSettings(T model); + Task SaveSettingsAsync(T model); bool Delete(T model); + Task DeleteAsync(T model); } } \ No newline at end of file diff --git a/PlexRequests.Core/JsonRequestService.cs b/PlexRequests.Core/JsonRequestService.cs index 5a5ec2e4f..d44069271 100644 --- a/PlexRequests.Core/JsonRequestService.cs +++ b/PlexRequests.Core/JsonRequestService.cs @@ -78,6 +78,13 @@ public RequestedModel CheckRequest(int providerId) return blob != null ? ByteConverterHelper.ReturnObject(blob.Content) : null; } + public async Task CheckRequestAsync(int providerId) + { + var blobs = await Repo.GetAllAsync(); + var blob = blobs.FirstOrDefault(x => x.ProviderId == providerId); + return blob != null ? ByteConverterHelper.ReturnObject(blob.Content) : null; + } + public RequestedModel CheckRequest(string musicId) { var blobs = Repo.GetAll(); @@ -85,6 +92,13 @@ public RequestedModel CheckRequest(string musicId) return blob != null ? ByteConverterHelper.ReturnObject(blob.Content) : null; } + public async Task CheckRequestAsync(string musicId) + { + var blobs = await Repo.GetAllAsync(); + var blob = blobs.FirstOrDefault(x => x.MusicId == musicId); + return blob != null ? ByteConverterHelper.ReturnObject(blob.Content) : null; + } + public void DeleteRequest(RequestedModel request) { var blob = Repo.Get(request.Id); diff --git a/PlexRequests.Core/SettingsServiceV2.cs b/PlexRequests.Core/SettingsServiceV2.cs index 3fb53cd35..5705544d0 100644 --- a/PlexRequests.Core/SettingsServiceV2.cs +++ b/PlexRequests.Core/SettingsServiceV2.cs @@ -24,6 +24,8 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // ************************************************************************/ #endregion + +using System.Threading.Tasks; using Newtonsoft.Json; using PlexRequests.Core.SettingModels; @@ -62,6 +64,21 @@ public T GetSettings() return model; } + public async Task GetSettingsAsync() + { + var result = await Repo.GetAsync(EntityName); + if (result == null) + { + return new T(); + } + result.Content = DecryptSettings(result); + var obj = string.IsNullOrEmpty(result.Content) ? null : JsonConvert.DeserializeObject(result.Content, SerializerSettings.Settings); + + var model = obj; + + return model; + } + public bool SaveSettings(T model) { var entity = Repo.Get(EntityName); @@ -88,6 +105,31 @@ public bool SaveSettings(T model) return result; } + public async Task SaveSettingsAsync(T model) + { + var entity = await Repo.GetAsync(EntityName); + + if (entity == null) + { + var newEntity = model; + + var settings = new GlobalSettings { SettingsName = EntityName, Content = JsonConvert.SerializeObject(newEntity, SerializerSettings.Settings) }; + settings.Content = EncryptSettings(settings); + var insertResult = await Repo.InsertAsync(settings); + + return insertResult != int.MinValue; + } + + var modified = model; + modified.Id = entity.Id; + + var globalSettings = new GlobalSettings { SettingsName = EntityName, Content = JsonConvert.SerializeObject(modified, SerializerSettings.Settings), Id = entity.Id }; + globalSettings.Content = EncryptSettings(globalSettings); + var result = await Repo.UpdateAsync(globalSettings); + + return result; + } + public bool Delete(T model) { var entity = Repo.Get(EntityName); @@ -100,6 +142,17 @@ public bool Delete(T model) return true; } + public async Task DeleteAsync(T model) + { + var entity = Repo.Get(EntityName); + if (entity != null) + { + return await Repo.DeleteAsync(entity); + } + + return true; + } + private string EncryptSettings(GlobalSettings settings) { return StringCipher.Encrypt(settings.Content, settings.SettingsName); diff --git a/PlexRequests.Core/Setup.cs b/PlexRequests.Core/Setup.cs index 4c6128259..87e16118e 100644 --- a/PlexRequests.Core/Setup.cs +++ b/PlexRequests.Core/Setup.cs @@ -187,7 +187,7 @@ private void MigrateToVersion1800() { try { - var userMapper = new UserMapper(new UserRepository(Db)); + var userMapper = new UserMapper(new UserRepository(Db, new MemoryCacheProvider())); var users = userMapper.GetUsers(); foreach (var u in users) diff --git a/PlexRequests.Store/PlexRequests.Store.csproj b/PlexRequests.Store/PlexRequests.Store.csproj index 19578aee5..f9feb0c3b 100644 --- a/PlexRequests.Store/PlexRequests.Store.csproj +++ b/PlexRequests.Store/PlexRequests.Store.csproj @@ -61,6 +61,7 @@ + diff --git a/PlexRequests.Store/Repository/BaseGenericRepository.cs b/PlexRequests.Store/Repository/BaseGenericRepository.cs new file mode 100644 index 000000000..ac8c45203 --- /dev/null +++ b/PlexRequests.Store/Repository/BaseGenericRepository.cs @@ -0,0 +1,179 @@ +#region Copyright +// /************************************************************************ +// Copyright (c) 2016 Jamie Rees +// File: BaseGenericRepository.cs +// Created By: Jamie Rees +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// ************************************************************************/ +#endregion + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Dapper.Contrib.Extensions; +using NLog; +using PlexRequests.Helpers; + +namespace PlexRequests.Store.Repository +{ + public abstract class BaseGenericRepository where T : class + { + protected BaseGenericRepository(ISqliteConfiguration config, ICacheProvider cache) + { + Config = config; + Cache = cache; + } + protected ICacheProvider Cache { get; } + protected ISqliteConfiguration Config { get; } + private static readonly Logger Log = LogManager.GetCurrentClassLogger(); + public abstract T Get(string id); + public abstract Task GetAsync(int id); + public abstract T Get(int id); + public abstract Task GetAsync(string id); + + public long Insert(T entity) + { + ResetCache(); + using (var cnn = Config.DbConnection()) + { + cnn.Open(); + return cnn.Insert(entity); + } + } + + public void Delete(T entity) + { + ResetCache(); + using (var db = Config.DbConnection()) + { + db.Open(); + db.Delete(entity); + } + } + + public async Task DeleteAsync(T entity) + { + ResetCache(); + using (var db = Config.DbConnection()) + { + db.Open(); + await db.DeleteAsync(entity); + } + } + + public bool Update(T entity) + { + ResetCache(); + Log.Trace("Updating entity"); + Log.Trace(entity.DumpJson()); + using (var db = Config.DbConnection()) + { + db.Open(); + return db.Update(entity); + } + } + + public async Task UpdateAsync(T entity) + { + ResetCache(); + Log.Trace("Updating entity"); + Log.Trace(entity.DumpJson()); + using (var db = Config.DbConnection()) + { + db.Open(); + return await db.UpdateAsync(entity); + } + } + + public bool UpdateAll(IEnumerable entity) + { + ResetCache(); + Log.Trace("Updating all entities"); + var result = new HashSet(); + + using (var db = Config.DbConnection()) + { + db.Open(); + foreach (var e in entity) + { + result.Add(db.Update(e)); + } + } + return result.All(x => true); + } + + public async Task UpdateAllAsync(IEnumerable entity) + { + ResetCache(); + Log.Trace("Updating all entities"); + var result = new HashSet(); + + using (var db = Config.DbConnection()) + { + db.Open(); + foreach (var e in entity) + { + result.Add(await db.UpdateAsync(e)); + } + } + return result.All(x => true); + } + + public async Task InsertAsync(T entity) + { + ResetCache(); + using (var cnn = Config.DbConnection()) + { + cnn.Open(); + return await cnn.InsertAsync(entity); + } + } + + private void ResetCache() + { + Cache.Remove("Get"); + Cache.Remove("GetAll"); + } + public IEnumerable GetAll() + { + + using (var db = Config.DbConnection()) + { + db.Open(); + var result = db.GetAll(); + return result; + } + + } + public async Task> GetAllAsync() + { + + using (var db = Config.DbConnection()) + { + db.Open(); + var result = await db.GetAllAsync(); + return result; + } + + } + } +} \ No newline at end of file diff --git a/PlexRequests.Store/Repository/GenericRepository.cs b/PlexRequests.Store/Repository/GenericRepository.cs index 17e7b9c0f..6fb1e8216 100644 --- a/PlexRequests.Store/Repository/GenericRepository.cs +++ b/PlexRequests.Store/Repository/GenericRepository.cs @@ -1,4 +1,5 @@ #region Copyright + // /************************************************************************ // Copyright (c) 2016 Jamie Rees // File: GenericRepository.cs @@ -23,59 +24,38 @@ // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // ************************************************************************/ + #endregion + using System; using System.Collections.Generic; using System.Linq; - +using System.Threading.Tasks; using Dapper.Contrib.Extensions; - using NLog; - using PlexRequests.Helpers; namespace PlexRequests.Store.Repository { - public class GenericRepository : IRepository where T : Entity + public class GenericRepository : BaseGenericRepository, IRepository where T : Entity { - private ICacheProvider Cache { get; } - public GenericRepository(ISqliteConfiguration config, ICacheProvider cache) - { - Config = config; - Cache = cache; - } - - private static Logger Log = LogManager.GetCurrentClassLogger(); - - private ISqliteConfiguration Config { get; } - public long Insert(T entity) + + public GenericRepository(ISqliteConfiguration config, ICacheProvider cache) : base(config, cache) { - ResetCache(); - using (var cnn = Config.DbConnection()) - { - cnn.Open(); - return cnn.Insert(entity); - } + } - - public IEnumerable GetAll() + + public override T Get(string id) { - - using (var db = Config.DbConnection()) - { - db.Open(); - var result = db.GetAll(); - return result; - } - + throw new NotSupportedException("Get(string) is not supported. Use Get(int)"); } - public T Get(string id) + public override Task GetAsync(string id) { - throw new NotSupportedException("Get(string) is not supported. Use Get(int)"); + throw new NotSupportedException("GetAsync(string) is not supported. Use GetAsync(int)"); } - public T Get(int id) + public override T Get(int id) { var key = "Get" + id; var item = Cache.GetOrSet( @@ -91,49 +71,22 @@ public T Get(int id) return item; } - public void Delete(T entity) - { - ResetCache(); - using (var db = Config.DbConnection()) - { - db.Open(); - db.Delete(entity); - } - } - - public bool Update(T entity) - { - ResetCache(); - Log.Trace("Updating entity"); - Log.Trace(entity.DumpJson()); - using (var db = Config.DbConnection()) - { - db.Open(); - return db.Update(entity); - } - } - - public bool UpdateAll(IEnumerable entity) + public override async Task GetAsync(int id) { - ResetCache(); - Log.Trace("Updating all entities"); - var result = new HashSet(); - - using (var db = Config.DbConnection()) - { - db.Open(); - foreach (var e in entity) + var key = "Get" + id; + var item = await Cache.GetOrSetAsync( + key, + async () => { - result.Add(db.Update(e)); - } - } - return result.All(x => true); + using (var db = Config.DbConnection()) + { + db.Open(); + return await db.GetAsync(id); + } + }); + return item; } - private void ResetCache() - { - Cache.Remove("Get"); - Cache.Remove("GetAll"); - } + } -} +} \ No newline at end of file diff --git a/PlexRequests.Store/Repository/IRepository.cs b/PlexRequests.Store/Repository/IRepository.cs index 4d301047c..15cf2a2c5 100644 --- a/PlexRequests.Store/Repository/IRepository.cs +++ b/PlexRequests.Store/Repository/IRepository.cs @@ -25,6 +25,7 @@ // ************************************************************************/ #endregion using System.Collections.Generic; +using System.Threading.Tasks; namespace PlexRequests.Store.Repository { @@ -35,12 +36,15 @@ public interface IRepository /// /// The entity. long Insert(T entity); + Task InsertAsync(T entity); /// /// Gets all. /// /// IEnumerable GetAll(); + Task> GetAllAsync(); + /// /// Gets the specified identifier. @@ -48,12 +52,15 @@ public interface IRepository /// The identifier. /// T Get(string id); + Task GetAsync(string id); T Get(int id); + Task GetAsync(int id); /// /// Deletes the specified entity. /// /// The entity. void Delete(T entity); + Task DeleteAsync(T entity); /// /// Updates the specified entity. @@ -61,6 +68,7 @@ public interface IRepository /// The entity. /// bool Update(T entity); + Task UpdateAsync(T entity); /// /// Updates all. @@ -68,5 +76,6 @@ public interface IRepository /// The entity. /// bool UpdateAll(IEnumerable entity); + Task UpdateAllAsync(IEnumerable entity); } } diff --git a/PlexRequests.Store/Repository/ISettingsRepository.cs b/PlexRequests.Store/Repository/ISettingsRepository.cs index 393da6ef7..3f6761c66 100644 --- a/PlexRequests.Store/Repository/ISettingsRepository.cs +++ b/PlexRequests.Store/Repository/ISettingsRepository.cs @@ -25,7 +25,7 @@ // ************************************************************************/ #endregion using System.Collections.Generic; - +using System.Threading.Tasks; using PlexRequests.Store.Models; namespace PlexRequests.Store.Repository @@ -37,12 +37,14 @@ public interface ISettingsRepository /// /// The entity. long Insert(GlobalSettings entity); + Task InsertAsync(GlobalSettings entity); /// /// Gets all. /// /// IEnumerable GetAll(); + Task> GetAllAsync(); /// /// Gets the specified identifier. @@ -50,12 +52,14 @@ public interface ISettingsRepository /// Name of the settings. /// GlobalSettings Get(string settingsName); + Task GetAsync(string settingsName); /// /// Deletes the specified entity. /// /// The entity. /// + Task DeleteAsync(GlobalSettings entity); bool Delete(GlobalSettings entity); /// @@ -63,6 +67,7 @@ public interface ISettingsRepository /// /// The entity. /// + Task UpdateAsync(GlobalSettings entity); bool Update(GlobalSettings entity); diff --git a/PlexRequests.Store/Repository/SettingsJsonRepository.cs b/PlexRequests.Store/Repository/SettingsJsonRepository.cs index 64d98f78a..50a59a6af 100644 --- a/PlexRequests.Store/Repository/SettingsJsonRepository.cs +++ b/PlexRequests.Store/Repository/SettingsJsonRepository.cs @@ -26,7 +26,7 @@ #endregion using System.Collections.Generic; using System.Linq; - +using System.Threading.Tasks; using Dapper.Contrib.Extensions; using PlexRequests.Helpers; @@ -57,6 +57,15 @@ public long Insert(GlobalSettings entity) } } + public async Task InsertAsync(GlobalSettings entity) + { + ResetCache(); + using (var con = Db.DbConnection()) + { + return await con.InsertAsync(entity); + } + } + public IEnumerable GetAll() { var key = TypeName + "GetAll"; @@ -71,6 +80,20 @@ public IEnumerable GetAll() return item; } + public async Task> GetAllAsync() + { + var key = TypeName + "GetAll"; + var item = await Cache.GetOrSetAsync(key, async() => + { + using (var con = Db.DbConnection()) + { + var page = await con.GetAllAsync(); + return page; + } + }, 5); + return item; + } + public GlobalSettings Get(string pageName) { var key = pageName + "Get"; @@ -85,6 +108,38 @@ public GlobalSettings Get(string pageName) return item; } + public async Task GetAsync(string settingsName) + { + var key = settingsName + "Get"; + var item = await Cache.GetOrSetAsync(key, async() => + { + using (var con = Db.DbConnection()) + { + var page = await con.GetAllAsync(); + return page.SingleOrDefault(x => x.SettingsName == settingsName); + } + }, 5); + return item; + } + + public async Task DeleteAsync(GlobalSettings entity) + { + ResetCache(); + using (var con = Db.DbConnection()) + { + return await con.DeleteAsync(entity); + } + } + + public async Task UpdateAsync(GlobalSettings entity) + { + ResetCache(); + using (var con = Db.DbConnection()) + { + return await con.UpdateAsync(entity); + } + } + public bool Delete(GlobalSettings entity) { ResetCache(); diff --git a/PlexRequests.Store/UserRepository.cs b/PlexRequests.Store/UserRepository.cs index 467e0487c..0a938e49f 100644 --- a/PlexRequests.Store/UserRepository.cs +++ b/PlexRequests.Store/UserRepository.cs @@ -27,41 +27,31 @@ using System; using System.Collections.Generic; using System.Linq; - +using System.Threading.Tasks; using Dapper.Contrib.Extensions; - +using PlexRequests.Helpers; using PlexRequests.Store.Repository; namespace PlexRequests.Store { - public class UserRepository : IRepository where T : UserEntity + public class UserRepository : BaseGenericRepository, IRepository where T : UserEntity { - public UserRepository(ISqliteConfiguration config) + public UserRepository(ISqliteConfiguration config, ICacheProvider cache) : base(config, cache) { - Config = config; + } - private ISqliteConfiguration Config { get; } - public long Insert(T entity) + public override T Get(int id) { - using (var cnn = Config.DbConnection()) - { - cnn.Open(); - return cnn.Insert(entity); - } + throw new NotSupportedException("Get(int) is not supported. Use Get(string)"); } - public IEnumerable GetAll() + public override Task GetAsync(int id) { - using (var db = Config.DbConnection()) - { - db.Open(); - var result = db.GetAll(); - return result; - } + throw new NotSupportedException("GetAsync(int) is not supported. Use GetAsync(string)"); } - public T Get(string id) + public override T Get(string id) { using (var db = Config.DbConnection()) { @@ -72,33 +62,18 @@ public T Get(string id) } } - public T Get(int id) - { - throw new NotSupportedException("Get(int) is not supported. Use Get(string)"); - } - - public void Delete(T entity) + public override async Task GetAsync(string id) { using (var db = Config.DbConnection()) { db.Open(); - db.Delete(entity); + var result = await db.GetAllAsync(); + var selected = result.FirstOrDefault(x => x.UserGuid == id); + return selected; } } - public bool Update(T entity) - { - using (var db = Config.DbConnection()) - { - db.Open(); - return db.Update(entity); - } - } - public bool UpdateAll(IEnumerable entity) - { - throw new NotSupportedException(); - } } } diff --git a/PlexRequests.UI/Modules/SearchModule.cs b/PlexRequests.UI/Modules/SearchModule.cs index 0979c1c6a..05c835350 100644 --- a/PlexRequests.UI/Modules/SearchModule.cs +++ b/PlexRequests.UI/Modules/SearchModule.cs @@ -92,7 +92,7 @@ public SearchModule(ICacheProvider cache, ISettingsService EmailNotificationSettings = email; - Get["/"] = parameters => RequestLoad(); + Get["/", true] = async (x, ct) => await RequestLoad(); Get["movie/{searchTerm}", true] = async (x, ct) => await SearchMovie((string)x.searchTerm); Get["tv/{searchTerm}", true] = async (x, ct) => await SearchTvShow((string)x.searchTerm); @@ -102,12 +102,12 @@ public SearchModule(ICacheProvider cache, ISettingsService Get["movie/upcoming", true] = async (x, ct) => await UpcomingMovies(); Get["movie/playing", true] = async (x, ct) => await CurrentlyPlayingMovies(); - Post["request/movie"] = parameters => RequestMovie((int)Request.Form.movieId); - Post["request/tv"] = parameters => RequestTvShow((int)Request.Form.tvId, (string)Request.Form.seasons); - Post["request/album"] = parameters => RequestAlbum((string)Request.Form.albumId); + Post["request/movie", true] = async (x, ct) => await RequestMovie((int)Request.Form.movieId); + Post["request/tv", true] = async (x, ct) => await RequestTvShow((int)Request.Form.tvId, (string)Request.Form.seasons); + Post["request/album", true] = async (x, ct) => await RequestAlbum((string)Request.Form.albumId); - Post["/notifyuser"] = x => NotifyUser((bool)Request.Form.notify); - Get["/notifyuser"] = x => GetUserNotificationSettings(); + Post["/notifyuser", true] = async (x, ct) => await NotifyUser((bool)Request.Form.notify); + Get["/notifyuser", true] = async (x, ct) => await GetUserNotificationSettings(); Get["/seasons"] = x => GetSeasons(); } @@ -136,9 +136,9 @@ public SearchModule(ICacheProvider cache, ISettingsService private IRepository UsersToNotifyRepo { get; } private static Logger Log = LogManager.GetCurrentClassLogger(); - private Negotiator RequestLoad() + private async Task RequestLoad() { - var settings = PrService.GetSettings(); + var settings = await PrService.GetSettingsAsync(); Log.Trace("Loading Index"); return View["Search/Index", settings]; @@ -215,7 +215,7 @@ await Task.Factory.StartNew( var cpCached = CpCacher.QueuedIds(); var plexMovies = Checker.GetPlexMovies(); - var settings = PrService.GetSettings(); + var settings = await PrService.GetSettingsAsync(); var viewMovies = new List(); foreach (MovieResult movie in apiMovies) { @@ -350,7 +350,7 @@ private async Task SearchTvShow(string searchTerm) private async Task SearchMusic(string searchTerm) { var apiAlbums = new List(); - await Task.Factory.StartNew(() => MusicBrainzApi.SearchAlbum(searchTerm)).ContinueWith((t) => + await Task.Run(() => MusicBrainzApi.SearchAlbum(searchTerm)).ContinueWith((t) => { apiAlbums = t.Result.releases ?? new List(); }); @@ -359,7 +359,7 @@ await Task.Factory.StartNew(() => MusicBrainzApi.SearchAlbum(searchTerm)).Contin allResults = allResults.Where(x => x.Type == RequestType.Album); var dbAlbum = allResults.ToDictionary(x => x.MusicBrainzId); - + var plexAlbums = Checker.GetPlexAlbums(); var viewAlbum = new List(); @@ -398,27 +398,26 @@ await Task.Factory.StartNew(() => MusicBrainzApi.SearchAlbum(searchTerm)).Contin return Response.AsJson(viewAlbum); } - private Response RequestMovie(int movieId) + private async Task RequestMovie(int movieId) { var movieApi = new TheMovieDbApi(); var movieInfo = movieApi.GetMovieInformation(movieId).Result; var fullMovieName = $"{movieInfo.Title}{(movieInfo.ReleaseDate.HasValue ? $" ({movieInfo.ReleaseDate.Value.Year})" : string.Empty)}"; Log.Trace("Getting movie info from TheMovieDb"); - Log.Trace(movieInfo.DumpJson); //#if !DEBUG - var settings = PrService.GetSettings(); + var settings = await PrService.GetSettingsAsync(); // check if the movie has already been requested Log.Info("Requesting movie with id {0}", movieId); - var existingRequest = RequestService.CheckRequest(movieId); + var existingRequest = await RequestService.CheckRequestAsync(movieId); if (existingRequest != null) { // check if the current user is already marked as a requester for this movie, if not, add them if (!existingRequest.UserHasRequested(Username)) { existingRequest.RequestedUsers.Add(Username); - RequestService.UpdateRequest(existingRequest); + await RequestService.UpdateRequestAsync(existingRequest); } return Response.AsJson(new JsonResponseModel { Result = true, Message = settings.UsersCanViewOnlyOwnRequests ? $"{fullMovieName} was successfully added!" : $"{fullMovieName} has already been requested!" }); @@ -457,13 +456,10 @@ private Response RequestMovie(int movieId) }; - Log.Trace(settings.DumpJson()); if (ShouldAutoApprove(RequestType.Movie, settings)) { - var cpSettings = CpService.GetSettings(); + var cpSettings = await CpService.GetSettingsAsync(); - Log.Trace("Settings: "); - Log.Trace(cpSettings.DumpJson); if (cpSettings.Enabled) { Log.Info("Adding movie to CP (No approval required)"); @@ -474,8 +470,7 @@ private Response RequestMovie(int movieId) { model.Approved = true; Log.Info("Adding movie to database (No approval required)"); - RequestService.AddRequest(model); - + await RequestService.AddRequestAsync(model); if (ShouldSendNotification()) { @@ -486,7 +481,7 @@ private Response RequestMovie(int movieId) DateTime = DateTime.Now, NotificationType = NotificationType.NewRequest }; - NotificationService.Publish(notificationModel); + await NotificationService.Publish(notificationModel); } return Response.AsJson(new JsonResponseModel { Result = true, Message = $"{fullMovieName} was successfully added!" }); } @@ -502,7 +497,7 @@ private Response RequestMovie(int movieId) { model.Approved = true; Log.Info("Adding movie to database (No approval required)"); - RequestService.AddRequest(model); + await RequestService.AddRequestAsync(model); if (ShouldSendNotification()) { @@ -513,7 +508,7 @@ private Response RequestMovie(int movieId) DateTime = DateTime.Now, NotificationType = NotificationType.NewRequest }; - NotificationService.Publish(notificationModel); + await NotificationService.Publish(notificationModel); } return Response.AsJson(new JsonResponseModel { Result = true, Message = $"{fullMovieName} was successfully added!" }); @@ -523,10 +518,10 @@ private Response RequestMovie(int movieId) try { Log.Info("Adding movie to database"); - var id = RequestService.AddRequest(model); + var id = await RequestService.AddRequestAsync(model); var notificationModel = new NotificationModel { Title = model.Title, User = Username, DateTime = DateTime.Now, NotificationType = NotificationType.NewRequest }; - NotificationService.Publish(notificationModel); + await NotificationService.Publish(notificationModel); return Response.AsJson(new JsonResponseModel { Result = true, Message = $"{fullMovieName} was successfully added!" }); } @@ -543,9 +538,8 @@ private Response RequestMovie(int movieId) /// /// The show identifier. /// The seasons. - /// if set to true [notify]. /// - private Response RequestTvShow(int showId, string seasons) + private async Task RequestTvShow(int showId, string seasons) { var tvApi = new TvMazeApi(); @@ -555,18 +549,18 @@ private Response RequestTvShow(int showId, string seasons) string fullShowName = $"{showInfo.name} ({firstAir.Year})"; //#if !DEBUG - var settings = PrService.GetSettings(); + var settings = await PrService.GetSettingsAsync(); // check if the show has already been requested Log.Info("Requesting tv show with id {0}", showId); - var existingRequest = RequestService.CheckRequest(showId); + var existingRequest = await RequestService.CheckRequestAsync(showId); if (existingRequest != null) { // check if the current user is already marked as a requester for this show, if not, add them if (!existingRequest.UserHasRequested(Username)) { existingRequest.RequestedUsers.Add(Username); - RequestService.UpdateRequest(existingRequest); + await RequestService.UpdateRequestAsync(existingRequest); } return Response.AsJson(new JsonResponseModel { Result = true, Message = settings.UsersCanViewOnlyOwnRequests ? $"{fullShowName} was successfully added!" : $"{fullShowName} has already been requested!" }); } @@ -635,16 +629,16 @@ private Response RequestTvShow(int showId, string seasons) if (ShouldAutoApprove(RequestType.TvShow, settings)) { - var sonarrSettings = SonarrService.GetSettings(); + var sonarrSettings = await SonarrService.GetSettingsAsync(); var sender = new TvSender(SonarrApi, SickrageApi); if (sonarrSettings.Enabled) { var result = sender.SendToSonarr(sonarrSettings, model); - if (result != null && !string.IsNullOrEmpty(result.title)) + if (!string.IsNullOrEmpty(result?.title)) { model.Approved = true; Log.Debug("Adding tv to database requests (No approval required & Sonarr)"); - RequestService.AddRequest(model); + await RequestService.AddRequestAsync(model); if (ShouldSendNotification()) { @@ -655,7 +649,7 @@ private Response RequestTvShow(int showId, string seasons) DateTime = DateTime.Now, NotificationType = NotificationType.NewRequest }; - NotificationService.Publish(notify1); + await NotificationService.Publish(notify1); } return Response.AsJson(new JsonResponseModel { Result = true, Message = $"{fullShowName} was successfully added!" }); } @@ -673,7 +667,7 @@ private Response RequestTvShow(int showId, string seasons) { model.Approved = true; Log.Debug("Adding tv to database requests (No approval required & SickRage)"); - RequestService.AddRequest(model); + await RequestService.AddRequestAsync(model); if (ShouldSendNotification()) { var notify2 = new NotificationModel @@ -683,7 +677,7 @@ private Response RequestTvShow(int showId, string seasons) DateTime = DateTime.Now, NotificationType = NotificationType.NewRequest }; - NotificationService.Publish(notify2); + await NotificationService.Publish(notify2); } return Response.AsJson(new JsonResponseModel { Result = true, Message = $"{fullShowName} was successfully added!" }); @@ -695,7 +689,7 @@ private Response RequestTvShow(int showId, string seasons) { model.Approved = true; Log.Debug("Adding tv to database requests (No approval required) and Sonarr/Sickrage not setup"); - RequestService.AddRequest(model); + await RequestService.AddRequestAsync(model); if (ShouldSendNotification()) { var notify2 = new NotificationModel @@ -705,7 +699,7 @@ private Response RequestTvShow(int showId, string seasons) DateTime = DateTime.Now, NotificationType = NotificationType.NewRequest }; - NotificationService.Publish(notify2); + await NotificationService.Publish(notify2); } return Response.AsJson(new JsonResponseModel { Result = true, Message = $"{fullShowName} was successfully added!" }); } @@ -714,10 +708,10 @@ private Response RequestTvShow(int showId, string seasons) } - RequestService.AddRequest(model); + await RequestService.AddRequestAsync(model); var notificationModel = new NotificationModel { Title = model.Title, User = Username, DateTime = DateTime.Now, NotificationType = NotificationType.NewRequest }; - NotificationService.Publish(notificationModel); + await NotificationService.Publish(notificationModel); return Response.AsJson(new JsonResponseModel { Result = true, Message = $"{fullShowName} was successfully added!" }); } @@ -728,7 +722,8 @@ private bool ShouldSendNotification() var claims = Context.CurrentUser?.Claims; if (claims != null) { - if (claims.Contains(UserClaims.Admin) || claims.Contains(UserClaims.PowerUser)) + var enumerable = claims as string[] ?? claims.ToArray(); + if (enumerable.Contains(UserClaims.Admin) || enumerable.Contains(UserClaims.PowerUser)) { sendNotification = false; // Don't bother sending a notification if the user is an admin } @@ -737,10 +732,10 @@ private bool ShouldSendNotification() } - private Response RequestAlbum(string releaseId) + private async Task RequestAlbum(string releaseId) { - var settings = PrService.GetSettings(); - var existingRequest = RequestService.CheckRequest(releaseId); + var settings = await PrService.GetSettingsAsync(); + var existingRequest = await RequestService.CheckRequestAsync(releaseId); Log.Debug("Checking for an existing request"); if (existingRequest != null) @@ -751,12 +746,11 @@ private Response RequestAlbum(string releaseId) Log.Debug("Not in the requested list so adding them and updating the request. User: {0}", Username); existingRequest.RequestedUsers.Add(Username); - RequestService.UpdateRequest(existingRequest); + await RequestService.UpdateRequestAsync(existingRequest); } return Response.AsJson(new JsonResponseModel { Result = true, Message = settings.UsersCanViewOnlyOwnRequests ? $"{existingRequest.Title} was successfully added!" : $"{existingRequest.Title} has already been requested!" }); } - Log.Debug("This is a new request"); var albumInfo = MusicBrainzApi.GetAlbum(releaseId); @@ -816,7 +810,7 @@ private Response RequestAlbum(string releaseId) if (!hpSettings.Enabled) { - RequestService.AddRequest(model); + await RequestService.AddRequestAsync(model); return Response.AsJson(new JsonResponseModel { @@ -826,9 +820,9 @@ private Response RequestAlbum(string releaseId) } var sender = new HeadphonesSender(HeadphonesApi, hpSettings, RequestService); - sender.AddAlbum(model).Wait(); + await sender.AddAlbum(model); model.Approved = true; - RequestService.AddRequest(model); + await RequestService.AddRequestAsync(model); if (ShouldSendNotification()) { @@ -839,7 +833,7 @@ private Response RequestAlbum(string releaseId) DateTime = DateTime.Now, NotificationType = NotificationType.NewRequest }; - NotificationService.Publish(notify2); + await NotificationService.Publish(notify2); } return @@ -859,9 +853,9 @@ private Response RequestAlbum(string releaseId) DateTime = DateTime.Now, NotificationType = NotificationType.NewRequest }; - NotificationService.Publish(notify2); + await NotificationService.Publish(notify2); } - var result = RequestService.AddRequest(model); + await RequestService.AddRequestAsync(model); return Response.AsJson(new JsonResponseModel { Result = true, @@ -902,10 +896,12 @@ private bool ShouldAutoApprove(RequestType requestType, PlexRequestSettings prSe } } - private Response NotifyUser(bool notify) + private async Task NotifyUser(bool notify) { - var auth = Auth.GetSettings().UserAuthentication; - var email = EmailNotificationSettings.GetSettings().EnableUserEmailNotifications; + var authSettings = await Auth.GetSettingsAsync(); + var auth = authSettings.UserAuthentication; + var emailSettings = await EmailNotificationSettings.GetSettingsAsync(); + var email = emailSettings.EnableUserEmailNotifications; if (!auth) { return Response.AsJson(new JsonResponseModel { Result = false, Message = "Sorry, but this functionality is currently only for users with Plex accounts" }); @@ -915,7 +911,7 @@ private Response NotifyUser(bool notify) return Response.AsJson(new JsonResponseModel { Result = false, Message = "Sorry, but your administrator has not yet enabled this functionality." }); } var username = Username; - var originalList = UsersToNotifyRepo.GetAll(); + var originalList = await UsersToNotifyRepo.GetAllAsync(); if (!notify) { if (originalList == null) @@ -925,7 +921,7 @@ private Response NotifyUser(bool notify) var userToRemove = originalList.FirstOrDefault(x => x.Username == username); if (userToRemove != null) { - UsersToNotifyRepo.Delete(userToRemove); + await UsersToNotifyRepo.DeleteAsync(userToRemove); } return Response.AsJson(new JsonResponseModel { Result = true }); } @@ -934,7 +930,7 @@ private Response NotifyUser(bool notify) if (originalList == null) { var userModel = new UsersToNotify { Username = username }; - var insertResult = UsersToNotifyRepo.Insert(userModel); + var insertResult = await UsersToNotifyRepo.InsertAsync(userModel); return Response.AsJson(insertResult != -1 ? new JsonResponseModel { Result = true } : new JsonResponseModel { Result = false, Message = "Could not save, please try again" }); } @@ -946,15 +942,16 @@ private Response NotifyUser(bool notify) else { var userModel = new UsersToNotify { Username = username }; - var insertResult = UsersToNotifyRepo.Insert(userModel); + var insertResult = await UsersToNotifyRepo.InsertAsync(userModel); return Response.AsJson(insertResult != -1 ? new JsonResponseModel { Result = true } : new JsonResponseModel { Result = false, Message = "Could not save, please try again" }); } } - private Response GetUserNotificationSettings() + private async Task GetUserNotificationSettings() { - var retval = UsersToNotifyRepo.GetAll().FirstOrDefault(x => x.Username == Username); - return Response.AsJson(retval != null); + var all = await UsersToNotifyRepo.GetAllAsync(); + var retVal = all.FirstOrDefault(x => x.Username == Username); + return Response.AsJson(retVal != null); } private Response GetSeasons() From fc57a2be471364556c6bf6d05f3a8d744d647209 Mon Sep 17 00:00:00 2001 From: tidusjar Date: Fri, 27 May 2016 22:13:06 +0100 Subject: [PATCH 22/26] Fixed styling on modal --- PlexRequests.UI/Content/Themes/plex.css | 12 ++++++++++++ PlexRequests.UI/Content/Themes/plex.min.css | 2 +- PlexRequests.UI/Content/Themes/plex.scss | 13 +++++++++++++ 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/PlexRequests.UI/Content/Themes/plex.css b/PlexRequests.UI/Content/Themes/plex.css index 783cf6d76..c0a7597af 100644 --- a/PlexRequests.UI/Content/Themes/plex.css +++ b/PlexRequests.UI/Content/Themes/plex.css @@ -144,3 +144,15 @@ button.list-group-item:focus { .modal-footer { background-color: #282828; } +.modal-content { + position: relative; + background-color: #282828; + border: 1px solid transparent; + border-radius: 0; + -webkit-box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5); + box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5); + -webkit-background-clip: padding-box; + -moz-background-clip: padding-box; + background-clip: padding-box; + outline: 0; } + diff --git a/PlexRequests.UI/Content/Themes/plex.min.css b/PlexRequests.UI/Content/Themes/plex.min.css index 5bfca0787..2fa5bbcc9 100644 --- a/PlexRequests.UI/Content/Themes/plex.min.css +++ b/PlexRequests.UI/Content/Themes/plex.min.css @@ -1 +1 @@ -.form-control-custom{background-color:#333 !important;}.nav-tabs>li.active>a,.nav-tabs>li.active>a:hover,.nav-tabs>li.active>a:focus{background:#df691a;}scroll-top-wrapper{background-color:#333;}.scroll-top-wrapper:hover{background-color:#df691a;}body{font-family:Open Sans Regular,Helvetica Neue,Helvetica,Arial,sans-serif;color:#eee;background-color:#1f1f1f;}.table-striped>tbody>tr:nth-of-type(odd){background-color:#333;}.table-hover>tbody>tr:hover{background-color:#282828;}fieldset{padding:15px;}legend{border-bottom:1px solid #333;}.form-control{color:#fefefe;background-color:#333;}.radio input[type="radio"],.radio-inline input[type="radio"],.checkbox input[type="checkbox"],.checkbox-inline input[type="checkbox"]{margin-left:-0;}.form-horizontal .radio,.form-horizontal .checkbox,.form-horizontal .radio-inline,.form-horizontal .checkbox-inline{margin-top:-15px;}.dropdown-menu{background-color:#282828;}.dropdown-menu .divider{background-color:#333;}.dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus{background-color:#333;}.input-group-addon{background-color:#333;}.nav>li>a:hover,.nav>li>a:focus{background-color:#df691a;}.nav-tabs>li>a:hover{border-color:#df691a #df691a transparent;}.nav-tabs>li.active>a,.nav-tabs>li.active>a:hover,.nav-tabs>li.active>a:focus{background-color:#df691a;border:1px solid #df691a;}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:hover,.nav-tabs.nav-justified>.active>a:focus{border:1px solid #df691a;}.navbar-default{background-color:#0a0a0a;}.navbar-default .navbar-brand{color:#df691a;}.navbar-default .navbar-nav>li>a:hover,.navbar-default .navbar-nav>li>a:focus{color:#f0ad4e;background-color:#282828;}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.active>a:hover,.navbar-default .navbar-nav>.active>a:focus{background-color:#282828;}.navbar-default .navbar-nav>.open>a,.navbar-default .navbar-nav>.open>a:hover,.navbar-default .navbar-nav>.open>a:focus{background-color:#df691a;color:#fff;}.pagination>li>a,.pagination>li>span{background-color:#282828;}.pagination>li>a:hover,.pagination>li>span:hover,.pagination>li>a:focus,.pagination>li>span:focus{background-color:#333;}.pagination>.disabled>span,.pagination>.disabled>span:hover,.pagination>.disabled>span:focus,.pagination>.disabled>a,.pagination>.disabled>a:hover,.pagination>.disabled>a:focus{color:#fefefe;background-color:#333;}.list-group-item{background-color:#282828;}a.list-group-item:hover,button.list-group-item:hover,a.list-group-item:focus,button.list-group-item:focus{background-color:#333;}.input-addon,.input-group-addon{color:#df691a;}.modal-header,.modal-footer{background-color:#282828;} \ No newline at end of file +.form-control-custom{background-color:#333 !important;}.nav-tabs>li.active>a,.nav-tabs>li.active>a:hover,.nav-tabs>li.active>a:focus{background:#df691a;}scroll-top-wrapper{background-color:#333;}.scroll-top-wrapper:hover{background-color:#df691a;}body{font-family:Open Sans Regular,Helvetica Neue,Helvetica,Arial,sans-serif;color:#eee;background-color:#1f1f1f;}.table-striped>tbody>tr:nth-of-type(odd){background-color:#333;}.table-hover>tbody>tr:hover{background-color:#282828;}fieldset{padding:15px;}legend{border-bottom:1px solid #333;}.form-control{color:#fefefe;background-color:#333;}.radio input[type="radio"],.radio-inline input[type="radio"],.checkbox input[type="checkbox"],.checkbox-inline input[type="checkbox"]{margin-left:-0;}.form-horizontal .radio,.form-horizontal .checkbox,.form-horizontal .radio-inline,.form-horizontal .checkbox-inline{margin-top:-15px;}.dropdown-menu{background-color:#282828;}.dropdown-menu .divider{background-color:#333;}.dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus{background-color:#333;}.input-group-addon{background-color:#333;}.nav>li>a:hover,.nav>li>a:focus{background-color:#df691a;}.nav-tabs>li>a:hover{border-color:#df691a #df691a transparent;}.nav-tabs>li.active>a,.nav-tabs>li.active>a:hover,.nav-tabs>li.active>a:focus{background-color:#df691a;border:1px solid #df691a;}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:hover,.nav-tabs.nav-justified>.active>a:focus{border:1px solid #df691a;}.navbar-default{background-color:#0a0a0a;}.navbar-default .navbar-brand{color:#df691a;}.navbar-default .navbar-nav>li>a:hover,.navbar-default .navbar-nav>li>a:focus{color:#f0ad4e;background-color:#282828;}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.active>a:hover,.navbar-default .navbar-nav>.active>a:focus{background-color:#282828;}.navbar-default .navbar-nav>.open>a,.navbar-default .navbar-nav>.open>a:hover,.navbar-default .navbar-nav>.open>a:focus{background-color:#df691a;color:#fff;}.pagination>li>a,.pagination>li>span{background-color:#282828;}.pagination>li>a:hover,.pagination>li>span:hover,.pagination>li>a:focus,.pagination>li>span:focus{background-color:#333;}.pagination>.disabled>span,.pagination>.disabled>span:hover,.pagination>.disabled>span:focus,.pagination>.disabled>a,.pagination>.disabled>a:hover,.pagination>.disabled>a:focus{color:#fefefe;background-color:#333;}.list-group-item{background-color:#282828;}a.list-group-item:hover,button.list-group-item:hover,a.list-group-item:focus,button.list-group-item:focus{background-color:#333;}.input-addon,.input-group-addon{color:#df691a;}.modal-header,.modal-footer{background-color:#282828;}.modal-content{position:relative;background-color:#282828;border:1px solid transparent;border-radius:0;-webkit-box-shadow:0 3px 9px rgba(0,0,0,.5);box-shadow:0 3px 9px rgba(0,0,0,.5);-webkit-background-clip:padding-box;-moz-background-clip:padding-box;background-clip:padding-box;outline:0;} \ No newline at end of file diff --git a/PlexRequests.UI/Content/Themes/plex.scss b/PlexRequests.UI/Content/Themes/plex.scss index 8e8a8aee3..1de0e2092 100644 --- a/PlexRequests.UI/Content/Themes/plex.scss +++ b/PlexRequests.UI/Content/Themes/plex.scss @@ -181,3 +181,16 @@ button.list-group-item:focus { .modal-footer { background-color: #282828; } + +.modal-content { + position: relative; + background-color: #282828; + border: 1px solid transparent; + border-radius: 0; + -webkit-box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5); + box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5); + -webkit-background-clip: padding-box; + -moz-background-clip: padding-box; + background-clip: padding-box; + outline: 0; +} From 79a8cf205988dfc976ffe5ec162b8e5d1cc4d574 Mon Sep 17 00:00:00 2001 From: tidusjar Date: Fri, 27 May 2016 22:19:03 +0100 Subject: [PATCH 23/26] Removed static declarations --- PlexRequests.Services/Notification/NotificationService.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/PlexRequests.Services/Notification/NotificationService.cs b/PlexRequests.Services/Notification/NotificationService.cs index 3e52e43fa..79e5dcb51 100644 --- a/PlexRequests.Services/Notification/NotificationService.cs +++ b/PlexRequests.Services/Notification/NotificationService.cs @@ -76,7 +76,7 @@ public void UnSubscribe(INotification notification) Observers.TryRemove(notification.NotificationName, out notification); } - private static async Task NotifyAsync(INotification notification, NotificationModel model) + private async Task NotifyAsync(INotification notification, NotificationModel model) { try { @@ -89,7 +89,7 @@ private static async Task NotifyAsync(INotification notification, NotificationMo } - private static async Task NotifyAsync(INotification notification, NotificationModel model, Settings settings) + private async Task NotifyAsync(INotification notification, NotificationModel model, Settings settings) { try { From 01a2bb3adcba929fd1a4c6416a31f9637ef0c919 Mon Sep 17 00:00:00 2001 From: Sean Callinan Date: Sat, 28 May 2016 10:15:25 +1200 Subject: [PATCH 24/26] Use HTTPS for the poster images, so there aren't any mixed content warnings when serving the application via an HTTPS reverse proxy --- PlexRequests.UI/Modules/SearchModule.cs | 2 +- PlexRequests.UI/Views/Requests/Index.cshtml | 2 +- PlexRequests.UI/Views/Search/Index.cshtml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/PlexRequests.UI/Modules/SearchModule.cs b/PlexRequests.UI/Modules/SearchModule.cs index efae9678a..9a578da98 100644 --- a/PlexRequests.UI/Modules/SearchModule.cs +++ b/PlexRequests.UI/Modules/SearchModule.cs @@ -473,7 +473,7 @@ private Response RequestMovie(int movieId) Type = RequestType.Movie, Overview = movieInfo.Overview, ImdbId = movieInfo.ImdbId, - PosterPath = "http://image.tmdb.org/t/p/w150/" + movieInfo.PosterPath, + PosterPath = "https://image.tmdb.org/t/p/w150/" + movieInfo.PosterPath, Title = movieInfo.Title, ReleaseDate = movieInfo.ReleaseDate ?? DateTime.MinValue, Status = movieInfo.Status, diff --git a/PlexRequests.UI/Views/Requests/Index.cshtml b/PlexRequests.UI/Views/Requests/Index.cshtml index cdf45b288..df5ce4890 100644 --- a/PlexRequests.UI/Views/Requests/Index.cshtml +++ b/PlexRequests.UI/Views/Requests/Index.cshtml @@ -132,7 +132,7 @@
{{#if_eq type "movie"}} {{#if posterPath}} - poster + poster {{/if}} {{/if_eq}} {{#if_eq type "tv"}} diff --git a/PlexRequests.UI/Views/Search/Index.cshtml b/PlexRequests.UI/Views/Search/Index.cshtml index 64f56a0ce..a34bec151 100644 --- a/PlexRequests.UI/Views/Search/Index.cshtml +++ b/PlexRequests.UI/Views/Search/Index.cshtml @@ -144,7 +144,7 @@ {{#if_eq type "movie"}} {{#if posterPath}} - poster + poster {{/if}} {{/if_eq}} {{#if_eq type "tv"}} From a35516b6465f6ded9b5dfefa0b33700057adea34 Mon Sep 17 00:00:00 2001 From: tidusjar Date: Sat, 28 May 2016 21:54:36 +0100 Subject: [PATCH 25/26] Updated dapper.contrib. Looks like there was a bug in the async methods. --- PlexRequests.Store/PlexRequests.Store.csproj | 15 +++++++++------ PlexRequests.Store/packages.config | 4 ++-- PlexRequests.UI/Modules/ApprovalModule.cs | 4 ++-- PlexRequests.UI/Modules/SearchModule.cs | 5 +++-- 4 files changed, 16 insertions(+), 12 deletions(-) diff --git a/PlexRequests.Store/PlexRequests.Store.csproj b/PlexRequests.Store/PlexRequests.Store.csproj index f9feb0c3b..c5dd29053 100644 --- a/PlexRequests.Store/PlexRequests.Store.csproj +++ b/PlexRequests.Store/PlexRequests.Store.csproj @@ -31,11 +31,20 @@ 4 + + ..\packages\Dapper.1.50.0-beta8\lib\net45\Dapper.dll + True + + + ..\packages\Dapper.Contrib.1.50.0-beta8\lib\net45\Dapper.Contrib.dll + True + ..\Assemblies\Mono.Data.Sqlite.dll + @@ -43,12 +52,6 @@ - - ..\packages\Dapper.1.42\lib\net45\Dapper.dll - - - ..\packages\Dapper.Contrib.1.43\lib\net45\Dapper.Contrib.dll - ..\packages\Newtonsoft.Json.8.0.2\lib\net45\Newtonsoft.Json.dll diff --git a/PlexRequests.Store/packages.config b/PlexRequests.Store/packages.config index 0347c0d1b..457f93723 100644 --- a/PlexRequests.Store/packages.config +++ b/PlexRequests.Store/packages.config @@ -1,7 +1,7 @@  - - + + \ No newline at end of file diff --git a/PlexRequests.UI/Modules/ApprovalModule.cs b/PlexRequests.UI/Modules/ApprovalModule.cs index 33356ca02..47ba387ef 100644 --- a/PlexRequests.UI/Modules/ApprovalModule.cs +++ b/PlexRequests.UI/Modules/ApprovalModule.cs @@ -180,7 +180,7 @@ private Response RequestTvAndUpdateStatus(RequestedModel request, string quality private Response RequestMovieAndUpdateStatus(RequestedModel request, string qualityId) { var cpSettings = CpService.GetSettings(); - var cp = new CouchPotatoApi(); + Log.Info("Adding movie to CouchPotato : {0}", request.Title); if (!cpSettings.Enabled) { @@ -199,7 +199,7 @@ private Response RequestMovieAndUpdateStatus(RequestedModel request, string qual }); } - var result = cp.AddMovie(request.ImdbId, cpSettings.ApiKey, request.Title, cpSettings.FullUri, string.IsNullOrEmpty(qualityId) ? cpSettings.ProfileId : qualityId); + var result = CpApi.AddMovie(request.ImdbId, cpSettings.ApiKey, request.Title, cpSettings.FullUri, string.IsNullOrEmpty(qualityId) ? cpSettings.ProfileId : qualityId); Log.Trace("Adding movie to CP result {0}", result); if (result) { diff --git a/PlexRequests.UI/Modules/SearchModule.cs b/PlexRequests.UI/Modules/SearchModule.cs index 27aa8a2ba..0de1a23b9 100644 --- a/PlexRequests.UI/Modules/SearchModule.cs +++ b/PlexRequests.UI/Modules/SearchModule.cs @@ -380,7 +380,7 @@ await Task.Run(() => MusicBrainzApi.SearchAlbum(searchTerm)).ContinueWith((t) => DateTime release; DateTimeHelper.CustomParse(a.ReleaseEvents?.FirstOrDefault()?.date, out release); var artist = a.ArtistCredit?.FirstOrDefault()?.artist; - if (Checker.IsAlbumAvailable(plexAlbums.ToArray(), a.title, release.ToString("yyyy"), artist.name)) + if (Checker.IsAlbumAvailable(plexAlbums.ToArray(), a.title, release.ToString("yyyy"), artist?.name)) { viewA.Available = true; } @@ -433,8 +433,9 @@ private async Task RequestMovie(int movieId) return Response.AsJson(new JsonResponseModel { Result = false, Message = $"{fullMovieName} is already in Plex!" }); } } - catch (ApplicationSettingsException) + catch (Exception e) { + Log.Error(e); return Response.AsJson(new JsonResponseModel { Result = false, Message = $"We could not check if {fullMovieName} is in Plex, are you sure it's correctly setup?" }); } //#endif From 8824f9bfcdbca9354507651327e5ca48b6a84f3f Mon Sep 17 00:00:00 2001 From: tidusjar Date: Sun, 29 May 2016 16:51:16 +0100 Subject: [PATCH 26/26] bump build ver --- appveyor.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 08772ff6e..ee0d12bee 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -3,9 +3,9 @@ configuration: Release assembly_info: patch: true file: '**\AssemblyInfo.*' - assembly_version: '1.7.4' + assembly_version: '1.7.5' assembly_file_version: '{version}' - assembly_informational_version: '1.7.4' + assembly_informational_version: '1.7.5' before_build: - cmd: appveyor-retry nuget restore build: