mirror of
https://github.com/Ombi-app/Ombi.git
synced 2025-08-14 02:26:55 -07:00
Revert "Merge branch 'DotNetCore' into dev"
This reverts commit90827aa7f9
, reversing changes made to205f72a83d
.
This commit is contained in:
parent
ab67ff692c
commit
2e5e113743
93 changed files with 12 additions and 11559 deletions
16
Ombi/.gitignore
vendored
16
Ombi/.gitignore
vendored
|
@ -1,16 +0,0 @@
|
|||
../app/**/*.js
|
||||
../app/**/*.js.map
|
||||
../wwwroot/**
|
||||
|
||||
# dependencies
|
||||
../node_modules
|
||||
../bower_components
|
||||
|
||||
# misc
|
||||
/.sass-cache
|
||||
/connect.lock
|
||||
/coverage/*
|
||||
/libpeerconnection.log
|
||||
npm-debug.log
|
||||
testem.log
|
||||
/typings
|
|
@ -1,6 +0,0 @@
|
|||
;https://docs.microsoft.com/en-us/dotnet/articles/core/deploying/
|
||||
cd ..
|
||||
dotnet restore
|
||||
dotnet publish -c Release /p:AppRuntimeIdentifier=win10-x64
|
||||
|
||||
exit
|
|
@ -1,9 +0,0 @@
|
|||
;https://docs.microsoft.com/en-us/dotnet/articles/core/deploying/
|
||||
cd ..
|
||||
dotnet restore
|
||||
dotnet publish -c Release /p:AppRuntimeIdentifier=win10-x64
|
||||
dotnet publish -c Release /p:AppRuntimeIdentifier=osx.10.12-x64
|
||||
dotnet publish -c Release /p:AppRuntimeIdentifier=ubuntu.16.10-x64
|
||||
dotnet publish -c Release /p:AppRuntimeIdentifier=debian.8-x64
|
||||
|
||||
exit
|
|
@ -1,29 +0,0 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Ombi.Api
|
||||
{
|
||||
public class Api
|
||||
{
|
||||
public static JsonSerializerSettings Settings = new JsonSerializerSettings
|
||||
{
|
||||
NullValueHandling = NullValueHandling.Ignore
|
||||
};
|
||||
public async Task<T> Get<T>(Uri uri)
|
||||
{
|
||||
var h = new HttpClient();
|
||||
var response = await h.GetAsync(uri);
|
||||
|
||||
if (!response.IsSuccessStatusCode)
|
||||
{
|
||||
// Logging
|
||||
}
|
||||
var receiveString = await response.Content.ReadAsStringAsync();
|
||||
return JsonConvert.DeserializeObject<T>(receiveString, Settings);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,78 +0,0 @@
|
|||
#region Copyright
|
||||
// /************************************************************************
|
||||
// Copyright (c) 2017 Jamie Rees
|
||||
// File: ApiHelper.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;
|
||||
|
||||
namespace Ombi.Api
|
||||
{
|
||||
public static class ApiHelper
|
||||
{
|
||||
public static Uri ChangePath(this Uri uri, string path, params string[] args)
|
||||
{
|
||||
var builder = new UriBuilder(uri);
|
||||
|
||||
if (args != null && args.Length > 0)
|
||||
{
|
||||
builder.Path = builder.Path + string.Format(path, args);
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.Path += path;
|
||||
}
|
||||
return builder.Uri;
|
||||
}
|
||||
public static Uri ChangePath(this Uri uri, string path)
|
||||
{
|
||||
return ChangePath(uri, path, null);
|
||||
}
|
||||
|
||||
public static Uri AddQueryParameter(this Uri uri, string parameter, string value)
|
||||
{
|
||||
if (string.IsNullOrEmpty(parameter) || string.IsNullOrEmpty(value)) return uri;
|
||||
var builder = new UriBuilder(uri);
|
||||
var startingTag = string.Empty;
|
||||
var hasQuery = false;
|
||||
if (string.IsNullOrEmpty(builder.Query))
|
||||
{
|
||||
startingTag = "?";
|
||||
}
|
||||
else
|
||||
{
|
||||
hasQuery = true;
|
||||
startingTag = builder.Query.Contains("?") ? "&" : "?";
|
||||
}
|
||||
|
||||
builder.Query = hasQuery
|
||||
? $"{builder.Query}{startingTag}{parameter}={value}"
|
||||
: $"{startingTag}{parameter}={value}";
|
||||
return builder.Uri;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard1.4</TargetFramework>
|
||||
<!--<NetStandardImplicitPackageVersion>1.6.1</NetStandardImplicitPackageVersion>-->
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Newtonsoft.Json" Version="10.0.2" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
|
@ -1,15 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Ombi.Core.Models.Search;
|
||||
|
||||
namespace Ombi.Core
|
||||
{
|
||||
public interface IMovieEngine
|
||||
{
|
||||
Task<IEnumerable<SearchMovieViewModel>> NowPlayingMovies();
|
||||
Task<IEnumerable<SearchMovieViewModel>> PopularMovies();
|
||||
Task<IEnumerable<SearchMovieViewModel>> ProcessMovieSearch(string search);
|
||||
Task<IEnumerable<SearchMovieViewModel>> TopRatedMovies();
|
||||
Task<IEnumerable<SearchMovieViewModel>> UpcomingMovies();
|
||||
}
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
using System.Threading.Tasks;
|
||||
using Ombi.Core.Models.Search;
|
||||
using Ombi.Store.Entities;
|
||||
|
||||
namespace Ombi.Core.Engine
|
||||
{
|
||||
public interface IRequestEngine
|
||||
{
|
||||
Task<RequestEngineResult> RequestMovie(SearchMovieViewModel model);
|
||||
bool ShouldAutoApprove(RequestType requestType);
|
||||
}
|
||||
}
|
|
@ -1,191 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Ombi.Core.Models.Requests;
|
||||
using Ombi.Core.Models.Search;
|
||||
using Ombi.Core.Requests.Models;
|
||||
using Ombi.Helpers;
|
||||
using Ombi.Store.Entities;
|
||||
using Ombi.TheMovieDbApi.Models;
|
||||
|
||||
namespace Ombi.Core.Engine
|
||||
{
|
||||
public class MovieEngine : IMovieEngine
|
||||
{
|
||||
|
||||
public MovieEngine(IRequestService service)
|
||||
{
|
||||
RequestService = service;
|
||||
}
|
||||
private IRequestService RequestService { get; }
|
||||
public async Task<IEnumerable<SearchMovieViewModel>> ProcessMovieSearch(string search)
|
||||
{
|
||||
var api = new TheMovieDbApi.TheMovieDbApi();
|
||||
var result = await api.SearchMovie(search);
|
||||
if (result != null)
|
||||
{
|
||||
return await TransformMovieResultsToResponse(result.results);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
public async Task<IEnumerable<SearchMovieViewModel>> PopularMovies()
|
||||
{
|
||||
var api = new TheMovieDbApi.TheMovieDbApi();
|
||||
var result = await api.PopularMovies();
|
||||
if (result != null)
|
||||
{
|
||||
return await TransformMovieResultsToResponse(result.results);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<SearchMovieViewModel>> TopRatedMovies()
|
||||
{
|
||||
var api = new TheMovieDbApi.TheMovieDbApi();
|
||||
var result = await api.TopRated();
|
||||
if (result != null)
|
||||
{
|
||||
return await TransformMovieResultsToResponse(result.results);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<SearchMovieViewModel>> UpcomingMovies()
|
||||
{
|
||||
var api = new TheMovieDbApi.TheMovieDbApi();
|
||||
var result = await api.Upcoming();
|
||||
if (result != null)
|
||||
{
|
||||
return await TransformMovieResultsToResponse(result.results);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
public async Task<IEnumerable<SearchMovieViewModel>> NowPlayingMovies()
|
||||
{
|
||||
var api = new TheMovieDbApi.TheMovieDbApi();
|
||||
var result = await api.NowPlaying();
|
||||
if (result != null)
|
||||
{
|
||||
return await TransformMovieResultsToResponse(result.results);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
private async Task<List<SearchMovieViewModel>> TransformMovieResultsToResponse(IEnumerable<SearchResult> movies)
|
||||
{
|
||||
await Task.Yield();
|
||||
var viewMovies = new List<SearchMovieViewModel>();
|
||||
//var counter = 0;
|
||||
Dictionary<int, RequestModel> dbMovies = await RequestedMovies();
|
||||
foreach (var movie in movies)
|
||||
{
|
||||
var viewMovie = new SearchMovieViewModel
|
||||
{
|
||||
Adult = movie.adult,
|
||||
BackdropPath = movie.backdrop_path,
|
||||
Id = movie.id,
|
||||
OriginalLanguage = movie.original_language,
|
||||
OriginalTitle = movie.original_title,
|
||||
Overview = movie.overview,
|
||||
Popularity = movie.popularity,
|
||||
PosterPath = movie.poster_path,
|
||||
ReleaseDate = string.IsNullOrEmpty(movie.release_date) ? DateTime.MinValue : DateTime.Parse(movie.release_date),
|
||||
Title = movie.title,
|
||||
Video = movie.video,
|
||||
VoteAverage = movie.vote_average,
|
||||
VoteCount = movie.vote_count
|
||||
};
|
||||
viewMovies.Add(viewMovie);
|
||||
|
||||
//if (counter <= 5) // Let's only do it for the first 5 items
|
||||
//{
|
||||
// var movieInfo = MovieApi.GetMovieInformationWithVideos(movie.Id);
|
||||
|
||||
// // TODO needs to be careful about this, it's adding extra time to search...
|
||||
// // https://www.themoviedb.org/talk/5807f4cdc3a36812160041f2
|
||||
// viewMovie.ImdbId = movieInfo?.imdb_id;
|
||||
// viewMovie.Homepage = movieInfo?.homepage;
|
||||
// var videoId = movieInfo?.video ?? false
|
||||
// ? movieInfo?.videos?.results?.FirstOrDefault()?.key
|
||||
// : string.Empty;
|
||||
|
||||
// viewMovie.Trailer = string.IsNullOrEmpty(videoId)
|
||||
// ? string.Empty
|
||||
// : $"https://www.youtube.com/watch?v={videoId}";
|
||||
|
||||
// counter++;
|
||||
//}
|
||||
|
||||
// var canSee = CanUserSeeThisRequest(viewMovie.Id, Security.HasPermissions(User, Permissions.UsersCanViewOnlyOwnRequests), dbMovies);
|
||||
|
||||
// var plexSettings = await PlexService.GetSettingsAsync();
|
||||
// var embySettings = await EmbySettings.GetSettingsAsync();
|
||||
// if (plexSettings.Enable)
|
||||
// {
|
||||
// var content = PlexContentRepository.GetAll();
|
||||
// var plexMovies = PlexChecker.GetPlexMovies(content);
|
||||
|
||||
// var plexMovie = PlexChecker.GetMovie(plexMovies.ToArray(), movie.Title,
|
||||
// movie.ReleaseDate?.Year.ToString(),
|
||||
// viewMovie.ImdbId);
|
||||
// if (plexMovie != null)
|
||||
// {
|
||||
// viewMovie.Available = true;
|
||||
// viewMovie.PlexUrl = plexMovie.Url;
|
||||
// }
|
||||
// }
|
||||
// if (embySettings.Enable)
|
||||
// {
|
||||
// var embyContent = EmbyContentRepository.GetAll();
|
||||
// var embyMovies = EmbyChecker.GetEmbyMovies(embyContent);
|
||||
|
||||
// var embyMovie = EmbyChecker.GetMovie(embyMovies.ToArray(), movie.Title,
|
||||
// movie.ReleaseDate?.Year.ToString(), viewMovie.ImdbId);
|
||||
// if (embyMovie != null)
|
||||
// {
|
||||
// viewMovie.Available = true;
|
||||
// }
|
||||
// }
|
||||
if (dbMovies.ContainsKey(movie.id) /*&& canSee*/) // compare to the requests db
|
||||
{
|
||||
var dbm = dbMovies[movie.id];
|
||||
|
||||
viewMovie.Requested = true;
|
||||
viewMovie.Approved = dbm.Approved;
|
||||
viewMovie.Available = dbm.Available;
|
||||
}
|
||||
// else if (canSee)
|
||||
// {
|
||||
// bool exists = IsMovieInCache(movie, viewMovie.ImdbId);
|
||||
// viewMovie.Approved = exists;
|
||||
// viewMovie.Requested = exists;
|
||||
// }
|
||||
// viewMovies.Add(viewMovie);
|
||||
//}
|
||||
|
||||
|
||||
}
|
||||
return viewMovies;
|
||||
}
|
||||
|
||||
|
||||
private long _dbMovieCacheTime = 0;
|
||||
private Dictionary<int, RequestModel> _dbMovies;
|
||||
private async Task<Dictionary<int, RequestModel>> RequestedMovies()
|
||||
{
|
||||
long now = DateTime.Now.Ticks;
|
||||
if (_dbMovies == null || (now - _dbMovieCacheTime) > 10000)
|
||||
{
|
||||
var allResults = await RequestService.GetAllAsync();
|
||||
allResults = allResults.Where(x => x.Type == RequestType.Movie);
|
||||
|
||||
var distinctResults = allResults.DistinctBy(x => x.ProviderId);
|
||||
_dbMovies = distinctResults.ToDictionary(x => x.ProviderId);
|
||||
_dbMovieCacheTime = now;
|
||||
}
|
||||
return _dbMovies;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,232 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Ombi.Core.Models.Requests;
|
||||
using Ombi.Core.Models.Search;
|
||||
using Ombi.Core.Requests.Models;
|
||||
using Ombi.Store.Entities;
|
||||
using Ombi.TheMovieDbApi;
|
||||
|
||||
namespace Ombi.Core.Engine
|
||||
{
|
||||
public class RequestEngine : IRequestEngine
|
||||
{
|
||||
public RequestEngine(IMovieDbApi movieApi, IRequestService requestService)
|
||||
{
|
||||
MovieApi = movieApi;
|
||||
RequestService = requestService;
|
||||
}
|
||||
private IMovieDbApi MovieApi { get; }
|
||||
private IRequestService RequestService { get; }
|
||||
public async Task<RequestEngineResult> RequestMovie(SearchMovieViewModel model)
|
||||
{
|
||||
var movieInfo = await MovieApi.GetMovieInformation(model.Id);
|
||||
if (movieInfo == null)
|
||||
{
|
||||
return new RequestEngineResult
|
||||
{
|
||||
RequestAdded = false,
|
||||
Message = "There was an issue adding this movie!"
|
||||
};
|
||||
//Response.AsJson(new JsonResponseModel
|
||||
//{
|
||||
// Result = false,
|
||||
// Message = "There was an issue adding this movie!"
|
||||
//});
|
||||
}
|
||||
var fullMovieName =
|
||||
$"{movieInfo.title}{(!string.IsNullOrEmpty(movieInfo.release_date) ? $" ({DateTime.Parse(movieInfo.release_date).Year})" : string.Empty)}";
|
||||
|
||||
var existingRequest = await RequestService.CheckRequestAsync(model.Id);
|
||||
if (existingRequest != null)
|
||||
{
|
||||
// check if the current user is already marked as a requester for this movie, if not, add them
|
||||
//if (!existingRequest.UserHasRequested(Username))
|
||||
//{
|
||||
// existingRequest.RequestedUsers.Add(Username);
|
||||
// await RequestService.UpdateRequestAsync(existingRequest);
|
||||
//}
|
||||
|
||||
return new RequestEngineResult
|
||||
{
|
||||
RequestAdded = true,
|
||||
|
||||
};
|
||||
//Response.AsJson(new JsonResponseModel
|
||||
//{
|
||||
// Result = true,
|
||||
// Message =
|
||||
// Security.HasPermissions(User, Permissions.UsersCanViewOnlyOwnRequests)
|
||||
// ? $"{fullMovieName} {Ombi.UI.Resources.UI.Search_SuccessfullyAdded}"
|
||||
// : $"{fullMovieName} {Resources.UI.Search_AlreadyRequested}"
|
||||
//});
|
||||
}
|
||||
|
||||
|
||||
// TODO
|
||||
//try
|
||||
//{
|
||||
|
||||
// var content = PlexContentRepository.GetAll();
|
||||
// var movies = PlexChecker.GetPlexMovies(content);
|
||||
// if (PlexChecker.IsMovieAvailable(movies.ToArray(), movieInfo.Title, movieInfo.ReleaseDate?.Year.ToString()))
|
||||
// {
|
||||
// return
|
||||
// Response.AsJson(new JsonResponseModel
|
||||
// {
|
||||
// Result = false,
|
||||
// Message = $"{fullMovieName} is already in Plex!"
|
||||
// });
|
||||
// }
|
||||
//}
|
||||
//catch (Exception e)
|
||||
//{
|
||||
// Log.Error(e);
|
||||
// return
|
||||
// Response.AsJson(new JsonResponseModel
|
||||
// {
|
||||
// Result = false,
|
||||
// Message = string.Format(Resources.UI.Search_CouldNotCheckPlex, fullMovieName, GetMediaServerName())
|
||||
// });
|
||||
//}
|
||||
|
||||
var requestModel = new RequestModel
|
||||
{
|
||||
ProviderId = movieInfo.id,
|
||||
Type = RequestType.Movie,
|
||||
Overview = movieInfo.overview,
|
||||
ImdbId = movieInfo.imdb_id,
|
||||
PosterPath = movieInfo.poster_path,
|
||||
Title = movieInfo.title,
|
||||
ReleaseDate = !string.IsNullOrEmpty(movieInfo.release_date) ? DateTime.Parse(movieInfo.release_date) : DateTime.MinValue,
|
||||
Status = movieInfo.status,
|
||||
RequestedDate = DateTime.UtcNow,
|
||||
Approved = false,
|
||||
//RequestedUsers = new List<string> { Username },
|
||||
Issues = IssueState.None,
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
if (ShouldAutoApprove(RequestType.Movie))
|
||||
{
|
||||
// model.Approved = true;
|
||||
|
||||
// var result = await MovieSender.Send(model);
|
||||
// if (result.Result)
|
||||
// {
|
||||
// return await AddRequest(model, settings,
|
||||
// $"{fullMovieName} {Resources.UI.Search_SuccessfullyAdded}");
|
||||
// }
|
||||
// if (result.Error)
|
||||
|
||||
// {
|
||||
// return
|
||||
// Response.AsJson(new JsonResponseModel
|
||||
// {
|
||||
// Message = "Could not add movie, please contact your administrator",
|
||||
// Result = false
|
||||
// });
|
||||
// }
|
||||
// if (!result.MovieSendingEnabled)
|
||||
// {
|
||||
|
||||
// return await AddRequest(model, settings, $"{fullMovieName} {Resources.UI.Search_SuccessfullyAdded}");
|
||||
// }
|
||||
|
||||
// return Response.AsJson(new JsonResponseModel
|
||||
// {
|
||||
// Result = false,
|
||||
// Message = Resources.UI.Search_CouchPotatoError
|
||||
// });
|
||||
}
|
||||
|
||||
|
||||
return await AddRequest(requestModel, /*settings,*/
|
||||
$"{fullMovieName} has been successfully added!");
|
||||
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
//Log.Fatal(e);
|
||||
//await FaultQueue.QueueItemAsync(model, movieInfo.Id.ToString(), RequestType.Movie, FaultType.RequestFault, e.Message);
|
||||
|
||||
//await NotificationService.Publish(new NotificationModel
|
||||
//{
|
||||
// DateTime = DateTime.Now,
|
||||
// User = Username,
|
||||
// RequestType = RequestType.Movie,
|
||||
// Title = model.Title,
|
||||
// NotificationType = NotificationType.ItemAddedToFaultQueue
|
||||
//});
|
||||
|
||||
//return Response.AsJson(new JsonResponseModel
|
||||
//{
|
||||
// Result = true,
|
||||
// Message = $"{fullMovieName} {Resources.UI.Search_SuccessfullyAdded}"
|
||||
//});
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public bool ShouldAutoApprove(RequestType requestType)
|
||||
{
|
||||
//var admin = Security.HasPermissions(Context.CurrentUser, Permissions.Administrator);
|
||||
//// if the user is an admin, they go ahead and allow auto-approval
|
||||
//if (admin) return true;
|
||||
|
||||
//// check by request type if the category requires approval or not
|
||||
//switch (requestType)
|
||||
//{
|
||||
// case RequestType.Movie:
|
||||
// return Security.HasPermissions(User, Permissions.AutoApproveMovie);
|
||||
// case RequestType.TvShow:
|
||||
// return Security.HasPermissions(User, Permissions.AutoApproveTv);
|
||||
// case RequestType.Album:
|
||||
// return Security.HasPermissions(User, Permissions.AutoApproveAlbum);
|
||||
// default:
|
||||
// return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
private async Task<RequestEngineResult> AddRequest(RequestModel model, /*PlexRequestSettings settings,*/ string message)
|
||||
{
|
||||
await RequestService.AddRequestAsync(model);
|
||||
|
||||
//if (ShouldSendNotification(model.Type, settings))
|
||||
//{
|
||||
// var notificationModel = new NotificationModel
|
||||
// {
|
||||
// Title = model.Title,
|
||||
// User = Username,
|
||||
// DateTime = DateTime.Now,
|
||||
// NotificationType = NotificationType.NewRequest,
|
||||
// RequestType = model.Type,
|
||||
// ImgSrc = model.Type == RequestType.Movie ? $"https://image.tmdb.org/t/p/w300/{model.PosterPath}" : model.PosterPath
|
||||
// };
|
||||
// await NotificationService.Publish(notificationModel);
|
||||
//}
|
||||
|
||||
//var limit = await RequestLimitRepo.GetAllAsync();
|
||||
//var usersLimit = limit.FirstOrDefault(x => x.Username == Username && x.RequestType == model.Type);
|
||||
//if (usersLimit == null)
|
||||
//{
|
||||
// await RequestLimitRepo.InsertAsync(new RequestLimit
|
||||
// {
|
||||
// Username = Username,
|
||||
// RequestType = model.Type,
|
||||
// FirstRequestDate = DateTime.UtcNow,
|
||||
// RequestCount = 1
|
||||
// });
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// usersLimit.RequestCount++;
|
||||
// await RequestLimitRepo.UpdateAsync(usersLimit);
|
||||
//}
|
||||
|
||||
return new RequestEngineResult{RequestAdded = true};
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
namespace Ombi.Core.Engine
|
||||
{
|
||||
public class RequestEngineResult
|
||||
{
|
||||
public bool RequestAdded { get; set; }
|
||||
public string Message { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Ombi.Core.Models.Requests;
|
||||
using Ombi.Store.Entities;
|
||||
|
||||
namespace Ombi.Core.Requests.Models
|
||||
{
|
||||
public interface IRequestService
|
||||
{
|
||||
int AddRequest(RequestModel model);
|
||||
Task<int> AddRequestAsync(RequestModel model);
|
||||
void BatchDelete(IEnumerable<RequestModel> model);
|
||||
void BatchUpdate(IEnumerable<RequestModel> model);
|
||||
RequestModel CheckRequest(int providerId);
|
||||
RequestModel CheckRequest(string musicId);
|
||||
Task<RequestModel> CheckRequestAsync(int providerId);
|
||||
Task<RequestModel> CheckRequestAsync(string musicId);
|
||||
void DeleteRequest(RequestModel request);
|
||||
Task DeleteRequestAsync(RequestModel request);
|
||||
RequestModel Get(int id);
|
||||
IEnumerable<RequestModel> GetAll();
|
||||
Task<IEnumerable<RequestModel>> GetAllAsync();
|
||||
Task<RequestModel> GetAsync(int id);
|
||||
RequestBlobs UpdateRequest(RequestModel model);
|
||||
}
|
||||
}
|
|
@ -1,174 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Ombi.Core.Requests.Models;
|
||||
using Ombi.Helpers;
|
||||
using Ombi.Store.Entities;
|
||||
using Ombi.Store.Repository;
|
||||
|
||||
namespace Ombi.Core.Models.Requests
|
||||
{
|
||||
public class JsonRequestService : IRequestService
|
||||
{
|
||||
public JsonRequestService(IRequestRepository repo)
|
||||
{
|
||||
Repo = repo;
|
||||
}
|
||||
private IRequestRepository Repo { get; }
|
||||
public int AddRequest(RequestModel model)
|
||||
{
|
||||
var entity = new RequestBlobs { Type = model.Type, Content = ByteConverterHelper.ReturnBytes(model), ProviderId = model.ProviderId };
|
||||
var id = Repo.Insert(entity);
|
||||
|
||||
return id.Id;
|
||||
}
|
||||
|
||||
public async Task<int> AddRequestAsync(RequestModel model)
|
||||
{
|
||||
var entity = new RequestBlobs { Type = model.Type, Content = ByteConverterHelper.ReturnBytes(model), ProviderId = model.ProviderId };
|
||||
var id = await Repo.InsertAsync(entity).ConfigureAwait(false);
|
||||
|
||||
return id.Id;
|
||||
}
|
||||
|
||||
public RequestModel CheckRequest(int providerId)
|
||||
{
|
||||
var blobs = Repo.GetAll();
|
||||
var blob = blobs.FirstOrDefault(x => x.ProviderId == providerId); if (blob == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
var model = ByteConverterHelper.ReturnObject<RequestModel>(blob.Content);
|
||||
model.Id = blob.Id;
|
||||
return model;
|
||||
}
|
||||
|
||||
public async Task<RequestModel> CheckRequestAsync(int providerId)
|
||||
{
|
||||
var blobs = await Repo.GetAllAsync().ConfigureAwait(false);
|
||||
var blob = blobs.FirstOrDefault(x => x.ProviderId == providerId); if (blob == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
var model = ByteConverterHelper.ReturnObject<RequestModel>(blob.Content);
|
||||
model.Id = blob.Id;
|
||||
return model;
|
||||
}
|
||||
|
||||
public RequestModel CheckRequest(string musicId)
|
||||
{
|
||||
var blobs = Repo.GetAll();
|
||||
var blob = blobs.FirstOrDefault(x => x.MusicId == musicId); if (blob == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
var model = ByteConverterHelper.ReturnObject<RequestModel>(blob.Content);
|
||||
model.Id = blob.Id;
|
||||
return model;
|
||||
}
|
||||
|
||||
public async Task<RequestModel> CheckRequestAsync(string musicId)
|
||||
{
|
||||
var blobs = await Repo.GetAllAsync().ConfigureAwait(false);
|
||||
var blob = blobs.FirstOrDefault(x => x.MusicId == musicId);
|
||||
|
||||
if (blob == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
var model = ByteConverterHelper.ReturnObject<RequestModel>(blob.Content);
|
||||
model.Id = blob.Id;
|
||||
return model;
|
||||
}
|
||||
|
||||
public void DeleteRequest(RequestModel request)
|
||||
{
|
||||
var blob = Repo.Get(request.Id);
|
||||
Repo.Delete(blob);
|
||||
}
|
||||
|
||||
public async Task DeleteRequestAsync(RequestModel request)
|
||||
{
|
||||
var blob = await Repo.GetAsync(request.Id).ConfigureAwait(false);
|
||||
Repo.Delete(blob);
|
||||
}
|
||||
|
||||
public RequestBlobs UpdateRequest(RequestModel model)
|
||||
{
|
||||
var entity = new RequestBlobs { Type = model.Type, Content = ByteConverterHelper.ReturnBytes(model), ProviderId = model.ProviderId, Id = model.Id };
|
||||
return Repo.Update(entity);
|
||||
}
|
||||
|
||||
public RequestModel Get(int id)
|
||||
{
|
||||
var blob = Repo.Get(id);
|
||||
if (blob == null)
|
||||
{
|
||||
return new RequestModel();
|
||||
}
|
||||
var model = ByteConverterHelper.ReturnObject<RequestModel>(blob.Content);
|
||||
model.Id = blob.Id; // They should always be the same, but for somereason a user didn't have it in the db https://github.com/tidusjar/Ombi/issues/862#issuecomment-269743847
|
||||
return model;
|
||||
}
|
||||
|
||||
public async Task<RequestModel> GetAsync(int id)
|
||||
{
|
||||
var blob = await Repo.GetAsync(id).ConfigureAwait(false);
|
||||
if (blob == null)
|
||||
{
|
||||
return new RequestModel();
|
||||
}
|
||||
var model = ByteConverterHelper.ReturnObject<RequestModel>(blob.Content);
|
||||
model.Id = blob.Id;
|
||||
return model;
|
||||
}
|
||||
|
||||
public IEnumerable<RequestModel> GetAll()
|
||||
{
|
||||
var blobs = Repo.GetAll().ToList();
|
||||
var retVal = new List<RequestModel>();
|
||||
|
||||
foreach (var b in blobs)
|
||||
{
|
||||
if (b == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
var model = ByteConverterHelper.ReturnObject<RequestModel>(b.Content);
|
||||
model.Id = b.Id;
|
||||
retVal.Add(model);
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<RequestModel>> GetAllAsync()
|
||||
{
|
||||
var blobs = await Repo.GetAllAsync().ConfigureAwait(false);
|
||||
var retVal = new List<RequestModel>();
|
||||
|
||||
foreach (var b in blobs)
|
||||
{
|
||||
if (b == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
var model = ByteConverterHelper.ReturnObject<RequestModel>(b.Content);
|
||||
model.Id = b.Id;
|
||||
retVal.Add(model);
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
public void BatchUpdate(IEnumerable<RequestModel> model)
|
||||
{
|
||||
var entities = model.Select(m => new RequestBlobs { Type = m.Type, Content = ByteConverterHelper.ReturnBytes(m), ProviderId = m.ProviderId, Id = m.Id }).ToList();
|
||||
Repo.UpdateAll(entities);
|
||||
}
|
||||
|
||||
public void BatchDelete(IEnumerable<RequestModel> model)
|
||||
{
|
||||
var entities = model.Select(m => new RequestBlobs { Type = m.Type, Content = ByteConverterHelper.ReturnBytes(m), ProviderId = m.ProviderId, Id = m.Id }).ToList();
|
||||
Repo.DeleteAll(entities);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,132 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Newtonsoft.Json;
|
||||
using Ombi.Store.Entities;
|
||||
|
||||
namespace Ombi.Core.Models.Requests
|
||||
{
|
||||
public class RequestModel : Entity
|
||||
{
|
||||
public RequestModel()
|
||||
{
|
||||
RequestedUsers = new List<string>();
|
||||
Episodes = new List<EpisodesModel>();
|
||||
}
|
||||
|
||||
public int ProviderId { get; set; }
|
||||
public string ImdbId { get; set; }
|
||||
public string TvDbId { get; set; }
|
||||
public string Overview { get; set; }
|
||||
public string Title { get; set; }
|
||||
public string PosterPath { get; set; }
|
||||
public DateTime ReleaseDate { get; set; }
|
||||
public RequestType Type { get; set; }
|
||||
public string Status { get; set; }
|
||||
public bool Approved { get; set; }
|
||||
|
||||
public DateTime RequestedDate { get; set; }
|
||||
public bool Available { get; set; }
|
||||
public IssueState Issues { get; set; }
|
||||
public string OtherMessage { get; set; }
|
||||
public string AdminNote { get; set; }
|
||||
public int[] SeasonList { get; set; }
|
||||
public int SeasonCount { get; set; }
|
||||
public string SeasonsRequested { get; set; }
|
||||
public string MusicBrainzId { get; set; }
|
||||
public List<string> RequestedUsers { get; set; }
|
||||
public string ArtistName { get; set; }
|
||||
public string ArtistId { get; set; }
|
||||
public int IssueId { get; set; }
|
||||
public List<EpisodesModel> Episodes { get; set; }
|
||||
public bool Denied { get; set; }
|
||||
public string DeniedReason { get; set; }
|
||||
/// <summary>
|
||||
/// For TV Shows with a custom root folder
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The root folder selected.
|
||||
/// </value>
|
||||
public int RootFolderSelected { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
public List<string> AllUsers
|
||||
{
|
||||
get
|
||||
{
|
||||
var u = new List<string>();
|
||||
if (RequestedUsers != null && RequestedUsers.Any())
|
||||
{
|
||||
u.AddRange(RequestedUsers);
|
||||
}
|
||||
return u;
|
||||
}
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public bool CanApprove => !Approved && !Available;
|
||||
|
||||
public string ReleaseId { get; set; }
|
||||
|
||||
public bool UserHasRequested(string username)
|
||||
{
|
||||
return AllUsers.Any(x => x.Equals(username, StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static class RequestTypeDisplay
|
||||
{
|
||||
public static string GetString(this RequestType type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case RequestType.Movie:
|
||||
return "Movie";
|
||||
case RequestType.TvShow:
|
||||
return "TV Show";
|
||||
case RequestType.Album:
|
||||
return "Album";
|
||||
default:
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum IssueState
|
||||
{
|
||||
None = 99,
|
||||
WrongAudio = 0,
|
||||
NoSubtitles = 1,
|
||||
WrongContent = 2,
|
||||
PlaybackIssues = 3,
|
||||
Other = 4, // Provide a message
|
||||
}
|
||||
|
||||
public class EpisodesModel : IEquatable<EpisodesModel>
|
||||
{
|
||||
public int SeasonNumber { get; set; }
|
||||
public int EpisodeNumber { get; set; }
|
||||
public bool Equals(EpisodesModel other)
|
||||
{
|
||||
// Check whether the compared object is null.
|
||||
if (ReferenceEquals(other, null)) return false;
|
||||
|
||||
//Check whether the compared object references the same data.
|
||||
if (ReferenceEquals(this, other)) return true;
|
||||
|
||||
//Check whether the properties are equal.
|
||||
return SeasonNumber.Equals(other.SeasonNumber) && EpisodeNumber.Equals(other.EpisodeNumber);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
var hashSeason = SeasonNumber.GetHashCode();
|
||||
var hashEp = EpisodeNumber.GetHashCode();
|
||||
|
||||
//Calculate the hash code.
|
||||
return hashSeason + hashEp;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,54 +0,0 @@
|
|||
#region Copyright
|
||||
// /************************************************************************
|
||||
// Copyright (c) 2017 Jamie Rees
|
||||
// File: SearchMovieViewModel.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;
|
||||
|
||||
namespace Ombi.Core.Models.Search
|
||||
{
|
||||
public class SearchMovieViewModel : SearchViewModel
|
||||
{
|
||||
public bool Adult { get; set; }
|
||||
public string BackdropPath { get; set; }
|
||||
public List<int> GenreIds { get; set; }
|
||||
public int Id { get; set; }
|
||||
public string OriginalLanguage { get; set; }
|
||||
public string OriginalTitle { get; set; }
|
||||
public string Overview { get; set; }
|
||||
public double Popularity { get; set; }
|
||||
public string PosterPath { get; set; }
|
||||
public DateTime? ReleaseDate { get; set; }
|
||||
public string Title { get; set; }
|
||||
public bool Video { get; set; }
|
||||
public double VoteAverage { get; set; }
|
||||
public int VoteCount { get; set; }
|
||||
public bool AlreadyInCp { get; set; }
|
||||
public string Trailer { get; set; }
|
||||
public string Homepage { get; set; }
|
||||
public string ImdbId { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
#region Copyright
|
||||
// /************************************************************************
|
||||
// Copyright (c) 2017 Jamie Rees
|
||||
// File: SearchViewModel.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 Ombi.Core.Models.Search
|
||||
{
|
||||
public class SearchViewModel
|
||||
{
|
||||
public bool Approved { get; set; }
|
||||
public bool Requested { get; set; }
|
||||
public bool Available { get; set; }
|
||||
public string PlexUrl { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard1.4</TargetFramework>
|
||||
<!--<NetStandardImplicitPackageVersion>1.6.1</NetStandardImplicitPackageVersion>-->
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="1.1.1" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Design" Version="1.1.1" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="10.0.2" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Ombi.Helpers\Ombi.Helpers.csproj" />
|
||||
<ProjectReference Include="..\Ombi.Store\Ombi.Store.csproj" />
|
||||
<ProjectReference Include="..\Ombi.TheMovieDbApi\Ombi.TheMovieDbApi.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
|
@ -1,14 +0,0 @@
|
|||
using System.Threading.Tasks;
|
||||
|
||||
namespace Ombi.Core.Settings
|
||||
{
|
||||
public interface ISettingsService<T>
|
||||
{
|
||||
T GetSettings();
|
||||
Task<T> GetSettingsAsync();
|
||||
bool SaveSettings(T model);
|
||||
Task<bool> SaveSettingsAsync(T model);
|
||||
bool Delete(T model);
|
||||
Task<bool> DeleteAsync(T model);
|
||||
}
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
namespace Ombi.Core.Settings.Models
|
||||
{
|
||||
public class Settings
|
||||
{
|
||||
public int Id { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,129 +0,0 @@
|
|||
using System.Threading.Tasks;
|
||||
using Newtonsoft.Json;
|
||||
using Ombi.Helpers;
|
||||
using Ombi.Store.Entities;
|
||||
using Ombi.Store.Repository;
|
||||
|
||||
namespace Ombi.Core.Settings
|
||||
{
|
||||
public class SettingsServiceV2<T> : ISettingsService<T>
|
||||
where T : Models.Settings, new()
|
||||
{
|
||||
|
||||
public SettingsServiceV2(ISettingsRepository repo)
|
||||
{
|
||||
Repo = repo;
|
||||
EntityName = typeof(T).Name;
|
||||
}
|
||||
|
||||
private ISettingsRepository Repo { get; }
|
||||
private string EntityName { get; }
|
||||
|
||||
public T GetSettings()
|
||||
{
|
||||
var result = Repo.Get(EntityName);
|
||||
if (result == null)
|
||||
{
|
||||
return new T();
|
||||
}
|
||||
result.Content = DecryptSettings(result);
|
||||
var obj = string.IsNullOrEmpty(result.Content) ? null : JsonConvert.DeserializeObject<T>(result.Content, SerializerSettings.Settings);
|
||||
|
||||
var model = obj;
|
||||
|
||||
return model;
|
||||
}
|
||||
|
||||
public async Task<T> GetSettingsAsync()
|
||||
{
|
||||
var result = await Repo.GetAsync(EntityName).ConfigureAwait(false);
|
||||
if (result == null)
|
||||
{
|
||||
return new T();
|
||||
}
|
||||
result.Content = DecryptSettings(result);
|
||||
return string.IsNullOrEmpty(result.Content) ? null : JsonConvert.DeserializeObject<T>(result.Content, SerializerSettings.Settings);
|
||||
}
|
||||
|
||||
public bool SaveSettings(T model)
|
||||
{
|
||||
var entity = Repo.Get(EntityName);
|
||||
|
||||
if (entity == null)
|
||||
{
|
||||
var newEntity = model;
|
||||
|
||||
var settings = new GlobalSettings { SettingsName = EntityName, Content = JsonConvert.SerializeObject(newEntity, SerializerSettings.Settings) };
|
||||
settings.Content = EncryptSettings(settings);
|
||||
var insertResult = Repo.Insert(settings);
|
||||
|
||||
return insertResult != null;
|
||||
}
|
||||
|
||||
|
||||
var modified = model;
|
||||
modified.Id = entity.Id;
|
||||
|
||||
var globalSettings = new GlobalSettings { SettingsName = EntityName, Content = JsonConvert.SerializeObject(modified, SerializerSettings.Settings), Id = entity.Id };
|
||||
globalSettings.Content = EncryptSettings(globalSettings);
|
||||
Repo.Update(globalSettings);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public async Task<bool> SaveSettingsAsync(T model)
|
||||
{
|
||||
var entity = await Repo.GetAsync(EntityName);
|
||||
|
||||
if (entity == null)
|
||||
{
|
||||
var newEntity = model;
|
||||
|
||||
var settings = new GlobalSettings { SettingsName = EntityName, Content = JsonConvert.SerializeObject(newEntity, SerializerSettings.Settings) };
|
||||
settings.Content = EncryptSettings(settings);
|
||||
var insertResult = await Repo.InsertAsync(settings).ConfigureAwait(false);
|
||||
|
||||
return insertResult != null;
|
||||
}
|
||||
|
||||
var modified = model;
|
||||
modified.Id = entity.Id;
|
||||
|
||||
var globalSettings = new GlobalSettings { SettingsName = EntityName, Content = JsonConvert.SerializeObject(modified, SerializerSettings.Settings), Id = entity.Id };
|
||||
globalSettings.Content = EncryptSettings(globalSettings);
|
||||
await Repo.UpdateAsync(globalSettings).ConfigureAwait(false);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Delete(T model)
|
||||
{
|
||||
var entity = Repo.Get(EntityName);
|
||||
if (entity != null)
|
||||
{
|
||||
Repo.Delete(entity);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public async Task DeleteAsync(T model)
|
||||
{
|
||||
var entity = Repo.Get(EntityName);
|
||||
if (entity != null)
|
||||
{
|
||||
await Repo.DeleteAsync(entity);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private string EncryptSettings(GlobalSettings settings)
|
||||
{
|
||||
return StringCipher.Encrypt(settings.Content, settings.SettingsName);
|
||||
}
|
||||
|
||||
private string DecryptSettings(GlobalSettings settings)
|
||||
{
|
||||
return StringCipher.Decrypt(settings.Content, settings.SettingsName);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,57 +0,0 @@
|
|||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Ombi.Core;
|
||||
using Ombi.Core.Engine;
|
||||
using Ombi.Core.Models.Requests;
|
||||
using Ombi.Core.Requests.Models;
|
||||
using Ombi.Core.Settings;
|
||||
using Ombi.Store.Context;
|
||||
using Ombi.Store.Repository;
|
||||
using Ombi.TheMovieDbApi;
|
||||
|
||||
namespace Ombi.DependencyInjection
|
||||
{
|
||||
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
|
||||
public static class IocExtensions
|
||||
{
|
||||
public static IServiceCollection RegisterDependencies(this IServiceCollection services)
|
||||
{
|
||||
services.RegisterEngines();
|
||||
services.RegisterApi();
|
||||
services.RegisterServices();
|
||||
services.RegisterStore();
|
||||
|
||||
return services;
|
||||
}
|
||||
|
||||
public static IServiceCollection RegisterEngines(this IServiceCollection services)
|
||||
{
|
||||
services.AddTransient<IMovieEngine, MovieEngine>();
|
||||
services.AddTransient<IRequestEngine, RequestEngine>();
|
||||
return services;
|
||||
}
|
||||
|
||||
public static IServiceCollection RegisterApi(this IServiceCollection services)
|
||||
{
|
||||
services.AddTransient<IMovieDbApi, TheMovieDbApi.TheMovieDbApi>();
|
||||
return services;
|
||||
}
|
||||
|
||||
public static IServiceCollection RegisterStore(this IServiceCollection services)
|
||||
{
|
||||
services.AddEntityFrameworkSqlite().AddDbContext<OmbiContext>();
|
||||
|
||||
services.AddTransient<IOmbiContext, OmbiContext>();
|
||||
services.AddTransient<IRequestRepository, RequestJsonRepository>();
|
||||
services.AddTransient<ISettingsRepository, SettingsJsonRepository>();
|
||||
services.AddTransient(typeof(ISettingsService<>), typeof(SettingsServiceV2<>));
|
||||
return services;
|
||||
}
|
||||
public static IServiceCollection RegisterServices(this IServiceCollection services)
|
||||
{
|
||||
services.AddTransient<IRequestService, JsonRequestService>();
|
||||
return services;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard1.4</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Ombi.Core\Ombi.Core.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="Microsoft.Extensions.DependencyInjection.Abstractions">
|
||||
<HintPath>..\..\..\..\..\.nuget\packages\microsoft.extensions.dependencyinjection.abstractions\1.1.0\lib\netstandard1.0\Microsoft.Extensions.DependencyInjection.Abstractions.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
|
@ -1,28 +0,0 @@
|
|||
using System;
|
||||
using System.Text;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Ombi.Helpers
|
||||
{
|
||||
public class ByteConverterHelper
|
||||
{
|
||||
public static byte[] ReturnBytes(object obj)
|
||||
{
|
||||
var json = JsonConvert.SerializeObject(obj);
|
||||
var bytes = Encoding.UTF8.GetBytes(json);
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
public static T ReturnObject<T>(byte[] bytes)
|
||||
{
|
||||
var json = Encoding.UTF8.GetString(bytes);
|
||||
var model = JsonConvert.DeserializeObject<T>(json);
|
||||
return model;
|
||||
}
|
||||
public static string ReturnFromBytes(byte[] bytes)
|
||||
{
|
||||
return Encoding.UTF8.GetString(bytes);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ombi.Helpers
|
||||
{
|
||||
public static class LinqHelpers
|
||||
{
|
||||
public static IEnumerable<TSource> DistinctBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
|
||||
{
|
||||
HashSet<TKey> knownKeys = new HashSet<TKey>();
|
||||
foreach (TSource source1 in source)
|
||||
{
|
||||
if (knownKeys.Add(keySelector(source1)))
|
||||
yield return source1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard1.4</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Newtonsoft.Json" Version="10.0.2" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
|
@ -1,15 +0,0 @@
|
|||
using Newtonsoft.Json;
|
||||
|
||||
namespace Ombi.Helpers
|
||||
{
|
||||
public static class SerializerSettings
|
||||
{
|
||||
public static readonly JsonSerializerSettings Settings = new JsonSerializerSettings
|
||||
{
|
||||
Formatting = Formatting.None,
|
||||
//TypeNameHandling = TypeNameHandling.Objects,
|
||||
//TypeNameAssemblyFormat = FormatterAssemblyStyle.Simple,
|
||||
NullValueHandling = NullValueHandling.Ignore
|
||||
};
|
||||
}
|
||||
}
|
|
@ -1,120 +0,0 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
|
||||
namespace Ombi.Helpers
|
||||
{
|
||||
public class StringCipher
|
||||
{
|
||||
// This constant determines the number of iterations for the password bytes generation function.
|
||||
private const int DerivationIterations = 1000;
|
||||
// This constant is used to determine the keysize of the encryption algorithm in bits.
|
||||
// We divide this by 8 within the code below to get the equivalent number of bytes.
|
||||
private const int Keysize = 256;
|
||||
|
||||
/// <summary>
|
||||
/// Decrypts the specified cipher text.
|
||||
/// </summary>
|
||||
/// <param name="cipherText">The cipher text.</param>
|
||||
/// <param name="passPhrase">The pass phrase.</param>
|
||||
/// <returns></returns>
|
||||
public static string Decrypt(string cipherText, string passPhrase)
|
||||
{
|
||||
// Get the complete stream of bytes that represent:
|
||||
// [32 bytes of Salt] + [32 bytes of IV] + [n bytes of CipherText]
|
||||
var cipherTextBytesWithSaltAndIv = Convert.FromBase64String(cipherText);
|
||||
// Get the saltbytes by extracting the first 32 bytes from the supplied cipherText bytes.
|
||||
var saltStringBytes = cipherTextBytesWithSaltAndIv.Take(Keysize / 8).ToArray();
|
||||
// Get the IV bytes by extracting the next 32 bytes from the supplied cipherText bytes.
|
||||
var ivStringBytes = cipherTextBytesWithSaltAndIv.Skip(Keysize / 8).Take(Keysize / 8).ToArray();
|
||||
// Get the actual cipher text bytes by removing the first 64 bytes from the cipherText string.
|
||||
var cipherTextBytes = cipherTextBytesWithSaltAndIv.Skip((Keysize / 8) * 2).Take(cipherTextBytesWithSaltAndIv.Length - ((Keysize / 8) * 2)).ToArray();
|
||||
|
||||
using (var password = new Rfc2898DeriveBytes(passPhrase, saltStringBytes, DerivationIterations))
|
||||
{
|
||||
var keyBytes = password.GetBytes(Keysize / 8);
|
||||
var aes = Aes.Create();
|
||||
using (var symmetricKey = new RijndaelManaged())
|
||||
{
|
||||
symmetricKey.BlockSize = 256;
|
||||
symmetricKey.Mode = CipherMode.CBC;
|
||||
symmetricKey.Padding = PaddingMode.PKCS7;
|
||||
using (var decryptor = symmetricKey.CreateDecryptor(keyBytes, ivStringBytes))
|
||||
{
|
||||
using (var memoryStream = new MemoryStream(cipherTextBytes))
|
||||
{
|
||||
using (var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read))
|
||||
{
|
||||
var plainTextBytes = new byte[cipherTextBytes.Length];
|
||||
var decryptedByteCount = cryptoStream.Read(plainTextBytes, 0, plainTextBytes.Length);
|
||||
memoryStream.Close();
|
||||
cryptoStream.Close();
|
||||
return Encoding.UTF8.GetString(plainTextBytes, 0, decryptedByteCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Encrypts the specified plain text.
|
||||
/// </summary>
|
||||
/// <param name="plainText">The plain text.</param>
|
||||
/// <param name="passPhrase">The pass phrase.</param>
|
||||
/// <returns></returns>
|
||||
public static string Encrypt(string plainText, string passPhrase)
|
||||
{
|
||||
// Salt and IV is randomly generated each time, but is preprended to encrypted cipher text
|
||||
// so that the same Salt and IV values can be used when decrypting.
|
||||
var saltStringBytes = Generate256BitsOfRandomEntropy();
|
||||
var ivStringBytes = Generate256BitsOfRandomEntropy();
|
||||
var plainTextBytes = Encoding.UTF8.GetBytes(plainText);
|
||||
using (var password = new Rfc2898DeriveBytes(passPhrase, saltStringBytes, DerivationIterations))
|
||||
{
|
||||
var keyBytes = password.GetBytes(Keysize / 8);
|
||||
using (var symmetricKey = new RijndaelManaged())
|
||||
{
|
||||
symmetricKey.BlockSize = 256;
|
||||
symmetricKey.Mode = CipherMode.CBC;
|
||||
symmetricKey.Padding = PaddingMode.PKCS7;
|
||||
using (var encryptor = symmetricKey.CreateEncryptor(keyBytes, ivStringBytes))
|
||||
{
|
||||
using (var memoryStream = new MemoryStream())
|
||||
{
|
||||
using (var cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write))
|
||||
{
|
||||
cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length);
|
||||
cryptoStream.FlushFinalBlock();
|
||||
// Create the final bytes as a concatenation of the random salt bytes, the random iv bytes and the cipher bytes.
|
||||
var cipherTextBytes = saltStringBytes;
|
||||
cipherTextBytes = cipherTextBytes.Concat(ivStringBytes).ToArray();
|
||||
cipherTextBytes = cipherTextBytes.Concat(memoryStream.ToArray()).ToArray();
|
||||
memoryStream.Close();
|
||||
cryptoStream.Close();
|
||||
return Convert.ToBase64String(cipherTextBytes);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate256s the bits of random entropy.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private static byte[] Generate256BitsOfRandomEntropy()
|
||||
{
|
||||
var randomBytes = new byte[32]; // 32 Bytes will give us 256 bits.
|
||||
using (var rngCsp = new RNGCryptoServiceProvider())
|
||||
{
|
||||
// Fill the array with cryptographically secure random bytes.
|
||||
rngCsp.GetBytes(randomBytes);
|
||||
}
|
||||
return randomBytes;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Ombi.Store.Entities;
|
||||
|
||||
namespace Ombi.Store.Context
|
||||
{
|
||||
public interface IOmbiContext : IDisposable
|
||||
{
|
||||
int SaveChanges();
|
||||
Task<int> SaveChangesAsync(CancellationToken cancellationToken = default(CancellationToken));
|
||||
DbSet<RequestBlobs> Requests { get; set; }
|
||||
DbSet<GlobalSettings> Settings { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,25 +0,0 @@
|
|||
using Microsoft.EntityFrameworkCore;
|
||||
using Ombi.Store.Entities;
|
||||
|
||||
namespace Ombi.Store.Context
|
||||
{
|
||||
public class OmbiContext : DbContext, IOmbiContext
|
||||
{
|
||||
private static bool _created;
|
||||
public OmbiContext()
|
||||
{
|
||||
if (_created) return;
|
||||
|
||||
_created = true;
|
||||
Database.EnsureCreated();
|
||||
Database.Migrate();
|
||||
}
|
||||
public DbSet<RequestBlobs> Requests { get; set; }
|
||||
public DbSet<GlobalSettings> Settings { get; set; }
|
||||
|
||||
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
|
||||
{
|
||||
optionsBuilder.UseSqlite("Data Source=Ombi.db");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Ombi.Store.Entities
|
||||
{
|
||||
public abstract class Entity
|
||||
{
|
||||
[Key]
|
||||
public int Id { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace Ombi.Store.Entities
|
||||
{
|
||||
[Table("GlobalSettings")]
|
||||
public class GlobalSettings : Entity
|
||||
{
|
||||
public string Content { get; set; }
|
||||
public string SettingsName { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace Ombi.Store.Entities
|
||||
{
|
||||
[Table("RequestBlobs")]
|
||||
public class RequestBlobs : Entity
|
||||
{
|
||||
public int ProviderId { get; set; }
|
||||
public byte[] Content { get; set; }
|
||||
public RequestType Type { get; set; }
|
||||
public string MusicId { get; set; }
|
||||
|
||||
}
|
||||
public enum RequestType
|
||||
{
|
||||
Movie,
|
||||
TvShow,
|
||||
Album
|
||||
}
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard1.4</TargetFramework>
|
||||
<!--<NetStandardImplicitPackageVersion>1.6.1</NetStandardImplicitPackageVersion>-->
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="1.1.1" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Design" Version="1.1.1" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="10.0.2" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<DotNetCliToolReference Include="Microsoft.EntityFrameworkCore.Tools.DotNet" Version="1.0.0" />
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -1,20 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Ombi.Store.Entities;
|
||||
|
||||
namespace Ombi.Store.Repository
|
||||
{
|
||||
public interface IRequestRepository
|
||||
{
|
||||
void Delete(RequestBlobs entity);
|
||||
void DeleteAll(IEnumerable<RequestBlobs> entity);
|
||||
RequestBlobs Get(int id);
|
||||
IEnumerable<RequestBlobs> GetAll();
|
||||
Task<IEnumerable<RequestBlobs>> GetAllAsync();
|
||||
Task<RequestBlobs> GetAsync(int id);
|
||||
RequestBlobs Insert(RequestBlobs entity);
|
||||
Task<RequestBlobs> InsertAsync(RequestBlobs entity);
|
||||
RequestBlobs Update(RequestBlobs entity);
|
||||
void UpdateAll(IEnumerable<RequestBlobs> entity);
|
||||
}
|
||||
}
|
|
@ -1,49 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Ombi.Store.Entities;
|
||||
|
||||
namespace Ombi.Store.Repository
|
||||
{
|
||||
public interface ISettingsRepository
|
||||
{
|
||||
/// <summary>
|
||||
/// Inserts the specified entity.
|
||||
/// </summary>
|
||||
/// <param name="entity">The entity.</param>
|
||||
GlobalSettings Insert(GlobalSettings entity);
|
||||
Task<GlobalSettings> InsertAsync(GlobalSettings entity);
|
||||
|
||||
/// <summary>
|
||||
/// Gets all.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
IEnumerable<GlobalSettings> GetAll();
|
||||
Task<IEnumerable<GlobalSettings>> GetAllAsync();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the specified identifier.
|
||||
/// </summary>
|
||||
/// <param name="settingsName">Name of the settings.</param>
|
||||
/// <returns></returns>
|
||||
GlobalSettings Get(string settingsName);
|
||||
Task<GlobalSettings> GetAsync(string settingsName);
|
||||
|
||||
/// <summary>
|
||||
/// Deletes the specified entity.
|
||||
/// </summary>
|
||||
/// <param name="entity">The entity.</param>
|
||||
/// <returns></returns>
|
||||
Task DeleteAsync(GlobalSettings entity);
|
||||
void Delete(GlobalSettings entity);
|
||||
|
||||
/// <summary>
|
||||
/// Updates the specified entity.
|
||||
/// </summary>
|
||||
/// <param name="entity">The entity.</param>
|
||||
/// <returns></returns>
|
||||
Task UpdateAsync(GlobalSettings entity);
|
||||
void Update(GlobalSettings entity);
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -1,126 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Ombi.Store.Context;
|
||||
using Ombi.Store.Entities;
|
||||
|
||||
namespace Ombi.Store.Repository
|
||||
{
|
||||
public class RequestJsonRepository : IRequestRepository
|
||||
{
|
||||
//private ICacheProvider Cache { get; }
|
||||
|
||||
public RequestJsonRepository(IOmbiContext ctx)
|
||||
{
|
||||
Db = ctx;
|
||||
}
|
||||
|
||||
private IOmbiContext Db { get; }
|
||||
|
||||
public RequestBlobs Insert(RequestBlobs entity)
|
||||
{
|
||||
|
||||
var id = Db.Requests.Add(entity);
|
||||
Db.SaveChanges();
|
||||
return id.Entity;
|
||||
|
||||
}
|
||||
|
||||
public async Task<RequestBlobs> InsertAsync(RequestBlobs entity)
|
||||
{
|
||||
|
||||
var id = await Db.Requests.AddAsync(entity).ConfigureAwait(false);
|
||||
await Db.SaveChangesAsync();
|
||||
return id.Entity;
|
||||
|
||||
}
|
||||
|
||||
public IEnumerable<RequestBlobs> GetAll()
|
||||
{
|
||||
//var key = "GetAll";
|
||||
//var item = Cache.GetOrSet(key, () =>
|
||||
//{
|
||||
|
||||
var page = Db.Requests.ToList();
|
||||
return page;
|
||||
|
||||
//}, 5);
|
||||
//return item;
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<RequestBlobs>> GetAllAsync()
|
||||
{
|
||||
//var key = "GetAll";
|
||||
//var item = await Cache.GetOrSetAsync(key, async () =>
|
||||
//{
|
||||
|
||||
var page = await Db.Requests.ToListAsync().ConfigureAwait(false);
|
||||
return page;
|
||||
|
||||
//}, 5);
|
||||
//return item;
|
||||
}
|
||||
|
||||
public RequestBlobs Get(int id)
|
||||
{
|
||||
//var key = "Get" + id;
|
||||
//var item = Cache.GetOrSet(key, () =>
|
||||
//{
|
||||
|
||||
var page = Db.Requests.Find(id);
|
||||
return page;
|
||||
|
||||
//}, 5);
|
||||
//return item;
|
||||
}
|
||||
|
||||
public async Task<RequestBlobs> GetAsync(int id)
|
||||
{
|
||||
//var key = "Get" + id;
|
||||
//var item = await Cache.GetOrSetAsync(key, async () =>
|
||||
//{
|
||||
|
||||
var page = await Db.Requests.FindAsync(id).ConfigureAwait(false);
|
||||
return page;
|
||||
|
||||
//}, 5);
|
||||
//return item;
|
||||
}
|
||||
|
||||
public void Delete(RequestBlobs entity)
|
||||
{
|
||||
//ResetCache();
|
||||
|
||||
Db.Requests.Remove(entity);
|
||||
Db.SaveChanges();
|
||||
|
||||
}
|
||||
|
||||
public RequestBlobs Update(RequestBlobs entity)
|
||||
{
|
||||
|
||||
return Db.Requests.Update(entity).Entity;
|
||||
Db.SaveChanges();
|
||||
|
||||
}
|
||||
|
||||
public void UpdateAll(IEnumerable<RequestBlobs> entity)
|
||||
{
|
||||
|
||||
Db.Requests.UpdateRange(entity);
|
||||
Db.SaveChanges();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void DeleteAll(IEnumerable<RequestBlobs> entity)
|
||||
{
|
||||
|
||||
Db.Requests.RemoveRange(entity);
|
||||
Db.SaveChanges();
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,84 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Ombi.Store.Context;
|
||||
using Ombi.Store.Entities;
|
||||
|
||||
namespace Ombi.Store.Repository
|
||||
{
|
||||
public class SettingsJsonRepository : ISettingsRepository
|
||||
{
|
||||
public SettingsJsonRepository(IOmbiContext ctx)
|
||||
{
|
||||
Db = ctx;
|
||||
}
|
||||
|
||||
private IOmbiContext Db { get; }
|
||||
|
||||
public GlobalSettings Insert(GlobalSettings entity)
|
||||
{
|
||||
|
||||
var settings = Db.Settings.Add(entity);
|
||||
Db.SaveChanges();
|
||||
return settings.Entity;
|
||||
|
||||
}
|
||||
|
||||
public async Task<GlobalSettings> InsertAsync(GlobalSettings entity)
|
||||
{
|
||||
|
||||
var settings = await Db.Settings.AddAsync(entity).ConfigureAwait(false);
|
||||
await Db.SaveChangesAsync().ConfigureAwait(false);
|
||||
return settings.Entity;
|
||||
}
|
||||
|
||||
public IEnumerable<GlobalSettings> GetAll()
|
||||
{
|
||||
|
||||
var page = Db.Settings.ToList();
|
||||
return page;
|
||||
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<GlobalSettings>> GetAllAsync()
|
||||
{
|
||||
var page = await Db.Settings.ToListAsync();
|
||||
return page;
|
||||
}
|
||||
|
||||
public GlobalSettings Get(string pageName)
|
||||
{
|
||||
return Db.Settings.FirstOrDefault(x => x.SettingsName == pageName);
|
||||
}
|
||||
|
||||
public async Task<GlobalSettings> GetAsync(string settingsName)
|
||||
{
|
||||
return await Db.Settings.FirstOrDefaultAsync(x => x.SettingsName == settingsName);
|
||||
}
|
||||
|
||||
public async Task DeleteAsync(GlobalSettings entity)
|
||||
{
|
||||
Db.Settings.Remove(entity);
|
||||
await Db.SaveChangesAsync();
|
||||
}
|
||||
|
||||
public async Task UpdateAsync(GlobalSettings entity)
|
||||
{
|
||||
Db.Settings.Update(entity);
|
||||
await Db.SaveChangesAsync();
|
||||
}
|
||||
|
||||
public void Delete(GlobalSettings entity)
|
||||
{
|
||||
Db.Settings.Remove(entity);
|
||||
Db.SaveChanges();
|
||||
}
|
||||
|
||||
public void Update(GlobalSettings entity)
|
||||
{
|
||||
Db.Settings.Update(entity);
|
||||
Db.SaveChanges();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
using System.Threading.Tasks;
|
||||
using Ombi.Api;
|
||||
using Ombi.TheMovieDbApi.Models;
|
||||
|
||||
namespace Ombi.TheMovieDbApi
|
||||
{
|
||||
public interface IMovieDbApi
|
||||
{
|
||||
Task<MovieResponse> GetMovieInformation(int movieId);
|
||||
Task<TheMovieDbContainer<SearchResult>> NowPlaying();
|
||||
Task<TheMovieDbContainer<SearchResult>> PopularMovies();
|
||||
Task<TheMovieDbContainer<SearchResult>> SearchMovie(string searchTerm);
|
||||
Task<TheMovieDbContainer<SearchResult>> TopRated();
|
||||
Task<TheMovieDbContainer<SearchResult>> Upcoming();
|
||||
}
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
namespace Ombi.TheMovieDbApi.Models
|
||||
{
|
||||
public class BelongsToCollection
|
||||
{
|
||||
public int id { get; set; }
|
||||
public string name { get; set; }
|
||||
public string poster_path { get; set; }
|
||||
public string backdrop_path { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
namespace Ombi.TheMovieDbApi.Models
|
||||
{
|
||||
public class Genre
|
||||
{
|
||||
public int id { get; set; }
|
||||
public string name { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,58 +0,0 @@
|
|||
#region Copyright
|
||||
// /************************************************************************
|
||||
// Copyright (c) 2017 Jamie Rees
|
||||
// File: MovieResponse.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 Ombi.TheMovieDbApi.Models
|
||||
{
|
||||
|
||||
public class MovieResponse
|
||||
{
|
||||
public bool adult { get; set; }
|
||||
public string backdrop_path { get; set; }
|
||||
public BelongsToCollection belongs_to_collection { get; set; }
|
||||
public int budget { get; set; }
|
||||
public Genre[] genres { get; set; }
|
||||
public string homepage { get; set; }
|
||||
public int id { get; set; }
|
||||
public string imdb_id { get; set; }
|
||||
public string original_language { get; set; }
|
||||
public string original_title { get; set; }
|
||||
public string overview { get; set; }
|
||||
public float popularity { get; set; }
|
||||
public string poster_path { get; set; }
|
||||
public ProductionCompanies[] production_companies { get; set; }
|
||||
public ProductionCountries[] production_countries { get; set; }
|
||||
public string release_date { get; set; }
|
||||
public int revenue { get; set; }
|
||||
public int runtime { get; set; }
|
||||
public SpokenLanguages[] spoken_languages { get; set; }
|
||||
public string status { get; set; }
|
||||
public string tagline { get; set; }
|
||||
public string title { get; set; }
|
||||
public bool video { get; set; }
|
||||
public float vote_average { get; set; }
|
||||
public int vote_count { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
namespace Ombi.TheMovieDbApi.Models
|
||||
{
|
||||
public class ProductionCompanies
|
||||
{
|
||||
public string name { get; set; }
|
||||
public int id { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
namespace Ombi.TheMovieDbApi.Models
|
||||
{
|
||||
public class ProductionCountries
|
||||
{
|
||||
public string iso_3166_1 { get; set; }
|
||||
public string name { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,46 +0,0 @@
|
|||
#region Copyright
|
||||
// /************************************************************************
|
||||
// Copyright (c) 2017 Jamie Rees
|
||||
// File: SearchResult.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 Ombi.TheMovieDbApi.Models
|
||||
{
|
||||
public class SearchResult
|
||||
{
|
||||
public string poster_path { get; set; }
|
||||
public bool adult { get; set; }
|
||||
public string overview { get; set; }
|
||||
public string release_date { get; set; }
|
||||
public int?[] genre_ids { get; set; }
|
||||
public int id { get; set; }
|
||||
public string original_title { get; set; }
|
||||
public string original_language { get; set; }
|
||||
public string title { get; set; }
|
||||
public string backdrop_path { get; set; }
|
||||
public float popularity { get; set; }
|
||||
public int vote_count { get; set; }
|
||||
public bool video { get; set; }
|
||||
public float vote_average { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
namespace Ombi.TheMovieDbApi.Models
|
||||
{
|
||||
public class SpokenLanguages
|
||||
{
|
||||
public string iso_639_1 { get; set; }
|
||||
public string name { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
#region Copyright
|
||||
// /************************************************************************
|
||||
// Copyright (c) 2017 Jamie Rees
|
||||
// File: TheMovieDbContainer.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 Ombi.TheMovieDbApi.Models
|
||||
{
|
||||
public class TheMovieDbContainer<T>
|
||||
{
|
||||
public int page { get; set; }
|
||||
public List<T> results { get; set; }
|
||||
public int total_results { get; set; }
|
||||
public int total_pages { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard1.4</TargetFramework>
|
||||
<!--<NetStandardImplicitPackageVersion>1.6.1</NetStandardImplicitPackageVersion>-->
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Ombi.Api\Ombi.Api.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
|
@ -1,67 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Ombi.Api;
|
||||
using Ombi.TheMovieDbApi.Models;
|
||||
|
||||
namespace Ombi.TheMovieDbApi
|
||||
{
|
||||
public class TheMovieDbApi : IMovieDbApi
|
||||
{
|
||||
public TheMovieDbApi()
|
||||
{
|
||||
Api = new Api.Api();
|
||||
}
|
||||
private const string ApiToken = "b8eabaf5608b88d0298aa189dd90bf00";
|
||||
private static readonly Uri BaseUri = new Uri("http://api.themoviedb.org/3/");
|
||||
public Api.Api Api { get; }
|
||||
|
||||
public async Task<MovieResponse> GetMovieInformation(int movieId)
|
||||
{
|
||||
var url = BaseUri.ChangePath("movie/{0}", movieId.ToString());
|
||||
url = AddHeaders(url);
|
||||
return await Api.Get<MovieResponse>(url);
|
||||
}
|
||||
|
||||
public async Task<TheMovieDbContainer<SearchResult>> SearchMovie(string searchTerm)
|
||||
{
|
||||
var url = BaseUri.ChangePath("search/movie/");
|
||||
url = AddHeaders(url);
|
||||
url = url.AddQueryParameter("query", searchTerm);
|
||||
return await Api.Get<TheMovieDbContainer<SearchResult>>(url);
|
||||
}
|
||||
|
||||
public async Task<TheMovieDbContainer<SearchResult>> PopularMovies()
|
||||
{
|
||||
var url = BaseUri.ChangePath("movie/popular");
|
||||
url = AddHeaders(url);
|
||||
return await Api.Get<TheMovieDbContainer<SearchResult>>(url);
|
||||
}
|
||||
|
||||
public async Task<TheMovieDbContainer<SearchResult>> TopRated()
|
||||
{
|
||||
var url = BaseUri.ChangePath("movie/top_rated");
|
||||
url = AddHeaders(url);
|
||||
return await Api.Get<TheMovieDbContainer<SearchResult>>(url);
|
||||
}
|
||||
|
||||
public async Task<TheMovieDbContainer<SearchResult>> Upcoming()
|
||||
{
|
||||
var url = BaseUri.ChangePath("movie/upcoming");
|
||||
url = AddHeaders(url);
|
||||
return await Api.Get<TheMovieDbContainer<SearchResult>>(url);
|
||||
}
|
||||
|
||||
public async Task<TheMovieDbContainer<SearchResult>> NowPlaying()
|
||||
{
|
||||
var url = BaseUri.ChangePath("movie/now_playing");
|
||||
url = AddHeaders(url);
|
||||
return await Api.Get<TheMovieDbContainer<SearchResult>>(url);
|
||||
}
|
||||
|
||||
private Uri AddHeaders(Uri url)
|
||||
{
|
||||
return url.AddQueryParameter("api_key", ApiToken);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,71 +0,0 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 15
|
||||
VisualStudioVersion = 15.0.26228.10
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ombi", "Ombi\Ombi.csproj", "{C987AA67-AFE1-468F-ACD3-EAD5A48E1F6A}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{9D30CCF8-A115-4EB7-A34D-07780D752789}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
..\appveyor.yml = ..\appveyor.yml
|
||||
Build\publish windows.bat = Build\publish windows.bat
|
||||
Build\publish.bat = Build\publish.bat
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ombi.Core", "Ombi.Core\Ombi.Core.csproj", "{F56E79C7-791D-4668-A0EC-29E3BBC8D24B}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Api", "Api", "{9293CA11-360A-4C20-A674-B9E794431BF5}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ombi.TheMovieDbApi", "Ombi.TheMovieDbApi\Ombi.TheMovieDbApi.csproj", "{132DA282-5894-4570-8916-D8C18ED2CE84}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ombi.Api", "Ombi.Api\Ombi.Api.csproj", "{EA31F915-31F9-4318-B521-1500CDF40DDF}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ombi.Helpers", "Ombi.Helpers\Ombi.Helpers.csproj", "{C182B435-1FAB-49C5-9BF9-F7F5C6EF3C94}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ombi.Store", "Ombi.Store\Ombi.Store.csproj", "{68086581-1EFD-4390-8100-47F87D1CB628}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ombi.DependencyInjection", "Ombi.DependencyInjection\Ombi.DependencyInjection.csproj", "{B39E4558-C557-48E7-AA74-19C5CD809617}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{C987AA67-AFE1-468F-ACD3-EAD5A48E1F6A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{C987AA67-AFE1-468F-ACD3-EAD5A48E1F6A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{C987AA67-AFE1-468F-ACD3-EAD5A48E1F6A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{C987AA67-AFE1-468F-ACD3-EAD5A48E1F6A}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{F56E79C7-791D-4668-A0EC-29E3BBC8D24B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{F56E79C7-791D-4668-A0EC-29E3BBC8D24B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{F56E79C7-791D-4668-A0EC-29E3BBC8D24B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{F56E79C7-791D-4668-A0EC-29E3BBC8D24B}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{132DA282-5894-4570-8916-D8C18ED2CE84}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{132DA282-5894-4570-8916-D8C18ED2CE84}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{132DA282-5894-4570-8916-D8C18ED2CE84}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{132DA282-5894-4570-8916-D8C18ED2CE84}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{EA31F915-31F9-4318-B521-1500CDF40DDF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{EA31F915-31F9-4318-B521-1500CDF40DDF}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{EA31F915-31F9-4318-B521-1500CDF40DDF}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{EA31F915-31F9-4318-B521-1500CDF40DDF}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{C182B435-1FAB-49C5-9BF9-F7F5C6EF3C94}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{C182B435-1FAB-49C5-9BF9-F7F5C6EF3C94}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{C182B435-1FAB-49C5-9BF9-F7F5C6EF3C94}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{C182B435-1FAB-49C5-9BF9-F7F5C6EF3C94}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{68086581-1EFD-4390-8100-47F87D1CB628}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{68086581-1EFD-4390-8100-47F87D1CB628}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{68086581-1EFD-4390-8100-47F87D1CB628}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{68086581-1EFD-4390-8100-47F87D1CB628}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{B39E4558-C557-48E7-AA74-19C5CD809617}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{B39E4558-C557-48E7-AA74-19C5CD809617}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{B39E4558-C557-48E7-AA74-19C5CD809617}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{B39E4558-C557-48E7-AA74-19C5CD809617}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(NestedProjects) = preSolution
|
||||
{132DA282-5894-4570-8916-D8C18ED2CE84} = {9293CA11-360A-4C20-A674-B9E794431BF5}
|
||||
{EA31F915-31F9-4318-B521-1500CDF40DDF} = {9293CA11-360A-4C20-A674-B9E794431BF5}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
17
Ombi/Ombi/.gitignore
vendored
17
Ombi/Ombi/.gitignore
vendored
|
@ -1,17 +0,0 @@
|
|||
/app/**/*.js
|
||||
/app/**/*.js.map
|
||||
/wwwroot/**
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
/bower_components
|
||||
|
||||
# misc
|
||||
/.sass-cache
|
||||
/connect.lock
|
||||
/coverage/*
|
||||
/libpeerconnection.log
|
||||
npm-debug.log
|
||||
testem.log
|
||||
/typings
|
||||
/systemjs.config.js*
|
|
@ -1,36 +0,0 @@
|
|||
#region Copyright
|
||||
// /************************************************************************
|
||||
// Copyright (c) 2017 Jamie Rees
|
||||
// File: BaseApiController.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 Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace Ombi.Controllers
|
||||
{
|
||||
[Route("api/[controller]")]
|
||||
public class BaseApiController : Controller
|
||||
{
|
||||
}
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace Ombi.Controllers
|
||||
{
|
||||
public class HomeController : Controller
|
||||
{
|
||||
public IActionResult Index()
|
||||
{
|
||||
return View();
|
||||
}
|
||||
|
||||
public IActionResult About()
|
||||
{
|
||||
ViewData["Message"] = "Your application description page.";
|
||||
|
||||
return View();
|
||||
}
|
||||
|
||||
public IActionResult Contact()
|
||||
{
|
||||
ViewData["Message"] = "Your contact page.";
|
||||
|
||||
return View();
|
||||
}
|
||||
|
||||
public IActionResult Error()
|
||||
{
|
||||
return View();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Ombi.Core.Engine;
|
||||
using Ombi.Core.Models.Search;
|
||||
|
||||
namespace Ombi.Controllers
|
||||
{
|
||||
public class RequestController : BaseApiController
|
||||
{
|
||||
public RequestController(IRequestEngine engine)
|
||||
{
|
||||
RequestEngine = engine;
|
||||
}
|
||||
|
||||
private IRequestEngine RequestEngine { get; }
|
||||
|
||||
[HttpPost("movie")]
|
||||
public async Task<RequestEngineResult> SearchMovie([FromBody]SearchMovieViewModel movie)
|
||||
{
|
||||
return await RequestEngine.RequestMovie(movie);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,50 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Ombi.Core;
|
||||
using Ombi.Core.Models.Search;
|
||||
|
||||
namespace Ombi.Controllers
|
||||
{
|
||||
public class SearchController : BaseApiController
|
||||
{
|
||||
public SearchController(IMovieEngine movie)
|
||||
{
|
||||
MovieEngine = movie;
|
||||
}
|
||||
|
||||
private IMovieEngine MovieEngine { get; }
|
||||
|
||||
[HttpGet("movie/{searchTerm}")]
|
||||
public async Task<IEnumerable<SearchMovieViewModel>> SearchMovie(string searchTerm)
|
||||
{
|
||||
return await MovieEngine.ProcessMovieSearch(searchTerm);
|
||||
}
|
||||
|
||||
[HttpGet("movie/popular")]
|
||||
public async Task<IEnumerable<SearchMovieViewModel>> Popular()
|
||||
{
|
||||
return await MovieEngine.PopularMovies();
|
||||
}
|
||||
[HttpGet("movie/nowplaying")]
|
||||
public async Task<IEnumerable<SearchMovieViewModel>> NowPlayingMovies()
|
||||
{
|
||||
return await MovieEngine.NowPlayingMovies();
|
||||
}
|
||||
[HttpGet("movie/toprated")]
|
||||
public async Task<IEnumerable<SearchMovieViewModel>> TopRatedMovies()
|
||||
{
|
||||
return await MovieEngine.TopRatedMovies();
|
||||
}
|
||||
[HttpGet("movie/upcoming")]
|
||||
public async Task<IEnumerable<SearchMovieViewModel>> UpcomingMovies()
|
||||
{
|
||||
return await MovieEngine.UpcomingMovies();
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -1,37 +0,0 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp1.1</TargetFramework>
|
||||
<RuntimeIdentifiers>win10-x64;osx.10.12-x64;ubuntu.16.10-x64;debian.8-x64;</RuntimeIdentifiers>
|
||||
|
||||
</PropertyGroup>
|
||||
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore" Version="1.1.1" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="1.1.2" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.SpaServices" Version="1.1.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.StaticFiles" Version="1.1.1" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="1.1.1" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Design" Version="1.1.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="1.1.1" />
|
||||
<PackageReference Include="Microsoft.VisualStudio.Web.BrowserLink" Version="1.1.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="wwwroot\**" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Remove="ViewModels\**" />
|
||||
<Content Remove="ViewModels\**" />
|
||||
<EmbeddedResource Remove="ViewModels\**" />
|
||||
<None Remove="ViewModels\**" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Ombi.Core\Ombi.Core.csproj" />
|
||||
<ProjectReference Include="..\Ombi.DependencyInjection\Ombi.DependencyInjection.csproj" />
|
||||
<ProjectReference Include="..\Ombi.TheMovieDbApi\Ombi.TheMovieDbApi.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -1,24 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
|
||||
namespace Ombi
|
||||
{
|
||||
public class Program
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
var host = new WebHostBuilder()
|
||||
.UseKestrel()
|
||||
.UseContentRoot(Directory.GetCurrentDirectory())
|
||||
.UseIISIntegration()
|
||||
.UseStartup<Startup>()
|
||||
.Build();
|
||||
|
||||
host.Run();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
{
|
||||
"iisSettings": {
|
||||
"windowsAuthentication": false,
|
||||
"anonymousAuthentication": true,
|
||||
"iisExpress": {
|
||||
"applicationUrl": "http://localhost:52038/",
|
||||
"sslPort": 0
|
||||
}
|
||||
},
|
||||
"profiles": {
|
||||
"IIS Express": {
|
||||
"commandName": "IISExpress",
|
||||
"launchBrowser": true,
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
},
|
||||
"Ombi": {
|
||||
"commandName": "Project"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,81 +0,0 @@
|
|||
using System.IO;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.StaticFiles;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.FileProviders;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Ombi.DependencyInjection;
|
||||
using Ombi.Store.Context;
|
||||
|
||||
namespace Ombi
|
||||
{
|
||||
public class Startup
|
||||
{
|
||||
public Startup(IHostingEnvironment env)
|
||||
{
|
||||
var builder = new ConfigurationBuilder()
|
||||
.SetBasePath(env.ContentRootPath)
|
||||
.AddJsonFile("appsettings.json", false, true)
|
||||
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", true)
|
||||
.AddEnvironmentVariables();
|
||||
Configuration = builder.Build();
|
||||
|
||||
}
|
||||
|
||||
public IConfigurationRoot Configuration { get; }
|
||||
|
||||
// This method gets called by the runtime. Use this method to add services to the container.
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
// Add framework services.
|
||||
services.AddMvc();
|
||||
services.RegisterDependencies(); // Ioc and EF
|
||||
}
|
||||
|
||||
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
||||
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
|
||||
{
|
||||
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
|
||||
loggerFactory.AddDebug();
|
||||
|
||||
if (env.IsDevelopment())
|
||||
{
|
||||
app.UseDeveloperExceptionPage();
|
||||
}
|
||||
else
|
||||
{
|
||||
app.UseExceptionHandler("/Home/Error");
|
||||
}
|
||||
|
||||
var provider = new FileExtensionContentTypeProvider();
|
||||
provider.Mappings[".map"] = "application/octet-stream";
|
||||
|
||||
app.UseStaticFiles(new StaticFileOptions()
|
||||
{
|
||||
ContentTypeProvider = provider
|
||||
});
|
||||
|
||||
app.UseStaticFiles(new StaticFileOptions
|
||||
{
|
||||
FileProvider = new PhysicalFileProvider(
|
||||
Path.Combine(Directory.GetCurrentDirectory(), @"app")),
|
||||
RequestPath = new PathString("/app"),
|
||||
});
|
||||
|
||||
app.UseMvc(routes =>
|
||||
{
|
||||
routes.MapRoute(
|
||||
name: "default",
|
||||
template: "{controller=Home}/{action=Index}/{id?}");
|
||||
|
||||
routes.MapSpaFallbackRoute(
|
||||
name: "spa-fallback",
|
||||
defaults: new { controller = "Home", action = "Index" });
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,2 +0,0 @@
|
|||
body {
|
||||
}
|
|
@ -1,242 +0,0 @@
|
|||
$primary-colour: #df691a;
|
||||
$primary-colour-outline: #ff761b;
|
||||
$bg-colour: #333333;
|
||||
$bg-colour-disabled: #252424;
|
||||
$i:
|
||||
!important
|
||||
;
|
||||
|
||||
.form-control-custom {
|
||||
background-color: $bg-colour $i;
|
||||
}
|
||||
|
||||
.form-control-custom-disabled {
|
||||
background-color: $bg-colour-disabled $i;
|
||||
}
|
||||
|
||||
.nav-tabs > li.active > a,
|
||||
.nav-tabs > li.active > a:hover,
|
||||
.nav-tabs > li.active > a:focus {
|
||||
background: $primary-colour;
|
||||
}
|
||||
|
||||
.scroll-top-wrapper {
|
||||
background-color: $bg-colour;
|
||||
}
|
||||
|
||||
.scroll-top-wrapper:hover {
|
||||
background-color: $primary-colour;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: Open Sans Regular,Helvetica Neue,Helvetica,Arial,sans-serif;
|
||||
color: #eee;
|
||||
background-color: #1f1f1f;
|
||||
}
|
||||
|
||||
.table-striped > tbody > tr:nth-of-type(odd) {
|
||||
background-color: #333;
|
||||
}
|
||||
|
||||
.table-hover > tbody > tr:hover {
|
||||
background-color: #282828;
|
||||
}
|
||||
|
||||
fieldset {
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
legend {
|
||||
border-bottom: 1px solid #333333;
|
||||
}
|
||||
|
||||
.form-control {
|
||||
color: #fefefe;
|
||||
background-color: #333;
|
||||
}
|
||||
|
||||
.radio input[type="radio"],
|
||||
.radio-inline input[type="radio"],
|
||||
.checkbox input[type="checkbox"],
|
||||
.checkbox-inline input[type="checkbox"] {
|
||||
margin-left: -0px;
|
||||
}
|
||||
|
||||
.form-horizontal .radio,
|
||||
.form-horizontal .checkbox,
|
||||
.form-horizontal .radio-inline,
|
||||
.form-horizontal .checkbox-inline {
|
||||
margin-top: -15px;
|
||||
}
|
||||
|
||||
.dropdown-menu {
|
||||
background-color: #282828;
|
||||
}
|
||||
|
||||
.dropdown-menu .divider {
|
||||
background-color: #333333;
|
||||
}
|
||||
|
||||
.dropdown-menu > li > a:hover,
|
||||
.dropdown-menu > li > a:focus {
|
||||
background-color: #333;
|
||||
}
|
||||
|
||||
.input-group-addon {
|
||||
background-color: #333333;
|
||||
}
|
||||
|
||||
.nav > li > a:hover,
|
||||
.nav > li > a:focus {
|
||||
background-color: #df691a;
|
||||
}
|
||||
|
||||
.nav-tabs > li > a:hover {
|
||||
border-color: #df691a #df691a transparent;
|
||||
}
|
||||
|
||||
.nav-tabs > li.active > a,
|
||||
.nav-tabs > li.active > a:hover,
|
||||
.nav-tabs > li.active > a:focus {
|
||||
background-color: #df691a;
|
||||
border: 1px solid #df691a;
|
||||
}
|
||||
|
||||
.nav-tabs.nav-justified > .active > a,
|
||||
.nav-tabs.nav-justified > .active > a:hover,
|
||||
.nav-tabs.nav-justified > .active > a:focus {
|
||||
border: 1px solid #df691a;
|
||||
}
|
||||
|
||||
/*.navbar {
|
||||
position: relative;
|
||||
min-height: 40px;
|
||||
margin-bottom: 21px;
|
||||
z-index: 1000;
|
||||
padding: 0px 3px;
|
||||
font-size: 24px;
|
||||
background-color: #000;
|
||||
box-shadow: 0px 0px 0px 3px rgba(0, 0, 0, 0.2);
|
||||
}*/
|
||||
|
||||
.navbar-default {
|
||||
background-color: #0a0a0a;
|
||||
border-color: #0a0a0a;
|
||||
}
|
||||
|
||||
.navbar-default .navbar-brand {
|
||||
color: #DF691A;
|
||||
}
|
||||
|
||||
.nav-tabs {
|
||||
border-bottom: 1px solid $bg-colour-disabled;
|
||||
}
|
||||
|
||||
.navbar-default .navbar-nav > li > a:hover,
|
||||
.navbar-default .navbar-nav > li > a:focus {
|
||||
color: #F0ad4e;
|
||||
background-color: #282828;
|
||||
}
|
||||
|
||||
.navbar-default .navbar-nav > .active > a,
|
||||
.navbar-default .navbar-nav > .active > a:hover,
|
||||
.navbar-default .navbar-nav > .active > a:focus {
|
||||
background-color: #282828;
|
||||
}
|
||||
|
||||
.navbar-default .navbar-nav > .open > a,
|
||||
.navbar-default .navbar-nav > .open > a:hover,
|
||||
.navbar-default .navbar-nav > .open > a:focus {
|
||||
background-color: #df691a;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.pagination > li > a,
|
||||
.pagination > li > span {
|
||||
background-color: #282828;
|
||||
}
|
||||
|
||||
.pagination > li > a:hover,
|
||||
.pagination > li > span:hover,
|
||||
.pagination > li > a:focus,
|
||||
.pagination > li > span:focus {
|
||||
background-color: #333;
|
||||
}
|
||||
|
||||
.pagination > .disabled > span,
|
||||
.pagination > .disabled > span:hover,
|
||||
.pagination > .disabled > span:focus,
|
||||
.pagination > .disabled > a,
|
||||
.pagination > .disabled > a:hover,
|
||||
.pagination > .disabled > a:focus {
|
||||
color: #fefefe;
|
||||
background-color: #333333;
|
||||
}
|
||||
|
||||
.list-group-item {
|
||||
background-color: #282828;
|
||||
}
|
||||
|
||||
a.list-group-item:hover,
|
||||
button.list-group-item:hover,
|
||||
a.list-group-item:focus,
|
||||
button.list-group-item:focus {
|
||||
background-color: #333333;
|
||||
}
|
||||
|
||||
.input-addon,
|
||||
.input-group-addon {
|
||||
color: #df691a;
|
||||
}
|
||||
|
||||
.modal-header,
|
||||
.modal-footer {
|
||||
background-color: #282828;
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
position: relative;
|
||||
background-color: #282828;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 0;
|
||||
-webkit-box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5);
|
||||
box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5);
|
||||
-webkit-background-clip: padding-box;
|
||||
-moz-background-clip: padding-box;
|
||||
background-clip: padding-box;
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
.badge {
|
||||
display: inline-block;
|
||||
min-width: 10px;
|
||||
padding: 3px 7px;
|
||||
font-size: 12px;
|
||||
font-weight: 300;
|
||||
color: #ebebeb;
|
||||
line-height: 1;
|
||||
vertical-align: middle;
|
||||
white-space: nowrap;
|
||||
text-align: center;
|
||||
background-color: $bg-colour;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.bootstrap-datetimepicker-widget.dropdown-menu {
|
||||
background-color: $bg-colour;
|
||||
}
|
||||
|
||||
.bootstrap-datetimepicker-widget.dropdown-menu.bottom:after {
|
||||
border-bottom: 6px solid $bg-colour $i;
|
||||
}
|
||||
|
||||
#sidebar-wrapper {
|
||||
background: $bg-colour-disabled;
|
||||
}
|
||||
|
||||
#cacherRunning {
|
||||
background-color: $bg-colour;
|
||||
text-align: center;
|
||||
font-size: 15px;
|
||||
padding: 3px 0;
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
@import "./bootstrap.css";
|
||||
//@import "./lib/tether.css";
|
||||
@import "../node_modules/primeng/resources/themes/omega/theme.scss";
|
||||
@import "./lib/primeng.css";
|
||||
|
||||
$fa-font-path: "../fonts/lib";
|
||||
@import "../bower_components/font-awesome/scss/font-awesome.scss";
|
|
@ -1,704 +0,0 @@
|
|||
@import './_imports.scss';
|
||||
|
||||
$form-color: #4e5d6c;
|
||||
$form-color-lighter: #637689;
|
||||
$primary-colour: #df691a;
|
||||
$primary-colour-outline: #ff761b;
|
||||
$info-colour: #5bc0de;
|
||||
$warning-colour: #f0ad4e;
|
||||
$danger-colour: #d9534f;
|
||||
$success-colour: #5cb85c;
|
||||
$i:!important;
|
||||
|
||||
@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 $i;
|
||||
}
|
||||
|
||||
.btn-group-separated .btn,
|
||||
.btn-group-separated .btn + .btn {
|
||||
margin-left: 3px;
|
||||
}
|
||||
|
||||
.multiSelect {
|
||||
background-color: $form-color;
|
||||
}
|
||||
|
||||
.form-control-custom {
|
||||
background-color: $form-color $i;
|
||||
color: white $i;
|
||||
border-radius: 0;
|
||||
box-shadow: 0 0 0 !important;
|
||||
}
|
||||
|
||||
|
||||
h1 {
|
||||
font-size: 3.5rem $i;
|
||||
font-weight: 600 $i;
|
||||
}
|
||||
|
||||
.request-title {
|
||||
margin-top: 0 $i;
|
||||
font-size: 1.9rem $i;
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: 1.1rem $i;
|
||||
}
|
||||
|
||||
label {
|
||||
display: inline-block $i;
|
||||
margin-bottom: .5rem $i;
|
||||
font-size: 16px $i;
|
||||
}
|
||||
.small-label {
|
||||
display: inline-block $i;
|
||||
margin-bottom: .5rem $i;
|
||||
font-size: 11px $i;
|
||||
}
|
||||
|
||||
.small-checkbox{
|
||||
min-height:0 $i;
|
||||
|
||||
}
|
||||
|
||||
|
||||
.round-checkbox {
|
||||
border-radius:8px;
|
||||
}
|
||||
|
||||
.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: $danger-colour $i;
|
||||
background-color: transparent;
|
||||
background-image: none;
|
||||
border-color: $danger-colour $i;
|
||||
}
|
||||
|
||||
.btn-danger-outline:focus,
|
||||
.btn-danger-outline.focus,
|
||||
.btn-danger-outline:active,
|
||||
.btn-danger-outline.active,
|
||||
.btn-danger-outline:hover,
|
||||
.open > .btn-danger-outline.dropdown-toggle {
|
||||
color: #fff $i;
|
||||
background-color: $danger-colour $i;
|
||||
border-color: $danger-colour $i;
|
||||
}
|
||||
|
||||
|
||||
.btn-primary-outline {
|
||||
color: $primary-colour-outline $i;
|
||||
background-color: transparent;
|
||||
background-image: none;
|
||||
border-color: $primary-colour-outline $i;
|
||||
}
|
||||
|
||||
.btn-primary-outline:focus,
|
||||
.btn-primary-outline.focus,
|
||||
.btn-primary-outline:active,
|
||||
.btn-primary-outline.active,
|
||||
.btn-primary-outline:hover,
|
||||
.open > .btn-primary-outline.dropdown-toggle {
|
||||
color: #fff $i;
|
||||
background-color: $primary-colour $i;
|
||||
border-color: $primary-colour $i;
|
||||
}
|
||||
|
||||
.btn-info-outline {
|
||||
color: $info-colour $i;
|
||||
background-color: transparent;
|
||||
background-image: none;
|
||||
border-color: $info-colour $i;
|
||||
}
|
||||
|
||||
.btn-info-outline:focus,
|
||||
.btn-info-outline.focus,
|
||||
.btn-info-outline:active,
|
||||
.btn-info-outline.active,
|
||||
.btn-info-outline:hover,
|
||||
.open > .btn-info-outline.dropdown-toggle {
|
||||
color: #fff $i;
|
||||
background-color: $info-colour $i;
|
||||
border-color: $info-colour $i;
|
||||
}
|
||||
|
||||
.btn-warning-outline {
|
||||
color: $warning-colour $i;
|
||||
background-color: transparent;
|
||||
background-image: none;
|
||||
border-color: $warning-colour $i;
|
||||
}
|
||||
|
||||
.btn-warning-outline:focus,
|
||||
.btn-warning-outline.focus,
|
||||
.btn-warning-outline:active,
|
||||
.btn-warning-outline.active,
|
||||
.btn-warning-outline:hover,
|
||||
.open > .btn-warning-outline.dropdown-toggle {
|
||||
color: #fff $i;
|
||||
background-color: $warning-colour $i;
|
||||
border-color: $warning-colour $i;
|
||||
}
|
||||
|
||||
.btn-success-outline {
|
||||
color: $success-colour $i;
|
||||
background-color: transparent;
|
||||
background-image: none;
|
||||
border-color: $success-colour $i;
|
||||
}
|
||||
|
||||
.btn-success-outline:focus,
|
||||
.btn-success-outline.focus,
|
||||
.btn-success-outline:active,
|
||||
.btn-success-outline.active,
|
||||
.btn-success-outline:hover,
|
||||
.open > .btn-success-outline.dropdown-toggle {
|
||||
color: #fff $i;
|
||||
background-color: $success-colour $i;
|
||||
border-color: $success-colour $i;
|
||||
}
|
||||
|
||||
#movieList .mix {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#tvList .mix {
|
||||
display: none;
|
||||
}
|
||||
|
||||
$border-radius: 10px;
|
||||
|
||||
.scroll-top-wrapper {
|
||||
position: fixed;
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
overflow: hidden;
|
||||
text-align: center;
|
||||
z-index: 99999999;
|
||||
background-color: $form-color;
|
||||
color: #eeeeee;
|
||||
width: 50px;
|
||||
height: 48px;
|
||||
line-height: 48px;
|
||||
right: 30px;
|
||||
bottom: 30px;
|
||||
padding-top: 2px;
|
||||
border-top-left-radius: $border-radius;
|
||||
border-top-right-radius: $border-radius;
|
||||
border-bottom-right-radius: $border-radius;
|
||||
border-bottom-left-radius: $border-radius;
|
||||
-webkit-transition: all 0.5s ease-in-out;
|
||||
-moz-transition: all 0.5s ease-in-out;
|
||||
-ms-transition: all 0.5s ease-in-out;
|
||||
-o-transition: all 0.5s ease-in-out;
|
||||
transition: all 0.5s ease-in-out;
|
||||
}
|
||||
|
||||
.scroll-top-wrapper:hover {
|
||||
background-color: $form-color-lighter;
|
||||
}
|
||||
|
||||
.scroll-top-wrapper.show {
|
||||
visibility: visible;
|
||||
cursor: pointer;
|
||||
opacity: 1.0;
|
||||
}
|
||||
|
||||
.scroll-top-wrapper i.fa {
|
||||
line-height: inherit;
|
||||
}
|
||||
|
||||
|
||||
.no-search-results {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.no-search-results .no-search-results-icon {
|
||||
font-size: 10em;
|
||||
color: $form-color;
|
||||
}
|
||||
|
||||
.no-search-results .no-search-results-text {
|
||||
margin: 20px 0;
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
.form-control-search {
|
||||
padding: 13px 105px 13px 16px;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.form-control-withbuttons {
|
||||
padding-right: 105px;
|
||||
}
|
||||
|
||||
.input-group-addon .btn-group {
|
||||
position: absolute;
|
||||
right: 45px;
|
||||
z-index: 3;
|
||||
top: 10px;
|
||||
box-shadow: 0 0 0;
|
||||
}
|
||||
|
||||
.input-group-addon .btn-group .btn {
|
||||
border: 1px solid rgba(255,255,255,.7) !important;
|
||||
padding: 3px 12px;
|
||||
color: rgba(255,255,255,.7) !important;
|
||||
}
|
||||
|
||||
.btn-split .btn {
|
||||
border-radius: 0 !important;
|
||||
}
|
||||
|
||||
.btn-split .btn:not(.dropdown-toggle) {
|
||||
border-radius: .25rem 0 0 .25rem $i;
|
||||
}
|
||||
|
||||
.btn-split .btn.dropdown-toggle {
|
||||
border-radius: 0 .25rem .25rem 0 $i;
|
||||
padding: 12px 8px;
|
||||
}
|
||||
|
||||
#updateAvailable {
|
||||
background-color: #df691a;
|
||||
text-align: center;
|
||||
font-size: 15px;
|
||||
padding: 3px 0;
|
||||
}
|
||||
|
||||
#cacherRunning {
|
||||
background-color: $form-color;
|
||||
text-align: center;
|
||||
font-size: 15px;
|
||||
padding: 3px 0;
|
||||
}
|
||||
|
||||
.checkbox label {
|
||||
display: inline-block;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
padding-left: 25px;
|
||||
margin-right: 15px;
|
||||
font-size: 13px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.checkbox label:before {
|
||||
content: "";
|
||||
display: inline-block;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
margin-right: 10px;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
bottom: 1px;
|
||||
border: 2px solid #eee;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.checkbox input[type=checkbox] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.checkbox input[type=checkbox]:checked + label:before {
|
||||
content: "\2713";
|
||||
font-size: 13px;
|
||||
color: #fafafa;
|
||||
text-align: center;
|
||||
line-height: 13px;
|
||||
}
|
||||
|
||||
.small-checkbox label {
|
||||
display: inline-block;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
padding-left: 25px;
|
||||
margin-right: 15px;
|
||||
font-size: 13px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.small-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: 8px;
|
||||
min-height:0px $i;
|
||||
}
|
||||
|
||||
.small-checkbox input[type=checkbox] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.small-checkbox input[type=checkbox]:checked + label:before {
|
||||
content: "\2713";
|
||||
font-size: 13px;
|
||||
color: #fafafa;
|
||||
text-align: center;
|
||||
line-height: 13px;
|
||||
}
|
||||
|
||||
.small-checkbox label {
|
||||
min-height: 0 $i;
|
||||
padding-left: 20px;
|
||||
margin-bottom: 0;
|
||||
font-weight: normal;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.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: $form-color;
|
||||
}
|
||||
|
||||
.bootstrap-datetimepicker-widget.dropdown-menu.bottom:after {
|
||||
border-bottom: 6px solid $form-color $i;
|
||||
}
|
||||
|
||||
.bootstrap-datetimepicker-widget table td.active,
|
||||
.bootstrap-datetimepicker-widget table td.active:hover {
|
||||
color: #fff $i;
|
||||
}
|
||||
|
||||
.landing-header {
|
||||
display: block;
|
||||
margin: 60px auto;
|
||||
}
|
||||
|
||||
.landing-block {
|
||||
background: #2f2f2f $i;
|
||||
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 $i;
|
||||
margin-bottom: 0 $i;
|
||||
}
|
||||
|
||||
.tooltip_templates {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.shadow {
|
||||
-moz-box-shadow: 3px 3px 5px 6px #191919;
|
||||
-webkit-box-shadow: 3px 3px 5px 6px #191919;
|
||||
box-shadow: 3px 3px 5px 6px #191919;
|
||||
}
|
||||
.img-circle {
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
#wrapper {
|
||||
padding-left: 0;
|
||||
-webkit-transition: all 0.5s ease;
|
||||
-moz-transition: all 0.5s ease;
|
||||
-o-transition: all 0.5s ease;
|
||||
transition: all 0.5s ease;
|
||||
}
|
||||
|
||||
#wrapper.toggled {
|
||||
padding-right: 250px;
|
||||
}
|
||||
|
||||
#sidebar-wrapper {
|
||||
z-index: 1000;
|
||||
position: fixed;
|
||||
right: 250px;
|
||||
width: 0;
|
||||
height: 100%;
|
||||
margin-right: -250px;
|
||||
overflow-y: auto;
|
||||
background: #4e5d6c;
|
||||
padding-left:0;
|
||||
-webkit-transition: all 0.5s ease;
|
||||
-moz-transition: all 0.5s ease;
|
||||
-o-transition: all 0.5s ease;
|
||||
transition: all 0.5s ease;
|
||||
}
|
||||
|
||||
#wrapper.toggled #sidebar-wrapper {
|
||||
width: 500px;
|
||||
}
|
||||
|
||||
#page-content-wrapper {
|
||||
width: 100%;
|
||||
position: absolute;
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
#wrapper.toggled #page-content-wrapper {
|
||||
position: absolute;
|
||||
margin-left: -250px;
|
||||
}
|
||||
|
||||
/* Sidebar Styles */
|
||||
|
||||
.sidebar-nav {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
width: 500px;
|
||||
margin: 0;
|
||||
padding-left: 0;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.sidebar-nav li {
|
||||
text-indent: 20px;
|
||||
line-height: 40px;
|
||||
}
|
||||
|
||||
.sidebar-nav li a {
|
||||
display: block;
|
||||
text-decoration: none;
|
||||
color: #999999;
|
||||
}
|
||||
|
||||
.sidebar-nav li a:hover {
|
||||
text-decoration: none;
|
||||
color: #fff;
|
||||
background: rgba(255,255,255,0.2);
|
||||
}
|
||||
|
||||
.sidebar-nav li a:active,
|
||||
.sidebar-nav li a:focus {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.sidebar-nav > .sidebar-brand {
|
||||
height: 65px;
|
||||
font-size: 18px;
|
||||
line-height: 60px;
|
||||
}
|
||||
|
||||
.sidebar-nav > .sidebar-brand a {
|
||||
color: #999999;
|
||||
}
|
||||
|
||||
.sidebar-nav > .sidebar-brand a:hover {
|
||||
color: #fff;
|
||||
background: none;
|
||||
}
|
||||
|
||||
@media(min-width:768px) {
|
||||
#wrapper {
|
||||
padding-right: 250px;
|
||||
}
|
||||
|
||||
#wrapper.toggled {
|
||||
padding-right: 0;
|
||||
}
|
||||
|
||||
#sidebar-wrapper {
|
||||
width: 500px;
|
||||
}
|
||||
|
||||
#wrapper.toggled #sidebar-wrapper {
|
||||
width: 0;
|
||||
}
|
||||
|
||||
#page-content-wrapper {
|
||||
padding: 20px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
#wrapper.toggled #page-content-wrapper {
|
||||
position: relative;
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
#lightbox {
|
||||
|
||||
background-color: grey;
|
||||
filter:alpha(opacity=50); /* IE */
|
||||
opacity: 0.5; /* Safari, Opera */
|
||||
-moz-opacity:0.50; /* FireFox */
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
z-index: 20;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
background-repeat:no-repeat;
|
||||
background-position:center;
|
||||
position:absolute;
|
||||
}
|
||||
|
||||
|
||||
.list-group-item-dropdown {
|
||||
position: relative;
|
||||
display: block;
|
||||
padding: 10px 15px;
|
||||
margin-bottom: -1px;
|
||||
background-color: #3e3e3e;
|
||||
border: 1px solid transparent;
|
||||
}
|
||||
|
||||
.wizard-heading{
|
||||
text-align: center;
|
||||
}
|
||||
.wizard-img{
|
||||
width: 300px;
|
||||
display: block $i;
|
||||
margin: 0 auto $i;
|
||||
}
|
||||
|
||||
.pace {
|
||||
-webkit-pointer-events: none;
|
||||
pointer-events: none;
|
||||
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.pace-inactive {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.pace .pace-progress {
|
||||
background: $primary-colour;
|
||||
position: fixed;
|
||||
z-index: 2000;
|
||||
top: 0;
|
||||
right: 100%;
|
||||
width: 100%;
|
||||
height: 5px;
|
||||
}
|
||||
|
||||
.navbar-brand {
|
||||
float: left;
|
||||
font-size: 19px;
|
||||
line-height: 21px;
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
.gravatar{
|
||||
border-radius:1em;
|
||||
}
|
||||
|
||||
|
||||
// Bootstrap overrides
|
||||
|
||||
html {
|
||||
font-size: 10px;
|
||||
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
body {
|
||||
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
font-size: 14px;
|
||||
line-height: 1.42857143;
|
||||
color: #333;
|
||||
background-color: #fff;
|
||||
}
|
6998
Ombi/Ombi/Styles/bootstrap.css
vendored
6998
Ombi/Ombi/Styles/bootstrap.css
vendored
File diff suppressed because it is too large
Load diff
|
@ -1 +0,0 @@
|
|||
|
|
@ -1,26 +0,0 @@
|
|||
@*<!DOCTYPE html>*@
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>@ViewData["Title"] - Ombi</title>
|
||||
<base href="@Url.Content("~/")" />
|
||||
<script src="@Url.Content("~/lib/pace.js")?v=@ViewBag.AssemblyVersion"></script>
|
||||
<link href="@Url.Content("~/css/lib/pace-theme-minimal.css")" rel="stylesheet" />
|
||||
<link href="@Url.Content("~/css/base.css")" rel="stylesheet" type="text/css"/>
|
||||
<link href="@Url.Content("~/css/Themes/plex.css")" rel="stylesheet" type="text/css" />
|
||||
@*<link href="@Url.Content("~/css/lib/primeng.css")" rel="stylesheet" />*@
|
||||
|
||||
<script src="@Url.Content("~/lib/system.js")?v="></script>
|
||||
<script src="@Url.Content("~/lib/jquery.js")?v="></script>
|
||||
<script src="@Url.Content("~/lib/tether.js")?v="></script>
|
||||
<script src="@Url.Content("~/lib/bootstrap.js")?v="></script>
|
||||
<script src="@Url.Content("~/lib/systemjs.config.js")?v="></script>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
|
||||
@RenderBody()
|
||||
<ombi></ombi>
|
||||
</body>
|
||||
</html>
|
|
@ -1,2 +0,0 @@
|
|||
@using Ombi
|
||||
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
|
|
@ -1,3 +0,0 @@
|
|||
@{
|
||||
Layout = "_Layout";
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
|
||||
<nav class="navbar navbar-default navbar-fixed-top">
|
||||
<div class="container-fluid">
|
||||
<div class="navbar-header">
|
||||
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
|
||||
<span class="sr-only">Toggle navigation</span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
</button>
|
||||
<a class="navbar-brand" [routerLink]="['/']">Ombi</a>
|
||||
</div>
|
||||
|
||||
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
|
||||
<ul class="nav navbar-nav">
|
||||
<li ><a [routerLink]="['/search']"><i class="fa fa-search"></i> Search</a></li>
|
||||
</ul>
|
||||
<ul class="nav navbar-nav">
|
||||
<li ><a [routerLink]="['/settings/ombi']"><i class="fa fa-search"></i> Settings</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
|
||||
|
||||
<div class="container" style="padding-top: 5%">
|
||||
<router-outlet></router-outlet>
|
||||
</div>
|
||||
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'ombi',
|
||||
moduleId: module.id,
|
||||
templateUrl: './app.component.html'
|
||||
})
|
||||
export class AppComponent {
|
||||
|
||||
}
|
|
@ -1,51 +0,0 @@
|
|||
import { NgModule } from '@angular/core';
|
||||
import { BrowserModule } from '@angular/platform-browser';
|
||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
|
||||
import { AppComponent } from './app.component';
|
||||
|
||||
import { RouterModule, Routes } from '@angular/router';
|
||||
import { HttpModule } from '@angular/http';
|
||||
|
||||
import { SearchComponent } from './search/search.component';
|
||||
import { PageNotFoundComponent } from './errors/not-found.component';
|
||||
|
||||
// Services
|
||||
import { SearchService } from './services/search.service';
|
||||
import { RequestService } from './services/request.service';
|
||||
|
||||
// Modules
|
||||
import { SettingsModule } from './settings/settings.module';
|
||||
|
||||
import { ButtonModule } from 'primeng/primeng';
|
||||
import { GrowlModule } from 'primeng/components/growl/growl';
|
||||
|
||||
const routes: Routes = [
|
||||
{ path: '*', component: PageNotFoundComponent },
|
||||
{ path: 'search', component: SearchComponent }
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
RouterModule.forRoot(routes),
|
||||
BrowserModule,
|
||||
BrowserAnimationsModule,
|
||||
HttpModule,
|
||||
GrowlModule,
|
||||
ButtonModule,
|
||||
FormsModule,
|
||||
SettingsModule
|
||||
],
|
||||
declarations: [
|
||||
AppComponent,
|
||||
PageNotFoundComponent,
|
||||
SearchComponent
|
||||
],
|
||||
providers: [
|
||||
SearchService,
|
||||
RequestService
|
||||
],
|
||||
bootstrap: [AppComponent]
|
||||
})
|
||||
export class AppModule { }
|
|
@ -1,27 +0,0 @@
|
|||
// Config
|
||||
|
||||
enum envs {
|
||||
local = 0,
|
||||
next = 1,
|
||||
live = 2
|
||||
}
|
||||
|
||||
var envVar = "#{Environment}";
|
||||
var env = envs.local;
|
||||
if (envs[envVar]) {
|
||||
env = envs[envVar];
|
||||
}
|
||||
|
||||
export var config = {
|
||||
envs: envs,
|
||||
env: env,
|
||||
systemJS: {
|
||||
bundle: <boolean>{
|
||||
[envs.local]: false,
|
||||
[envs.next]: true,
|
||||
[envs.live]: true
|
||||
}[env]
|
||||
}
|
||||
}
|
||||
|
||||
export default config;
|
|
@ -1,7 +0,0 @@
|
|||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
moduleId: module.id,
|
||||
template: '<h2>Page not found</h2>'
|
||||
})
|
||||
export class PageNotFoundComponent { }
|
|
@ -1,4 +0,0 @@
|
|||
export interface IRequestEngineResult {
|
||||
requestAdded: boolean,
|
||||
message: string
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
export interface ISearchMovieResult {
|
||||
backdropPath: string,
|
||||
adult: boolean,
|
||||
overview: string,
|
||||
releaseDate: Date,
|
||||
genreIds: number[],
|
||||
id: number,
|
||||
originalTitle: string,
|
||||
originalLanguage: string,
|
||||
title: string,
|
||||
posterPath: string,
|
||||
popularity: number,
|
||||
voteCount: number,
|
||||
video: boolean,
|
||||
voteAverage: number,
|
||||
alreadyInCp: boolean,
|
||||
trailer: string,
|
||||
homepage: string,
|
||||
imdbId:string
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
import './polyfills';
|
||||
|
||||
import { enableProdMode } from '@angular/core';
|
||||
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
|
||||
|
||||
import { AppModule } from './app.module';
|
||||
import { config } from './config';
|
||||
|
||||
if (config.env !== config.envs.local) {
|
||||
enableProdMode();
|
||||
}
|
||||
|
||||
platformBrowserDynamic().bootstrapModule(AppModule);
|
|
@ -1,14 +0,0 @@
|
|||
// TypeScript transpiles our app to ES5 but some dependencies are written in ES6 so must polyfill
|
||||
import 'core-js/es6/string';
|
||||
import 'core-js/es6/array';
|
||||
import 'core-js/es6/object';
|
||||
|
||||
import 'core-js/es7/reflect';
|
||||
import 'zone.js/dist/zone';
|
||||
|
||||
import { config } from './config';
|
||||
|
||||
if (config.env === config.envs.local) {
|
||||
Error['stackTraceLimit'] = Infinity;
|
||||
require('zone.js/dist/long-stack-trace-zone');
|
||||
}
|
|
@ -1,248 +0,0 @@
|
|||
<h1 id="searchTitle">Search</h1>
|
||||
<h4>Search Paragraph</h4>
|
||||
<br />
|
||||
<!-- Nav tabs -->
|
||||
|
||||
|
||||
<ul id="nav-tabs" class="nav nav-tabs" role="tablist">
|
||||
|
||||
<li role="presentation" class="active">
|
||||
<a id="movieTabButton" href="#MoviesTab" aria-controls="home" role="tab" data-toggle="tab"><i class="fa fa-film"></i> Movies</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li role="presentation">
|
||||
<a id="actorTabButton" href="#ActorsTab" aria-controls="profile" role="tab" data-toggle="tab"><i class="fa fa-users"></i> Actors</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li role="presentation">
|
||||
<a id="tvTabButton" href="#TvShowTab" aria-controls="profile" role="tab" data-toggle="tab"><i class="fa fa-television"></i> TV Shows</a>
|
||||
|
||||
</li>
|
||||
<!--
|
||||
<li role="presentation">
|
||||
<a href="#MusicTab" aria-controls="profile" role="tab" data-toggle="tab"><i class="fa fa-music"></i> Albums</a>
|
||||
</li>-->
|
||||
|
||||
</ul>
|
||||
|
||||
<!-- Tab panes -->
|
||||
<div class="tab-content">
|
||||
|
||||
<!-- Movie tab -->
|
||||
<div role="tabpanel" class="tab-pane active" id="MoviesTab">
|
||||
<div class="input-group">
|
||||
<input id="movieSearchContent" type="text" class="form-control form-control-custom form-control-search form-control-withbuttons" (keyup)="search($event)">
|
||||
<div class="input-group-addon">
|
||||
<div class="btn-group">
|
||||
<a href="#" class="btn btn-sm btn-primary-outline dropdown-toggle" data-toggle="dropdown" aria-expanded="false">
|
||||
Suggestions
|
||||
<i class="fa fa-chevron-down"></i>
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a (click)="popularMovies()">Popular Movies</a></li>
|
||||
<li><a (click)="upcomingMovies()">Upcoming Movies</a></li>
|
||||
<li><a (click)="topRatedMovies()">Top Rated Movies</a></li>
|
||||
<li><a (click)="nowPlayingMovies()">Now Playing Movies</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<i id="movieSearchButton" class="fa fa-search"></i>
|
||||
</div>
|
||||
</div>
|
||||
<br />
|
||||
<br />
|
||||
<!-- Movie content -->
|
||||
<div id="movieList">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Actors tab -->
|
||||
<div role="tabpanel" class="tab-pane" id="ActorsTab">
|
||||
<div class="input-group">
|
||||
<input id="actorSearchContent" type="text" class="form-control form-control-custom form-control-search form-control-withbuttons">
|
||||
<div class="input-group-addon">
|
||||
<i id="actorSearchButton" class="fa fa-search"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="checkbox">
|
||||
<input type="checkbox" id="actorsSearchNew" name="actorsSearchNew"><label for="actorsSearchNew">@UI.Search_NewOnly</label>
|
||||
</div>
|
||||
|
||||
<br />
|
||||
<br />
|
||||
<!-- Movie content -->
|
||||
<div id="actorMovieList">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- TV tab -->
|
||||
<div role="tabpanel" class="tab-pane" id="TvShowTab">
|
||||
<div class="input-group">
|
||||
<input id="tvSearchContent" type="text" class="form-control form-control-custom form-control-search form-control-withbuttons">
|
||||
<div class="input-group-addon">
|
||||
<div class="btn-group">
|
||||
<a href="#" class="btn btn-sm btn-primary-outline dropdown-toggle" data-toggle="dropdown" aria-expanded="false">
|
||||
@UI.Search_Suggestions
|
||||
<i class="fa fa-chevron-down"></i>
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a id="popularShows" >Popular Shows</a></li>
|
||||
<li><a id="trendingShows" href="#">Trending Shows</a></li>
|
||||
<li><a id="mostWatchedShows" href="#">Most Watched Shows</a></li>
|
||||
<li><a id="anticipatedShows" href="#">Most Anticipated Shows</a></li>
|
||||
</ul>
|
||||
</div><i id="tvSearchButton" class="fa fa-search"></i>
|
||||
</div>
|
||||
</div>
|
||||
<br />
|
||||
<br />
|
||||
<!-- TV content -->
|
||||
<div id="tvList">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Music tab -->
|
||||
<!-- <div role="tabpanel" class="tab-pane" id="MusicTab">
|
||||
<div class="input-group">
|
||||
<input id="musicSearchContent" type="text" class="form-control form-control-custom form-control-search">
|
||||
<div class="input-group-addon">
|
||||
<i id="musicSearchButton" class="fa fa-search"></i>
|
||||
</div>
|
||||
</div>
|
||||
<br />
|
||||
<br />
|
||||
<div id="musicList">
|
||||
</div>
|
||||
</div>
|
||||
-->
|
||||
|
||||
<div *ngFor="let result of movieResults">
|
||||
<div class="row">
|
||||
<div id="{{id}}imgDiv" class="col-sm-2">
|
||||
|
||||
|
||||
<img *ngIf="result.posterPath" class="img-responsive" src="https://image.tmdb.org/t/p/w150/{{result.posterPath}}" alt="poster">
|
||||
|
||||
</div>
|
||||
<div class="col-sm-8">
|
||||
<div>
|
||||
<a href="https://www.themoviedb.org/movie/{{result.id}}/" target="_blank">
|
||||
<h4>{{result.title}} ({{result.releaseDate}})</h4>
|
||||
</a>
|
||||
|
||||
|
||||
<span *ngIf="result.firstAired" class="label label-info" target="_blank">Air Date: {{result.firstAired}}</span>
|
||||
|
||||
|
||||
<span *ngIf="result.releaseDate" class="label label-info" target="_blank">Release Date: {{result.releaseDate}}</span>
|
||||
|
||||
<span *ngIf="result.available" class="label label-success">@UI.Search_Available</span>
|
||||
|
||||
<span *ngIf="result.approved" class="label label-info">@UI.Search_Processing_Request</span>
|
||||
|
||||
<div *ngIf="result.requested; then requested else notRequested"></div>
|
||||
<template #requested>
|
||||
<span class="label label-warning">Pending Approval</span>
|
||||
</template>
|
||||
|
||||
<template #notRequested>
|
||||
<span class="label label-danger">Not Yet Requested</span>
|
||||
</template>
|
||||
|
||||
|
||||
<span id="{{id}}netflixTab"></span>
|
||||
|
||||
<a *ngIf="result.homepage" href="{{result.homepage}}" target="_blank"><span class="label label-info">HomePage</span></a>
|
||||
|
||||
<a *ngIf="result.trailer" href="{{result.trailer}}" target="_blank"><span class="label label-info">Trailer</span></a>
|
||||
|
||||
|
||||
<br />
|
||||
<br />
|
||||
</div>
|
||||
<p style="font-size:0.9rem !important">{{result.overview}}</p>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="col-sm-2">
|
||||
<input name="{{type}}Id" type="text" value="{{result.id}}" hidden="hidden" />
|
||||
|
||||
<div *ngIf="result.available">
|
||||
<button style="text-align: right" class="btn btn-success-outline disabled" disabled><i class="fa fa-check"></i> Available</button>
|
||||
|
||||
<div *ngIf="result.url">
|
||||
<br />
|
||||
<br />
|
||||
<a style="text-align: right" class="btn btn-sm btn-primary-outline" href="{{result.url}}" target="_blank"><i class="fa fa-eye"></i> View In Plex</a>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div *ngIf="result.requested; then requestedBtn else notRequestedBtn"></div>
|
||||
<template #requestedBtn>
|
||||
<button style="text-align: right" class="btn btn-primary-outline disabled" [disabled]><i class="fa fa-check"></i> Requested</button>
|
||||
</template>
|
||||
<template #notRequestedBtn>
|
||||
<button id="{{result.id}}" style="text-align: right" class="btn btn-primary-outline" (click)="request(result)"><i class="fa fa-plus"></i> Request</button>
|
||||
</template>
|
||||
|
||||
<!--{{#if_eq type "tv"}}
|
||||
{{#if_eq tvFullyAvailable true}}
|
||||
@*//TODO Not used yet*@
|
||||
<button style="text-align: right" class="btn btn-success-outline disabled" disabled><i class="fa fa-check"></i> @UI.Search_Available</button><br />
|
||||
{{else}}
|
||||
{{#if_eq enableTvRequestsForOnlySeries true}}
|
||||
<button id="{{id}}" style="text-align: right" class="btn {{#if available}}btn-success-outline{{else}}btn-primary-outline dropdownTv{{/if}} btn-primary-outline" season-select="0" type="button" {{#if available}} disabled{{/if}}><i class="fa fa-plus"></i> {{#if available}}@UI.Search_Available{{else}}@UI.Search_Request{{/if}}</button>
|
||||
{{else}}
|
||||
<div class="dropdown">
|
||||
<button id="{{id}}" class="btn {{#if available}}btn-success-outline{{else}}btn-primary-outline{{/if}} dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
|
||||
<i class="fa fa-plus"></i> {{#if available}}@UI.Search_Available{{else}}@UI.Search_Request {{/if}}
|
||||
<span class="caret"></span>
|
||||
</button>
|
||||
<ul class="dropdown-menu" aria-labelledby="dropdownMenu1">
|
||||
<li><a id="{{id}}" season-select="0" class="dropdownTv " href="#">@UI.Search_AllSeasons</a></li>
|
||||
{{#if_eq disableTvRequestsBySeason false}}
|
||||
<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="SeasonSelect" data-identifier="{{id}}" data-toggle="modal" data-target="#seasonsModal" href="#">@UI.Search_SelectSeason...</a></li>
|
||||
{{/if_eq}}
|
||||
{{#if_eq disableTvRequestsByEpisode false}}
|
||||
<li><a id="EpisodeSelect" data-identifier="{{id}}" data-toggle="modal" data-target="#episodesModal" href="#">@UI.Search_SelectEpisode...</a></li>
|
||||
{{/if_eq}}
|
||||
</ul>
|
||||
</div>
|
||||
{{/if_eq}}
|
||||
{{#if available}}
|
||||
{{#if url}}
|
||||
<br />
|
||||
<a style="text-align: right" class="btn btn-sm btn-primary-outline" href="{{url}}" target="_blank"><i class="fa fa-eye"></i> @UI.Search_ViewInPlex</a>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
{{/if_eq}}
|
||||
{{/if_eq}}-->
|
||||
|
||||
|
||||
<br />
|
||||
<div *ngIf="result.available">
|
||||
<input name="providerId" type="text" value="{{id}}" hidden="hidden" />
|
||||
<input name="type" type="text" value="{{type}}" hidden="hidden" />
|
||||
<div class="dropdown">
|
||||
<button class="btn btn-sm btn-danger-outline dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
|
||||
<i class="fa fa-exclamation"></i> @UI.Search_ReportIssue
|
||||
<span class="caret"></span>
|
||||
</button>
|
||||
<ul class="dropdown-menu" aria-labelledby="dropdownMenu1">
|
||||
<li><a issue-select="0" class="dropdownIssue" href="#">@UI.Issues_WrongAudio</a></li>
|
||||
<li><a issue-select="1" class="dropdownIssue" href="#">@UI.Issues_NoSubs</a></li>
|
||||
<li><a issue-select="2" class="dropdownIssue" href="#">@UI.Issues_WrongContent</a></li>
|
||||
<li><a issue-select="3" class="dropdownIssue" href="#">@UI.Issues_Playback</a></li>
|
||||
<li><a issue-select="4" class="dropdownIssue" href="#" data-toggle="modal" data-target="#issuesModal">@UI.Issues_Other</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<hr />
|
||||
</div>
|
|
@ -1,78 +0,0 @@
|
|||
import { Component, OnInit } from '@angular/core';
|
||||
import { Subject } from 'rxjs/Subject';
|
||||
import 'rxjs/add/operator/debounceTime';
|
||||
import 'rxjs/add/operator/distinctUntilChanged';
|
||||
import 'rxjs/add/operator/map';
|
||||
|
||||
import { SearchService } from '../services/search.service';
|
||||
import { RequestService } from '../services/request.service';
|
||||
|
||||
import { ISearchMovieResult } from '../interfaces/ISearchMovieResult';
|
||||
import { IRequestEngineResult } from '../interfaces/IRequestEngineResult';
|
||||
|
||||
@Component({
|
||||
selector: 'ombi',
|
||||
moduleId: module.id,
|
||||
templateUrl: './search.component.html',
|
||||
providers: [SearchService, RequestService]
|
||||
})
|
||||
export class SearchComponent implements OnInit {
|
||||
|
||||
searchText: string;
|
||||
searchChanged: Subject<string> = new Subject<string>();
|
||||
movieResults: ISearchMovieResult[];
|
||||
result: IRequestEngineResult;
|
||||
|
||||
constructor(private searchService: SearchService, private requestService: RequestService) {
|
||||
this.searchChanged
|
||||
.debounceTime(600) // Wait Xms afterthe last event before emitting last event
|
||||
.distinctUntilChanged() // only emit if value is different from previous value
|
||||
.subscribe(x => {
|
||||
this.searchText = x as string;
|
||||
if (this.searchText === "") {
|
||||
this.clearResults();
|
||||
return;
|
||||
}
|
||||
this.searchService.searchMovie(this.searchText).subscribe(x => this.movieResults = x);
|
||||
});
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.searchText = "";
|
||||
this.movieResults = [];
|
||||
this.result = {
|
||||
message: "",
|
||||
requestAdded:false
|
||||
}
|
||||
}
|
||||
|
||||
search(text: any) {
|
||||
this.searchChanged.next(text.target.value);
|
||||
}
|
||||
|
||||
request(searchResult: ISearchMovieResult) {
|
||||
this.requestService.requestMovie(searchResult).subscribe(x => this.result = x);
|
||||
}
|
||||
|
||||
popularMovies() {
|
||||
this.clearResults();
|
||||
this.searchService.popularMovies().subscribe(x => this.movieResults = x);
|
||||
}
|
||||
nowPlayingMovies() {
|
||||
this.clearResults();
|
||||
this.searchService.nowPlayingMovies().subscribe(x => this.movieResults = x);
|
||||
}
|
||||
topRatedMovies() {
|
||||
this.clearResults();
|
||||
this.searchService.topRatedMovies().subscribe(x => this.movieResults = x);
|
||||
}
|
||||
upcomingMovies() {
|
||||
this.clearResults();
|
||||
this.searchService.upcomignMovies().subscribe(x => this.movieResults = x);
|
||||
}
|
||||
|
||||
private clearResults() {
|
||||
this.movieResults = [];
|
||||
}
|
||||
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
import { Http } from '@angular/http';
|
||||
import { Observable } from 'rxjs/Rx';
|
||||
|
||||
import { ServiceHelpers } from './service.helpers';
|
||||
import { IRequestEngineResult } from '../interfaces/IRequestEngineResult';
|
||||
import { ISearchMovieResult } from '../interfaces/ISearchMovieResult';
|
||||
|
||||
@Injectable()
|
||||
export class RequestService {
|
||||
constructor(private http: Http) {
|
||||
}
|
||||
|
||||
requestMovie(movie: ISearchMovieResult): Observable<IRequestEngineResult> {
|
||||
return this.http.post('/api/Request/Movie/', JSON.stringify(movie), ServiceHelpers.RequestOptions).map(ServiceHelpers.extractData);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
import { Http } from '@angular/http';
|
||||
import { Observable } from 'rxjs/Rx';
|
||||
|
||||
import { ServiceHelpers } from './service.helpers';
|
||||
import { ISearchMovieResult } from '../interfaces/ISearchMovieResult';
|
||||
|
||||
@Injectable()
|
||||
export class SearchService {
|
||||
constructor(private http: Http) {
|
||||
}
|
||||
|
||||
searchMovie(searchTerm: string): Observable<ISearchMovieResult[]> {
|
||||
return this.http.get('/api/Search/Movie/' + searchTerm).map(ServiceHelpers.extractData);
|
||||
}
|
||||
|
||||
popularMovies(): Observable<ISearchMovieResult[]> {
|
||||
return this.http.get('/api/Search/Movie/Popular').map(ServiceHelpers.extractData);
|
||||
}
|
||||
upcomignMovies(): Observable<ISearchMovieResult[]> {
|
||||
return this.http.get('/api/Search/Movie/upcoming').map(ServiceHelpers.extractData);
|
||||
}
|
||||
nowPlayingMovies(): Observable<ISearchMovieResult[]> {
|
||||
return this.http.get('/api/Search/Movie/nowplaying').map(ServiceHelpers.extractData);
|
||||
}
|
||||
topRatedMovies(): Observable<ISearchMovieResult[]> {
|
||||
return this.http.get('/api/Search/Movie/toprated').map(ServiceHelpers.extractData);
|
||||
}
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
import { Headers, RequestOptions, Response } from '@angular/http';
|
||||
|
||||
export class ServiceHelpers {
|
||||
public static Headers = new Headers({ 'Content-Type': 'application/json' });
|
||||
|
||||
public static RequestOptions = new RequestOptions({
|
||||
headers: ServiceHelpers.Headers
|
||||
});
|
||||
|
||||
public static extractData(res: Response) {
|
||||
console.log(res);
|
||||
return res.json();
|
||||
}
|
||||
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
|
|
@ -1,11 +0,0 @@
|
|||
import { Component } from '@angular/core';
|
||||
@Component({
|
||||
selector: 'ombi',
|
||||
moduleId: module.id,
|
||||
templateUrl: './ombi.component.html',
|
||||
})
|
||||
export class OmbiComponent {
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
import { NgModule, } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { RouterModule, Routes } from '@angular/router';
|
||||
|
||||
import { OmbiComponent } from './ombi/ombi.component'
|
||||
|
||||
|
||||
const routes: Routes = [
|
||||
{ path: 'Settings/Ombi', component: OmbiComponent }
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
CommonModule,
|
||||
FormsModule,
|
||||
RouterModule.forChild(routes),
|
||||
|
||||
],
|
||||
declarations: [
|
||||
OmbiComponent
|
||||
],
|
||||
exports: [
|
||||
RouterModule
|
||||
],
|
||||
providers: [
|
||||
]
|
||||
})
|
||||
export class SettingsModule { }
|
|
@ -1,10 +0,0 @@
|
|||
{
|
||||
"Logging": {
|
||||
"IncludeScopes": false,
|
||||
"LogLevel": {
|
||||
"Default": "Debug",
|
||||
"System": "Information",
|
||||
"Microsoft": "Information"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
{
|
||||
"Logging": {
|
||||
"IncludeScopes": false,
|
||||
"LogLevel": {
|
||||
"Default": "Warning"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
{
|
||||
"name": "ombi",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"PACE": "pace#^1.0.2",
|
||||
"font-awesome": "^4.7.0"
|
||||
}
|
||||
}
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
// Configure bundling and minification for the project.
|
||||
// More info at https://go.microsoft.com/fwlink/?LinkId=808241
|
||||
[
|
||||
{
|
||||
"outputFileName": "wwwroot/css/site.min.css",
|
||||
// An array of relative input file paths. Globbing patterns supported
|
||||
"inputFiles": [
|
||||
"wwwroot/css/site.css"
|
||||
]
|
||||
},
|
||||
{
|
||||
"outputFileName": "wwwroot/js/site.min.js",
|
||||
"inputFiles": [
|
||||
"wwwroot/js/site.js"
|
||||
],
|
||||
// Optionally specify minification options
|
||||
"minify": {
|
||||
"enabled": true,
|
||||
"renameLocals": true
|
||||
},
|
||||
// Optionally generate .map file
|
||||
"sourceMap": false
|
||||
}
|
||||
]
|
|
@ -1,270 +0,0 @@
|
|||
/// <binding BeforeBuild='build' ProjectOpened='watch' />
|
||||
'use strict';
|
||||
var gulp = require('gulp');
|
||||
var sass = require('gulp-sass');
|
||||
var changed = require('gulp-changed');
|
||||
var rename = require('gulp-rename');
|
||||
//var uglify = require('gulp-uglify');
|
||||
var sourcemaps = require('gulp-sourcemaps');
|
||||
var path = require('path');
|
||||
var del = require('del');
|
||||
var merge = require('merge-stream');
|
||||
var gulpif = require('gulp-if');
|
||||
var runSequence = require('run-sequence');
|
||||
var cleancss = require('gulp-clean-css');
|
||||
var filter = require('gulp-filter');
|
||||
var systemJSBuilder = require('systemjs-builder');
|
||||
var run = require('gulp-run');
|
||||
|
||||
var paths = {
|
||||
wwwroot: './wwwroot/',
|
||||
npm: { // These will be resolved automatically and copied to output directory as its name, only works for pre-bundled modules e.g. angular
|
||||
src: [
|
||||
'@angular/animations',
|
||||
'@angular/animations/browser',
|
||||
'@angular/core',
|
||||
'@angular/common',
|
||||
'@angular/compiler',
|
||||
'@angular/platform-browser',
|
||||
'@angular/platform-browser-dynamic',
|
||||
'@angular/http',
|
||||
'@angular/router',
|
||||
'@angular/forms'
|
||||
],
|
||||
dest: './lib'
|
||||
},
|
||||
lib: { // These are simple single-file dependencies with optional rename, for more files or folders use modules
|
||||
src: [
|
||||
{
|
||||
file: './node_modules/@angular/platform-browser/bundles/platform-browser-animations.umd.js',
|
||||
rename: '@angular/platform-browser/animations'
|
||||
},
|
||||
{
|
||||
file: './node_modules/systemjs/dist/system.src.js',
|
||||
rename: 'system'
|
||||
},
|
||||
{
|
||||
file: './node_modules/systemjs/dist/system-polyfills.src.js',
|
||||
rename: 'system-polyfills'
|
||||
},
|
||||
{
|
||||
file: './node_modules/jquery/dist/jquery.min.js',
|
||||
rename: 'jquery'
|
||||
},
|
||||
'./bower_components/PACE/pace.js',
|
||||
'./node_modules/bootstrap/dist/js/bootstrap.js',
|
||||
'./node_modules/tether/dist/js/tether.js',
|
||||
'./systemjs.config.js'
|
||||
],
|
||||
dest: './lib/'
|
||||
},
|
||||
libcss: [ // Normal css files to be copied
|
||||
{
|
||||
src: [
|
||||
'./bower_components/PACE/themes/purple/pace-theme-minimal.css',
|
||||
'./bower_components/font-awesome/css/font-awesome.css',
|
||||
'./node_modules/primeng/resources/primeng.css',
|
||||
'./node_modules/tether/dist/css/tether.css'
|
||||
],
|
||||
dest: './css/lib/'
|
||||
},
|
||||
{
|
||||
src: './Styles/**/*.css',
|
||||
dest: './css',
|
||||
filter: '**/*.css'
|
||||
}
|
||||
],
|
||||
libfonts: [ // Library fonts
|
||||
{
|
||||
src: [
|
||||
'./bower_components/font-awesome/fonts/*'
|
||||
],
|
||||
dest: './fonts/lib/'
|
||||
},
|
||||
{
|
||||
src: [
|
||||
'./node_modules/primeng/resources/themes/omega/fonts/*'
|
||||
],
|
||||
dest: './fonts/'
|
||||
}
|
||||
],
|
||||
libimages: [ // Library images
|
||||
{
|
||||
src: [
|
||||
'./node_modules/primeng/resources/themes/omega/images/*'
|
||||
],
|
||||
dest: './images/'
|
||||
}
|
||||
],
|
||||
modules: [ // This is for modules with multiple files that require each other, used when npm can't be used
|
||||
{
|
||||
name: 'zone.js',
|
||||
src: ['./node_modules/zone.js/**/*.js'],
|
||||
dest: './lib/zone.js/'
|
||||
},
|
||||
{
|
||||
name: 'rxjs',
|
||||
src: ['./node_modules/rxjs/**/*.js', '!./node_modules/rxjs/src/**/*.js'],
|
||||
dest: './lib/rxjs/'
|
||||
},
|
||||
{
|
||||
name: 'core-js',
|
||||
src: ['./node_modules/core-js/**/*.js'],
|
||||
dest: './lib/core-js/'
|
||||
},
|
||||
{
|
||||
name: 'primeng',
|
||||
src: './node_modules/primeng/**/*.js',
|
||||
dest: './lib/primeng/'
|
||||
}
|
||||
],
|
||||
sass: { // Simple sass->css compilation
|
||||
src: ['./Styles/**/*.scss', '!./Styles/primeng/**'],
|
||||
dest: './css/',
|
||||
filter: '**/*.css'
|
||||
},
|
||||
bundle: { // This is the config for the bundler, you shouldn't need to change this
|
||||
root: './',
|
||||
dest: './lib/bundle.js',
|
||||
bundle: 'app/main.js',
|
||||
}
|
||||
}
|
||||
|
||||
gulp.task('npm', function () {
|
||||
var streams = []
|
||||
for (let module of paths.npm.src) {
|
||||
let file = require.resolve(module);
|
||||
streams.push(
|
||||
gulp.src(file)
|
||||
.pipe(gulpif(global.full, sourcemaps.init()))
|
||||
//.pipe(gulpif(global.full, uglify({ source_map: true })))
|
||||
.pipe(rename((path => { path.basename = module })))
|
||||
.pipe(gulpif(global.full, sourcemaps.write('../maps')))
|
||||
.pipe(gulp.dest(path.join(paths.wwwroot, paths.npm.dest)))
|
||||
);
|
||||
}
|
||||
return merge(streams);
|
||||
})
|
||||
|
||||
gulp.task('lib', function () {
|
||||
var streams = []
|
||||
for (let module of paths.lib.src) {
|
||||
streams.push(
|
||||
gulp.src(typeof module === "string" ? module : module.file)
|
||||
.pipe(gulpif(global.full, sourcemaps.init()))
|
||||
//.pipe(gulpif(global.full, uglify({ source_map: true })))
|
||||
.pipe(rename(function (path) {
|
||||
if (typeof module !== "string" && module.rename) {
|
||||
path.basename = module.rename;
|
||||
}
|
||||
}))
|
||||
.pipe(gulpif(global.full, sourcemaps.write('maps')))
|
||||
.pipe(gulp.dest(path.join(paths.wwwroot, paths.lib.dest)))
|
||||
);
|
||||
}
|
||||
return merge(streams);
|
||||
})
|
||||
|
||||
gulp.task('libcss', function () {
|
||||
var streams = []
|
||||
for (let module of paths.libcss) {
|
||||
var f = filter("**/*.css", { restore: true });
|
||||
streams.push(
|
||||
gulp.src(module.src)
|
||||
.pipe(f)
|
||||
.pipe(gulpif(global.full, sourcemaps.init()))
|
||||
.pipe(gulpif(global.full, cleancss()))
|
||||
.pipe(gulpif(global.full, sourcemaps.write(`${module.name ? '.' : ''}./maps/${module.name ? module.name : ''}`)))
|
||||
.pipe(f.restore)
|
||||
.pipe(gulp.dest(path.join(paths.wwwroot, module.dest)))
|
||||
);
|
||||
}
|
||||
return merge(streams);
|
||||
})
|
||||
|
||||
|
||||
gulp.task('libfonts', function () {
|
||||
var streams = []
|
||||
for (let module of paths.libfonts) {
|
||||
streams.push(
|
||||
gulp.src(module.src)
|
||||
.pipe(gulp.dest(path.join(paths.wwwroot, module.dest)))
|
||||
);
|
||||
}
|
||||
return merge(streams);
|
||||
})
|
||||
|
||||
|
||||
gulp.task('libimages', function () {
|
||||
var streams = []
|
||||
for (let module of paths.libimages) {
|
||||
streams.push(
|
||||
gulp.src(module.src)
|
||||
.pipe(gulp.dest(path.join(paths.wwwroot, module.dest)))
|
||||
);
|
||||
}
|
||||
return merge(streams);
|
||||
})
|
||||
|
||||
gulp.task('modules', function () {
|
||||
var streams = []
|
||||
for (let module of paths.modules) {
|
||||
streams.push(
|
||||
gulp.src(module.src)
|
||||
.pipe(gulpif(global.full, sourcemaps.init()))
|
||||
// .pipe(gulpif(global.full, uglify({ source_map: true })))
|
||||
.pipe(gulpif(global.full, sourcemaps.write(`${module.name ? '.' : ''}./maps/${module.name ? module.name : ''}`)))
|
||||
.pipe(gulp.dest(path.join(paths.wwwroot, module.dest)))
|
||||
);
|
||||
}
|
||||
return merge(streams);
|
||||
})
|
||||
|
||||
gulp.task('sass', function () {
|
||||
return gulp.src(paths.sass.src)
|
||||
.pipe(changed(paths.sass.dest))
|
||||
.pipe(gulpif(global.full, sourcemaps.init()))
|
||||
.pipe(sass({ outputStyle: global.full ? 'compressed' : 'nested' }).on('error', sass.logError))
|
||||
.pipe(gulpif(global.full, sourcemaps.write('maps')))
|
||||
.pipe(gulp.dest(path.join(paths.wwwroot, paths.sass.dest)))
|
||||
});
|
||||
|
||||
gulp.task('bundle', function () {
|
||||
var builder = new systemJSBuilder(paths.bundle.root);
|
||||
builder.config({
|
||||
baseURL: paths.wwwroot,
|
||||
packages: {
|
||||
'.': {
|
||||
defaultExtension: 'js'
|
||||
}
|
||||
},
|
||||
paths: {
|
||||
'*': 'lib/*',
|
||||
'app/*': 'app/*'
|
||||
}
|
||||
});
|
||||
del.sync(path.join(paths.wwwroot, paths.bundle.dest), { force: true });
|
||||
return builder.bundle(paths.bundle.bundle, path.join(paths.wwwroot, paths.bundle.dest), {
|
||||
sourceMaps: true
|
||||
})
|
||||
})
|
||||
|
||||
gulp.task('typescript', function () {
|
||||
return run('tsc').exec();
|
||||
});
|
||||
|
||||
gulp.task('fullvar', () => { global.full = true });
|
||||
gulp.task('libs')
|
||||
gulp.task('copy', ['lib', 'libcss', 'libfonts', 'libimages', 'npm', 'modules']);
|
||||
gulp.task('compile', ['sass']);
|
||||
gulp.task('build', callback => runSequence('copy', 'compile', callback));
|
||||
gulp.task('full', callback => runSequence('build', callback));
|
||||
|
||||
// Use this in a build server environment to compile and bundle everything
|
||||
gulp.task('publish', callback => runSequence('fullvar', 'full', 'typescript', 'bundle', callback));
|
||||
|
||||
// Auto compiles sass files on change, note that this doesn't seem to pick up new files at the moment
|
||||
gulp.task('watch', function () {
|
||||
gulp.watch(paths.sass.src, ['sass']);
|
||||
gulp.watch('./Styles/**/*.css', ['libcss']); // legacy css
|
||||
});
|
|
@ -1,45 +0,0 @@
|
|||
{
|
||||
"name": "ombi",
|
||||
"version": "1.0.0",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@angular/animations": "^4.0.0",
|
||||
"@angular/common": "^4.0.0",
|
||||
"@angular/compiler": "^4.0.0",
|
||||
"@angular/compiler-cli": "^4.0.0",
|
||||
"@angular/core": "^4.0.0",
|
||||
"@angular/forms": "^4.0.0",
|
||||
"@angular/http": "^4.0.0",
|
||||
"@angular/platform-browser": "^4.0.0",
|
||||
"@angular/platform-browser-dynamic": "^4.0.0",
|
||||
"@angular/platform-server": "^4.0.0",
|
||||
"@angular/router": "^4.0.0",
|
||||
"@types/jquery": "^2.0.33",
|
||||
"@types/systemjs": "^0.20.2",
|
||||
"core-js": "^2.4.1",
|
||||
"del": "^2.2.2",
|
||||
"gulp": "~3.9.1",
|
||||
"gulp-changed": "^1.3.0",
|
||||
"gulp-clean-css": "^3.0.4",
|
||||
"gulp-filter": "^5.0.0",
|
||||
"gulp-if": "^2.0.2",
|
||||
"gulp-rename": "^1.2.2",
|
||||
"gulp-run": "^1.7.1",
|
||||
"gulp-sass": "^2.3.2",
|
||||
"gulp-sourcemaps": "^1.9.0",
|
||||
"gulp-systemjs-builder": "^0.15.0",
|
||||
"gulp-uglify": "^2.1.2",
|
||||
"jquery": "2.2.1",
|
||||
"merge-stream": "^1.0.1",
|
||||
"nanoscroller": "^0.8.7",
|
||||
"primeng": "^2.0.5",
|
||||
"run-sequence": "^1.2.2",
|
||||
"rxjs": "^5.0.3",
|
||||
"systemjs": "^0.19.41",
|
||||
"systemjs-builder": "^0.15.34",
|
||||
"tether": "^1.4.0",
|
||||
"typescript": "^2.2.1",
|
||||
"zone.js": "^0.8.5",
|
||||
"bootstrap": "3.3.6"
|
||||
}
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
System.import('/app/config.js').then((module: any) => {
|
||||
var config = module.config.systemJS;
|
||||
System.config({
|
||||
baseURL: '/lib',
|
||||
packages: {
|
||||
'.': {
|
||||
defaultExtension: 'js'
|
||||
}
|
||||
},
|
||||
map: { app: '../app' }
|
||||
})
|
||||
|
||||
if (config.bundle) {
|
||||
System.import('bundle').then(() => {
|
||||
System.import('/app/main');
|
||||
})
|
||||
} else {
|
||||
System.import('/app/main')
|
||||
}
|
||||
});
|
|
@ -1,20 +0,0 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"target": "es5",
|
||||
"lib": [ "es5", "es2015" ],
|
||||
"module": "commonjs",
|
||||
"moduleResolution": "node",
|
||||
"sourceMap": true,
|
||||
"strictNullChecks": true,
|
||||
"noUnusedLocals": true,
|
||||
"noImplicitThis": true,
|
||||
"noImplicitReturns": true,
|
||||
"noImplicitAny": true,
|
||||
"suppressImplicitAnyIndexErrors": true,
|
||||
"alwaysStrict": true,
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"skipLibCheck": true
|
||||
},
|
||||
"compileOnSave": true
|
||||
}
|
55
appveyor.yml
55
appveyor.yml
|
@ -1,56 +1,21 @@
|
|||
version: 3.0.{build}
|
||||
version: 2.2.{build}
|
||||
configuration: Release
|
||||
os: Visual Studio 2015 Preview
|
||||
assembly_info:
|
||||
patch: true
|
||||
file: '**\AssemblyInfo.*'
|
||||
assembly_version: '3.0.0'
|
||||
assembly_version: '2.2.1'
|
||||
assembly_file_version: '{version}'
|
||||
assembly_informational_version: '3.0.0'
|
||||
assembly_informational_version: '2.2.1'
|
||||
before_build:
|
||||
- cmd: cd ombi/ombi
|
||||
- appveyor-retry dotnet restore
|
||||
- appveyor-retry npm install bower -g
|
||||
- appveyor-retry npm install -g gulp
|
||||
- appveyor-retry npm install -g typescript
|
||||
- appveyor-retry npm install
|
||||
- appveyor-retry bower install
|
||||
- gulp publish
|
||||
build_script:
|
||||
- dotnet build
|
||||
- cmd: appveyor-retry nuget restore
|
||||
build:
|
||||
verbosity: minimal
|
||||
after_build:
|
||||
- dotnet publish -c Release /p:AppRuntimeIdentifier=win10-x64
|
||||
- dotnet publish -c Release /p:AppRuntimeIdentifier=osx.10.12-x64
|
||||
- dotnet publish -c Release /p:AppRuntimeIdentifier=ubuntu.16.10-x64
|
||||
- dotnet publish -c Release /p:AppRuntimeIdentifier=debian.8-x64
|
||||
- cmd: >-
|
||||
7z a Ombi_windows.zip %APPVEYOR_BUILD_FOLDER%\Ombi\Ombi\bin\Release\netcoreapp1.1\win10-x64\publish
|
||||
|
||||
|
||||
7z a Ombi_osx.zip %APPVEYOR_BUILD_FOLDER%\Ombi\Ombi\bin\Release\netcoreapp1.1\osx.10.12-x64\publish
|
||||
|
||||
|
||||
7z a Ombi_ubuntu.zip %APPVEYOR_BUILD_FOLDER%\Ombi\Ombi\bin\Release\netcoreapp1.1\ubuntu.16.10-x64\publish
|
||||
|
||||
|
||||
7z a Ombi_debian.zip %APPVEYOR_BUILD_FOLDER%\Ombi\Ombi\bin\Release\netcoreapp1.1\debian.8-x64\publish
|
||||
7z a Ombi.zip %APPVEYOR_BUILD_FOLDER%\Ombi.UI\bin\Release\
|
||||
|
||||
appveyor PushArtifact Ombi.zip
|
||||
|
||||
appveyor PushArtifact Ombi_windows.zip
|
||||
|
||||
|
||||
appveyor PushArtifact Ombi_osx.zip
|
||||
|
||||
|
||||
appveyor PushArtifact Ombi_ubuntu.zip
|
||||
|
||||
|
||||
appveyor PushArtifact Ombi_debian.zip
|
||||
|
||||
|
||||
|
||||
cache:
|
||||
- '%USERPROFILE%\.nuget\packages'
|
||||
deploy:
|
||||
- provider: GitHub
|
||||
release: Ombi v$(appveyor_build_version)
|
||||
|
@ -59,3 +24,7 @@ deploy:
|
|||
draft: true
|
||||
on:
|
||||
branch: master
|
||||
- provider: Environment
|
||||
name: Microserver
|
||||
on:
|
||||
branch: dev
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue