From fa5efb6c66d4be22879ae80863c80d48d8a055cb Mon Sep 17 00:00:00 2001 From: tidusjar Date: Mon, 8 May 2017 21:02:04 +0100 Subject: [PATCH] docker support and more, redesign the episodes --- Ombi/Ombi.Core/Engine/TvRequestEngine.cs | 44 +++++-- Ombi/Ombi.Core/Engine/TvSearchEngine.cs | 52 +++++++- .../Ombi.Core/Models/Requests/RequestModel.cs | 14 +- .../Models/Search/SearchTvShowViewModel.cs | 3 +- Ombi/Ombi.Mapping/Profiles/TvProfile.cs | 16 +-- Ombi/Ombi.Store/Context/OmbiContext.cs | 6 +- Ombi/Ombi.Store/Entities/RequestBlobs.cs | 1 - Ombi/Ombi.Store/Ombi.Store.csproj | 13 ++ Ombi/Ombi.Store/Sql.Designer.cs | 89 +++++++++++++ Ombi/Ombi.Store/Sql.resx | 124 ++++++++++++++++++ Ombi/Ombi.Store/SqlTables.sql | 49 +++++++ Ombi/Ombi/.vscode/launch.json | 39 ++++++ Ombi/Ombi/.vscode/settings.json | 5 + Ombi/Ombi/.vscode/tasks.json | 66 ++++++++++ Ombi/Ombi/Controllers/SearchController.cs | 6 +- Ombi/Ombi/Dockerfile | 8 ++ Ombi/Ombi/Ombi.csproj | 9 ++ Ombi/Ombi/build.sh | 21 +++ Ombi/Ombi/wwwroot/app/app.module.ts | 5 +- .../wwwroot/app/interfaces/IRequestModel.ts | 12 +- .../search/seriesinformation.component.html | 64 +++++++++ .../app/search/seriesinformation.component.ts | 67 ++++++++++ .../app/search/tvsearch.component.html | 3 +- .../wwwroot/app/search/tvsearch.component.ts | 8 +- .../wwwroot/app/services/search.service.ts | 7 +- 25 files changed, 689 insertions(+), 42 deletions(-) create mode 100644 Ombi/Ombi.Store/Sql.Designer.cs create mode 100644 Ombi/Ombi.Store/Sql.resx create mode 100644 Ombi/Ombi.Store/SqlTables.sql create mode 100644 Ombi/Ombi/.vscode/launch.json create mode 100644 Ombi/Ombi/.vscode/settings.json create mode 100644 Ombi/Ombi/.vscode/tasks.json create mode 100644 Ombi/Ombi/Dockerfile create mode 100644 Ombi/Ombi/build.sh create mode 100644 Ombi/Ombi/wwwroot/app/search/seriesinformation.component.html create mode 100644 Ombi/Ombi/wwwroot/app/search/seriesinformation.component.ts diff --git a/Ombi/Ombi.Core/Engine/TvRequestEngine.cs b/Ombi/Ombi.Core/Engine/TvRequestEngine.cs index 1dff36ab5..946136aa3 100644 --- a/Ombi/Ombi.Core/Engine/TvRequestEngine.cs +++ b/Ombi/Ombi.Core/Engine/TvRequestEngine.cs @@ -52,27 +52,47 @@ namespace Ombi.Core.Engine RequestAll = tv.RequestAll }; + var episodes = await TvApi.EpisodeLookup(showInfo.id); + + foreach (var e in episodes) + { + var season = model.SeasonRequests.FirstOrDefault(x => x.SeasonNumber == e.season); + season?.Episodes.Add(new EpisodesRequested + { + Url = e.url, + Title = e.name, + AirDate = DateTime.Parse(e.airstamp), + EpisodeNumber = e.number, + }); + } + if (tv.LatestSeason) { var latest = showInfo.Season.OrderBy(x => x).FirstOrDefault(); - model.SeasonRequests = showInfo.Season.Any() - ? new List {new SeasonRequestModel + foreach (var modelSeasonRequest in model.SeasonRequests) + { + if (modelSeasonRequest.SeasonNumber == latest.SeasonNumber) { - SeasonNumber = latest.SeasonNumber, - Episodes = latest.EpisodeNumber - }} - : new List(); + foreach (var episodesRequested in modelSeasonRequest.Episodes) + { + episodesRequested.Requested = true; + } + } + } } if (tv.FirstSeason) { var first = showInfo.Season.OrderByDescending(x => x).FirstOrDefault(); - model.SeasonRequests = showInfo.Season.Any() - ? new List {new SeasonRequestModel + foreach (var modelSeasonRequest in model.SeasonRequests) + { + if (modelSeasonRequest.SeasonNumber == first.SeasonNumber) { - SeasonNumber = first.SeasonNumber, - Episodes = first.EpisodeNumber - }} - : new List(); + foreach (var episodesRequested in modelSeasonRequest.Episodes) + { + episodesRequested.Requested = true; + } + } + } } diff --git a/Ombi/Ombi.Core/Engine/TvSearchEngine.cs b/Ombi/Ombi.Core/Engine/TvSearchEngine.cs index 9eedb5a31..d030a20d1 100644 --- a/Ombi/Ombi.Core/Engine/TvSearchEngine.cs +++ b/Ombi/Ombi.Core/Engine/TvSearchEngine.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Linq; using System.Security.Principal; using System.Threading.Tasks; @@ -48,10 +49,30 @@ namespace Ombi.Core.Engine return null; } - public async Task GetShowInformation(int tvdbId) + public async Task GetShowInformation(int tvmazeId) { - var show = await TvMazeApi.ShowLookupByTheTvDbId(tvdbId); - return Mapper.Map(show); + var show = await TvMazeApi.ShowLookup(tvmazeId); + var episodes = await TvMazeApi.EpisodeLookup(show.id); + + var mapped = Mapper.Map(show); + + foreach (var e in episodes) + { + var season = mapped.SeasonRequests.FirstOrDefault(x => x.SeasonNumber == e.season); + season?.Episodes.Add(new EpisodesRequested + { + Url = e.url, + Title = e.name, + AirDate = DateTime.Parse(e.airstamp), + EpisodeNumber = e.number, + + }); + } + + var existingRequests = await GetTvRequests(); + var plexSettings = await PlexSettings.GetSettingsAsync(); + var embySettings = await EmbySettings.GetSettingsAsync(); + return ProcessResult(mapped, existingRequests, plexSettings, embySettings); } //public async Task> Popular() @@ -118,11 +139,28 @@ namespace Ombi.Core.Engine var tvdbid = item.Id; if (existingRequests.ContainsKey(tvdbid)) { - var dbt = existingRequests[tvdbid]; + var existingRequest = existingRequests[tvdbid]; item.Requested = true; - item.SeasonRequests = dbt.SeasonRequests.ToList(); - item.Approved = dbt.Approved; + item.Approved = existingRequest.Approved; + + // Let's modify the seasonsrequested to reflect what we have requested... + foreach (var season in item.SeasonRequests) + { + // Find the existing request season + var existingSeason = + existingRequest.SeasonRequests.FirstOrDefault(x => x.SeasonNumber == season.SeasonNumber); + + foreach (var ep in existingSeason.Episodes) + { + // Find the episode from what we are searching + var episodeSearching = season.Episodes.FirstOrDefault(x => x.EpisodeNumber == ep.EpisodeNumber); + episodeSearching.Requested = ep.Requested; + episodeSearching.Available = ep.Available; + episodeSearching.Approved = ep.Approved; + } + + } } //if (sonarrCached.Select(x => x.TvdbId).Contains(tvdbid) || sickRageCache.Contains(tvdbid)) // // compare to the sonarr/sickrage db diff --git a/Ombi/Ombi.Core/Models/Requests/RequestModel.cs b/Ombi/Ombi.Core/Models/Requests/RequestModel.cs index cc4aecf2a..f6885c16e 100644 --- a/Ombi/Ombi.Core/Models/Requests/RequestModel.cs +++ b/Ombi/Ombi.Core/Models/Requests/RequestModel.cs @@ -59,7 +59,19 @@ namespace Ombi.Core.Models.Requests public class SeasonRequestModel { public int SeasonNumber { get; set; } - public List Episodes { get; set; } + public List Episodes { get; set; } = new List(); + } + + public class EpisodesRequested + { + public int EpisodeNumber { get; set; } + public string Title { get; set; } + public DateTime AirDate { get; set; } + public string Url { get; set; } + public bool Requested { get; set; } + public string Status { get; set; } + public bool Available { get; set; } + public bool Approved { get; set; } } } \ No newline at end of file diff --git a/Ombi/Ombi.Core/Models/Search/SearchTvShowViewModel.cs b/Ombi/Ombi.Core/Models/Search/SearchTvShowViewModel.cs index 12b2d0556..f0165014a 100644 --- a/Ombi/Ombi.Core/Models/Search/SearchTvShowViewModel.cs +++ b/Ombi/Ombi.Core/Models/Search/SearchTvShowViewModel.cs @@ -6,7 +6,7 @@ namespace Ombi.Core.Models.Search public class SearchTvShowViewModel : SearchViewModel { public int Id { get; set; } - public string SeriesName { get; set; } + public string Title { get; set; } public List Aliases { get; set; } public string Banner { get; set; } public int SeriesId { get; set; } @@ -48,5 +48,6 @@ namespace Ombi.Core.Models.Search public bool FirstSeason { get; set; } public bool LatestSeason { get; set; } + } } \ No newline at end of file diff --git a/Ombi/Ombi.Mapping/Profiles/TvProfile.cs b/Ombi/Ombi.Mapping/Profiles/TvProfile.cs index 3a20f46c4..67e775064 100644 --- a/Ombi/Ombi.Mapping/Profiles/TvProfile.cs +++ b/Ombi/Ombi.Mapping/Profiles/TvProfile.cs @@ -24,12 +24,10 @@ namespace Ombi.Mapping.Profiles .ForMember(dest => dest.Rating, opts => opts.MapFrom(src => src.score.ToString(CultureInfo.CurrentUICulture))) .ForMember(dest => dest.Runtime, opts => opts.MapFrom(src => src.show.runtime.ToString())) .ForMember(dest => dest.SeriesId, opts => opts.MapFrom(src => src.show.id)) - .ForMember(dest => dest.SeriesName, opts => opts.MapFrom(src => src.show.name)) + .ForMember(dest => dest.Title, opts => opts.MapFrom(src => src.show.name)) .ForMember(dest => dest.Banner, opts => opts.MapFrom(src => !string.IsNullOrEmpty(src.show.image.medium) ? src.show.image.medium.Replace("http", "https") : string.Empty)) .ForMember(dest => dest.Status, opts => opts.MapFrom(src => src.show.status)); - - CreateMap() - .ConstructUsing(x => new SeasonRequestModel { Episodes = x.EpisodeNumber, SeasonNumber = x.SeasonNumber }); + CreateMap() .ForMember(dest => dest.Id, opts => opts.MapFrom(src => src.externals.thetvdb)) .ForMember(dest => dest.FirstAired, opts => opts.MapFrom(src => src.premiered)) @@ -40,7 +38,7 @@ namespace Ombi.Mapping.Profiles .ForMember(dest => dest.Rating, opts => opts.MapFrom(src => src.rating.ToString())) .ForMember(dest => dest.Runtime, opts => opts.MapFrom(src => src.runtime.ToString(CultureInfo.CurrentUICulture))) .ForMember(dest => dest.SeriesId, opts => opts.MapFrom(src => src.id)) - .ForMember(dest => dest.SeriesName, opts => opts.MapFrom(src => src.name)) + .ForMember(dest => dest.Title, opts => opts.MapFrom(src => src.name)) .ForMember(dest => dest.Banner, opts => opts.MapFrom(src => !string.IsNullOrEmpty(src.image.medium) ? src.image.medium.Replace("http", "https") : string.Empty)) .ForMember(dest => dest.Status, opts => opts.MapFrom(src => src.status)) .ForMember(dest => dest.SeasonRequests, opts => opts.MapFrom(src => src.Season)); @@ -53,7 +51,7 @@ namespace Ombi.Mapping.Profiles // .ForMember(dest => dest.Overview, opts => opts.MapFrom(src => src.Overview.RemoveHtml())) // .ForMember(dest => dest.Rating, opts => opts.MapFrom(src => src.Rating.ToString())) // .ForMember(dest => dest.Runtime, opts => opts.MapFrom(src => src.Runtime.ToString())) - // .ForMember(dest => dest.SeriesName, opts => opts.MapFrom(src => src.Title)) + // .ForMember(dest => dest.Title, opts => opts.MapFrom(src => src.Title)) // .ForMember(dest => dest.Status, opts => opts.MapFrom(src => src.Status.DisplayName)) // .ForMember(dest => dest.Trailer, opts => opts.MapFrom(src => src.Trailer)) // .ForMember(dest => dest.Homepage, opts => opts.MapFrom(src => src.Homepage)); @@ -66,7 +64,7 @@ namespace Ombi.Mapping.Profiles // .ForMember(dest => dest.Overview, opts => opts.MapFrom(src => src.Show.Overview.RemoveHtml())) // .ForMember(dest => dest.Rating, opts => opts.MapFrom(src => src.Show.Rating.ToString())) // .ForMember(dest => dest.Runtime, opts => opts.MapFrom(src => src.Show.Runtime.ToString())) - // .ForMember(dest => dest.SeriesName, opts => opts.MapFrom(src => src.Show.Title)) + // .ForMember(dest => dest.Title, opts => opts.MapFrom(src => src.Show.Title)) // .ForMember(dest => dest.Status, opts => opts.MapFrom(src => src.Show.Status.DisplayName)) // .ForMember(dest => dest.Trailer, opts => opts.MapFrom(src => src.Show.Trailer)) // .ForMember(dest => dest.Homepage, opts => opts.MapFrom(src => src.Show.Homepage)); @@ -79,7 +77,7 @@ namespace Ombi.Mapping.Profiles // .ForMember(dest => dest.Overview, opts => opts.MapFrom(src => src.Show.Overview.RemoveHtml())) // .ForMember(dest => dest.Rating, opts => opts.MapFrom(src => src.Show.Rating.ToString())) // .ForMember(dest => dest.Runtime, opts => opts.MapFrom(src => src.Show.Runtime.ToString())) - // .ForMember(dest => dest.SeriesName, opts => opts.MapFrom(src => src.Show.Title)) + // .ForMember(dest => dest.Title, opts => opts.MapFrom(src => src.Show.Title)) // .ForMember(dest => dest.Status, opts => opts.MapFrom(src => src.Show.Status.DisplayName)) // .ForMember(dest => dest.Trailer, opts => opts.MapFrom(src => src.Show.Trailer)) // .ForMember(dest => dest.Homepage, opts => opts.MapFrom(src => src.Show.Homepage)); @@ -92,7 +90,7 @@ namespace Ombi.Mapping.Profiles // .ForMember(dest => dest.Overview, opts => opts.MapFrom(src => src.Show.Overview.RemoveHtml())) // .ForMember(dest => dest.Rating, opts => opts.MapFrom(src => src.Show.Rating.ToString())) // .ForMember(dest => dest.Runtime, opts => opts.MapFrom(src => src.Show.Runtime.ToString())) - // .ForMember(dest => dest.SeriesName, opts => opts.MapFrom(src => src.Show.Title)) + // .ForMember(dest => dest.Title, opts => opts.MapFrom(src => src.Show.Title)) // .ForMember(dest => dest.Status, opts => opts.MapFrom(src => src.Show.Status.DisplayName)) // .ForMember(dest => dest.Trailer, opts => opts.MapFrom(src => src.Show.Trailer)) // .ForMember(dest => dest.Homepage, opts => opts.MapFrom(src => src.Show.Homepage)); diff --git a/Ombi/Ombi.Store/Context/OmbiContext.cs b/Ombi/Ombi.Store/Context/OmbiContext.cs index ab069feb9..1ce4becf7 100644 --- a/Ombi/Ombi.Store/Context/OmbiContext.cs +++ b/Ombi/Ombi.Store/Context/OmbiContext.cs @@ -14,8 +14,10 @@ namespace Ombi.Store.Context _created = true; Database.EnsureCreated(); Database.Migrate(); - - + + // Run Script + + Database.ExecuteSqlCommand(Sql.SqlTables, 0); } public DbSet Requests { get; set; } diff --git a/Ombi/Ombi.Store/Entities/RequestBlobs.cs b/Ombi/Ombi.Store/Entities/RequestBlobs.cs index 21c60a13e..a145a7e5d 100644 --- a/Ombi/Ombi.Store/Entities/RequestBlobs.cs +++ b/Ombi/Ombi.Store/Entities/RequestBlobs.cs @@ -8,7 +8,6 @@ namespace Ombi.Store.Entities public int ProviderId { get; set; } public byte[] Content { get; set; } public RequestType Type { get; set; } - public string MusicId { get; set; } } public enum RequestType diff --git a/Ombi/Ombi.Store/Ombi.Store.csproj b/Ombi/Ombi.Store/Ombi.Store.csproj index c3bae1c70..06d58a435 100644 --- a/Ombi/Ombi.Store/Ombi.Store.csproj +++ b/Ombi/Ombi.Store/Ombi.Store.csproj @@ -17,4 +17,17 @@ + + + True + True + Sql.resx + + + + + ResXFileCodeGenerator + Sql.Designer.cs + + \ No newline at end of file diff --git a/Ombi/Ombi.Store/Sql.Designer.cs b/Ombi/Ombi.Store/Sql.Designer.cs new file mode 100644 index 000000000..29f27c02a --- /dev/null +++ b/Ombi/Ombi.Store/Sql.Designer.cs @@ -0,0 +1,89 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Ombi.Store { + using System; + using System.Reflection; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Sql { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Sql() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Ombi.Store.Sql", typeof(Sql).GetTypeInfo().Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized string similar to CREATE TABLE IF NOT EXISTS GlobalSettings + ///( + /// Id INTEGER PRIMARY KEY AUTOINCREMENT, + /// SettingsName varchar(50) NOT NULL, + /// Content BLOB NOT NULL + ///); + /// + ///CREATE TABLE IF NOT EXISTS PlexContent + ///( + /// Id INTEGER PRIMARY KEY AUTOINCREMENT, + /// Title varchar(50) NOT NULL, + /// ProviderId varchar(50) NOT NULL, + /// Url varchar(100) NOT NULL, + /// Key varchar(50) NOT NULL, + /// AddedAt varchar(50) NOT NULL, + /// Type INTEGER NOT NULL, + /// Relea [rest of string was truncated]";. + /// + internal static string SqlTables { + get { + return ResourceManager.GetString("SqlTables", resourceCulture); + } + } + } +} diff --git a/Ombi/Ombi.Store/Sql.resx b/Ombi/Ombi.Store/Sql.resx new file mode 100644 index 000000000..08548bd87 --- /dev/null +++ b/Ombi/Ombi.Store/Sql.resx @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + SqlTables.sql;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 + + \ No newline at end of file diff --git a/Ombi/Ombi.Store/SqlTables.sql b/Ombi/Ombi.Store/SqlTables.sql new file mode 100644 index 000000000..b1da9bab7 --- /dev/null +++ b/Ombi/Ombi.Store/SqlTables.sql @@ -0,0 +1,49 @@ +CREATE TABLE IF NOT EXISTS GlobalSettings +( + Id INTEGER PRIMARY KEY AUTOINCREMENT, + SettingsName varchar(50) NOT NULL, + Content BLOB NOT NULL +); + +CREATE TABLE IF NOT EXISTS PlexContent +( + Id INTEGER PRIMARY KEY AUTOINCREMENT, + Title varchar(50) NOT NULL, + ProviderId varchar(50) NOT NULL, + Url varchar(100) NOT NULL, + Key varchar(50) NOT NULL, + AddedAt varchar(50) NOT NULL, + Type INTEGER NOT NULL, + ReleaseYear varchar(100) NOT NULL +); + +CREATE TABLE IF NOT EXISTS SeasonsContent +( + Id INTEGER PRIMARY KEY AUTOINCREMENT, + SeasonNumber INTEGER NOT NULL, + SeasonKey INTEGER NOT NULL, + ParentKey INTEGER NOT NULL + +); + +CREATE TABLE IF NOT EXISTS RequestBlobs +( + Id INTEGER PRIMARY KEY AUTOINCREMENT, + ProviderId INTEGER NOT NULL, + Content BLOB NOT NULL, + Type INTEGER NOT NULL + +); + +CREATE TABLE IF NOT EXISTS Users +( + Id INTEGER PRIMARY KEY AUTOINCREMENT, + Username VARCHAR(100) NOT NULL, + Alias VARCHAR(100) NULL, + ClaimsSerialized BLOB NOT NULL, + EmailAddress VARCHAR(100) NULL, + Password VARCHAR(100) NULL, + Salt BLOB NULL, + UserType INTEGER NOT NULL + +); \ No newline at end of file diff --git a/Ombi/Ombi/.vscode/launch.json b/Ombi/Ombi/.vscode/launch.json new file mode 100644 index 000000000..84b170821 --- /dev/null +++ b/Ombi/Ombi/.vscode/launch.json @@ -0,0 +1,39 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name":".NET Core Docker Launch (web)", + "type": "coreclr", + "request": "launch", + "preLaunchTask": "composeForDebug", + "cwd": "/app", + "program": "/app/Ombi.dll", + "sourceFileMap": { + "/app": "${workspaceRoot}" + }, + + "launchBrowser": { + "enabled": true, + "args": "${auto-detect-url}", + "windows": { + "command": "cmd.exe", + "args": "/C start ${auto-detect-url}" + }, + "osx": { + "command": "open" + } + }, + + "pipeTransport": { + "pipeProgram": "/bin/bash", + "pipeCwd": "${workspaceRoot}", + "pipeArgs": [ "-c", "./dockerTask.sh startDebugging" ], + "windows": { + "pipeProgram": "${env.windir}\\System32\\WindowsPowerShell\\v1.0\\powershell.exe", + "pipeCwd": "${workspaceRoot}", + "pipeArgs": [ ".\\dockerTask.ps1", "-StartDebugging" ] + } + } + } + ] +} \ No newline at end of file diff --git a/Ombi/Ombi/.vscode/settings.json b/Ombi/Ombi/.vscode/settings.json new file mode 100644 index 000000000..741a1d169 --- /dev/null +++ b/Ombi/Ombi/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "files.associations": { + "dockerfile.*": "dockerfile" + } +} \ No newline at end of file diff --git a/Ombi/Ombi/.vscode/tasks.json b/Ombi/Ombi/.vscode/tasks.json new file mode 100644 index 000000000..2c4b21350 --- /dev/null +++ b/Ombi/Ombi/.vscode/tasks.json @@ -0,0 +1,66 @@ +{ + // See https://go.microsoft.com/fwlink/?LinkId=733558 + // for the documentation about the tasks.json format + "version": "0.1.0", + "windows": { + "command": "powershell", + "options": { + "cwd": "${workspaceRoot}" + }, + "tasks": [ + { + "taskName": "build", + "suppressTaskName": true, + "args": ["-ExecutionPolicy", "RemoteSigned", ".\\dockerTask.ps1", "-Build", "-Environment", "debug" ], + "isBuildCommand": true, + "showOutput": "always", + "echoCommand": true + }, + { + "taskName": "compose", + "suppressTaskName": true, + "args": ["-ExecutionPolicy", "RemoteSigned", ".\\dockerTask.ps1", "-Compose", "-Environment", "debug" ], + "isBuildCommand": false, + "showOutput": "always", + "echoCommand": true + }, + { + "taskName": "composeForDebug", + "suppressTaskName": true, + "args": ["-ExecutionPolicy", "RemoteSigned", ".\\dockerTask.ps1", "-ComposeForDebug", "-Environment", "debug" ], + "isBuildCommand": false, + "showOutput": "always", + "echoCommand": true + } + ] + }, + "osx": { + "command": "/bin/bash", + "options": { + "cwd": "${workspaceRoot}" + }, + "tasks": [ + { + "taskName": "build", + "suppressTaskName": true, + "args": [ "-c", "./dockerTask.sh build debug" ], + "isBuildCommand": true, + "showOutput": "always" + }, + { + "taskName": "compose", + "suppressTaskName": true, + "args": [ "-c", "./dockerTask.sh compose debug" ], + "isBuildCommand": false, + "showOutput": "always" + }, + { + "taskName": "composeForDebug", + "suppressTaskName": true, + "args": [ "-c", "./dockerTask.sh composeForDebug debug" ], + "isBuildCommand": false, + "showOutput": "always" + } + ] + } +} \ No newline at end of file diff --git a/Ombi/Ombi/Controllers/SearchController.cs b/Ombi/Ombi/Controllers/SearchController.cs index e98a2bd70..36e9cc320 100644 --- a/Ombi/Ombi/Controllers/SearchController.cs +++ b/Ombi/Ombi/Controllers/SearchController.cs @@ -66,10 +66,10 @@ namespace Ombi.Controllers return await TvEngine.Search(searchTerm); } - [HttpGet("tv/seasons/{tvdbId}")] - public async Task> GetSeasons(int tvdbId) + [HttpGet("tv/info/{tvdbId}")] + public async Task GetShowInfo(int tvdbId) { - return await TvEngine.GetSeasons(tvdbId); + return await TvEngine.GetShowInformation(tvdbId); } //[HttpGet("tv/popular")] diff --git a/Ombi/Ombi/Dockerfile b/Ombi/Ombi/Dockerfile new file mode 100644 index 000000000..ea0c4ab92 --- /dev/null +++ b/Ombi/Ombi/Dockerfile @@ -0,0 +1,8 @@ +FROM microsoft/dotnet:1.1-sdk-msbuild +ARG source=./bin/Release/netcoreapp1.1/publish +WORKDIR /app +COPY $source . +ENV ASPNETCORE_URLS http://*:5000 +EXPOSE 5000 +ENTRYPOINT ["dotnet", "Ombi.dll"] +COPY . /app \ No newline at end of file diff --git a/Ombi/Ombi/Ombi.csproj b/Ombi/Ombi/Ombi.csproj index 33e0d2754..ceadebd0e 100644 --- a/Ombi/Ombi/Ombi.csproj +++ b/Ombi/Ombi/Ombi.csproj @@ -89,6 +89,15 @@ PreserveNewest + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + PreserveNewest diff --git a/Ombi/Ombi/build.sh b/Ombi/Ombi/build.sh new file mode 100644 index 000000000..c15b1cb28 --- /dev/null +++ b/Ombi/Ombi/build.sh @@ -0,0 +1,21 @@ +SERVICE="Ombi" +# change directory to location of project.json +pushd ./ +# run dotnet publish, specify release build +dotnet publish -c Release +# equivalent to cd .. (go back to previous directory) +#popd +# Create a docker image tagged with the name of the project:latest +docker build -t "$SERVICE":latest . +# Check to see if this container exists. +CONTAINER=`docker ps --all | grep "$SERVICE"` +# if it doesn't, then just run this. +if [ -z "$CONTAINER" ]; then + docker run -i -p 8000:5000 --name $SERVICE -t $SERVICE:latest +# if it does exist; nuke it and then run the new one +else + docker rm $SERVICE + docker run -i -p 8000:5000 --name $SERVICE -t $SERVICE:latest +fi + +read -p "Press enter to continue" \ No newline at end of file diff --git a/Ombi/Ombi/wwwroot/app/app.module.ts b/Ombi/Ombi/wwwroot/app/app.module.ts index 10b74e9e4..11e0b66e1 100644 --- a/Ombi/Ombi/wwwroot/app/app.module.ts +++ b/Ombi/Ombi/wwwroot/app/app.module.ts @@ -15,6 +15,7 @@ import { InfiniteScrollModule } from 'ngx-infinite-scroll' import { SearchComponent } from './search/search.component'; import { MovieSearchComponent } from './search/moviesearch.component'; import { TvSearchComponent } from './search/tvsearch.component'; +import { SeriesInformationComponent } from './search/seriesinformation.component'; // Request import { RequestComponent } from './requests/request.component'; @@ -50,6 +51,7 @@ const routes: Routes = [ { path: '*', component: PageNotFoundComponent }, { path: '', redirectTo: '/search', pathMatch: 'full' }, { path: 'search', component: SearchComponent, canActivate: [AuthGuard] }, + { path: 'search/show/:id', component: SeriesInformationComponent, canActivate: [AuthGuard] }, { path: 'requests', component: RequestComponent, canActivate: [AuthGuard] }, { path: 'login', component: LoginComponent }, { path: 'landingpage', component: LandingPageComponent }, @@ -84,7 +86,8 @@ const routes: Routes = [ LandingPageComponent, UserManagementComponent, MovieRequestsComponent, - TvRequestsComponent + TvRequestsComponent, + SeriesInformationComponent ], providers: [ SearchService, diff --git a/Ombi/Ombi/wwwroot/app/interfaces/IRequestModel.ts b/Ombi/Ombi/wwwroot/app/interfaces/IRequestModel.ts index f6f82683c..81eb37fbc 100644 --- a/Ombi/Ombi/wwwroot/app/interfaces/IRequestModel.ts +++ b/Ombi/Ombi/wwwroot/app/interfaces/IRequestModel.ts @@ -39,7 +39,17 @@ export interface ITvRequestModel extends IMediaBase { export interface ISeasonRequests { seasonNumber: number, - episodes:number[], + episodes: IEpisodesRequested[], +} + +export interface IEpisodesRequested { + episodeNumber: number, + title: string, + airDate: Date, + url: string, + requested: boolean, + status: string, + available:boolean } diff --git a/Ombi/Ombi/wwwroot/app/search/seriesinformation.component.html b/Ombi/Ombi/wwwroot/app/search/seriesinformation.component.html new file mode 100644 index 000000000..c476baf8f --- /dev/null +++ b/Ombi/Ombi/wwwroot/app/search/seriesinformation.component.html @@ -0,0 +1,64 @@ +
+ +
+

