Compare commits

..

No commits in common. "develop" and "v4.48.5" have entirely different histories.

17 changed files with 99 additions and 440 deletions

View file

@ -1,39 +1,3 @@
## [4.49.3](https://github.com/Ombi-app/Ombi/compare/v4.49.2...v4.49.3) (2025-08-17)
### Bug Fixes
* **plex-api:** update Plex Watchlist URL ([11fd7a5](https://github.com/Ombi-app/Ombi/commit/11fd7a5fc853da75974a16bf4fdecd72a836f54b))
## [4.49.2](https://github.com/Ombi-app/Ombi/compare/v4.49.1...v4.49.2) (2025-07-12)
### Performance Improvements
* **discover:** :zap: Improve the loading performance on the discover page ([97d5167](https://github.com/Ombi-app/Ombi/commit/97d5167db6c9f915021f32b96b281d7db3741d7f))
## [4.49.1](https://github.com/Ombi-app/Ombi/compare/v4.49.0...v4.49.1) (2025-07-12)
### Bug Fixes
* **auth:** Fixed an issue where refreshing the page as a power user would stop the application from loading [#5242](https://github.com/Ombi-app/Ombi/issues/5242) ([cee4014](https://github.com/Ombi-app/Ombi/commit/cee40146ee02f7fb79e2019d6fe2f9d5c5dbdfc8))
# [4.49.0](https://github.com/Ombi-app/Ombi/compare/v4.48.5...v4.49.0) (2025-07-11)
### Features
* Added the ability for the Watchlist to automatically refresh the users token. This will reduce the need for the user to log in ([067c029](https://github.com/Ombi-app/Ombi/commit/067c029f42e9fd853d060fdb2093013b15ac14c0))
## [4.48.5](https://github.com/Ombi-app/Ombi/compare/v4.48.4...v4.48.5) (2025-05-14) ## [4.48.5](https://github.com/Ombi-app/Ombi/compare/v4.48.4...v4.48.5) (2025-05-14)
@ -2211,3 +2175,35 @@
## [4.43.5](https://github.com/Ombi-app/Ombi/compare/v4.43.4...v4.43.5) (2023-08-24)
## [4.43.4](https://github.com/Ombi-app/Ombi/compare/v4.43.3...v4.43.4) (2023-07-28)
### Bug Fixes
* **user-importer:** Fixed not importing all correct users [#4989](https://github.com/Ombi-app/Ombi/issues/4989) ([34c32f8](https://github.com/Ombi-app/Ombi/commit/34c32f8338705ea3f790d95b91c9ada21a41b9f2))
## [4.43.3](https://github.com/Ombi-app/Ombi/compare/v4.43.2...v4.43.3) (2023-07-28)
### Bug Fixes
* switch back to the old plex friends API [#4989](https://github.com/Ombi-app/Ombi/issues/4989) ([c8ad12e](https://github.com/Ombi-app/Ombi/commit/c8ad12eb5f53889609d1793ae907afd33ba6ef38))
## [4.43.2](https://github.com/Ombi-app/Ombi/compare/v4.43.1...v4.43.2) (2023-07-19)
### Bug Fixes
* **plex-api:** Switch over to the new API to avoid deprecation & save… ([#4986](https://github.com/Ombi-app/Ombi/issues/4986)) ([2f2d35e](https://github.com/Ombi-app/Ombi/commit/2f2d35ec867a8e5488e368db294bd37bcf92d843))
* Remove old trending source ([#4987](https://github.com/Ombi-app/Ombi/issues/4987)) ([aacaa3e](https://github.com/Ombi-app/Ombi/commit/aacaa3e140b43f5d196da612f785cc4451717752))

View file

@ -122,10 +122,10 @@ Here are some of the features Ombi has:
</a> </a>
</td> </td>
<td align="center"> <td align="center">
<a href="https://github.com/AmyJeanes"> <a href="https://github.com/MattJeanes">
<img src="https://avatars.githubusercontent.com/u/2363642?v=4" width="50;" alt="AmyJeanes"/> <img src="https://avatars.githubusercontent.com/u/2363642?v=4" width="50;" alt="MattJeanes"/>
<br /> <br />
<sub><b>Amy Jeanes</b></sub> <sub><b>Matt Jeanes</b></sub>
</a> </a>
</td> </td>
<td align="center"> <td align="center">

View file

@ -29,6 +29,5 @@ namespace Ombi.Api.Plex
Task<PlexAddWrapper> AddUser(string emailAddress, string serverId, string authToken, int[] libs); Task<PlexAddWrapper> AddUser(string emailAddress, string serverId, string authToken, int[] libs);
Task<PlexWatchlistContainer> GetWatchlist(string plexToken, CancellationToken cancellationToken); Task<PlexWatchlistContainer> GetWatchlist(string plexToken, CancellationToken cancellationToken);
Task<PlexWatchlistMetadataContainer> GetWatchlistMetadata(string ratingKey, string plexToken, CancellationToken cancellationToken); Task<PlexWatchlistMetadataContainer> GetWatchlistMetadata(string ratingKey, string plexToken, CancellationToken cancellationToken);
Task<bool> Ping(string authToken, CancellationToken cancellationToken = default);
} }
} }

View file

@ -68,7 +68,7 @@ namespace Ombi.Api.Plex
private const string FriendsUri = "https://plex.tv/api/users"; private const string FriendsUri = "https://plex.tv/api/users";
private const string GetAccountUri = "https://plex.tv/users/account.json"; private const string GetAccountUri = "https://plex.tv/users/account.json";
private const string ServerUri = "https://plex.tv/pms/servers.xml"; private const string ServerUri = "https://plex.tv/pms/servers.xml";
private const string WatchlistUri = "https://discover.provider.plex.tv/"; private const string WatchlistUri = "https://metadata.provider.plex.tv/";
/// <summary> /// <summary>
/// Sign into the Plex API /// Sign into the Plex API
@ -320,30 +320,6 @@ namespace Ombi.Api.Plex
return result; return result;
} }
/// <summary>
/// Pings the Plex API to validate if a token is still valid
/// </summary>
/// <param name="authToken">The authentication token to validate</param>
/// <param name="cancellationToken">Cancellation token</param>
/// <returns>True if the token is valid, false otherwise</returns>
public async Task<bool> Ping(string authToken, CancellationToken cancellationToken = default)
{
try
{
var request = new Request("api/v2/ping", "https://plex.tv/", HttpMethod.Get);
await AddHeaders(request, authToken);
// We don't need to parse the response, just check if the request succeeds
await Api.Request(request, cancellationToken);
return true;
}
catch
{
// If the request fails (401, 403, etc.), the token is invalid
return false;
}
}
/// <summary> /// <summary>
/// Adds the required headers and also the authorization header /// Adds the required headers and also the authorization header

View file

@ -1,52 +0,0 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Ombi.Api.Plex;
namespace Ombi.Core.Authentication
{
public interface IPlexTokenKeepAliveService
{
Task<bool> KeepTokenAliveAsync(string token, CancellationToken cancellationToken);
}
public class PlexTokenKeepAliveService : IPlexTokenKeepAliveService
{
private readonly IPlexApi _plexApi;
private readonly ILogger<PlexTokenKeepAliveService> _logger;
public PlexTokenKeepAliveService(IPlexApi plexApi, ILogger<PlexTokenKeepAliveService> logger)
{
_plexApi = plexApi;
_logger = logger;
}
public async Task<bool> KeepTokenAliveAsync(string token, CancellationToken cancellationToken)
{
try
{
if (string.IsNullOrEmpty(token))
{
_logger.LogWarning("Token is null or empty");
return false;
}
// Use the Ping method to validate the token
var isValid = await _plexApi.Ping(token, cancellationToken);
if (!isValid)
{
_logger.LogWarning("Token validation failed - token may be expired or invalid");
}
return isValid;
}
catch (Exception ex)
{
_logger.LogError(ex, "Error occurred while keeping token alive");
return false;
}
}
}
}

View file

@ -107,7 +107,6 @@ namespace Ombi.DependencyInjection
services.AddTransient<IMusicSender, MusicSender>(); services.AddTransient<IMusicSender, MusicSender>();
services.AddTransient<IMassEmailSender, MassEmailSender>(); services.AddTransient<IMassEmailSender, MassEmailSender>();
services.AddTransient<IPlexOAuthManager, PlexOAuthManager>(); services.AddTransient<IPlexOAuthManager, PlexOAuthManager>();
services.AddTransient<IPlexTokenKeepAliveService, PlexTokenKeepAliveService>();
services.AddTransient<IVoteEngine, VoteEngine>(); services.AddTransient<IVoteEngine, VoteEngine>();
services.AddTransient<IDemoMovieSearchEngine, DemoMovieSearchEngine>(); services.AddTransient<IDemoMovieSearchEngine, DemoMovieSearchEngine>();
services.AddTransient<IDemoTvSearchEngine, DemoTvSearchEngine>(); services.AddTransient<IDemoTvSearchEngine, DemoTvSearchEngine>();

View file

@ -24,7 +24,6 @@ using Ombi.Notifications.Models;
using Ombi.Core.Notifications; using Ombi.Core.Notifications;
using Ombi.Helpers; using Ombi.Helpers;
using Ombi.Core; using Ombi.Core;
using Ombi.Core.Authentication;
namespace Ombi.Schedule.Tests namespace Ombi.Schedule.Tests
{ {
@ -44,8 +43,6 @@ namespace Ombi.Schedule.Tests
_mocker.Use(um); _mocker.Use(um);
_context = _mocker.GetMock<IJobExecutionContext>(); _context = _mocker.GetMock<IJobExecutionContext>();
_context.Setup(x => x.CancellationToken).Returns(CancellationToken.None); _context.Setup(x => x.CancellationToken).Returns(CancellationToken.None);
// Mock the keep-alive service to return true by default
_mocker.Use<IPlexTokenKeepAliveService>(Mock.Of<IPlexTokenKeepAliveService>(s => s.KeepTokenAliveAsync(It.IsAny<string>(), It.IsAny<CancellationToken>()) == Task.FromResult(true)));
_subject = _mocker.CreateInstance<PlexWatchlistImport>(); _subject = _mocker.CreateInstance<PlexWatchlistImport>();
_mocker.Setup<IRepository<PlexWatchlistUserError>, IQueryable<PlexWatchlistUserError>>(x => x.GetAll()).Returns(new List<PlexWatchlistUserError>().AsQueryable().BuildMock()); _mocker.Setup<IRepository<PlexWatchlistUserError>, IQueryable<PlexWatchlistUserError>>(x => x.GetAll()).Returns(new List<PlexWatchlistUserError>().AsQueryable().BuildMock());
_mocker.Setup<INotificationHelper>(x => x.Notify(It.IsAny<NotificationOptions>())); _mocker.Setup<INotificationHelper>(x => x.Notify(It.IsAny<NotificationOptions>()));
@ -841,43 +838,5 @@ namespace Ombi.Schedule.Tests
// Assert // Assert
_mocker.Verify<INotificationHelper>(x => x.Notify(It.IsAny<NotificationOptions>()), Times.Never); _mocker.Verify<INotificationHelper>(x => x.Notify(It.IsAny<NotificationOptions>()), Times.Never);
} }
[Test]
public async Task SkipsUserIfTokenKeepAliveFails()
{
// Arrange: Set up the keep-alive service to return false (token invalid/expired)
var keepAliveMock = new Mock<IPlexTokenKeepAliveService>();
keepAliveMock.Setup(x => x.KeepTokenAliveAsync(It.IsAny<string>(), It.IsAny<CancellationToken>())).ReturnsAsync(false);
_mocker.Use(keepAliveMock.Object);
_subject = _mocker.CreateInstance<PlexWatchlistImport>();
_mocker.Setup<ISettingsService<PlexSettings>, Task<PlexSettings>>(x => x.GetSettingsAsync()).ReturnsAsync(new PlexSettings { Enable = true, EnableWatchlistImport = true });
// Act
await _subject.Execute(_context.Object);
// Assert: Should not attempt to import watchlist if keep-alive fails
keepAliveMock.Verify(x => x.KeepTokenAliveAsync(It.IsAny<string>(), It.IsAny<CancellationToken>()), Times.Once);
_mocker.Verify<IPlexApi>(x => x.GetWatchlist(It.IsAny<string>(), It.IsAny<CancellationToken>()), Times.Never);
_mocker.Verify<INotificationHelper>(x => x.Notify(It.IsAny<NotificationOptions>()), Times.Never); // or Times.Once if notification is expected
}
[Test]
public async Task CallsKeepAliveForEachPlexUser()
{
// Arrange: Multiple Plex users
var users = new List<OmbiUser>
{
new OmbiUser { Id = "abc1", UserType = UserType.PlexUser, MediaServerToken = "abc1", UserName = "abc1", NormalizedUserName = "ABC1" },
new OmbiUser { Id = "abc2", UserType = UserType.PlexUser, MediaServerToken = "abc2", UserName = "abc2", NormalizedUserName = "ABC2" },
};
var um = MockHelper.MockUserManager(users);
_mocker.Use(um);
var keepAliveMock = new Mock<IPlexTokenKeepAliveService>();
keepAliveMock.Setup(x => x.KeepTokenAliveAsync(It.IsAny<string>(), It.IsAny<CancellationToken>())).ReturnsAsync(true);
_mocker.Use(keepAliveMock.Object);
_subject = _mocker.CreateInstance<PlexWatchlistImport>();
_mocker.Setup<ISettingsService<PlexSettings>, Task<PlexSettings>>(x => x.GetSettingsAsync()).ReturnsAsync(new PlexSettings { Enable = true, EnableWatchlistImport = true });
// Act
await _subject.Execute(_context.Object);
// Assert: KeepAlive should be called for each user
keepAliveMock.Verify(x => x.KeepTokenAliveAsync(It.IsAny<string>(), It.IsAny<CancellationToken>()), Times.Exactly(users.Count));
}
} }
} }

View file

@ -43,12 +43,11 @@ namespace Ombi.Schedule.Jobs.Plex
private readonly IRepository<PlexWatchlistUserError> _userError; private readonly IRepository<PlexWatchlistUserError> _userError;
private readonly IMovieDbApi _movieDbApi; private readonly IMovieDbApi _movieDbApi;
private readonly INotificationHelper _notificationHelper; private readonly INotificationHelper _notificationHelper;
private readonly IPlexTokenKeepAliveService _tokenKeepAliveService;
public PlexWatchlistImport(IPlexApi plexApi, ISettingsService<PlexSettings> settings, OmbiUserManager ombiUserManager, public PlexWatchlistImport(IPlexApi plexApi, ISettingsService<PlexSettings> settings, OmbiUserManager ombiUserManager,
IMovieRequestEngine movieRequestEngine, ITvRequestEngine tvRequestEngine, INotificationHubService notificationHubService, IMovieRequestEngine movieRequestEngine, ITvRequestEngine tvRequestEngine, INotificationHubService notificationHubService,
ILogger<PlexWatchlistImport> logger, IExternalRepository<PlexWatchlistHistory> watchlistRepo, IRepository<PlexWatchlistUserError> userError, ILogger<PlexWatchlistImport> logger, IExternalRepository<PlexWatchlistHistory> watchlistRepo, IRepository<PlexWatchlistUserError> userError,
IMovieDbApi movieDbApi, INotificationHelper notificationHelper, IPlexTokenKeepAliveService tokenKeepAliveService) IMovieDbApi movieDbApi, INotificationHelper notificationHelper)
{ {
_plexApi = plexApi; _plexApi = plexApi;
_settings = settings; _settings = settings;
@ -61,7 +60,6 @@ namespace Ombi.Schedule.Jobs.Plex
_userError = userError; _userError = userError;
_movieDbApi = movieDbApi; _movieDbApi = movieDbApi;
_notificationHelper = notificationHelper; _notificationHelper = notificationHelper;
_tokenKeepAliveService = tokenKeepAliveService;
} }
public async Task Execute(IJobExecutionContext context) public async Task Execute(IJobExecutionContext context)
@ -99,36 +97,6 @@ namespace Ombi.Schedule.Jobs.Plex
} }
_logger.LogDebug($"Starting Watchlist Import for {user.UserName} with token {user.MediaServerToken}"); _logger.LogDebug($"Starting Watchlist Import for {user.UserName} with token {user.MediaServerToken}");
// Keep the token alive before attempting watchlist import
var keepAliveSuccess = await _tokenKeepAliveService.KeepTokenAliveAsync(user.MediaServerToken, context?.CancellationToken ?? CancellationToken.None);
if (!keepAliveSuccess)
{
_logger.LogWarning($"Token for user '{user.UserName}' is invalid or expired (keep-alive failed). Recording error and skipping.");
await _userError.Add(new PlexWatchlistUserError
{
UserId = user.Id,
MediaServerToken = user.MediaServerToken,
});
// Send notification to user about token expiration
if (settings.NotifyOnWatchlistTokenExpiration && !string.IsNullOrEmpty(user.Email))
{
var notificationModel = new NotificationOptions
{
NotificationType = NotificationType.PlexWatchlistTokenExpired,
Recipient = user.Email,
DateTime = DateTime.Now,
Substitutes = new Dictionary<string, string>
{
{ "UserName", user.UserName }
}
};
await _notificationHelper.Notify(notificationModel);
}
continue;
}
var watchlist = await _plexApi.GetWatchlist(user.MediaServerToken, context?.CancellationToken ?? CancellationToken.None); var watchlist = await _plexApi.GetWatchlist(user.MediaServerToken, context?.CancellationToken ?? CancellationToken.None);
if (watchlist?.AuthError ?? false) if (watchlist?.AuthError ?? false)
{ {

View file

@ -5,17 +5,13 @@
<mat-button-toggle id="{{id}}Tv" [ngClass]="{'button-active': discoverOptions === DiscoverOption.Tv}" value="{{DiscoverOption.Tv}}" class="discover-filter-button">{{'Discovery.Tv' | translate}}</mat-button-toggle> <mat-button-toggle id="{{id}}Tv" [ngClass]="{'button-active': discoverOptions === DiscoverOption.Tv}" value="{{DiscoverOption.Tv}}" class="discover-filter-button">{{'Discovery.Tv' | translate}}</mat-button-toggle>
</mat-button-toggle-group> </mat-button-toggle-group>
</div> </div>
@defer (when discoverResults.length > 0; prefetch on idle) { @defer (when discoverResults.length > 0) {
<p-carousel #carousel [numVisible]="10" [numScroll]="10" [page]="0" [value]="discoverResults" [responsiveOptions]="responsiveOptions" (onPage)="newPage()"> <p-carousel #carousel [numVisible]="10" [numScroll]="10" [page]="0" [value]="discoverResults" [responsiveOptions]="responsiveOptions" (onPage)="newPage()">
<ng-template let-result pTemplate="item"> <ng-template let-result pTemplate="item">
<discover-card [discoverType]="discoverType" [isAdmin]="isAdmin" [result]="result" [is4kEnabled]="is4kEnabled"></discover-card> <discover-card [discoverType]="discoverType" [isAdmin]="isAdmin" [result]="result" [is4kEnabled]="is4kEnabled"></discover-card>
</ng-template> </ng-template>
</p-carousel> </p-carousel>
} }
@placeholder(minimum 300) { @placeholder(minimum 500) {
<div class="row loading-container"> <p-skeleton width="100%" height="18rem"></p-skeleton>
<div class="col-2" *ngFor="let item of [1,2,3,4,5,6,7,8,9,10]">
<p-skeleton width="100%" height="270px"></p-skeleton>
</div>
</div>
} }

View file

@ -105,30 +105,6 @@
padding: 5px; padding: 5px;
} }
.loading-container {
display: flex;
gap: 10px;
padding: 0 20px;
margin-top: 20px;
}
.loading-container .col-2 {
flex: 0 0 auto;
width: calc(10% - 9px);
}
@media (max-width: 768px) {
.loading-container .col-2 {
width: calc(50% - 5px);
}
}
@media (max-width: 480px) {
.loading-container .col-2 {
width: calc(100% - 0px);
}
}
@media (min-width:755px){ @media (min-width:755px){
::ng-deep .p-carousel-item{ ::ng-deep .p-carousel-item{
flex: 1 0 200px !important; flex: 1 0 200px !important;

View file

@ -43,7 +43,7 @@ export class CarouselListComponent implements OnInit {
get mediaTypeStorageKey() { get mediaTypeStorageKey() {
return "DiscoverOptions" + this.discoverType.toString(); return "DiscoverOptions" + this.discoverType.toString();
}; };
private amountToLoad = 10; private amountToLoad = 17;
private currentlyLoaded = 0; private currentlyLoaded = 0;
private baseUrl: string = ""; private baseUrl: string = "";
@ -148,7 +148,6 @@ export class CarouselListComponent implements OnInit {
} }
public async ngOnInit() { public async ngOnInit() {
this.is4kEnabled = this.featureFacade.is4kEnabled(); this.is4kEnabled = this.featureFacade.is4kEnabled();
this.currentlyLoaded = 0; this.currentlyLoaded = 0;
const localDiscoverOptions = +this.storageService.get(this.mediaTypeStorageKey); const localDiscoverOptions = +this.storageService.get(this.mediaTypeStorageKey);
@ -156,15 +155,11 @@ export class CarouselListComponent implements OnInit {
this.discoverOptions = DiscoverOption[DiscoverOption[localDiscoverOptions]]; this.discoverOptions = DiscoverOption[DiscoverOption[localDiscoverOptions]];
} }
// Load initial data - just enough to fill the first carousel page let currentIteration = 0;
// This reduces initial API calls and improves loading performance while (this.discoverResults.length <= 14 && currentIteration <= 3) {
await this.loadData(false); currentIteration++;
// If we don't have enough results to fill the carousel, load one more batch
if (this.discoverResults.length < 10) {
await this.loadData(false); await this.loadData(false);
} }
} }
public async toggleChanged(event: MatButtonToggleChange) { public async toggleChanged(event: MatButtonToggleChange) {

View file

@ -1,108 +1,46 @@
<div class="small-middle-container"> <div class="small-middle-container">
@defer (on viewport; prefetch on idle) { <div class="section">
<div class="section"> <h2 id="genreHeading" data-toggle="collapse" href="#genreCollapse" role="button">{{ 'Discovery.Genres' | translate }}</h2>
<h2 id="genreHeading" data-toggle="collapse" href="#genreCollapse" role="button">{{ 'Discovery.Genres' | translate }}</h2> <genre-button-select class="collapse show" id="genreCollapse"></genre-button-select>
<genre-button-select class="collapse show" id="genreCollapse"></genre-button-select> </div>
<div class="section">
<h2>{{ 'Discovery.RecentlyRequestedTab' | translate }}</h2>
<div>
<ombi-recently-list [id]="'recentlyRequested'"></ombi-recently-list>
</div> </div>
} @placeholder(minimum 300) { </div>
<div class="section">
<h2>{{ 'Discovery.Genres' | translate }}</h2>
<p-skeleton width="100%" height="60px"></p-skeleton>
</div>
}
@defer (on viewport; prefetch on idle) {
<div class="section">
<h2>{{ 'Discovery.RecentlyRequestedTab' | translate }}</h2>
<div>
<ombi-recently-list [id]="'recentlyRequested'"></ombi-recently-list>
</div>
</div>
} @placeholder(minimum 300) {
<div class="section">
<h2>{{ 'Discovery.RecentlyRequestedTab' | translate }}</h2>
<div class="row loading-container">
<div class="col-2" *ngFor="let item of [1,2,3,4,5]">
<p-skeleton width="100%" height="270px"></p-skeleton>
</div>
</div>
</div>
}
@defer (on viewport; prefetch on idle) { <div class="section" [hidden]="!showSeasonal">
<div class="section" [hidden]="!showSeasonal"> <h2>{{ 'Discovery.SeasonalTab' | translate }}</h2>
<h2>{{ 'Discovery.SeasonalTab' | translate }}</h2> <div>
<div> <carousel-list
<carousel-list [id]="'seasonal'"
[id]="'seasonal'" [isAdmin]="isAdmin"
[isAdmin]="isAdmin" [discoverType]="DiscoverType.Seasonal"
[discoverType]="DiscoverType.Seasonal" (movieCount)="setSeasonalMovieCount($event)"
(movieCount)="setSeasonalMovieCount($event)" ></carousel-list>
></carousel-list>
</div>
</div> </div>
} @placeholder(minimum 300) { </div>
<div class="section">
<h2>{{ 'Discovery.SeasonalTab' | translate }}</h2>
<div class="row loading-container">
<div class="col-2" *ngFor="let item of [1,2,3,4,5,6,7,8,9,10]">
<p-skeleton width="100%" height="270px"></p-skeleton>
</div>
</div>
</div>
}
@defer (on viewport; prefetch on idle) { <div class="section">
<div class="section"> <h2>{{ 'Discovery.PopularTab' | translate }}</h2>
<h2>{{ 'Discovery.PopularTab' | translate }}</h2> <div>
<div> <carousel-list [id]="'popular'" [isAdmin]="isAdmin" [discoverType]="DiscoverType.Popular"></carousel-list>
<carousel-list [id]="'popular'" [isAdmin]="isAdmin" [discoverType]="DiscoverType.Popular"></carousel-list>
</div>
</div> </div>
} @placeholder(minimum 300) { </div>
<div class="section">
<h2>{{ 'Discovery.PopularTab' | translate }}</h2>
<div class="row loading-container">
<div class="col-2" *ngFor="let item of [1,2,3,4,5,6,7,8,9,10]">
<p-skeleton width="100%" height="270px"></p-skeleton>
</div>
</div>
</div>
}
@defer (on viewport; prefetch on idle) { <div class="section">
<div class="section"> <h2>{{ 'Discovery.TrendingTab' | translate }}</h2>
<h2>{{ 'Discovery.TrendingTab' | translate }}</h2> <div>
<div> <carousel-list [id]="'trending'" [isAdmin]="isAdmin" [discoverType]="DiscoverType.Trending"></carousel-list>
<carousel-list [id]="'trending'" [isAdmin]="isAdmin" [discoverType]="DiscoverType.Trending"></carousel-list>
</div>
</div> </div>
} @placeholder(minimum 300) { </div>
<div class="section">
<h2>{{ 'Discovery.TrendingTab' | translate }}</h2>
<div class="row loading-container">
<div class="col-2" *ngFor="let item of [1,2,3,4,5,6,7,8,9,10]">
<p-skeleton width="100%" height="270px"></p-skeleton>
</div>
</div>
</div>
}
@defer (on viewport; prefetch on idle) { <div class="section">
<div class="section"> <h2>{{ 'Discovery.UpcomingTab' | translate }}</h2>
<h2>{{ 'Discovery.UpcomingTab' | translate }}</h2> <div>
<div> <carousel-list [id]="'upcoming'" [isAdmin]="isAdmin" [discoverType]="DiscoverType.Upcoming"></carousel-list>
<carousel-list [id]="'upcoming'" [isAdmin]="isAdmin" [discoverType]="DiscoverType.Upcoming"></carousel-list>
</div>
</div> </div>
} @placeholder(minimum 300) { </div>
<div class="section">
<h2>{{ 'Discovery.UpcomingTab' | translate }}</h2>
<div class="row loading-container">
<div class="col-2" *ngFor="let item of [1,2,3,4,5,6,7,8,9,10]">
<p-skeleton width="100%" height="270px"></p-skeleton>
</div>
</div>
</div>
}
</div> </div>

View file

@ -9,28 +9,4 @@ h2{
margin-top:40px; margin-top:40px;
margin-left:40px; margin-left:40px;
font-size: 24px; font-size: 24px;
}
.loading-container {
display: flex;
gap: 10px;
padding: 0 20px;
margin-top: 20px;
}
.loading-container .col-2 {
flex: 0 0 auto;
width: calc(10% - 9px);
}
@media (max-width: 768px) {
.loading-container .col-2 {
width: calc(50% - 5px);
}
}
@media (max-width: 480px) {
.loading-container .col-2 {
width: calc(100% - 0px);
}
} }

View file

@ -1,4 +1,4 @@
@defer (when requests(); prefetch on idle) { @defer (when requests()) {
<div *ngIf="requests().length > 0"> <div *ngIf="requests().length > 0">
<p-carousel #carousel [value]="requests()" [numVisible]="3" [numScroll]="1" <p-carousel #carousel [value]="requests()" [numVisible]="3" [numScroll]="1"
[responsiveOptions]="responsiveOptions" [page]="0"> [responsiveOptions]="responsiveOptions" [page]="0">
@ -13,9 +13,21 @@
</ng-template> </ng-template>
</p-carousel> </p-carousel>
</div> </div>
}@placeholder(minimum 300) { }@placeholder(minimum 500) {
<div class="row loading-container"> <div class="row loading-container">
<div class="col-2" *ngFor="let item of [1,2,3,4,5]"> <div class="col-2">
<p-skeleton width="100%" height="270px"></p-skeleton>
</div>
<div class="col-2">
<p-skeleton width="100%" height="270px"></p-skeleton>
</div>
<div class="col-2">
<p-skeleton width="100%" height="270px"></p-skeleton>
</div>
<div class="col-2">
<p-skeleton width="100%" height="270px"></p-skeleton>
</div>
<div class="col-2">
<p-skeleton width="100%" height="270px"></p-skeleton> <p-skeleton width="100%" height="270px"></p-skeleton>
</div> </div>
</div> </div>

View file

@ -105,32 +105,12 @@
padding: 5px; padding: 5px;
} }
.loading-container {
display: flex;
gap: 10px;
padding: 0 20px;
margin-top: 20px;
}
.loading-container .col-2 {
flex: 0 0 auto;
width: calc(20% - 8px);
}
@media (max-width: 768px) {
.loading-container .col-2 {
width: calc(50% - 5px);
}
}
@media (max-width: 480px) {
.loading-container .col-2 {
width: calc(100% - 0px);
}
}
@media (min-width:755px){ @media (min-width:755px){
::ng-deep .p-carousel-item{ ::ng-deep .p-carousel-item{
flex: 1 0 200px !important; flex: 1 0 200px !important;
} }
}
.loading-container {
margin-left: 10rem;
} }

View file

@ -40,6 +40,7 @@ namespace Ombi.Controllers.V1
/// <summary> /// <summary>
/// The Settings Controller /// The Settings Controller
/// </summary> /// </summary>
[Admin]
[ApiV1] [ApiV1]
[Produces("application/json")] [Produces("application/json")]
[ApiController] [ApiController]
@ -77,7 +78,6 @@ namespace Ombi.Controllers.V1
/// Gets the Ombi settings. /// Gets the Ombi settings.
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
[Admin]
[HttpGet("ombi")] [HttpGet("ombi")]
public async Task<OmbiSettings> OmbiSettings() public async Task<OmbiSettings> OmbiSettings()
{ {
@ -110,7 +110,6 @@ namespace Ombi.Controllers.V1
/// </summary> /// </summary>
/// <param name="ombi">The ombi.</param> /// <param name="ombi">The ombi.</param>
/// <returns></returns> /// <returns></returns>
[Admin]
[HttpPost("ombi")] [HttpPost("ombi")]
public async Task<bool> OmbiSettings([FromBody]OmbiSettings ombi) public async Task<bool> OmbiSettings([FromBody]OmbiSettings ombi)
{ {
@ -146,7 +145,6 @@ namespace Ombi.Controllers.V1
return model; return model;
} }
[Admin]
[HttpPost("ombi/resetApi")] [HttpPost("ombi/resetApi")]
public async Task<string> ResetApiKey() public async Task<string> ResetApiKey()
{ {
@ -161,7 +159,6 @@ namespace Ombi.Controllers.V1
/// Gets the Plex Settings. /// Gets the Plex Settings.
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
[Admin]
[HttpGet("plex")] [HttpGet("plex")]
public async Task<PlexSettings> PlexSettings() public async Task<PlexSettings> PlexSettings()
{ {
@ -188,7 +185,6 @@ namespace Ombi.Controllers.V1
/// </summary> /// </summary>
/// <param name="plex">The plex.</param> /// <param name="plex">The plex.</param>
/// <returns></returns> /// <returns></returns>
[Admin]
[HttpPost("plex")] [HttpPost("plex")]
public async Task<bool> PlexSettings([FromBody]PlexSettings plex) public async Task<bool> PlexSettings([FromBody]PlexSettings plex)
{ {
@ -211,7 +207,6 @@ namespace Ombi.Controllers.V1
/// Gets the Emby Settings. /// Gets the Emby Settings.
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
[Admin]
[HttpGet("emby")] [HttpGet("emby")]
public async Task<EmbySettings> EmbySettings() public async Task<EmbySettings> EmbySettings()
{ {
@ -223,7 +218,6 @@ namespace Ombi.Controllers.V1
/// </summary> /// </summary>
/// <param name="emby">The emby.</param> /// <param name="emby">The emby.</param>
/// <returns></returns> /// <returns></returns>
[Admin]
[HttpPost("emby")] [HttpPost("emby")]
public async Task<bool> EmbySettings([FromBody]EmbySettings emby) public async Task<bool> EmbySettings([FromBody]EmbySettings emby)
{ {
@ -249,7 +243,6 @@ namespace Ombi.Controllers.V1
/// Gets the Jellyfin Settings. /// Gets the Jellyfin Settings.
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
[Admin]
[HttpGet("jellyfin")] [HttpGet("jellyfin")]
public async Task<JellyfinSettings> JellyfinSettings() public async Task<JellyfinSettings> JellyfinSettings()
{ {
@ -261,7 +254,6 @@ namespace Ombi.Controllers.V1
/// </summary> /// </summary>
/// <param name="jellyfin">The jellyfin.</param> /// <param name="jellyfin">The jellyfin.</param>
/// <returns></returns> /// <returns></returns>
[Admin]
[HttpPost("jellyfin")] [HttpPost("jellyfin")]
public async Task<bool> JellyfinSettings([FromBody]JellyfinSettings jellyfin) public async Task<bool> JellyfinSettings([FromBody]JellyfinSettings jellyfin)
{ {
@ -299,7 +291,6 @@ namespace Ombi.Controllers.V1
/// </summary> /// </summary>
/// <param name="settings">The settings.</param> /// <param name="settings">The settings.</param>
/// <returns></returns> /// <returns></returns>
[Admin]
[HttpPost("landingpage")] [HttpPost("landingpage")]
public async Task<bool> LandingPageSettings([FromBody]LandingPageSettings settings) public async Task<bool> LandingPageSettings([FromBody]LandingPageSettings settings)
{ {
@ -335,7 +326,6 @@ namespace Ombi.Controllers.V1
/// </summary> /// </summary>
/// <param name="settings">The settings.</param> /// <param name="settings">The settings.</param>
/// <returns></returns> /// <returns></returns>
[Admin]
[HttpPost("customization")] [HttpPost("customization")]
public async Task<bool> CustomizationSettings([FromBody]CustomizationSettings settings) public async Task<bool> CustomizationSettings([FromBody]CustomizationSettings settings)
{ {
@ -354,7 +344,6 @@ namespace Ombi.Controllers.V1
/// Get's the preset themes available /// Get's the preset themes available
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
[Admin]
[HttpGet("themes")] [HttpGet("themes")]
public async Task<IEnumerable<PresetThemeViewModel>> GetThemes() public async Task<IEnumerable<PresetThemeViewModel>> GetThemes()
{ {
@ -400,7 +389,6 @@ namespace Ombi.Controllers.V1
/// <param name="settings">The settings.</param> /// <param name="settings">The settings.</param>
/// <returns></returns> /// <returns></returns>
[HttpPost("sonarr")] [HttpPost("sonarr")]
[Admin]
public async Task<bool> SonarrSettings([FromBody]SonarrSettings settings) public async Task<bool> SonarrSettings([FromBody]SonarrSettings settings)
{ {
var result = await Save(settings); var result = await Save(settings);
@ -430,7 +418,6 @@ namespace Ombi.Controllers.V1
/// Gets the Lidarr Settings. /// Gets the Lidarr Settings.
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
[Admin]
[HttpGet("lidarr")] [HttpGet("lidarr")]
public async Task<LidarrSettings> LidarrSettings() public async Task<LidarrSettings> LidarrSettings()
{ {
@ -454,7 +441,6 @@ namespace Ombi.Controllers.V1
/// </summary> /// </summary>
/// <param name="settings">The settings.</param> /// <param name="settings">The settings.</param>
/// <returns></returns> /// <returns></returns>
[Admin]
[HttpPost("lidarr")] [HttpPost("lidarr")]
public async Task<bool> LidarrSettings([FromBody]LidarrSettings settings) public async Task<bool> LidarrSettings([FromBody]LidarrSettings settings)
{ {
@ -471,7 +457,6 @@ namespace Ombi.Controllers.V1
/// </summary> /// </summary>
/// <param name="settings">The settings.</param> /// <param name="settings">The settings.</param>
/// <returns></returns> /// <returns></returns>
[Admin]
[HttpPost("authentication")] [HttpPost("authentication")]
public async Task<bool> AuthenticationsSettings([FromBody]AuthenticationSettings settings) public async Task<bool> AuthenticationsSettings([FromBody]AuthenticationSettings settings)
{ {
@ -494,7 +479,6 @@ namespace Ombi.Controllers.V1
/// </summary> /// </summary>
/// <param name="settings">The settings.</param> /// <param name="settings">The settings.</param>
/// <returns></returns> /// <returns></returns>
[Admin]
[HttpPost("radarr")] [HttpPost("radarr")]
public async Task<bool> RadarrSettings([FromBody]RadarrCombinedModel settings) public async Task<bool> RadarrSettings([FromBody]RadarrCombinedModel settings)
{ {
@ -516,7 +500,6 @@ namespace Ombi.Controllers.V1
/// </summary> /// </summary>
/// <param name="settings">The settings.</param> /// <param name="settings">The settings.</param>
/// <returns></returns> /// <returns></returns>
[Admin]
[HttpPost("Update")] [HttpPost("Update")]
public async Task<bool> UpdateSettings([FromBody]UpdateSettings settings) public async Task<bool> UpdateSettings([FromBody]UpdateSettings settings)
{ {
@ -527,7 +510,6 @@ namespace Ombi.Controllers.V1
/// Gets the UserManagement Settings. /// Gets the UserManagement Settings.
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
[Admin]
[HttpGet("UserManagement")] [HttpGet("UserManagement")]
public async Task<UserManagementSettings> UserManagementSettings() public async Task<UserManagementSettings> UserManagementSettings()
{ {
@ -539,7 +521,6 @@ namespace Ombi.Controllers.V1
/// </summary> /// </summary>
/// <param name="settings">The settings.</param> /// <param name="settings">The settings.</param>
/// <returns></returns> /// <returns></returns>
[Admin]
[HttpPost("UserManagement")] [HttpPost("UserManagement")]
public async Task<bool> UserManagementSettings([FromBody]UserManagementSettings settings) public async Task<bool> UserManagementSettings([FromBody]UserManagementSettings settings)
{ {
@ -550,7 +531,6 @@ namespace Ombi.Controllers.V1
/// Gets the Update Settings. /// Gets the Update Settings.
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
[Admin]
[HttpGet("Update")] [HttpGet("Update")]
public async Task<UpdateSettings> UpdateSettings() public async Task<UpdateSettings> UpdateSettings()
{ {
@ -563,7 +543,6 @@ namespace Ombi.Controllers.V1
/// Gets the CouchPotatoSettings Settings. /// Gets the CouchPotatoSettings Settings.
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
[Admin]
[HttpGet("CouchPotato")] [HttpGet("CouchPotato")]
public async Task<CouchPotatoSettings> CouchPotatoSettings() public async Task<CouchPotatoSettings> CouchPotatoSettings()
{ {
@ -575,7 +554,6 @@ namespace Ombi.Controllers.V1
/// </summary> /// </summary>
/// <param name="settings">The settings.</param> /// <param name="settings">The settings.</param>
/// <returns></returns> /// <returns></returns>
[Admin]
[HttpPost("CouchPotato")] [HttpPost("CouchPotato")]
public async Task<bool> CouchPotatoSettings([FromBody]CouchPotatoSettings settings) public async Task<bool> CouchPotatoSettings([FromBody]CouchPotatoSettings settings)
{ {
@ -586,7 +564,6 @@ namespace Ombi.Controllers.V1
/// Gets the DogNzbSettings Settings. /// Gets the DogNzbSettings Settings.
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
[Admin]
[HttpGet("DogNzb")] [HttpGet("DogNzb")]
public async Task<DogNzbSettings> DogNzbSettings() public async Task<DogNzbSettings> DogNzbSettings()
{ {
@ -598,7 +575,6 @@ namespace Ombi.Controllers.V1
/// </summary> /// </summary>
/// <param name="settings">The settings.</param> /// <param name="settings">The settings.</param>
/// <returns></returns> /// <returns></returns>
[Admin]
[HttpPost("DogNzb")] [HttpPost("DogNzb")]
public async Task<bool> DogNzbSettings([FromBody]DogNzbSettings settings) public async Task<bool> DogNzbSettings([FromBody]DogNzbSettings settings)
{ {
@ -610,7 +586,6 @@ namespace Ombi.Controllers.V1
/// </summary> /// </summary>
/// <param name="settings">The settings.</param> /// <param name="settings">The settings.</param>
/// <returns></returns> /// <returns></returns>
[Admin]
[HttpPost("SickRage")] [HttpPost("SickRage")]
public async Task<bool> SickRageSettings([FromBody]SickRageSettings settings) public async Task<bool> SickRageSettings([FromBody]SickRageSettings settings)
{ {
@ -621,7 +596,6 @@ namespace Ombi.Controllers.V1
/// Gets the SickRage Settings. /// Gets the SickRage Settings.
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
[Admin]
[HttpGet("SickRage")] [HttpGet("SickRage")]
public async Task<SickRageSettings> SickRageSettings() public async Task<SickRageSettings> SickRageSettings()
{ {
@ -632,7 +606,6 @@ namespace Ombi.Controllers.V1
/// Gets the JobSettings Settings. /// Gets the JobSettings Settings.
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
[Admin]
[HttpGet("jobs")] [HttpGet("jobs")]
public async Task<JobSettings> JobSettings() public async Task<JobSettings> JobSettings()
{ {
@ -665,7 +638,6 @@ namespace Ombi.Controllers.V1
/// </summary> /// </summary>
/// <param name="settings">The settings.</param> /// <param name="settings">The settings.</param>
/// <returns></returns> /// <returns></returns>
[Admin]
[HttpPost("jobs")] [HttpPost("jobs")]
public async Task<JobSettingsViewModel> JobSettings([FromBody]JobSettings settings) public async Task<JobSettingsViewModel> JobSettings([FromBody]JobSettings settings)
{ {
@ -709,7 +681,6 @@ namespace Ombi.Controllers.V1
} }
[HttpPost("testcron")] [HttpPost("testcron")]
[Admin]
public CronTestModel TestCron([FromBody] CronViewModelBody body) public CronTestModel TestCron([FromBody] CronViewModelBody body)
{ {
var model = new CronTestModel(); var model = new CronTestModel();
@ -743,7 +714,6 @@ namespace Ombi.Controllers.V1
/// <param name="settings">The settings.</param> /// <param name="settings">The settings.</param>
/// <returns></returns> /// <returns></returns>
[HttpPost("Issues")] [HttpPost("Issues")]
[Admin]
public async Task<bool> IssueSettings([FromBody]IssueSettings settings) public async Task<bool> IssueSettings([FromBody]IssueSettings settings)
{ {
return await Save(settings); return await Save(settings);
@ -774,7 +744,6 @@ namespace Ombi.Controllers.V1
/// <param name="settings">The settings.</param> /// <param name="settings">The settings.</param>
/// <returns></returns> /// <returns></returns>
[HttpPost("vote")] [HttpPost("vote")]
[Admin]
public async Task<bool> VoteSettings([FromBody]VoteSettings settings) public async Task<bool> VoteSettings([FromBody]VoteSettings settings)
{ {
return await Save(settings); return await Save(settings);
@ -785,7 +754,6 @@ namespace Ombi.Controllers.V1
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
[HttpGet("vote")] [HttpGet("vote")]
[Admin]
public async Task<VoteSettings> VoteSettings() public async Task<VoteSettings> VoteSettings()
{ {
return await Get<VoteSettings>(); return await Get<VoteSettings>();
@ -804,7 +772,6 @@ namespace Ombi.Controllers.V1
/// </summary> /// </summary>
/// <param name="settings">The settings.</param> /// <param name="settings">The settings.</param>
[HttpPost("themoviedb")] [HttpPost("themoviedb")]
[Admin]
public async Task<bool> TheMovieDbSettings([FromBody]TheMovieDbSettings settings) public async Task<bool> TheMovieDbSettings([FromBody]TheMovieDbSettings settings)
{ {
return await Save(settings); return await Save(settings);
@ -813,7 +780,6 @@ namespace Ombi.Controllers.V1
/// <summary> /// <summary>
/// Get The Movie DB settings. /// Get The Movie DB settings.
/// </summary> /// </summary>
[Admin]
[HttpGet("themoviedb")] [HttpGet("themoviedb")]
public async Task<TheMovieDbSettings> TheMovieDbSettings() public async Task<TheMovieDbSettings> TheMovieDbSettings()
{ {
@ -825,7 +791,6 @@ namespace Ombi.Controllers.V1
/// </summary> /// </summary>
/// <param name="model">The model.</param> /// <param name="model">The model.</param>
/// <returns></returns> /// <returns></returns>
[Admin]
[HttpPost("notifications/email")] [HttpPost("notifications/email")]
public async Task<bool> EmailNotificationSettings([FromBody] EmailNotificationsViewModel model) public async Task<bool> EmailNotificationSettings([FromBody] EmailNotificationsViewModel model)
{ {
@ -843,7 +808,6 @@ namespace Ombi.Controllers.V1
/// Gets the Email Notification Settings. /// Gets the Email Notification Settings.
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
[Admin]
[HttpGet("notifications/email")] [HttpGet("notifications/email")]
public async Task<EmailNotificationsViewModel> EmailNotificationSettings() public async Task<EmailNotificationsViewModel> EmailNotificationSettings()
{ {
@ -874,7 +838,6 @@ namespace Ombi.Controllers.V1
/// </summary> /// </summary>
/// <param name="model">The model.</param> /// <param name="model">The model.</param>
/// <returns></returns> /// <returns></returns>
[Admin]
[HttpPost("notifications/discord")] [HttpPost("notifications/discord")]
public async Task<bool> DiscordNotificationSettings([FromBody] DiscordNotificationsViewModel model) public async Task<bool> DiscordNotificationSettings([FromBody] DiscordNotificationsViewModel model)
{ {
@ -892,7 +855,6 @@ namespace Ombi.Controllers.V1
/// Gets the discord Notification Settings. /// Gets the discord Notification Settings.
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
[Admin]
[HttpGet("notifications/discord")] [HttpGet("notifications/discord")]
public async Task<DiscordNotificationsViewModel> DiscordNotificationSettings() public async Task<DiscordNotificationsViewModel> DiscordNotificationSettings()
{ {
@ -911,7 +873,6 @@ namespace Ombi.Controllers.V1
/// </summary> /// </summary>
/// <param name="model">The model.</param> /// <param name="model">The model.</param>
/// <returns></returns> /// <returns></returns>
[Admin]
[HttpPost("notifications/telegram")] [HttpPost("notifications/telegram")]
public async Task<bool> TelegramNotificationSettings([FromBody] TelegramNotificationsViewModel model) public async Task<bool> TelegramNotificationSettings([FromBody] TelegramNotificationsViewModel model)
{ {
@ -929,7 +890,6 @@ namespace Ombi.Controllers.V1
/// Gets the telegram Notification Settings. /// Gets the telegram Notification Settings.
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
[Admin]
[HttpGet("notifications/telegram")] [HttpGet("notifications/telegram")]
public async Task<TelegramNotificationsViewModel> TelegramNotificationSettings() public async Task<TelegramNotificationsViewModel> TelegramNotificationSettings()
{ {
@ -947,7 +907,6 @@ namespace Ombi.Controllers.V1
/// </summary> /// </summary>
/// <param name="model">The model.</param> /// <param name="model">The model.</param>
/// <returns></returns> /// <returns></returns>
[Admin]
[HttpPost("notifications/pushbullet")] [HttpPost("notifications/pushbullet")]
public async Task<bool> PushbulletNotificationSettings([FromBody] PushbulletNotificationViewModel model) public async Task<bool> PushbulletNotificationSettings([FromBody] PushbulletNotificationViewModel model)
{ {
@ -965,7 +924,6 @@ namespace Ombi.Controllers.V1
/// Gets the pushbullet Notification Settings. /// Gets the pushbullet Notification Settings.
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
[Admin]
[HttpGet("notifications/pushbullet")] [HttpGet("notifications/pushbullet")]
public async Task<PushbulletNotificationViewModel> PushbulletNotificationSettings() public async Task<PushbulletNotificationViewModel> PushbulletNotificationSettings()
{ {
@ -983,7 +941,6 @@ namespace Ombi.Controllers.V1
/// </summary> /// </summary>
/// <param name="model">The model.</param> /// <param name="model">The model.</param>
/// <returns></returns> /// <returns></returns>
[Admin]
[HttpPost("notifications/pushover")] [HttpPost("notifications/pushover")]
public async Task<bool> PushoverNotificationSettings([FromBody] PushoverNotificationViewModel model) public async Task<bool> PushoverNotificationSettings([FromBody] PushoverNotificationViewModel model)
{ {
@ -1001,7 +958,6 @@ namespace Ombi.Controllers.V1
/// Gets the pushover Notification Settings. /// Gets the pushover Notification Settings.
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
[Admin]
[HttpGet("notifications/pushover")] [HttpGet("notifications/pushover")]
public async Task<PushoverNotificationViewModel> PushoverNotificationSettings() public async Task<PushoverNotificationViewModel> PushoverNotificationSettings()
{ {
@ -1020,7 +976,6 @@ namespace Ombi.Controllers.V1
/// </summary> /// </summary>
/// <param name="model">The model.</param> /// <param name="model">The model.</param>
/// <returns></returns> /// <returns></returns>
[Admin]
[HttpPost("notifications/slack")] [HttpPost("notifications/slack")]
public async Task<bool> SlacktNotificationSettings([FromBody] SlackNotificationsViewModel model) public async Task<bool> SlacktNotificationSettings([FromBody] SlackNotificationsViewModel model)
{ {
@ -1038,7 +993,6 @@ namespace Ombi.Controllers.V1
/// Gets the slack Notification Settings. /// Gets the slack Notification Settings.
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
[Admin]
[HttpGet("notifications/slack")] [HttpGet("notifications/slack")]
public async Task<SlackNotificationsViewModel> SlackNotificationSettings() public async Task<SlackNotificationsViewModel> SlackNotificationSettings()
{ {
@ -1056,7 +1010,6 @@ namespace Ombi.Controllers.V1
/// </summary> /// </summary>
/// <param name="model">The model.</param> /// <param name="model">The model.</param>
/// <returns></returns> /// <returns></returns>
[Admin]
[HttpPost("notifications/mattermost")] [HttpPost("notifications/mattermost")]
public async Task<bool> MattermostNotificationSettings([FromBody] MattermostNotificationsViewModel model) public async Task<bool> MattermostNotificationSettings([FromBody] MattermostNotificationsViewModel model)
{ {
@ -1074,7 +1027,6 @@ namespace Ombi.Controllers.V1
/// Gets the Mattermost Notification Settings. /// Gets the Mattermost Notification Settings.
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
[Admin]
[HttpGet("notifications/mattermost")] [HttpGet("notifications/mattermost")]
public async Task<MattermostNotificationsViewModel> MattermostNotificationSettings() public async Task<MattermostNotificationsViewModel> MattermostNotificationSettings()
{ {
@ -1091,7 +1043,6 @@ namespace Ombi.Controllers.V1
/// Gets the Twilio Notification Settings. /// Gets the Twilio Notification Settings.
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
[Admin]
[HttpGet("notifications/twilio")] [HttpGet("notifications/twilio")]
public async Task<TwilioSettingsViewModel> TwilioNotificationSettings() public async Task<TwilioSettingsViewModel> TwilioNotificationSettings()
{ {
@ -1113,7 +1064,6 @@ namespace Ombi.Controllers.V1
/// </summary> /// </summary>
/// <param name="model">The model.</param> /// <param name="model">The model.</param>
/// <returns></returns> /// <returns></returns>
[Admin]
[HttpPost("notifications/twilio")] [HttpPost("notifications/twilio")]
public async Task<bool> TwilioNotificationSettings([FromBody] TwilioSettingsViewModel model) public async Task<bool> TwilioNotificationSettings([FromBody] TwilioSettingsViewModel model)
{ {
@ -1132,7 +1082,6 @@ namespace Ombi.Controllers.V1
/// </summary> /// </summary>
/// <param name="model">The model.</param> /// <param name="model">The model.</param>
/// <returns></returns> /// <returns></returns>
[Admin]
[HttpPost("notifications/mobile")] [HttpPost("notifications/mobile")]
public async Task<bool> MobileNotificationSettings([FromBody] MobileNotificationsViewModel model) public async Task<bool> MobileNotificationSettings([FromBody] MobileNotificationsViewModel model)
{ {
@ -1150,7 +1099,6 @@ namespace Ombi.Controllers.V1
/// Gets the Mobile Notification Settings. /// Gets the Mobile Notification Settings.
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
[Admin]
[HttpGet("notifications/mobile")] [HttpGet("notifications/mobile")]
public async Task<MobileNotificationsViewModel> MobileNotificationSettings() public async Task<MobileNotificationsViewModel> MobileNotificationSettings()
{ {
@ -1168,7 +1116,6 @@ namespace Ombi.Controllers.V1
/// </summary> /// </summary>
/// <param name="model">The model.</param> /// <param name="model">The model.</param>
/// <returns></returns> /// <returns></returns>
[Admin]
[HttpPost("notifications/gotify")] [HttpPost("notifications/gotify")]
public async Task<bool> GotifyNotificationSettings([FromBody] GotifyNotificationViewModel model) public async Task<bool> GotifyNotificationSettings([FromBody] GotifyNotificationViewModel model)
{ {
@ -1186,7 +1133,6 @@ namespace Ombi.Controllers.V1
/// Gets the gotify Notification Settings. /// Gets the gotify Notification Settings.
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
[Admin]
[HttpGet("notifications/gotify")] [HttpGet("notifications/gotify")]
public async Task<GotifyNotificationViewModel> GotifyNotificationSettings() public async Task<GotifyNotificationViewModel> GotifyNotificationSettings()
{ {
@ -1204,7 +1150,6 @@ namespace Ombi.Controllers.V1
/// </summary> /// </summary>
/// <param name="model">The model.</param> /// <param name="model">The model.</param>
/// <returns></returns> /// <returns></returns>
[Admin]
[HttpPost("notifications/webhook")] [HttpPost("notifications/webhook")]
public async Task<bool> WebhookNotificationSettings([FromBody] WebhookNotificationViewModel model) public async Task<bool> WebhookNotificationSettings([FromBody] WebhookNotificationViewModel model)
{ {
@ -1218,7 +1163,6 @@ namespace Ombi.Controllers.V1
/// Gets the webhook notification settings. /// Gets the webhook notification settings.
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
[Admin]
[HttpGet("notifications/webhook")] [HttpGet("notifications/webhook")]
public async Task<WebhookNotificationViewModel> WebhookNotificationSettings() public async Task<WebhookNotificationViewModel> WebhookNotificationSettings()
{ {
@ -1233,7 +1177,6 @@ namespace Ombi.Controllers.V1
/// </summary> /// </summary>
/// <param name="model">The model.</param> /// <param name="model">The model.</param>
/// <returns></returns> /// <returns></returns>
[Admin]
[HttpPost("notifications/newsletter")] [HttpPost("notifications/newsletter")]
public async Task<bool> NewsletterSettings([FromBody] NewsletterNotificationViewModel model) public async Task<bool> NewsletterSettings([FromBody] NewsletterNotificationViewModel model)
{ {
@ -1248,7 +1191,6 @@ namespace Ombi.Controllers.V1
} }
[ApiExplorerSettings(IgnoreApi = true)] [ApiExplorerSettings(IgnoreApi = true)]
[Admin]
[HttpPost("notifications/newsletterdatabase")] [HttpPost("notifications/newsletterdatabase")]
public async Task<bool> UpdateNewsletterDatabase() public async Task<bool> UpdateNewsletterDatabase()
{ {
@ -1259,7 +1201,6 @@ namespace Ombi.Controllers.V1
/// Gets the Newsletter Notification Settings. /// Gets the Newsletter Notification Settings.
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
[Admin]
[HttpGet("notifications/newsletter")] [HttpGet("notifications/newsletter")]
public async Task<NewsletterNotificationViewModel> NewsletterSettings() public async Task<NewsletterNotificationViewModel> NewsletterSettings()
{ {

View file

@ -1,3 +1,3 @@
{ {
"version": "4.49.3" "version": "4.48.5"
} }