diff --git a/PlexRequests.Api.Models/PlexRequests.Api.Models.csproj b/PlexRequests.Api.Models/PlexRequests.Api.Models.csproj index 683e75456..ecd891927 100644 --- a/PlexRequests.Api.Models/PlexRequests.Api.Models.csproj +++ b/PlexRequests.Api.Models/PlexRequests.Api.Models.csproj @@ -84,6 +84,7 @@ + diff --git a/PlexRequests.Api.Models/Tv/TvMazeEpisodes.cs b/PlexRequests.Api.Models/Tv/TvMazeEpisodes.cs new file mode 100644 index 000000000..fb301bd7e --- /dev/null +++ b/PlexRequests.Api.Models/Tv/TvMazeEpisodes.cs @@ -0,0 +1,44 @@ +#region Copyright +// /************************************************************************ +// Copyright (c) 2016 Jamie Rees +// File: TvMazeEpisodes.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 +namespace PlexRequests.Api.Models.Tv +{ + public class TvMazeEpisodes + { + public int id { get; set; } + public string url { get; set; } + public string name { get; set; } + public int season { get; set; } + public int number { get; set; } + public string airdate { get; set; } + public string airtime { get; set; } + public string airstamp { get; set; } + public int runtime { get; set; } + public Image image { get; set; } + public string summary { get; set; } + public Links _links { get; set; } + } +} \ No newline at end of file diff --git a/PlexRequests.Api.Models/Tv/TvMazeSearch.cs b/PlexRequests.Api.Models/Tv/TvMazeSearch.cs index 399154c57..d879579bf 100644 --- a/PlexRequests.Api.Models/Tv/TvMazeSearch.cs +++ b/PlexRequests.Api.Models/Tv/TvMazeSearch.cs @@ -1,97 +1,119 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace PlexRequests.Api.Models.Tv -{ - public class Schedule - { - public string time { get; set; } - public List days { get; set; } - } - - public class Rating - { - public double? average { get; set; } - } - - public class Country - { - public string name { get; set; } - public string code { get; set; } - public string timezone { get; set; } - } - - public class Network - { - public int id { get; set; } - public string name { get; set; } - public Country country { get; set; } - } - - public class Externals - { - public int? tvrage { get; set; } - public int? thetvdb { get; set; } - public string imdb { get; set; } - } - - public class Image - { - public string medium { get; set; } - public string original { get; set; } - } - - public class Self - { - public string href { get; set; } - } - - public class Previousepisode - { - public string href { get; set; } - } - - public class Nextepisode - { - public string href { get; set; } - } - - public class Links - { - public Self self { get; set; } - public Previousepisode previousepisode { get; set; } - public Nextepisode nextepisode { get; set; } - } - - public class Show - { - public int id { get; set; } - public string url { get; set; } - public string name { get; set; } - public string type { get; set; } - public string language { get; set; } - public List genres { get; set; } - public string status { get; set; } - public int? runtime { get; set; } - public string premiered { get; set; } - public Schedule schedule { get; set; } - public Rating rating { get; set; } - public int weight { get; set; } - public Network network { get; set; } - public object webChannel { get; set; } - public Externals externals { get; set; } - public Image image { get; set; } - public string summary { get; set; } - public int updated { get; set; } - public Links _links { get; set; } - } - - public class TvMazeSearch - { - public double score { get; set; } - public Show show { get; set; } - } -} +#region Copyright +// /************************************************************************ +// Copyright (c) 2016 Jamie Rees +// File: TvMazeSearch.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.Collections.Generic; + +namespace PlexRequests.Api.Models.Tv +{ + public class Schedule + { + public List days { get; set; } + public string time { get; set; } + } + + public class Rating + { + public double? average { get; set; } + } + + public class Country + { + public string code { get; set; } + public string name { get; set; } + public string timezone { get; set; } + } + + public class Network + { + public Country country { get; set; } + public int id { get; set; } + public string name { get; set; } + } + + public class Externals + { + public string imdb { get; set; } + public int? thetvdb { get; set; } + public int? tvrage { get; set; } + } + + public class Image + { + public string medium { get; set; } + public string original { get; set; } + } + + public class Self + { + public string href { get; set; } + } + + public class Previousepisode + { + public string href { get; set; } + } + + public class Nextepisode + { + public string href { get; set; } + } + + public class Links + { + public Nextepisode nextepisode { get; set; } + public Previousepisode previousepisode { get; set; } + public Self self { get; set; } + } + + public class Show + { + public Links _links { get; set; } + public Externals externals { get; set; } + public List genres { get; set; } + public int id { get; set; } + public Image image { get; set; } + public string language { get; set; } + public string name { get; set; } + public Network network { get; set; } + public string premiered { get; set; } + public Rating rating { get; set; } + public int? runtime { get; set; } + public Schedule schedule { get; set; } + public string status { get; set; } + public string summary { get; set; } + public string type { get; set; } + public int updated { get; set; } + public string url { get; set; } + public object webChannel { get; set; } + public int weight { get; set; } + } + + public class TvMazeSearch + { + public double score { get; set; } + public Show show { get; set; } + } +} \ No newline at end of file diff --git a/PlexRequests.Api/TvMazeApi.cs b/PlexRequests.Api/TvMazeApi.cs index d287e80bf..5d5c60c0f 100644 --- a/PlexRequests.Api/TvMazeApi.cs +++ b/PlexRequests.Api/TvMazeApi.cs @@ -1,108 +1,121 @@ -#region Copyright -// /************************************************************************ -// Copyright (c) 2016 Jamie Rees -// File: TvMazeApi.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 NLog; - -using PlexRequests.Api.Models.Tv; - -using RestSharp; - -namespace PlexRequests.Api -{ - public class TvMazeApi : TvMazeBase - { - public TvMazeApi() - { - Api = new ApiRequest(); - } - private ApiRequest Api { get; } - private static Logger Log = LogManager.GetCurrentClassLogger(); - public List Search(string searchTerm) - { - var request = new RestRequest - { - Method = Method.GET, - Resource = "search/shows?q={searchTerm}" - }; - request.AddUrlSegment("searchTerm", searchTerm); - request.AddHeader("Content-Type", "application/json"); - - return Api.Execute>(request, new Uri(Uri)); - } - - public TvMazeShow ShowLookup(int showId) - { - var request = new RestRequest - { - Method = Method.GET, - Resource = "shows/{id}" - }; - request.AddUrlSegment("id", showId.ToString()); - request.AddHeader("Content-Type", "application/json"); - - return Api.Execute(request, new Uri(Uri)); - } - - public TvMazeShow ShowLookupByTheTvDbId(int theTvDbId) - { - var request = new RestRequest - { - Method = Method.GET, - Resource = "lookup/shows?thetvdb={id}" - }; - request.AddUrlSegment("id", theTvDbId.ToString()); - request.AddHeader("Content-Type", "application/json"); - - var obj = Api.Execute(request, new Uri(Uri)); - obj.seasonCount = GetSeasonCount(obj.id); - - return obj; - } - - public List GetSeasons(int id) - { - var request = new RestRequest - { - Method = Method.GET, - Resource = "shows/{id}/seasons" - }; - request.AddUrlSegment("id", id.ToString()); - request.AddHeader("Content-Type", "application/json"); - - return Api.Execute>(request, new Uri(Uri)); - } - public int GetSeasonCount(int id) - { - var obj = GetSeasons(id); - var seasons = obj.Select(x => x.number > 0); - return seasons.Count(); - } - - } +#region Copyright +// /************************************************************************ +// Copyright (c) 2016 Jamie Rees +// File: TvMazeApi.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 NLog; + +using PlexRequests.Api.Models.Tv; + +using RestSharp; + +namespace PlexRequests.Api +{ + public class TvMazeApi : TvMazeBase + { + public TvMazeApi() + { + Api = new ApiRequest(); + } + private ApiRequest Api { get; } + private static Logger Log = LogManager.GetCurrentClassLogger(); + public List Search(string searchTerm) + { + var request = new RestRequest + { + Method = Method.GET, + Resource = "search/shows?q={searchTerm}" + }; + request.AddUrlSegment("searchTerm", searchTerm); + request.AddHeader("Content-Type", "application/json"); + + return Api.Execute>(request, new Uri(Uri)); + } + + public TvMazeShow ShowLookup(int showId) + { + var request = new RestRequest + { + Method = Method.GET, + Resource = "shows/{id}" + }; + request.AddUrlSegment("id", showId.ToString()); + request.AddHeader("Content-Type", "application/json"); + + return Api.Execute(request, new Uri(Uri)); + } + + public IEnumerable EpisodeLookup(int showId) + { + var request = new RestRequest + { + Method = Method.GET, + Resource = "shows/{id}/episodes" + }; + request.AddUrlSegment("id", showId.ToString()); + request.AddHeader("Content-Type", "application/json"); + + return Api.Execute>(request, new Uri(Uri)); + } + + public TvMazeShow ShowLookupByTheTvDbId(int theTvDbId) + { + var request = new RestRequest + { + Method = Method.GET, + Resource = "lookup/shows?thetvdb={id}" + }; + request.AddUrlSegment("id", theTvDbId.ToString()); + request.AddHeader("Content-Type", "application/json"); + + var obj = Api.Execute(request, new Uri(Uri)); + obj.seasonCount = GetSeasonCount(obj.id); + + return obj; + } + + public List GetSeasons(int id) + { + var request = new RestRequest + { + Method = Method.GET, + Resource = "shows/{id}/seasons" + }; + request.AddUrlSegment("id", id.ToString()); + request.AddHeader("Content-Type", "application/json"); + + return Api.Execute>(request, new Uri(Uri)); + } + public int GetSeasonCount(int id) + { + var obj = GetSeasons(id); + var seasons = obj.Select(x => x.number > 0); + return seasons.Count(); + } + + } } \ No newline at end of file diff --git a/PlexRequests.UI/Content/base.css b/PlexRequests.UI/Content/base.css index c149b1b96..0a322e81c 100644 --- a/PlexRequests.UI/Content/base.css +++ b/PlexRequests.UI/Content/base.css @@ -329,3 +329,7 @@ label { .landing-title { font-weight: bold; } +.checkbox-custom { + margin-top: 0 !important; + margin-bottom: 0 !important; } + diff --git a/PlexRequests.UI/Content/base.min.css b/PlexRequests.UI/Content/base.min.css index 655178aec..de31f3f8e 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;}.landing-block .media{max-width:450px;}}@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;}.bootstrap-datetimepicker-widget.dropdown-menu{background-color:#4e5d6c;}.bootstrap-datetimepicker-widget.dropdown-menu.bottom:after{border-bottom:6px solid #4e5d6c !important;}.bootstrap-datetimepicker-widget table td.active,.bootstrap-datetimepicker-widget table td.active:hover{color:#fff !important;}.landing-header{display:block;margin:60px auto;}.landing-block{background:#2f2f2f !important;padding:5px;}.landing-block .media{margin:30px auto;max-width:450px;}.landing-block .media .media-left{display:inline-block;float:left;width:70px;}.landing-block .media .media-left i.fa{font-size:3em;}.landing-title{font-weight:bold;} \ No newline at end of file +@media(min-width:768px){.row{position:relative;}.bottom-align-text{position:absolute;bottom:0;right:0;}.landing-block .media{max-width:450px;}}@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;}.bootstrap-datetimepicker-widget.dropdown-menu{background-color:#4e5d6c;}.bootstrap-datetimepicker-widget.dropdown-menu.bottom:after{border-bottom:6px solid #4e5d6c !important;}.bootstrap-datetimepicker-widget table td.active,.bootstrap-datetimepicker-widget table td.active:hover{color:#fff !important;}.landing-header{display:block;margin:60px auto;}.landing-block{background:#2f2f2f !important;padding:5px;}.landing-block .media{margin:30px auto;max-width:450px;}.landing-block .media .media-left{display:inline-block;float:left;width:70px;}.landing-block .media .media-left i.fa{font-size:3em;}.landing-title{font-weight:bold;}.checkbox-custom{margin-top:0 !important;margin-bottom:0 !important;} \ No newline at end of file diff --git a/PlexRequests.UI/Content/base.scss b/PlexRequests.UI/Content/base.scss index 8a2b8533b..8b5a1e45e 100644 --- a/PlexRequests.UI/Content/base.scss +++ b/PlexRequests.UI/Content/base.scss @@ -384,7 +384,7 @@ $border-radius: 10px; .bootstrap-datetimepicker-widget table td.active, .bootstrap-datetimepicker-widget table td.active:hover { - color: #fff !important; + color: #fff $i; } .landing-header { @@ -393,7 +393,7 @@ $border-radius: 10px; } .landing-block { - background: #2f2f2f !important; + background: #2f2f2f $i; padding: 5px; } @@ -415,3 +415,8 @@ $border-radius: 10px; .landing-title { font-weight: bold; } + +.checkbox-custom{ + margin-top:0 $i; + margin-bottom:0 $i; +} \ No newline at end of file diff --git a/PlexRequests.UI/Content/search-1.7.js b/PlexRequests.UI/Content/search-1.7.js index 5aaf1403e..b149c2d42 100644 --- a/PlexRequests.UI/Content/search-1.7.js +++ b/PlexRequests.UI/Content/search-1.7.js @@ -12,9 +12,14 @@ $(function () { var searchSource = $("#search-template").html(); var seasonsSource = $("#seasons-template").html(); var musicSource = $("#music-template").html(); + var seasonsNumberSource = $("#seasonNumber-template").html(); + var episodeSource = $("#episode-template").html(); + var searchTemplate = Handlebars.compile(searchSource); var musicTemplate = Handlebars.compile(musicSource); var seasonsTemplate = Handlebars.compile(seasonsSource); + var seasonsNumberTemplate = Handlebars.compile(seasonsNumberSource); + var episodesTemplate = Handlebars.compile(episodeSource); var base = $('#baseUrl').text(); @@ -256,6 +261,7 @@ $(function () { $('#typeModal').val(type); }); + function focusSearch($content) { if ($content.length > 0) { $('input[type=text].form-control', $content).first().focus(); @@ -531,4 +537,71 @@ $(function () { }); + $('#episodesModal').on('show.bs.modal', function (event) { + var button = $(event.relatedTarget); // Button that triggered the modal + var id = button.data('identifier'); // Extract info from data-* attributes + var url = createBaseUrl(base, '/search/episodes/'); + var seenSeasons = []; + $.ajax({ + type: "get", + url: url, + data: { tvId: id }, + dataType: "json", + success: function (results) { + var $content = $("#episodesBody"); + $content.html(""); + $('#selectedEpisodeId').val(id); + results.forEach(function (result) { + + + var episodes = buildEpisodesView(result); + + if (!seenSeasons.find(x => x === episodes.season)) { + // Create the seasons heading + seenSeasons.push(episodes.season); + var context = buildSeasonsCount(result); + $content.append(seasonsNumberTemplate(context)); + } + var episodesResult = episodesTemplate(episodes); + $content.append(episodesResult); + }); + }, + error: function (e) { + console.log(e); + generateNotify("Something went wrong!", "danger"); + } + }); + + function buildSeasonsContext(result) { + var context = { + id: result + }; + return context; + }; + + function buildSeasonsCount(result) { + return { + seasonNumber: result.season + } + } + + + function buildEpisodesView(result) { + return { + id: result.id, + url: result.url, + name: result.name, + season: result.season, + number: result.number, + airdate: result.airdate, + airtime: result.airtime, + airstamp: result.airstamp, + runtime: result.runtime, + image: result.image, + summary: result.summary, + links : result._links + } + } + }); + }); diff --git a/PlexRequests.UI/Modules/SearchModule.cs b/PlexRequests.UI/Modules/SearchModule.cs index 62535a5d0..f6275ef2e 100644 --- a/PlexRequests.UI/Modules/SearchModule.cs +++ b/PlexRequests.UI/Modules/SearchModule.cs @@ -100,6 +100,7 @@ namespace PlexRequests.UI.Modules IssueService = issue; Analytics = a; RequestLimitRepo = rl; + TvApi = new TvMazeApi(); Get["SearchIndex","/", true] = async (x, ct) => await RequestLoad(); @@ -120,7 +121,9 @@ namespace PlexRequests.UI.Modules Get["/notifyuser", true] = async (x, ct) => await GetUserNotificationSettings(); Get["/seasons"] = x => GetSeasons(); + Get["/episodes"] = x => GetEpisodes(); } + private TvMazeApi TvApi { get; } private IPlexApi PlexApi { get; } private TheMovieDbApi MovieApi { get; } private INotificationService NotificationService { get; } @@ -854,14 +857,21 @@ namespace PlexRequests.UI.Modules private Response GetSeasons() { - var tv = new TvMazeApi(); var seriesId = (int)Request.Query.tvId; - var show = tv.ShowLookupByTheTvDbId(seriesId); - var seasons = tv.GetSeasons(show.id); + var show = TvApi.ShowLookupByTheTvDbId(seriesId); + var seasons = TvApi.GetSeasons(show.id); var model = seasons.Select(x => x.number); return Response.AsJson(model); } + private Response GetEpisodes() + { + var seriesId = (int)Request.Query.tvId; + var show = TvApi.ShowLookupByTheTvDbId(seriesId); + var seasons = TvApi.EpisodeLookup(show.id); + return Response.AsJson(seasons); + } + private async Task CheckRequestLimit(PlexRequestSettings s, RequestType type) { if (IsAdmin) diff --git a/PlexRequests.UI/Resources/UI.Designer.cs b/PlexRequests.UI/Resources/UI.Designer.cs index 690911e8f..429c6f090 100644 --- a/PlexRequests.UI/Resources/UI.Designer.cs +++ b/PlexRequests.UI/Resources/UI.Designer.cs @@ -888,6 +888,15 @@ namespace PlexRequests.UI.Resources { } } + /// + /// Looks up a localized string similar to Select Episode. + /// + public static string Search_SelectEpisode { + get { + return ResourceManager.GetString("Search_SelectEpisode", resourceCulture); + } + } + /// /// Looks up a localized string similar to Select . /// diff --git a/PlexRequests.UI/Resources/UI.resx b/PlexRequests.UI/Resources/UI.resx index 8ac13a49e..506a94488 100644 --- a/PlexRequests.UI/Resources/UI.resx +++ b/PlexRequests.UI/Resources/UI.resx @@ -431,4 +431,7 @@ French + + Select Episode + \ No newline at end of file diff --git a/PlexRequests.UI/Views/Search/Index.cshtml b/PlexRequests.UI/Views/Search/Index.cshtml index d81fa8a5e..b9cb4c633 100644 --- a/PlexRequests.UI/Views/Search/Index.cshtml +++ b/PlexRequests.UI/Views/Search/Index.cshtml @@ -192,6 +192,7 @@
  • @UI.Search_FirstSeason
  • @UI.Search_LatestSeason
  • @UI.Search_SelectSeason...
  • +
  • @UI.Search_SelectEpisode...
  • {{/if_eq}} @@ -291,6 +292,26 @@ + + + + + + + +