Season: {{season.seasonNumber}}

+ + + + + + + + + + + + + + + + + + + + +
+ + # + + + + Title + + + + Air Date + + + + Status + +
+ {{ep.episodeNumber}} + + {{ep.title}} + + {{ep.airDate | date: 'dd/MM/yyyy' }} + + Available + Processing Request +
+ + + +
+ Details/Edit +
+
+ + +
\ No newline at end of file diff --git a/Ombi/Ombi/wwwroot/app/search/seriesinformation.component.ts b/Ombi/Ombi/wwwroot/app/search/seriesinformation.component.ts new file mode 100644 index 000000000..5cf5bd441 --- /dev/null +++ b/Ombi/Ombi/wwwroot/app/search/seriesinformation.component.ts @@ -0,0 +1,67 @@ +import { Component, OnInit, OnDestroy } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; +import { Subject } from 'rxjs/Subject'; + +import "rxjs/add/operator/takeUntil"; + +import { SearchService } from '../services/search.service'; +import { RequestService } from '../services/request.service'; +import { NotificationService } from '../services/notification.service'; + +import { ISearchTvResult } from '../interfaces/ISearchTvResult'; +import { IRequestEngineResult } from '../interfaces/IRequestEngineResult'; + +@Component({ + selector: 'ombi', + moduleId: module.id, + templateUrl: './seriesinformation.component.html' +}) +export class SeriesInformationComponent implements OnInit, OnDestroy { + + constructor(private searchService: SearchService, private route: ActivatedRoute, + private requestService: RequestService, private notificationService: NotificationService) { + this.route.params + .takeUntil(this.subscriptions) + .subscribe(params => { + this.seriesId = +params['id']; // (+) converts string 'id' to a number + }); + } + + private subscriptions = new Subject(); + + result : IRequestEngineResult; + seriesId: number; + series: ISearchTvResult; + + + ngOnInit(): void { + this.searchService.getShowInformation(this.seriesId) + .takeUntil(this.subscriptions) + .subscribe(x => { + this.series = x; + }); + } + + + request() { + this.series.requested = true; + this.requestService.requestTv(this.series) + .takeUntil(this.subscriptions) + .subscribe(x => { + this.result = x; + if (this.result.requestAdded) { + this.notificationService.success("Request Added", + `Request for ${this.series.seriesName} has been added successfully`); + } else { + this.notificationService.warning("Request Added", this.result.message); + } + }); + } + + + + ngOnDestroy(): void { + this.subscriptions.next(); + this.subscriptions.complete(); + } +} \ No newline at end of file diff --git a/Ombi/Ombi/wwwroot/app/search/tvsearch.component.html b/Ombi/Ombi/wwwroot/app/search/tvsearch.component.html index 534580794..172f7776c 100644 --- a/Ombi/Ombi/wwwroot/app/search/tvsearch.component.html +++ b/Ombi/Ombi/wwwroot/app/search/tvsearch.component.html @@ -121,8 +121,7 @@
  • All Seasons
  • First Season
  • Latest Season
  • -
  • Select Season...
  • -
  • Select Episode...
  • +
  • Select ...
  • diff --git a/Ombi/Ombi/wwwroot/app/search/tvsearch.component.ts b/Ombi/Ombi/wwwroot/app/search/tvsearch.component.ts index c7e162a09..33c4e29ae 100644 --- a/Ombi/Ombi/wwwroot/app/search/tvsearch.component.ts +++ b/Ombi/Ombi/wwwroot/app/search/tvsearch.component.ts @@ -1,4 +1,5 @@ import { Component, OnInit, OnDestroy } from '@angular/core'; +import {Router} from '@angular/router'; import { Subject } from 'rxjs/Subject'; import 'rxjs/add/operator/debounceTime'; import 'rxjs/add/operator/distinctUntilChanged'; @@ -26,7 +27,8 @@ export class TvSearchComponent implements OnInit, OnDestroy { result: IRequestEngineResult; searchApplied = false; - constructor(private searchService: SearchService, private requestService: RequestService, private notificationService: NotificationService) { + constructor(private searchService: SearchService, private requestService: RequestService, + private notificationService: NotificationService, private route : Router) { this.searchChanged .debounceTime(600) // Wait Xms afterthe last event before emitting last event .distinctUntilChanged() // only emit if value is different from previous value @@ -128,6 +130,10 @@ export class TvSearchComponent implements OnInit, OnDestroy { this.request(searchResult); } + selectSeason(searchResult: ISearchTvResult) { + this.route.navigate(['/search/show', searchResult.seriesId]); + } + private clearResults() { this.tvResults = []; diff --git a/Ombi/Ombi/wwwroot/app/services/search.service.ts b/Ombi/Ombi/wwwroot/app/services/search.service.ts index 52099961f..195ce18aa 100644 --- a/Ombi/Ombi/wwwroot/app/services/search.service.ts +++ b/Ombi/Ombi/wwwroot/app/services/search.service.ts @@ -36,7 +36,12 @@ export class SearchService extends ServiceAuthHelpers { // TV searchTv(searchTerm: string): Observable { return this.http.get(`${this.url}/Tv/` + searchTerm).map(this.extractData); - } + } + + getShowInformation(theTvDbId: number): Observable { + return this.http.get(`${this.url}/Tv/info/${theTvDbId}`).map(this.extractData); + } + popularTv(): Observable { return this.http.get(`${this.url}/Tv/popular`).map(this.extractData); }