mirror of
https://github.com/Ombi-app/Ombi.git
synced 2025-07-11 15:56:05 -07:00
frontend and tv episodes api work for #254
This commit is contained in:
parent
d7c40164cb
commit
33ba1db20b
12 changed files with 433 additions and 210 deletions
|
@ -84,6 +84,7 @@
|
||||||
<Compile Include="Sonarr\SonarrProfile.cs" />
|
<Compile Include="Sonarr\SonarrProfile.cs" />
|
||||||
<Compile Include="Sonarr\SystemStatus.cs" />
|
<Compile Include="Sonarr\SystemStatus.cs" />
|
||||||
<Compile Include="Tv\Authentication.cs" />
|
<Compile Include="Tv\Authentication.cs" />
|
||||||
|
<Compile Include="Tv\TvMazeEpisodes.cs" />
|
||||||
<Compile Include="Tv\TvMazeSearch.cs" />
|
<Compile Include="Tv\TvMazeSearch.cs" />
|
||||||
<Compile Include="Tv\TvMazeSeasons.cs" />
|
<Compile Include="Tv\TvMazeSeasons.cs" />
|
||||||
<Compile Include="Tv\TVMazeShow.cs" />
|
<Compile Include="Tv\TVMazeShow.cs" />
|
||||||
|
|
44
PlexRequests.Api.Models/Tv/TvMazeEpisodes.cs
Normal file
44
PlexRequests.Api.Models/Tv/TvMazeEpisodes.cs
Normal file
|
@ -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; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,97 +1,119 @@
|
||||||
using System;
|
#region Copyright
|
||||||
using System.Collections.Generic;
|
// /************************************************************************
|
||||||
using System.Linq;
|
// Copyright (c) 2016 Jamie Rees
|
||||||
using System.Text;
|
// File: TvMazeSearch.cs
|
||||||
using System.Threading.Tasks;
|
// Created By: Jamie Rees
|
||||||
|
//
|
||||||
namespace PlexRequests.Api.Models.Tv
|
// Permission is hereby granted, free of charge, to any person obtaining
|
||||||
{
|
// a copy of this software and associated documentation files (the
|
||||||
public class Schedule
|
// "Software"), to deal in the Software without restriction, including
|
||||||
{
|
// without limitation the rights to use, copy, modify, merge, publish,
|
||||||
public string time { get; set; }
|
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
public List<object> days { get; set; }
|
// permit persons to whom the Software is furnished to do so, subject to
|
||||||
}
|
// the following conditions:
|
||||||
|
//
|
||||||
public class Rating
|
// The above copyright notice and this permission notice shall be
|
||||||
{
|
// included in all copies or substantial portions of the Software.
|
||||||
public double? average { get; set; }
|
//
|
||||||
}
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
public class Country
|
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
{
|
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
public string name { get; set; }
|
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
public string code { get; set; }
|
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
public string timezone { get; set; }
|
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
}
|
// ************************************************************************/
|
||||||
|
#endregion
|
||||||
public class Network
|
using System.Collections.Generic;
|
||||||
{
|
|
||||||
public int id { get; set; }
|
namespace PlexRequests.Api.Models.Tv
|
||||||
public string name { get; set; }
|
{
|
||||||
public Country country { get; set; }
|
public class Schedule
|
||||||
}
|
{
|
||||||
|
public List<object> days { get; set; }
|
||||||
public class Externals
|
public string time { get; set; }
|
||||||
{
|
}
|
||||||
public int? tvrage { get; set; }
|
|
||||||
public int? thetvdb { get; set; }
|
public class Rating
|
||||||
public string imdb { get; set; }
|
{
|
||||||
}
|
public double? average { get; set; }
|
||||||
|
}
|
||||||
public class Image
|
|
||||||
{
|
public class Country
|
||||||
public string medium { get; set; }
|
{
|
||||||
public string original { get; set; }
|
public string code { get; set; }
|
||||||
}
|
public string name { get; set; }
|
||||||
|
public string timezone { get; set; }
|
||||||
public class Self
|
}
|
||||||
{
|
|
||||||
public string href { get; set; }
|
public class Network
|
||||||
}
|
{
|
||||||
|
public Country country { get; set; }
|
||||||
public class Previousepisode
|
public int id { get; set; }
|
||||||
{
|
public string name { get; set; }
|
||||||
public string href { get; set; }
|
}
|
||||||
}
|
|
||||||
|
public class Externals
|
||||||
public class Nextepisode
|
{
|
||||||
{
|
public string imdb { get; set; }
|
||||||
public string href { get; set; }
|
public int? thetvdb { get; set; }
|
||||||
}
|
public int? tvrage { get; set; }
|
||||||
|
}
|
||||||
public class Links
|
|
||||||
{
|
public class Image
|
||||||
public Self self { get; set; }
|
{
|
||||||
public Previousepisode previousepisode { get; set; }
|
public string medium { get; set; }
|
||||||
public Nextepisode nextepisode { get; set; }
|
public string original { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Show
|
public class Self
|
||||||
{
|
{
|
||||||
public int id { get; set; }
|
public string href { get; set; }
|
||||||
public string url { get; set; }
|
}
|
||||||
public string name { get; set; }
|
|
||||||
public string type { get; set; }
|
public class Previousepisode
|
||||||
public string language { get; set; }
|
{
|
||||||
public List<object> genres { get; set; }
|
public string href { get; set; }
|
||||||
public string status { get; set; }
|
}
|
||||||
public int? runtime { get; set; }
|
|
||||||
public string premiered { get; set; }
|
public class Nextepisode
|
||||||
public Schedule schedule { get; set; }
|
{
|
||||||
public Rating rating { get; set; }
|
public string href { get; set; }
|
||||||
public int weight { get; set; }
|
}
|
||||||
public Network network { get; set; }
|
|
||||||
public object webChannel { get; set; }
|
public class Links
|
||||||
public Externals externals { get; set; }
|
{
|
||||||
public Image image { get; set; }
|
public Nextepisode nextepisode { get; set; }
|
||||||
public string summary { get; set; }
|
public Previousepisode previousepisode { get; set; }
|
||||||
public int updated { get; set; }
|
public Self self { get; set; }
|
||||||
public Links _links { get; set; }
|
}
|
||||||
}
|
|
||||||
|
public class Show
|
||||||
public class TvMazeSearch
|
{
|
||||||
{
|
public Links _links { get; set; }
|
||||||
public double score { get; set; }
|
public Externals externals { get; set; }
|
||||||
public Show show { get; set; }
|
public List<object> 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; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,108 +1,121 @@
|
||||||
#region Copyright
|
#region Copyright
|
||||||
// /************************************************************************
|
// /************************************************************************
|
||||||
// Copyright (c) 2016 Jamie Rees
|
// Copyright (c) 2016 Jamie Rees
|
||||||
// File: TvMazeApi.cs
|
// File: TvMazeApi.cs
|
||||||
// Created By: Jamie Rees
|
// Created By: Jamie Rees
|
||||||
//
|
//
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining
|
// Permission is hereby granted, free of charge, to any person obtaining
|
||||||
// a copy of this software and associated documentation files (the
|
// a copy of this software and associated documentation files (the
|
||||||
// "Software"), to deal in the Software without restriction, including
|
// "Software"), to deal in the Software without restriction, including
|
||||||
// without limitation the rights to use, copy, modify, merge, publish,
|
// without limitation the rights to use, copy, modify, merge, publish,
|
||||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
// permit persons to whom the Software is furnished to do so, subject to
|
// permit persons to whom the Software is furnished to do so, subject to
|
||||||
// the following conditions:
|
// the following conditions:
|
||||||
//
|
//
|
||||||
// The above copyright notice and this permission notice shall be
|
// The above copyright notice and this permission notice shall be
|
||||||
// included in all copies or substantial portions of the Software.
|
// included in all copies or substantial portions of the Software.
|
||||||
//
|
//
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
// ************************************************************************/
|
// ************************************************************************/
|
||||||
#endregion
|
#endregion
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using NLog;
|
using NLog;
|
||||||
|
|
||||||
using PlexRequests.Api.Models.Tv;
|
using PlexRequests.Api.Models.Tv;
|
||||||
|
|
||||||
using RestSharp;
|
using RestSharp;
|
||||||
|
|
||||||
namespace PlexRequests.Api
|
namespace PlexRequests.Api
|
||||||
{
|
{
|
||||||
public class TvMazeApi : TvMazeBase
|
public class TvMazeApi : TvMazeBase
|
||||||
{
|
{
|
||||||
public TvMazeApi()
|
public TvMazeApi()
|
||||||
{
|
{
|
||||||
Api = new ApiRequest();
|
Api = new ApiRequest();
|
||||||
}
|
}
|
||||||
private ApiRequest Api { get; }
|
private ApiRequest Api { get; }
|
||||||
private static Logger Log = LogManager.GetCurrentClassLogger();
|
private static Logger Log = LogManager.GetCurrentClassLogger();
|
||||||
public List<TvMazeSearch> Search(string searchTerm)
|
public List<TvMazeSearch> Search(string searchTerm)
|
||||||
{
|
{
|
||||||
var request = new RestRequest
|
var request = new RestRequest
|
||||||
{
|
{
|
||||||
Method = Method.GET,
|
Method = Method.GET,
|
||||||
Resource = "search/shows?q={searchTerm}"
|
Resource = "search/shows?q={searchTerm}"
|
||||||
};
|
};
|
||||||
request.AddUrlSegment("searchTerm", searchTerm);
|
request.AddUrlSegment("searchTerm", searchTerm);
|
||||||
request.AddHeader("Content-Type", "application/json");
|
request.AddHeader("Content-Type", "application/json");
|
||||||
|
|
||||||
return Api.Execute<List<TvMazeSearch>>(request, new Uri(Uri));
|
return Api.Execute<List<TvMazeSearch>>(request, new Uri(Uri));
|
||||||
}
|
}
|
||||||
|
|
||||||
public TvMazeShow ShowLookup(int showId)
|
public TvMazeShow ShowLookup(int showId)
|
||||||
{
|
{
|
||||||
var request = new RestRequest
|
var request = new RestRequest
|
||||||
{
|
{
|
||||||
Method = Method.GET,
|
Method = Method.GET,
|
||||||
Resource = "shows/{id}"
|
Resource = "shows/{id}"
|
||||||
};
|
};
|
||||||
request.AddUrlSegment("id", showId.ToString());
|
request.AddUrlSegment("id", showId.ToString());
|
||||||
request.AddHeader("Content-Type", "application/json");
|
request.AddHeader("Content-Type", "application/json");
|
||||||
|
|
||||||
return Api.Execute<TvMazeShow>(request, new Uri(Uri));
|
return Api.Execute<TvMazeShow>(request, new Uri(Uri));
|
||||||
}
|
}
|
||||||
|
|
||||||
public TvMazeShow ShowLookupByTheTvDbId(int theTvDbId)
|
public IEnumerable<TvMazeEpisodes> EpisodeLookup(int showId)
|
||||||
{
|
{
|
||||||
var request = new RestRequest
|
var request = new RestRequest
|
||||||
{
|
{
|
||||||
Method = Method.GET,
|
Method = Method.GET,
|
||||||
Resource = "lookup/shows?thetvdb={id}"
|
Resource = "shows/{id}/episodes"
|
||||||
};
|
};
|
||||||
request.AddUrlSegment("id", theTvDbId.ToString());
|
request.AddUrlSegment("id", showId.ToString());
|
||||||
request.AddHeader("Content-Type", "application/json");
|
request.AddHeader("Content-Type", "application/json");
|
||||||
|
|
||||||
var obj = Api.Execute<TvMazeShow>(request, new Uri(Uri));
|
return Api.Execute<List<TvMazeEpisodes>>(request, new Uri(Uri));
|
||||||
obj.seasonCount = GetSeasonCount(obj.id);
|
}
|
||||||
|
|
||||||
return obj;
|
public TvMazeShow ShowLookupByTheTvDbId(int theTvDbId)
|
||||||
}
|
{
|
||||||
|
var request = new RestRequest
|
||||||
public List<TvMazeSeasons> GetSeasons(int id)
|
{
|
||||||
{
|
Method = Method.GET,
|
||||||
var request = new RestRequest
|
Resource = "lookup/shows?thetvdb={id}"
|
||||||
{
|
};
|
||||||
Method = Method.GET,
|
request.AddUrlSegment("id", theTvDbId.ToString());
|
||||||
Resource = "shows/{id}/seasons"
|
request.AddHeader("Content-Type", "application/json");
|
||||||
};
|
|
||||||
request.AddUrlSegment("id", id.ToString());
|
var obj = Api.Execute<TvMazeShow>(request, new Uri(Uri));
|
||||||
request.AddHeader("Content-Type", "application/json");
|
obj.seasonCount = GetSeasonCount(obj.id);
|
||||||
|
|
||||||
return Api.Execute<List<TvMazeSeasons>>(request, new Uri(Uri));
|
return obj;
|
||||||
}
|
}
|
||||||
public int GetSeasonCount(int id)
|
|
||||||
{
|
public List<TvMazeSeasons> GetSeasons(int id)
|
||||||
var obj = GetSeasons(id);
|
{
|
||||||
var seasons = obj.Select(x => x.number > 0);
|
var request = new RestRequest
|
||||||
return seasons.Count();
|
{
|
||||||
}
|
Method = Method.GET,
|
||||||
|
Resource = "shows/{id}/seasons"
|
||||||
}
|
};
|
||||||
|
request.AddUrlSegment("id", id.ToString());
|
||||||
|
request.AddHeader("Content-Type", "application/json");
|
||||||
|
|
||||||
|
return Api.Execute<List<TvMazeSeasons>>(request, new Uri(Uri));
|
||||||
|
}
|
||||||
|
public int GetSeasonCount(int id)
|
||||||
|
{
|
||||||
|
var obj = GetSeasons(id);
|
||||||
|
var seasons = obj.Select(x => x.number > 0);
|
||||||
|
return seasons.Count();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
4
PlexRequests.UI/Content/base.css
vendored
4
PlexRequests.UI/Content/base.css
vendored
|
@ -329,3 +329,7 @@ label {
|
||||||
.landing-title {
|
.landing-title {
|
||||||
font-weight: bold; }
|
font-weight: bold; }
|
||||||
|
|
||||||
|
.checkbox-custom {
|
||||||
|
margin-top: 0 !important;
|
||||||
|
margin-bottom: 0 !important; }
|
||||||
|
|
||||||
|
|
2
PlexRequests.UI/Content/base.min.css
vendored
2
PlexRequests.UI/Content/base.min.css
vendored
File diff suppressed because one or more lines are too long
|
@ -384,7 +384,7 @@ $border-radius: 10px;
|
||||||
|
|
||||||
.bootstrap-datetimepicker-widget table td.active,
|
.bootstrap-datetimepicker-widget table td.active,
|
||||||
.bootstrap-datetimepicker-widget table td.active:hover {
|
.bootstrap-datetimepicker-widget table td.active:hover {
|
||||||
color: #fff !important;
|
color: #fff $i;
|
||||||
}
|
}
|
||||||
|
|
||||||
.landing-header {
|
.landing-header {
|
||||||
|
@ -393,7 +393,7 @@ $border-radius: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.landing-block {
|
.landing-block {
|
||||||
background: #2f2f2f !important;
|
background: #2f2f2f $i;
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -415,3 +415,8 @@ $border-radius: 10px;
|
||||||
.landing-title {
|
.landing-title {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.checkbox-custom{
|
||||||
|
margin-top:0 $i;
|
||||||
|
margin-bottom:0 $i;
|
||||||
|
}
|
|
@ -12,9 +12,14 @@ $(function () {
|
||||||
var searchSource = $("#search-template").html();
|
var searchSource = $("#search-template").html();
|
||||||
var seasonsSource = $("#seasons-template").html();
|
var seasonsSource = $("#seasons-template").html();
|
||||||
var musicSource = $("#music-template").html();
|
var musicSource = $("#music-template").html();
|
||||||
|
var seasonsNumberSource = $("#seasonNumber-template").html();
|
||||||
|
var episodeSource = $("#episode-template").html();
|
||||||
|
|
||||||
var searchTemplate = Handlebars.compile(searchSource);
|
var searchTemplate = Handlebars.compile(searchSource);
|
||||||
var musicTemplate = Handlebars.compile(musicSource);
|
var musicTemplate = Handlebars.compile(musicSource);
|
||||||
var seasonsTemplate = Handlebars.compile(seasonsSource);
|
var seasonsTemplate = Handlebars.compile(seasonsSource);
|
||||||
|
var seasonsNumberTemplate = Handlebars.compile(seasonsNumberSource);
|
||||||
|
var episodesTemplate = Handlebars.compile(episodeSource);
|
||||||
|
|
||||||
var base = $('#baseUrl').text();
|
var base = $('#baseUrl').text();
|
||||||
|
|
||||||
|
@ -256,6 +261,7 @@ $(function () {
|
||||||
$('#typeModal').val(type);
|
$('#typeModal').val(type);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
function focusSearch($content) {
|
function focusSearch($content) {
|
||||||
if ($content.length > 0) {
|
if ($content.length > 0) {
|
||||||
$('input[type=text].form-control', $content).first().focus();
|
$('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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -100,6 +100,7 @@ namespace PlexRequests.UI.Modules
|
||||||
IssueService = issue;
|
IssueService = issue;
|
||||||
Analytics = a;
|
Analytics = a;
|
||||||
RequestLimitRepo = rl;
|
RequestLimitRepo = rl;
|
||||||
|
TvApi = new TvMazeApi();
|
||||||
|
|
||||||
|
|
||||||
Get["SearchIndex","/", true] = async (x, ct) => await RequestLoad();
|
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["/notifyuser", true] = async (x, ct) => await GetUserNotificationSettings();
|
||||||
|
|
||||||
Get["/seasons"] = x => GetSeasons();
|
Get["/seasons"] = x => GetSeasons();
|
||||||
|
Get["/episodes"] = x => GetEpisodes();
|
||||||
}
|
}
|
||||||
|
private TvMazeApi TvApi { get; }
|
||||||
private IPlexApi PlexApi { get; }
|
private IPlexApi PlexApi { get; }
|
||||||
private TheMovieDbApi MovieApi { get; }
|
private TheMovieDbApi MovieApi { get; }
|
||||||
private INotificationService NotificationService { get; }
|
private INotificationService NotificationService { get; }
|
||||||
|
@ -854,14 +857,21 @@ namespace PlexRequests.UI.Modules
|
||||||
|
|
||||||
private Response GetSeasons()
|
private Response GetSeasons()
|
||||||
{
|
{
|
||||||
var tv = new TvMazeApi();
|
|
||||||
var seriesId = (int)Request.Query.tvId;
|
var seriesId = (int)Request.Query.tvId;
|
||||||
var show = tv.ShowLookupByTheTvDbId(seriesId);
|
var show = TvApi.ShowLookupByTheTvDbId(seriesId);
|
||||||
var seasons = tv.GetSeasons(show.id);
|
var seasons = TvApi.GetSeasons(show.id);
|
||||||
var model = seasons.Select(x => x.number);
|
var model = seasons.Select(x => x.number);
|
||||||
return Response.AsJson(model);
|
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<bool> CheckRequestLimit(PlexRequestSettings s, RequestType type)
|
private async Task<bool> CheckRequestLimit(PlexRequestSettings s, RequestType type)
|
||||||
{
|
{
|
||||||
if (IsAdmin)
|
if (IsAdmin)
|
||||||
|
|
9
PlexRequests.UI/Resources/UI.Designer.cs
generated
9
PlexRequests.UI/Resources/UI.Designer.cs
generated
|
@ -888,6 +888,15 @@ namespace PlexRequests.UI.Resources {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Select Episode.
|
||||||
|
/// </summary>
|
||||||
|
public static string Search_SelectEpisode {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("Search_SelectEpisode", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to Select .
|
/// Looks up a localized string similar to Select .
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -431,4 +431,7 @@
|
||||||
<data name="Layout_French" xml:space="preserve">
|
<data name="Layout_French" xml:space="preserve">
|
||||||
<value>French</value>
|
<value>French</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="Search_SelectEpisode" xml:space="preserve">
|
||||||
|
<value>Select Episode</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
|
@ -192,6 +192,7 @@
|
||||||
<li><a id="{{id}}" season-select="1" class="dropdownTv" href="#">@UI.Search_FirstSeason</a></li>
|
<li><a id="{{id}}" season-select="1" class="dropdownTv" href="#">@UI.Search_FirstSeason</a></li>
|
||||||
<li><a id="{{id}}" season-select="2" class="dropdownTv" href="#">@UI.Search_LatestSeason</a></li>
|
<li><a id="{{id}}" season-select="2" class="dropdownTv" href="#">@UI.Search_LatestSeason</a></li>
|
||||||
<li><a id="SeasonSelect" data-identifier="{{id}}" data-toggle="modal" data-target="#seasonsModal" href="#">@UI.Search_SelectSeason...</a></li>
|
<li><a id="SeasonSelect" data-identifier="{{id}}" data-toggle="modal" data-target="#seasonsModal" href="#">@UI.Search_SelectSeason...</a></li>
|
||||||
|
<li><a id="EpisodeSelect" data-identifier="{{id}}" data-toggle="modal" data-target="#episodesModal" href="#">@UI.Search_SelectEpisode...</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
{{/if_eq}}
|
{{/if_eq}}
|
||||||
|
@ -291,6 +292,26 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="modal fade" id="episodesModal">
|
||||||
|
<div class="modal-dialog modal-lg">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||||
|
<h4 class="modal-title">@UI.Search_Modal_SeasonsTitle</h4>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body" id="episodesBody">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div hidden="hidden" id="selectedEpisodeId"></div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-default" data-dismiss="modal">@UI.Common_Close</button>
|
||||||
|
<button type="button" id="episodesRequest" class="btn btn-primary">@UI.Search_Request</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<div class="modal fade" id="issuesModal">
|
<div class="modal fade" id="issuesModal">
|
||||||
<div class="modal-dialog">
|
<div class="modal-dialog">
|
||||||
|
@ -321,6 +342,24 @@
|
||||||
<input type="checkbox" class="selectedSeasons" id="{{id}}" name="{{id}}"><label for="{{id}}">@UI.Search_Season {{id}}</label>
|
<input type="checkbox" class="selectedSeasons" id="{{id}}" name="{{id}}"><label for="{{id}}">@UI.Search_Season {{id}}</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script id="seasonNumber-template" type="text/x-handlebars-template">
|
||||||
|
<div class="row"></div>
|
||||||
|
<div id="seasonNumber{{seasonNumber}}">
|
||||||
|
<strong>@UI.Search_Season {{seasonNumber}}</strong>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
<script id="episode-template" type="text/x-handlebars-template">
|
||||||
|
<div class="form-group col-md-6">
|
||||||
|
<div class="checkbox" style="margin-bottom:0px; margin-top:0px;">
|
||||||
|
<input type="checkbox" class="selectedEpisodes" id="{{id}}" name="{{id}}"><label for="{{id}}">{{number}}. {{name}}</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue